java - 创建类似 Inspector 的东西时 JScrollPane 和 GridBagLayout 出现问题

标签 java swing jscrollpane gridbaglayout inspector

我正在为我的程序创建类似检查器面板的东西,因此我可以在运行时轻松更改一些变量。

当您运行下面的代码时,您应该看到如下内容: inspector screenshot

有几件事困扰着我,但我仍然无法使它们正常工作。

  1. 项目与中心垂直对齐...我尝试将锚定到北方,但它保持不变。在下面的示例代码中,注释掉一行可以解决此问题:inspector.finish(),但该解决方案对我来说似乎有点老套。它的工作原理是添加空的 JPanel 作为面板上的最后一项,充当某种垂直粘合剂来扩展下部区域并将组件向上推。我不喜欢这个,因为使用这个解决方案,我无法再在运行时向检查器添加更多项目。
  2. 如果您向检查器添加更多项目(您可以通过更改用一些测试数据填充检查器的 n 变量来做到这一点),滚动条将不会显示,并且所有较低的项目都会显示即使它全部包裹在 JScrollPane 内,也超出了屏幕...我尝试了几种方法来解决此问题,但没有一个能正常工作。其中之一是将 JPanel 的 PreferredSize 设置为某些硬编码尺寸,但我不喜欢这样做,因为我不知道面板的确切大小。
  3. 当您按下一些微调器按钮,然后单击组合框(标题为“选择我”)时,选项将隐藏在下面的按钮后面。这看起来像是某种 z 排序问题。也许这是 swing 中的错误,不知道。
  4. 当您将窗口垂直调整为较小尺寸时,顶部的项目将开始缩小,而不是保持相同的尺寸。是否有任何选项可以将它们始终设置为恒定高度?

也许我使用了错误的布局管理器,但我不知道该选择哪一个。我正在考虑简单的网格布局,但这不允许我做一些事情,比如让一些行包含一个项目,其他行包含多个项目,这样它们将始终使用行的整个宽度“容量”。

示例代码:

import java.awt.*;
import javax.swing.*;

public class Test {

    // Setup test scenario
    public Test() {

        // Create window
        JFrame f = new JFrame();
        f.setLayout(new BorderLayout());
        f.setSize(800, 600);
        f.setTitle("Inspector");
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        // Create panel which will be used for the inspector
        JPanel p = new JPanel();
        p.setPreferredSize(new Dimension(200, 0));

        // Encapsulate it to the scroll panel so it can grow vertically
        JScrollPane sp = new JScrollPane();
        sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        sp.setViewportView(p);

        // Create the inspector inside panel p
        Inspector inspector = new Inspector(p);

        // Fill the inspector with some test data
        int n = 3;
        for (int i = 0; i < n; ++i) {
            inspector.addTitle("Title");
            inspector.addButton("push me");
            inspector.addCheckBox("check me");
            inspector.addSpinner("Spin me");
            inspector.addTextField("Edit me", "here");
            inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
            inspector.addSeparator();
        }
        //inspector.finish();

        // The inspector will be on the right side of the window
        f.getContentPane().add(sp, BorderLayout.LINE_END);

        // Show the window
        f.setVisible(true);
    }

    // Main method
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }

    // Inspector class itself
    private class Inspector {

        private final JPanel panel;
        private final GridBagConstraints constraints;
        private int itemsCount = 0;

        public Inspector(JPanel p) {
            panel = p;
            panel.setLayout(new GridBagLayout());

            constraints = new GridBagConstraints();
            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.weightx = 0.5;
        }

        // Adds component which will span across whole row
        private void addComponent(Component component) {
            constraints.gridx = 0;
            constraints.gridwidth = 2;
            constraints.gridy = itemsCount;

            panel.add(component, constraints);

            itemsCount++;
        }

        // Adds descriptive label on the left and component on the right side of the row
        private void addNamedComponent(String description, Component component) {
            constraints.gridx = 0;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 1;
            panel.add(new JLabel(description), constraints);

            constraints.gridx = 1;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 1;
            panel.add(component, constraints);

            itemsCount++;
        }

        public void addSeparator() {
            // (little hacky)
            addComponent(new JPanel());
        }

        public void addTitle(String title) {
            addComponent(new JLabel(title));
        }

        public void addButton(String actionName) {
            addComponent(new Button(actionName));
        }

        public void addCheckBox(String description) {
            addNamedComponent(description, new JCheckBox());
        }

        public void addSpinner(String description) {
            addNamedComponent(description, new JSpinner());
        }

        public void addTextField(String description, String text) {
            addNamedComponent(description, new JTextField(text));
        }

        public void addComboBox(String description, String[] options) {
            JComboBox<String> comboBox = new JComboBox<>();
            ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
            comboBox.setModel(model);

            addNamedComponent(description, comboBox);
        }

        public void finish() {
            constraints.gridx = 0;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 2;
            constraints.weighty = 1.0;

            panel.add(new JPanel(), constraints);
        }
    }
}

