GridBagLayout - 一行的高度会导致下一行的宽度发生变化

时间:2012-05-08 22:07:10

标签: java swing awt layout-manager gridbaglayout

我正在使用的UI显示一个面板,让用户可以选择一部电影并进行播放。有控件可以播放,暂停等。

布局看起来像我想要的样子。该面板使用GridBagLayout。第2行显示状态消息的文本区域,第3行显示带按钮和进度条的面板。

我遇到的问题是,当我在文本区域中有太多文本行时,第3行中的按钮会环绕。这与外框的高度无关。

第2行的高度影响第3行的宽度。我不明白这种行为。我想知道是否有人可以告诉我,我做错了什么以及如何解决它?我附上了代码。

在稍微不同的主题上,如果您正在查看代码,您是否还可以建议在最底部组件和最外面的面板之间留一个边距?

提前感谢您的帮助。

的问候,
彼得



    private static JButton CreateImageButton(String fileName) {
        JButton retVal = new JButton("xxx");
        return retVal;
    }

    public MoviePanel() {
        this.setLayout(new GridBagLayout());
        this.setBackground(Color.WHITE);

        JButton btnRefresh = CreateImageButton("refresh.png");
        GridBagConstraints c = new GridBagConstraints(); 
        c.gridx=0;
        c.gridy=0;
        c.fill = GridBagConstraints.NORTH;
        c.insets.left = 10; c.insets.right = 10; c.insets.top = 10;
        this.add(btnRefresh, c);

        JComboBox cbMovieList = new JComboBox();
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 0;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets.right = 10; c.insets.top = 10;
        c.weightx = 1.0;
        this.add(cbMovieList, c);

        JButton btnAuthorize = new JButton("Get Info");
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 1;
        c.anchor = GridBagConstraints.WEST;
        c.insets.top = 10;
        this.add(btnAuthorize, c);

        JTextArea txtInfo = new JTextArea();
        txtInfo.setFont( new Font("SansSerif", Font.BOLD, 12));
        txtInfo.setBackground(Color.cyan);
        // txtInfo.setText("abc\ndef");
        txtInfo.setText("abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyz");
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 2;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weighty = 1.0;
        c.insets.top = 10;

        this.add(txtInfo, c);

        JPanel controllerOuter = new JPanel();
        controllerOuter.setLayout(new BoxLayout(controllerOuter, BoxLayout.Y_AXIS));
        controllerOuter.setBorder(BorderFactory.createRaisedBevelBorder());

        FlowLayout controllerLayout = new FlowLayout(FlowLayout.CENTER);
        controllerLayout.setHgap(0);
        JPanel controller = new JPanel(controllerLayout);

        controller.setBorder(new EmptyBorder(10, 10, 10, 10));

        Dimension dim = new Dimension(60, 40);
        JButton btnPlay = CreateImageButton("play.png");
        btnPlay.setPreferredSize(dim);

        controller.add(btnPlay);
        JButton btnPause = CreateImageButton("pause.png");
        btnPause.setPreferredSize(dim);
        controller.add(btnPause);
        JButton btnStop = CreateImageButton("stop.png");
        btnStop.setPreferredSize(dim);
        controller.add(btnStop);
        JButton btnForward = CreateImageButton("forward.png");
        btnForward.setPreferredSize(dim);
        controller.add(btnForward);
        JComboBox cbAspectRatio = new JComboBox();
        cbAspectRatio.setPreferredSize(new Dimension(100, 40));
        cbAspectRatio.setBorder(new EmptyBorder(0, 10, 0, 0));
        controller.add(cbAspectRatio);

        controllerOuter.add(controller);

        JProgressBar pbProgress = new JProgressBar(0, 100);
        pbProgress.setPreferredSize(new Dimension(350, 40));
        pbProgress.setBorder(new EmptyBorder(0, 10, 10, 10));
        pbProgress.setValue(50);
        pbProgress.setString("50/100");
        pbProgress.setStringPainted(true);
        pbProgress.setForeground(Color.BLUE);
        pbProgress.setBorderPainted(true);
        controllerOuter.add(pbProgress);


        c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 3;
        c.gridwidth = 2;
        c.weightx = 1.0;
        this.add(controllerOuter, c);
    }

Here is the image

2 个答案:

答案 0 :(得分:4)

我在你的代码中看到了几件事:

  1. 你强制使用JButton的preferredSize。如果可能的话,我会删除它,因为这通常会比解决方案带来更多问题。如果你想强制使用preferredSize,你也应该注意设置最小和最大尺寸,否则你会得到像你正在观察的那样奇怪的行为
  2. 您使用BoxLayout显示控件。虽然这是完全可以接受的,但BoxLayout还依赖于最小/最大尺寸来执行您未设置的布局。
  3. 您使用imbricated布局。这也没关系,但为什么不只使用MoviePanel的GridBagLayout?
  4. 通常TextAreas包含在JScrollPane中,以防文本太大。你也可以在TextArea上设置LineWrap(true),这样它就不会在右边走得太远。通过在TextArea上设置行/列,您将定义其preferreSize(以防止它依赖于它包含的文本)。
  5. GridBagConstraints上,填充属性只能是:NONEVERTICALHORIZONTALBOTH(您对其中一个使用了VERTICAL) 。此外,不需要重新创建新实例,您可以反复重复使用相同的GridBagConstraint,当您为组件设置约束时,它将由LayoutManager自动克隆。
  6. 现在有了解决方案,我发现了几个:

    1. 添加contollerOuter时,还请指定c.fill = GridBagConstraints.HORIZONTAL;(这是解决问题的最简单方法)
    2. 当您设置JButtons的preferredSize时,也要将其minimumSize强制为相同的值。
    3. 仅使用GridBagLayout布局所有组件。 (这将是我最喜欢的)
    4. 使用X_AXIS将BoxLayout替换为FlowLayout。
    5. 重申GridBagConstraints属性:

      • gridx,gridy:指定位置
      • gridwidth,gridheight:指定colspan / rowspan
      • weightx,weighty:指定谁获得额外的水平/垂直空间以及比例
      • anchor:如果“单元格”大于组件
      • ,则指定具有“单元格”的组件的对齐方式
      • fill:指定组件是否应拉伸到单元格宽度/高度

