2

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

这是图像

4

2 回答 2

4

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

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

现在对于解决方案,我发现了几个:

  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:指定谁获得额外的水平/垂直空间以及比例
  • 锚点:指定组件与其“单元格”的对齐方式,如果“单元格”大于组件
  • 填充:指定组件是否应拉伸到单元格宽度/高度
于 2012-05-09T10:34:22.337 回答
3

只需JPanel为每个添加一个Center and Bottom即可为您解决问题,因此直到您JTextAreaGridBagLayout意愿服务于目的,然后BorderLayoutMAINJPanel将完成。此外,对整体进行添加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();
            }           
        });
    }
}

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

布局

于 2012-05-09T10:31:39.007 回答