最佳答案

无法向上或向下滚动的原因是您将 sp 的首选大小设置为 200x0。您需要删除此行。

p.setPreferredSize(new Dimension(200, 0));

至于所有内容都集中而不是顶部的问题。我更愿意将 p 保留为默认的 FlowLayout 并为每个“部分”提供它自己的面板,并使该面板成为 GridBagLayout。通过这样做,您可能不再需要 addSeparator() 了。

public class Test {

    // Setup test scenario
    public Test() {

        // Create window
        JFrame f = new JFrame();
        f.setLayout(new BorderLayout());
        f.setSize(800, 600);
        f.setTitle("Inspector");
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        // Create panel which will be used for the inspector
        JPanel p = new JPanel();

        // Encapsulate it to the scroll panel so it can grow vertically
        JScrollPane sp = new JScrollPane();
        sp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        sp.setViewportView(p);

        // Create the inspector inside panel p
        Inspector inspector = new Inspector(p);

        // Fill the inspector with some test data
        int n = 2;
        for (int i = 0; i < n; ++i) {
            inspector.addTitle("Title");
            inspector.addButton("push me");
            inspector.addCheckBox("check me");
            inspector.addSpinner("Spin me");
            inspector.addTextField("Edit me", "here");
            inspector.addComboBox("Choose one", new String[]{"A", "B", "C"});
        }

        // The inspector will be on the right side of the window
        f.getContentPane().add(sp, BorderLayout.LINE_END);

        // Show the window
        f.setVisible(true);
    }

    // Main method
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }

    // Inspector class itself
    private class Inspector {

        private final JPanel panel;
        private final GridBagConstraints constraints;
        private int itemsCount = 0;

        public Inspector(JPanel p) {
            panel = new JPanel();
            p.add(panel);
            panel.setLayout(new GridBagLayout());

            constraints = new GridBagConstraints();
            constraints.fill = GridBagConstraints.HORIZONTAL;
            constraints.weightx = 1.0;
        }

        // Adds component which will span across whole row
        private void addComponent(Component component) {
            constraints.gridx = 0;
            constraints.gridwidth = 2;
            constraints.gridy = itemsCount;

            panel.add(component, constraints);

            itemsCount++;
        }

        // Adds descriptive label on the left and component on the right side of the row
        private void addNamedComponent(String description, Component component) {
            constraints.gridx = 0;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 1;
            panel.add(new JLabel(description), constraints);

            constraints.gridx = 1;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 1;
            panel.add(component, constraints);

            itemsCount++;
        }

        public void addSeparator() {
            // (little hacky)
            addComponent(new JPanel());
        }

        public void addTitle(String title) {
            addComponent(new JLabel(title));
        }

        public void addButton(String actionName) {
            addComponent(new Button(actionName));
        }

        public void addCheckBox(String description) {
            addNamedComponent(description, new JCheckBox());
        }

        public void addSpinner(String description) {
            addNamedComponent(description, new JSpinner());
        }

        public void addTextField(String description, String text) {
            addNamedComponent(description, new JTextField(text));
        }

        public void addComboBox(String description, String[] options) {
            JComboBox<String> comboBox = new JComboBox<>();
            ComboBoxModel<String> model = new DefaultComboBoxModel<>(options);
            comboBox.setModel(model);

            addNamedComponent(description, comboBox);
        }

        public void finish() {
            constraints.gridx = 0;
            constraints.gridy = itemsCount;
            constraints.gridwidth = 2;
            constraints.weighty = 1.0;

            panel.add(new JPanel(), constraints);
        }
    }
}

关于java - 创建类似 Inspector 的东西时 JScrollPane 和 GridBagLayout 出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38840148/

相关文章:

java - 为什么是 ItemSkippedException?

java - 项目中的TopComponent(模块)加载顺序

Java swing 页眉和页脚背景颜色

jquery - jscrollpane 在 firefox 中不起作用,在 chrome 中起作用

java - 尝试使用 Maven 将 war 部署到 tomcat 时得到 403

java - 如何通过 SnowSQL 或 Java 函数将十六进制 'F933F177' 转换为十进制 -114.036361?

java - 使用 ScrollPane java 的动态按钮

java - JPanel 左侧的 JTextArea

java - 为什么这个 do while 循环无限运行?

Java MouseListener MouseClicked 只能工作一次