答案 1 :(得分:3)

只需为JPanel添加一个Center and Bottom就行了,所以直到JTextArea GridBagLayout BorderLayout将服务于目的,之后{{1} MAIN JPanel会做的。此外,将JScrollPane添加到整个事物中可以减少其他领域所需的工作量。看看代码和输出:

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

public class JTextPaneExample extends JPanel
{
    private Icon info = UIManager.getIcon("OptionPane.informationIcon");
    private Icon error = UIManager.getIcon("OptionPane.errorIcon");

    private static JButton CreateImageButton(String fileName) {
        JButton retVal = new JButton("xxx");
        return retVal;
    }

    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("JTextPane Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setLayout(new BorderLayout());
        this.setBackground(Color.WHITE);

        JPanel centerPanel = new JPanel();
        centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        centerPanel.setLayout(new GridBagLayout());
        centerPanel.setBackground(Color.WHITE);
        JButton btnRefresh = CreateImageButton("refresh.png");
        GridBagConstraints c = new GridBagConstraints(); 
        c.gridx=0;
        c.gridy=0;
        c.fill = GridBagConstraints.NORTH;
        c.insets.left = 10; c.insets.right = 10; c.insets.top = 10;
        centerPanel.add(btnRefresh, c);

        JComboBox cbMovieList = new JComboBox();
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 0;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets.right = 10; c.insets.top = 10;
        c.weightx = 1.0;
        centerPanel.add(cbMovieList, c);

        JButton btnAuthorize = new JButton("Get Info");
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 1;
        c.anchor = GridBagConstraints.WEST;
        c.insets.top = 10;
        centerPanel.add(btnAuthorize, c);

        JTextArea txtInfo = new JTextArea();
        txtInfo.setFont( new Font("SansSerif", Font.BOLD, 12));
        txtInfo.setBackground(Color.cyan);
        // txtInfo.setText("abc\ndef");
        txtInfo.setText("abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyz");
        JScrollPane scroller = new JScrollPane();
        scroller.setViewportView(txtInfo);
        c = new GridBagConstraints();
        c.gridx = 1;
        c.gridy = 2;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weighty = 1.0;
        c.insets.top = 10;

        centerPanel.add(scroller, c);

        JPanel controllerOuter = new JPanel();
        controllerOuter.setLayout(new BoxLayout(controllerOuter, BoxLayout.Y_AXIS));
        controllerOuter.setBorder(BorderFactory.createRaisedBevelBorder());

        FlowLayout controllerLayout = new FlowLayout(FlowLayout.CENTER);
        controllerLayout.setHgap(0);
        JPanel controller = new JPanel(controllerLayout);

        controller.setBorder(new EmptyBorder(10, 10, 10, 10));

        Dimension dim = new Dimension(60, 40);
        JButton btnPlay = CreateImageButton("play.png");
        btnPlay.setPreferredSize(dim);

        controller.add(btnPlay);
        JButton btnPause = CreateImageButton("pause.png");
        btnPause.setPreferredSize(dim);
        controller.add(btnPause);
        JButton btnStop = CreateImageButton("stop.png");
        btnStop.setPreferredSize(dim);
        controller.add(btnStop);
        JButton btnForward = CreateImageButton("forward.png");
        btnForward.setPreferredSize(dim);
        controller.add(btnForward);
        JComboBox cbAspectRatio = new JComboBox();
        cbAspectRatio.setPreferredSize(new Dimension(100, 40));
        cbAspectRatio.setBorder(new EmptyBorder(0, 10, 0, 0));
        controller.add(cbAspectRatio);

        controllerOuter.add(controller);

        JProgressBar pbProgress = new JProgressBar(0, 100);
        pbProgress.setPreferredSize(new Dimension(350, 40));
        pbProgress.setBorder(new EmptyBorder(0, 10, 10, 10));
        pbProgress.setValue(50);
        pbProgress.setString("50/100");
        pbProgress.setStringPainted(true);
        pbProgress.setForeground(Color.BLUE);
        pbProgress.setBorderPainted(true);
        controllerOuter.add(pbProgress);

        add(centerPanel, BorderLayout.CENTER);
        add(controllerOuter, BorderLayout.PAGE_END);

        frame.getContentPane().add(this);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new JTextPaneExample().createAndDisplayGUI();
            }           
        });
    }
}

添加更多行时输出如下:

LAYOUT