Swing:垂直堆叠组件,无需 MigLayout

发布于 2024-11-15 12:50:10 字数 3935 浏览 1 评论 0原文

我终于得到了我想要的垂直堆叠组件的行为,这些组件具有随时间变化的首选高度。但我需要使用 MigLayout。

有没有办法不用 MigLayout 来做到这一点? (这是针对一个库的,除非必须,否则我不想强制依赖)

这是我正在寻找的行为(我的测试程序实现了):

在此处输入图像描述

按垂直顺序,有一个调整大小按钮、“空白空间”(好吧,一个 JLabel 标记为这样)、一个红色矩形和一个绿色正方形。调整大小按钮具有固定高度。红色方块的大小是随机的,可以在任意时间改变。绿色方块设置其首选高度以匹配其宽度,我想扩展其宽度以填充容器。空白空间水平和垂直扩展以填充容器中的剩余空间。

什么可以代替 MigLayout?

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;

public class AutoResizeDemo extends JPanel
{   
    static private class ResizingPanel extends JPanel
    {
        final private Color color;

        private Dimension dpref = new Dimension(100,100);

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int w = getWidth();
            int h = getHeight();
            g.setColor(this.color);
            g.fillRect(0, 0, w, h);
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, w-1, h-1); 
            String s = this.dpref.width+"x"+this.dpref.height;
            FontMetrics fm = g.getFontMetrics();
            g.drawString(s, 0, fm.getHeight());
        }

        public ResizingPanel(Color color, boolean isSquare)
        {
            this.color = color;
            if (isSquare)
            {
                addComponentListener(new ComponentAdapter() {
                    @Override public void componentResized(ComponentEvent e) {
                        doResize(getWidth(), getWidth());
                    }               
                });
            }
        }

        @Override public Dimension getPreferredSize() {
            return this.dpref;
        } 

        public void doResize(int w, int h)
        {
            this.dpref = new Dimension(w, h);
            revalidate();
        }
    }

    public AutoResizeDemo()
    {
        super(new MigLayout("","[grow]",""));
        setPreferredSize(new Dimension(200, 800));

        final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
        ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
        JPanel buttonPanel = new JPanel(new FlowLayout());

        final Random rand = new Random();
        addButton(buttonPanel, "resize",new Runnable() {
            @Override public void run() {
                resizingPanelRandom.doResize(
                        rand.nextInt(100)+100,
                        rand.nextInt(100)+100
                        );
            }           
        });
        add(buttonPanel, "wrap");
        JLabel spaceLabel = new JLabel("empty space");
        spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(spaceLabel, "push, grow, wrap");
        add(resizingPanelRandom, "wrap");
        add(resizingPanelSquare,"pushx, growx, wrap");
    }

    private void addButton(JPanel panel, String title, final Runnable r) {
        JButton button = new JButton(title);
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                r.run();
            }           
        });
        panel.add(button);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame(AutoResizeDemo.class.getSimpleName());
        frame.setContentPane(new AutoResizeDemo());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

}

I finally got the behavior I want for vertically stacking components that have a preferred height that changes with time. But I needed to use MigLayout.

Is there a way to do this w/o MigLayout? (It's for a library and I don't want to force the dependency unless I have to)

Here's the behavior I'm looking for (which my test program achieves):

enter image description here

In vertical order, there's a resize button, "empty space" (well, a JLabel marked as such), a red rectangle, and a green square. The resize button has fixed height. The red square has a random size that can change at arbitrary times. The green square sets its preferred height to match its width, and I want to expand its width to fill the container. The empty space expands horizontally and vertically to fill the remaining space in the container.

What would work instead of MigLayout?

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;

public class AutoResizeDemo extends JPanel
{   
    static private class ResizingPanel extends JPanel
    {
        final private Color color;

        private Dimension dpref = new Dimension(100,100);

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int w = getWidth();
            int h = getHeight();
            g.setColor(this.color);
            g.fillRect(0, 0, w, h);
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, w-1, h-1); 
            String s = this.dpref.width+"x"+this.dpref.height;
            FontMetrics fm = g.getFontMetrics();
            g.drawString(s, 0, fm.getHeight());
        }

        public ResizingPanel(Color color, boolean isSquare)
        {
            this.color = color;
            if (isSquare)
            {
                addComponentListener(new ComponentAdapter() {
                    @Override public void componentResized(ComponentEvent e) {
                        doResize(getWidth(), getWidth());
                    }               
                });
            }
        }

        @Override public Dimension getPreferredSize() {
            return this.dpref;
        } 

        public void doResize(int w, int h)
        {
            this.dpref = new Dimension(w, h);
            revalidate();
        }
    }

    public AutoResizeDemo()
    {
        super(new MigLayout("","[grow]",""));
        setPreferredSize(new Dimension(200, 800));

        final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
        ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
        JPanel buttonPanel = new JPanel(new FlowLayout());

        final Random rand = new Random();
        addButton(buttonPanel, "resize",new Runnable() {
            @Override public void run() {
                resizingPanelRandom.doResize(
                        rand.nextInt(100)+100,
                        rand.nextInt(100)+100
                        );
            }           
        });
        add(buttonPanel, "wrap");
        JLabel spaceLabel = new JLabel("empty space");
        spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(spaceLabel, "push, grow, wrap");
        add(resizingPanelRandom, "wrap");
        add(resizingPanelSquare,"pushx, growx, wrap");
    }

    private void addButton(JPanel panel, String title, final Runnable r) {
        JButton button = new JButton(title);
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                r.run();
            }           
        });
        panel.add(button);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame(AutoResizeDemo.class.getSimpleName());
        frame.setContentPane(new AutoResizeDemo());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

