【问题标题】:Dynamic width and fixed height of rows in JPanelJPanel中行的动态宽度和固定高度
【发布时间】:2015-09-02 08:34:15
【问题描述】:

我正在尝试使用 Java 布局管理器(我没有外部库,并且正在使用 Java 7)来创建一个布局,其中数据按行提供,其中行具有固定高度,但宽度填充以适合窗户。下面提供一个示例:

这个想法是我将在应用程序的整个运行过程中添加行,并且每一行都将简单地添加到底部列表中。如果在窗口中添加了太多行,则会出现一个滚动条(我已经对那个部分进行了排序)。

到目前为止,我的问题是,如果我对主 JPanel 使用 GridLayout,它将使行填充到整个窗口,并且随着添加更多行而使每行变小。我希望这样无论添加多少行,行高都将始终保持不变。

每一行由两列组成,它们的宽度应该相同。因此,为此我相信 GridLayout 会很好地工作,但我认为我需要将 GridLayout 添加到另一个基本上代表整行的面板。

我最好使用 Swing 布局管理器来实现所需的布局,但如果提出其他建议,那么我一定会研究它们。正如许多人似乎在我所看到的其他问题中发现的那样,Java 的布局管理器似乎在某些方面有点缺乏,不幸的是我无法判断什么时候缺乏我的知识,而不是语言本身。

【问题讨论】:

  • JTable......?您也可以查看GridBagLayout,但我可能会建议来自 SwingLabs 的VerticalLayoutSwingX library
  • @MadProgrammer 我曾考虑过,但不确定以这种方式使用是否真的合适。因此,如果我要使用 JTable,我将有 2 列,然后继续添加行。那一点当然不会太麻烦,但是我需要任何有趣的 CellRenderers 实现等来确保行的内容正常工作吗?例如,我将使用的组件之一是 JTextArea,我是否需要做任何特别的事情来确保它正确显示和运行?
  • 好吧,您不会将JTextArea 添加到JTable,而是在模型中管理文本。如果需要能够编辑值,那可能会使事情变得复杂。您将获得的好处是 JTable 已针对处理大量行进行了优化
  • “在我看到的其他问题中似乎有很多人发现,Java 的布局管理器在某些方面似乎有点欠缺”程序员对如何使用布局来实现跨平台的可靠 GUI 缺乏了解,但我只是偶尔看到您所指的内容。
  • @AndrewThompson 哈哈哈,这正是我的意思,我严重怀疑这是语言方面的无能。我见过,但正如你所说,这种情况非常罕见。

标签: java swing jpanel jscrollpane layout-manager


【解决方案1】:

我的第一个建议是使用JTable,虽然它可能“看起来”很复杂,但 API 已经过优化,非常高效并可以处理数千行

如果这不能满足您的需求,如果您不想使用任何 3rd 方库,我会考虑使用 GridBagLayout,诀窍是知道如何操纵它们以达到您想要的结果,因为例如,以下使用三个面板,作为主视图的主“外部”面板和两个内部面板。一个用于保存内容,另一个用作填充物,因此内容始终被推送到视图的顶部。

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                TestPane tp = new TestPane();
                JButton add = new JButton("Add Row");
                add.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        tp.addRow();
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(tp));
                frame.add(add, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel implements Scrollable {

        private JPanel content;
        private JPanel filler;

        private GridBagConstraints masterConstraints;

        public TestPane() {

            content = new JPanel(new GridBagLayout());
            filler = new JPanel();

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            add(content, gbc);
            gbc.weighty = 1;
            add(filler, gbc);

            masterConstraints = new GridBagConstraints();
            masterConstraints.gridwidth = GridBagConstraints.REMAINDER;
            masterConstraints.weightx = 1;
            masterConstraints.fill = GridBagConstraints.HORIZONTAL;
        }

        public void addRow() {
            JLabel label = new JLabel("This is just a label, but technically, you can anythig you want");
            content.add(label, masterConstraints);
            revalidate();
            repaint();
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return new Dimension(200, 200);
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 64;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 64;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            Container parent = getParent();
            boolean trackWidth = false;
            if (parent instanceof JViewport) {
                trackWidth = parent.getHeight() > getPreferredSize().width;
            }
            return trackWidth;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            Container parent = getParent();
            boolean trackHeight = false;
            if (parent instanceof JViewport) {
                trackHeight = parent.getHeight() > getPreferredSize().height;
            }
            return trackHeight;
        }

    }

}

查看How to Use GridBagLayout了解更多详情

“但是,没有更简单的方法吗?”我听到你在问!好吧,您可以使用来自 SwingLabs 的 VerticalLayout SwingX library(或 JTable

【讨论】:

  • 这看起来很完美,我希望有一个 GridBag 解决方案,而您已经提供了。正如你所说,我将不得不处理该行的内容,我可以在那里放任何东西,这看起来不错。非常感谢您,非常感谢!
  • 很高兴能帮上忙 ;)
猜你喜欢
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-26
  • 2011-01-01
相关资源
最近更新 更多