使用JScrollPane调整MigLayout大小

时间:2012-06-14 09:25:02

标签: java swing miglayout

我搜索了一下,但没有找到解决问题的好方法。

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

这是一个SSCCE(我在保留代码结构的同时摆脱了大部分部分。我希望它更具可读性):

import java.awt.Color;
import java.awt.Font;

import javax.swing.BorderFactory;
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.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;

import net.miginfocom.swing.MigLayout;

public class Tab extends JFrame {
  private static final long serialVersionUID = 1L;
  private JTextArea messageTextArea;
  private JPanel optionPanel, messagePanel;
  private JTabbedPane plotTabPane;

  public static void main(String[] args) {
    final Tab tab = new Tab();
    tab.setSize(1000, 600);
    tab.setVisible(true);
    new Thread(new Runnable() {
      @Override
      public void run() {
        int count = 0;
        tab.printRawMessage("start");
        while (true) {
          try {
            Thread.sleep(200);
          } catch (InterruptedException e) {}
          tab.printRawMessage("\ntestMessage" + count++);
        }
      }
    }).start();
  }

  public Tab() {
    super();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    initComponents();
  }

  private void initComponents() {
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new MigLayout("insets 0", "", ""));
    mainPanel.add(getLeftTopPanel(), "shrinky, top, w 450!");
    mainPanel.add(getRightPanel(), "spany 5, wrap, grow, pushx, wmin 400");
    mainPanel.add(getMessagePanel(), "pushy, growy, w 450!");

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

  protected JPanel getLeftTopPanel() {
    if (optionPanel == null) {
      optionPanel = new JPanel();
      optionPanel.setBorder(BorderFactory.createTitledBorder(null, "Configuration", TitledBorder.LEFT, TitledBorder.TOP, new Font("null", Font.BOLD, 12), Color.BLUE));
      optionPanel.setLayout(new MigLayout("insets 0", "", "top, align 50%"));

      JLabel label = new JLabel("Choose");
      label.setHorizontalAlignment(JLabel.RIGHT);
      optionPanel.add(label, "w 65!");
      optionPanel.add(new JSeparator(JSeparator.VERTICAL), "spany 5, growy, w 2!");
      optionPanel.add(new JComboBox(new String[] {"option1", "option2", "option3"}), "span, growx, wrap");

      optionPanel.add(new JLabel("Type"), "right");
      optionPanel.add(new JTextField("3"), "w 65!, split 2");
      optionPanel.add(new JLabel("Unit"), "wrap");

      optionPanel.add(new JLabel("Slide"), "right");
      optionPanel.add(new JSlider(0, 100), "span, growx, wrap");
    }
    return optionPanel;
  }

  protected JTabbedPane getRightPanel() {
    if (plotTabPane == null) {
      plotTabPane = new JTabbedPane();
      plotTabPane.add("Tab1", new JPanel());
      plotTabPane.add("Tab2", new JPanel());
    }
    return plotTabPane;
  }

  protected JPanel getMessagePanel() {
    if (messagePanel == null) {
      messagePanel = new JPanel();
      messagePanel.setBorder(BorderFactory.createTitledBorder(null, "Status Console", TitledBorder.LEFT, TitledBorder.TOP, new Font("null", Font.BOLD, 12), Color.BLUE));
      messagePanel.setLayout(new MigLayout("insets 0", "", "top, align 50%"));
      messagePanel.add(new JScrollPane(getMessageTextArea()), "push, grow");
    }
    return messagePanel;
  }

  protected JTextArea getMessageTextArea() {
    if (messageTextArea == null) {
      messageTextArea = new JTextArea();
      messageTextArea.setEditable(false);
      messageTextArea.setFont(new Font(null, Font.PLAIN, 20));
      messageTextArea.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
    }
    return messageTextArea;
  }

  public void printRawMessage(String rawMessage) {
    getMessageTextArea().append(rawMessage);
    getMessageTextArea().setCaretPosition(getMessageTextArea().getText().length());
  }
}

布局内容基本上发生在initComponents()

要查看问题:

  1. 启动应用程序(我使用了miglayout-4.0-swing.jar)。
  2. 等一下(不要调整窗口大小),直到有足够的消息在状态文本区域中创建滚动条。
  3. 现在这就是我想要的。 JTextArea一直到JFrame的底部,并在必要时滚动。
  4. 现在调整窗口大小。如你所见,一切都搞砸了。如果窗口最大化,它将会很好。
  5. 这是两个截图。第一个是我希望如何: Before resizing: good! 第二个是调整大小后: After resizing: bad!

    我的问题:有人可以告诉我,在调整大小之前我是如何保持布局的?我希望JTextArea一直到窗口底部。如果需要,滚动条应该出现。唯一的办法,状态面板可以低于窗口底部,如果窗口太小(因为配置面板有一个固定的高度)。

    我希望自己清楚明白。如果没有,请询​​问。 ;)

    编辑:如果删除顶部的JScrollPanel(包含所有组件的那个),您可以看到我想要的行为。只需改变

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

    setContentPane(mainPanel);
    

    看看我的意思。不幸的是,如果窗口非常小,我会松开滚动条。

2 个答案:

答案 0 :(得分:3)

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

  • 使用invokeLater()在EDT上构建GUI。
  • 使用javax.swing.Timer更新EDT上的GUI。
  • 使用pack()使窗口适合其子组件的首选大小和布局。
  • 使用DefaultCaret的更新政策来控制滚动。
  • 避免在公共访问者中进行不必要的懒惰实例化。
  • 避免setXxxSize();明智地覆盖getXxxSize()
  • 严格审查延长JFrame
  • 的决定

image

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");
    }
}

答案 1 :(得分:0)

mainPanel方法中为initComponents添加尺寸限制。例如:

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