櫻之舞 2024-11-22 12:50:11

使用 BoxLayout。

您可以使用 Box.createVerticalGlue() 作为空白空间。

BoxLayout 尊重组件的最大尺寸,因此您可能需要重写 getMaximumSize() 方法以返回红色和绿色框的首选尺寸。

对于绿色框,您还需要重写 getPreferredSize() 以保持高度与宽度同步。

Use a BoxLayout.

You would use Box.createVerticalGlue() for the empty space.

BoxLayout respects the maximum size of a component, so you would probably need to override the getMaximumSize() method to return the preferred size for the red and green boxes.

For the green box you would also need to Override getPreferredSize() to keep the height in sync with the width.

燃情 2024-11-22 12:50:11

您可以使用 SpringLayout 将所有组件连接在一起并连接到其容器的边缘来解决此问题。

按钮面板
按钮面板的左侧和顶部到容器面板的左侧和顶部

绿色面板
left、right、bottom到容器面板的left、right、bottom

Red Panel
容器面板从左到左以及绿色面板从下到上

空格标签
从上到南的按钮面板,从左到右到容器面板的左和右,从下到上的红色面板

编辑:喜欢 SpringLayout,它什么都做不了'不做。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;

public class AutoResizeDemo2 extends JPanel {
  static private class ResizingPanel extends JPanel {
    final private Color color;

    private Dimension dpref = new Dimension(100, 100);

    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      int w = getWidth();
      int h = getHeight();
      g.setColor(this.color);
      g.fillRect(0, 0, w, h);
      g.setColor(Color.BLACK);
      g.drawRect(0, 0, w - 1, h - 1);
      String s = this.dpref.width + "x" + this.dpref.height;
      FontMetrics fm = g.getFontMetrics();
      g.drawString(s, 0, fm.getHeight());
    }

    public ResizingPanel(Color color, boolean isSquare) {
      this.color = color;
      if (isSquare) {
        addComponentListener(new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
            doResize(getWidth(), getWidth());
          }
        });
      }
    }

    @Override
    public Dimension getPreferredSize() {
      return this.dpref;
    }

    public void doResize(int w, int h) {
      this.dpref = new Dimension(w, h);
      revalidate();
    }
  }

  public AutoResizeDemo2() {

    SpringLayout layout = new SpringLayout();
    setLayout(layout);

    setPreferredSize(new Dimension(200, 800));

    final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
    ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
    JPanel buttonPanel = new JPanel(new FlowLayout());

    final Random rand = new Random();
    addButton(buttonPanel, "resize", new Runnable() {
      @Override
      public void run() {
        resizingPanelRandom.doResize(rand.nextInt(100) + 100, rand.nextInt(100) + 100);
      }
    });
    add(buttonPanel);
    layout.putConstraint(SpringLayout.NORTH, buttonPanel, 5, SpringLayout.NORTH, this);
    layout.putConstraint(SpringLayout.WEST, buttonPanel, 5, SpringLayout.WEST, this);

    JLabel spaceLabel = new JLabel("empty space");
    spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

    add(resizingPanelSquare);
    layout.putConstraint(SpringLayout.SOUTH, resizingPanelSquare, -5, SpringLayout.SOUTH, this);
    layout.putConstraint(SpringLayout.WEST, resizingPanelSquare, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, resizingPanelSquare, -5, SpringLayout.EAST, this);

    add(resizingPanelRandom);
    layout.putConstraint(SpringLayout.SOUTH, resizingPanelRandom, -5, SpringLayout.NORTH, resizingPanelSquare);
    layout.putConstraint(SpringLayout.WEST, resizingPanelRandom, 5, SpringLayout.WEST, this);

    add(spaceLabel);
    layout.putConstraint(SpringLayout.NORTH, spaceLabel, 5, SpringLayout.SOUTH, buttonPanel);
    layout.putConstraint(SpringLayout.WEST, spaceLabel, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, spaceLabel, -5, SpringLayout.EAST, this);
    layout.putConstraint(SpringLayout.SOUTH, spaceLabel, -5, SpringLayout.NORTH, resizingPanelRandom);
  }

  private void addButton(JPanel panel, String title, final Runnable r) {
    JButton button = new JButton(title);
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        r.run();
      }
    });
    panel.add(button);
  }

  public static void main(String[] args) {
    JFrame frame = new JFrame(AutoResizeDemo2.class.getSimpleName());
    frame.setContentPane(new AutoResizeDemo2());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

  }

}

