【问题标题】:GridBagLayout - Height of one row causes the width of next row to changeGridBagLayout - 一行的高度导致下一行的宽度发生变化
【发布时间】:2012-05-17 10:43:39
【问题描述】:

我正在处理的 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);
    }

【问题讨论】:

  • 环绕是什么意思?我在 TA 中使用不同的文本多次运行您的代码,并且按钮总是在同一个地方。也许编辑您的帖子以添加您看到的问题的屏幕截图?
  • 刚刚添加了图片。如您所见,第五个控件在我降低框架高度后环绕。
  • 实际上我很困惑,因为你谈到了按钮包装,而它是包装的 ComboBox。我会尽快回复你

标签: java swing awt layout-manager gridbaglayout


【解决方案1】:

只需为Center and Bottom 分别添加一个JPanel 就可以了,所以直到你的JTextArea 你的GridBagLayout 将达到目的,然后主JPanelBorderLayout 就可以了.此外,将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();
            }           
        });
    }
}

这是添加更多行时的输出:

【讨论】:

    【解决方案2】:

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

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

    现在,我找到了几个解决方案:

    1. 添加contollerOuter 时,还要指定c.fill = GridBagConstraints.HORIZONTAL;(这是解决问题的最简单方法)
    2. 当您设置 JButton 的 preferredSize 时,还要强制它们的 minimumSize 为相同的值。
    3. 仅使用 GridBagLayout 来布局所有组件。 (这将是我的最爱)
    4. 将 FlowLayout 替换为带有 X_AXIS 的 BoxLayout。

    记住 GridBagConstraints 属性:

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

    【讨论】:

    • +1,我喜欢这个答案,只是不知道,今天好像我很懒,应该提到与设置大小有关的东西,然后我想,上帝知道OP在想什么:-),所以保持这个话题不变。
    • 感谢您的帮助。我会相应地修改代码。关于重用 GridBagConstraint,Oracle 网站上的提示是不要这样做,因为一些旧值可能会错误地被继承。问候。
    • @Peter 是的,这是真的。但是当您在同一“行”上布局多个组件时,我发现有时会很方便。但通常,我不会遇到这个问题,因为我在循环中使用相同的 GridBagConstraint 并从模型中获取值。你应该选择任何你觉得更舒服的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2015-01-21
    相关资源
    最近更新 更多