Java MigLayout使用JScrollPane调整大小

Java MigLayout使用JScrollPane调整大小,java,swing,miglayout,Java,Swing,Miglayout,我搜索了一下,没有找到我问题的好答案 我正在开发一个可以调整大小的gui。它包含一个状态JTextArea,位于JScrollPane内。这就是我的问题。只要我不手动调整JFrame的大小,“初始”布局就保持不变,一切看起来都很好。一旦我手动调整大小(如果JTextArea已经处于滚动模式),布局就会变得混乱 下面是一个SSCCE(我去掉了大部分部分,同时保留了代码的结构。我希望这样更可读): 布局基本上发生在initComponents()中 查看问题: 启动应用程序(我使用了miglayou

我搜索了一下,没有找到我问题的好答案

我正在开发一个可以调整大小的gui。它包含一个状态
JTextArea
,位于
JScrollPane
内。这就是我的问题。只要我不手动调整JFrame的大小,“初始”布局就保持不变,一切看起来都很好。一旦我手动调整大小(如果
JTextArea
已经处于滚动模式),布局就会变得混乱

下面是一个SSCCE(我去掉了大部分部分,同时保留了代码的结构。我希望这样更可读):

布局基本上发生在
initComponents()

查看问题:

  • 启动应用程序(我使用了miglayout-4.0-swing.jar)
  • 稍等一下(不要调整窗口大小),直到有足够的消息在状态文本区域中创建滚动条
  • 这就是我想要的。
    JTextArea
    一直到JFrame的底部,必要时可以滚动
  • 现在调整窗口的大小。正如你所看到的,一切都变得一团糟。只有在窗口最大化的情况下,它才是好的
  • 这里有两个截图。第一个是我想要的: 第二个是在调整大小之后:

    我的问题:有人能告诉我,在调整大小之前,我是如何保持布局不变的吗?我想让
    JTextArea
    一直到窗口底部。如有必要,应显示滚动条。如果窗口太小(因为配置面板的高度固定),则状态面板只能位于窗口底部下方

    我希望我说清楚了。如果没有,请询问。)

    编辑:如果删除顶部的JScrollPanel(保存所有组件的面板),您可以看到我想要的行为。换衣服

    JScrollPane contentScrollPane = new JScrollPane(mainPanel);
    contentScrollPane.setBorder(BorderFactory.createEmptyBorder());
    setContentPane(contentScrollPane);
    


    明白我的意思。不幸的是,如果窗口很小,我会用这种方法松开滚动条。

    initComponents
    方法中向
    mainPanel
    添加大小限制。例如:

        mainPanel.setMinimumSize(new Dimension(400, 400));
        mainPanel.setPreferredSize(new Dimension(400, 400));
        mainPanel.setMaximumSize(new Dimension(400, 400));
    

    关注您的状态区域并使用嵌套布局将产生如下所示的结果。特别注意到

    • 使用
      invokeLater()
      在EDT上构建GUI
    • 使用
      javax.swing.Timer
      更新EDT上的GUI
    • 使用
      pack()
      使窗口适合其子组件的首选大小和布局
    • 使用
      DefaultCaret
      的更新策略控制滚动
    • 避免在公共访问器中进行不必要的惰性实例化
    • 避免;明智地覆盖
      getXxxSize()
    • 批判性地检查扩展
      JFrame
      的决定


    嗯,我可以这样做,但是我必须为窗口大小调整创建一个侦听器,并将约束设置为可用的窗口大小。此外,这将导致小窗户的混乱(因此,我的固定尺寸配置面板无法完全安装在
    JFrame
    中……我认为一定有一种方法可以完全通过布局来实现这一点。但感谢您的贡献,我也考虑过这一点,它对我来说似乎非常混乱。我可能不理解,但我认为您不需要一个听众。这个想法是j要指定一个你想要滚动窗格出现的大小。这里我取了400×400,但是如果你认为它太小/大,你可以改变它。你也可以用你的子组件的大小和它来设置它。是的,那将用最小的尺寸来工作,但是我的问题。(从第二个屏幕截图中可以看出,状态面板在调整大小时向下扩展了很多)仍然存在。哇,非常感谢所有的输入。我从未真正“学会”如何正确地编写大规模gui,因此这对我有很大帮助。:)关于“批判性地检查扩展JFrame的决定”:在我的应用程序中,我有几个选项卡(扩展了JPanel,我刚刚更改了这个SSCCE的选项卡)位于一个JFrame(扩展)中。我在这个扩展的JFrame中有很多方法,比如
    addPlotData()
    setSelectionList()
    和类似的东西,控制gui显示的内容。是否最好使用某种类型的
    GuiManager
    类来保存这个JFrame并执行所有操作?或者首选的方法是什么?哦,你说的“避免公共访问器中不必要的惰性实例化”是什么意思?您的主类具有-a
    JFrame
    ;除非它重写的
    JFrame
    方法,否则它可能不是is-a
    JFrame
    。如果(xPanel==null),则有多个方法启动
    if
    ;我不明白它们为什么受到保护。我之所以对它们进行保护,是因为我不需要它们在这个类之外。但我需要它们在子类中(例如更改边框)。
    setContentPane(mainPanel);
    
        mainPanel.setMinimumSize(new Dimension(400, 400));
        mainPanel.setPreferredSize(new Dimension(400, 400));
        mainPanel.setMaximumSize(new Dimension(400, 400));
    
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.BorderFactory;
    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JSeparator;
    import javax.swing.JTabbedPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.Timer;
    import javax.swing.border.TitledBorder;
    import javax.swing.text.DefaultCaret;
    
    public class Tab extends JFrame {
    
        private JTextArea messageTextArea;
        private JPanel optionPanel, messagePanel;
        private JTabbedPane plotTabPane;
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
    
                    final Tab tab = new Tab();
                    tab.setVisible(true);
                    Timer t = new Timer(200, new ActionListener() {
    
                        int count = 0;
    
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            tab.printRawMessage("testMessage" + count++);
                        }
                    });
                    t.start();
                }
            });
        }
    
        public Tab() {
            initComponents();
        }
    
        private void initComponents() {
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel mainPanel = new JPanel(new GridLayout(1, 0));
            Box leftPanel = new Box(BoxLayout.Y_AXIS);
            leftPanel.add(getLeftTopPanel());
            leftPanel.add(getMessagePanel());
            mainPanel.add(leftPanel);
            mainPanel.add(getRightPanel());
            this.add(mainPanel);
            this.pack();
            this.setLocationRelativeTo(null);
        }
    
        protected JPanel getLeftTopPanel() {
            optionPanel = new JPanel();
            optionPanel.setBorder(BorderFactory.createTitledBorder(null,
                "Configuration", TitledBorder.LEFT, TitledBorder.TOP,
                new Font("null", Font.BOLD, 12), Color.BLUE));
            JLabel label = new JLabel("Choose");
            label.setHorizontalAlignment(JLabel.RIGHT);
            optionPanel.add(label);
            optionPanel.add(new JSeparator(JSeparator.VERTICAL));
            optionPanel.add(new JComboBox(
                new String[]{"option1", "option2", "option3"}));
            optionPanel.add(new JLabel("Type"));
            optionPanel.add(new JTextField("3"));
            return optionPanel;
        }
    
        protected JTabbedPane getRightPanel() {
            plotTabPane = new JTabbedPane();
            plotTabPane.add("Tab1", new JPanel());
            plotTabPane.add("Tab2", new JPanel());
            return plotTabPane;
        }
    
        protected JPanel getMessagePanel() {
            messagePanel = new JPanel(new GridLayout());
            messagePanel.setBorder(BorderFactory.createTitledBorder(null,
                "Status Console", TitledBorder.LEFT, TitledBorder.TOP,
                new Font("null", Font.BOLD, 12), Color.BLUE));
            final JScrollPane sp = new JScrollPane(getMessageTextArea());
            sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            messagePanel.add(sp);
            return messagePanel;
        }
    
        protected JTextArea getMessageTextArea() {
            messageTextArea = new JTextArea("", 10, 19);
            messageTextArea.setEditable(false);
            messageTextArea.setFont(new Font(null, Font.PLAIN, 20));
            messageTextArea.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
            DefaultCaret caret = (DefaultCaret) messageTextArea.getCaret();
            caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
            return messageTextArea;
        }
    
        public void printRawMessage(String rawMessage) {
            messageTextArea.append(rawMessage + "\n");
        }
    }