You can solve this using SpringLayout by wiring all your compenents together and to the edges of their container.

Button Panel
left and top of the button panel to left and top of the container panel

Green Panel
left, right and bottom to the left, right and bottom of the container panel

Red Panel
left to left of container panel and bottom to top of the green panel

Space Label
top to south of the button panel, left and right to left and right of the container panel, bottom to top of the red panel

Edit: I love SpringLayout, there's nothing it can't do.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;

public class AutoResizeDemo2 extends JPanel {
  static private class ResizingPanel extends JPanel {
    final private Color color;

    private Dimension dpref = new Dimension(100, 100);

    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      int w = getWidth();
      int h = getHeight();
      g.setColor(this.color);
      g.fillRect(0, 0, w, h);
      g.setColor(Color.BLACK);
      g.drawRect(0, 0, w - 1, h - 1);
      String s = this.dpref.width + "x" + this.dpref.height;
      FontMetrics fm = g.getFontMetrics();
      g.drawString(s, 0, fm.getHeight());
    }

    public ResizingPanel(Color color, boolean isSquare) {
      this.color = color;
      if (isSquare) {
        addComponentListener(new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
            doResize(getWidth(), getWidth());
          }
        });
      }
    }

    @Override
    public Dimension getPreferredSize() {
      return this.dpref;
    }

    public void doResize(int w, int h) {
      this.dpref = new Dimension(w, h);
      revalidate();
    }
  }

  public AutoResizeDemo2() {

    SpringLayout layout = new SpringLayout();
    setLayout(layout);

    setPreferredSize(new Dimension(200, 800));

    final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED, false);
    ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN, true);
    JPanel buttonPanel = new JPanel(new FlowLayout());

    final Random rand = new Random();
    addButton(buttonPanel, "resize", new Runnable() {
      @Override
      public void run() {
        resizingPanelRandom.doResize(rand.nextInt(100) + 100, rand.nextInt(100) + 100);
      }
    });
    add(buttonPanel);
    layout.putConstraint(SpringLayout.NORTH, buttonPanel, 5, SpringLayout.NORTH, this);
    layout.putConstraint(SpringLayout.WEST, buttonPanel, 5, SpringLayout.WEST, this);

    JLabel spaceLabel = new JLabel("empty space");
    spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

    add(resizingPanelSquare);
    layout.putConstraint(SpringLayout.SOUTH, resizingPanelSquare, -5, SpringLayout.SOUTH, this);
    layout.putConstraint(SpringLayout.WEST, resizingPanelSquare, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, resizingPanelSquare, -5, SpringLayout.EAST, this);

    add(resizingPanelRandom);
    layout.putConstraint(SpringLayout.SOUTH, resizingPanelRandom, -5, SpringLayout.NORTH, resizingPanelSquare);
    layout.putConstraint(SpringLayout.WEST, resizingPanelRandom, 5, SpringLayout.WEST, this);

    add(spaceLabel);
    layout.putConstraint(SpringLayout.NORTH, spaceLabel, 5, SpringLayout.SOUTH, buttonPanel);
    layout.putConstraint(SpringLayout.WEST, spaceLabel, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, spaceLabel, -5, SpringLayout.EAST, this);
    layout.putConstraint(SpringLayout.SOUTH, spaceLabel, -5, SpringLayout.NORTH, resizingPanelRandom);
  }

  private void addButton(JPanel panel, String title, final Runnable r) {
    JButton button = new JButton(title);
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        r.run();
      }
    });
    panel.add(button);
  }

  public static void main(String[] args) {
    JFrame frame = new JFrame(AutoResizeDemo2.class.getSimpleName());
    frame.setContentPane(new AutoResizeDemo2());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

  }

}
无风消散 2024-11-22 12:50:11

如果不进行大量分析,SpringLayout 很难确定它是如何布局的。尝试表格布局。布局中唯一棘手的部分是绿色方块的高度等于其宽度。对于布局管理器的支持来说,这有点不寻常,所以我只是对其进行特殊处理。一个可运行的示例:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.esotericsoftware.tablelayout.swing.Table;

public class Test extends JFrame {
    JButton button;
    JPanel red, green;

    public Test () {
        button = new JButton("Resize");
        button.addActionListener(new ActionListener() {
            public void actionPerformed (ActionEvent e) {
                red.setPreferredSize(new Dimension(138, new Random().nextInt(190) + 10));
                red.revalidate();
            }
        });

        red = new JPanel();
        red.setPreferredSize(new Dimension(138, 145));
        red.setBackground(Color.red);

        green = new JPanel();
        green.setPreferredSize(new Dimension(100, 100));
        green.setBackground(Color.green);

        // The DSL can be much easier to describe complex hierarchies.
        boolean dsl = false;
        if (dsl)
            dsl();
        else
            javaApi();

        setSize(160, 400);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void javaApi () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(), getWidth()));
                super.layout();
            }
        };
        table.pad(10).defaults().left().space(5);
        table.addCell(button);
        table.row();
        table.addCell().expandY();
        table.row();
        table.addCell(red);
        table.row();
        table.addCell(green).expandX().fillX();
        getContentPane().add(table);
    }

    private void dsl () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(), getWidth()));
                super.layout();
            }
        };
        table.register("button", button);
        table.register("red", red);
        table.register("green", green);
        table.parse("pad:10 * left space:5 " //
            + "[button] ---" //
            + "[] expandy ---" //
            + "[red] ---" //
            + "[green] expandx fillx" //
        );
        getContentPane().add(table);
    }

    public static void main (String[] args) throws Exception {
        new Test();
    }
}

基于表格,很容易一眼就了解布局。我包含了使用 Java API 和 DSL 的代码。 Java API 很好,因为您可以完成。这里只是布局代码:

table.pad(10).defaults().left().space(5);
table.addCell(button);
table.row();
table.addCell().expandY();
table.row();
table.addCell(red);
table.row();
table.addCell(green).expandX().fillX();

DSL 非常适合描述层次结构,但对于本例来说可能不是必需的。不幸的是,尽管可以在文件中描述大型 UI,但 Java 没有逐字字符串。此示例中不带 Java 字符串引号的 DSL 为:

pad:10 * left space:5
[button]
---
[] expandy
---
[red]
---
[green] expandx fillx

SpringLayout is difficult to determine how it is laid out without a lot of analyzing. Try TableLayout. The only tricky part of your layout is the green square's height being equal to its width. This is a bit unusual for a layout manager to support, so I would just special case it. A runnable example:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.esotericsoftware.tablelayout.swing.Table;

public class Test extends JFrame {
    JButton button;
    JPanel red, green;

    public Test () {
        button = new JButton("Resize");
        button.addActionListener(new ActionListener() {
            public void actionPerformed (ActionEvent e) {
                red.setPreferredSize(new Dimension(138, new Random().nextInt(190) + 10));
                red.revalidate();
            }
        });

        red = new JPanel();
        red.setPreferredSize(new Dimension(138, 145));
        red.setBackground(Color.red);

        green = new JPanel();
        green.setPreferredSize(new Dimension(100, 100));
        green.setBackground(Color.green);

        // The DSL can be much easier to describe complex hierarchies.
        boolean dsl = false;
        if (dsl)
            dsl();
        else
            javaApi();

        setSize(160, 400);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void javaApi () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(), getWidth()));
                super.layout();
            }
        };
        table.pad(10).defaults().left().space(5);
        table.addCell(button);
        table.row();
        table.addCell().expandY();
        table.row();
        table.addCell(red);
        table.row();
        table.addCell(green).expandX().fillX();
        getContentPane().add(table);
    }

    private void dsl () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(), getWidth()));
                super.layout();
            }
        };
        table.register("button", button);
        table.register("red", red);
        table.register("green", green);
        table.parse("pad:10 * left space:5 " //
            + "[button] ---" //
            + "[] expandy ---" //
            + "[red] ---" //
            + "[green] expandx fillx" //
        );
        getContentPane().add(table);
    }

    public static void main (String[] args) throws Exception {
        new Test();
    }
}

Being table based, it is easy to get an idea of the layout at a glance. I included code for using the Java API and also the DSL. The Java API is nice since you get completion. Here is just the layout code:

table.pad(10).defaults().left().space(5);
table.addCell(button);
table.row();
table.addCell().expandY();
table.row();
table.addCell(red);
table.row();
table.addCell(green).expandX().fillX();

The DSL is nice for describing hierarchies, probably not necessary for this example. Unfortunately Java doesn't have a verbatim string, though a large UI could be described in a file. The DSL for this example without the Java string quotes would be:

pad:10 * left space:5
[button]
---
[] expandy
---
[red]
---
[green] expandx fillx
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文