GridBagLayout:如何使用首选宽度水平垂直填充

时间:2017-10-23 09:36:16

标签: java swing jtable layout-manager gridbaglayout

我尝试在JScrollPane内垂直填充JTable(其中包含JPanel)时出现问题:该面板不应水平填充,而是{{1}应该只采取"必要的"空间。

我使用SO上的一些代码根据其内容设置表格首选宽度(我还覆盖了JScrollPane JTable方法。

这是我想要实现的截图:

enter image description here

getPreferredScrollableViewportSize更宽,因为在我的应用程序中它将成为JPanel的一部分,因此其他卡片的宽度和高度将决定此面板大小(在下面的代码中,我将覆盖方便的CardLayout方法,但我不想使用它。)

使用下面的代码可以实现这个结果,你只需要改变这行代码:

getPreferredSize

为:

Object [][] data = new Object [100][1];

问题是当Object [][] data = new Object [10][1]; 有更多行时,在这种情况下会出现垂直滚动条,但滚动窗格将会缩小":

enter image description here

这是我使用的代码:

JTable

如果我将import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.TableColumn; public class TableTest { public static void main (String [] a) { SwingUtilities.invokeLater (new Runnable () { @Override public void run () { createAndShowGUI (); } }); } private static void createAndShowGUI () { JFrame frame = new JFrame ("Table Test"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); frame.setContentPane (new MainPanel ()); frame.pack (); frame.setLocationRelativeTo (null); frame.setVisible (true); } } class MainPanel extends JPanel { private static int MAX_HEIGHT = 600; private static int MAX_WIDTH = 600; private JTable table; protected MainPanel () { super (new GridBagLayout ()); Object [][] data = new Object [100][1]; for (int i = 0; i < 10; i ++) data [i] = new String [] {"Some data ..."}; table = new JTable (data, new String [] {""}) { @Override public Dimension getPreferredScrollableViewportSize () { int width = 0; for (int column = 0; column < getColumnCount (); column ++) width += columnModel.getColumn (column).getPreferredWidth (); return new Dimension (Math.min (MAX_WIDTH, width), Math.min (MAX_HEIGHT, getRowHeight () * getRowCount ())); } }; table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF); table.setShowGrid (false); table.setTableHeader (null); resizeColumns (); JScrollPane scrollPane = new JScrollPane (table); scrollPane.setBackground (table.getBackground ()); scrollPane.getViewport ().setBackground (table.getBackground ()); // --- Adding components --- GridBagConstraints c = new GridBagConstraints (); c.fill = GridBagConstraints.VERTICAL; c.weightx = 0.0; c.weighty = 1.0; add (scrollPane, c); } @Override public Dimension getPreferredSize () { return new Dimension (500, 400); } protected void resizeColumns () { for (int column = 0; column < table.getColumnCount (); column ++) { TableColumn tableColumn = table.getColumnModel ().getColumn (column); int width = 0; for (int row = 0; row < table.getRowCount (); row ++) { width = Math.max (table.prepareRenderer (table.getCellRenderer (row, column), row, column).getPreferredSize ().width, width); } tableColumn.setPreferredWidth (width + table.getIntercellSpacing ().width); } } } 设置为c.fill并将GridBagConstraints.BOTH设置为任意正值,c.weightx将水平和垂直填充父面板。

如何在不手动设置JScrollPane大小的情况下使用表格的首选宽度?

修改

我的代码非常小,因为我看到我的问题与表列的数量无关。但我真正的程序必须处理更多的列,以及大量的行(在许多情况下是一百万或更多)。

JScrollPane是我的第一次尝试,因为我喜欢我可以使用原型值的方式,但加载数据的速度太慢(也可以在运行时更新),所有的GUI都冻结了超过20万行,也是因为我使用的是自定义渲染器。

此外,我已经尝试使用JList,但我真的希望滚动窗格高度填充我的面板,我尝试了不同的解决方案,但我仍然无法解决它。

EDIT2

正如@camickr建议的那样,我可以在我的面板上使用BorderLayout,在BorderLayout.WEST中添加滚动窗格,垂直填充面板,不占用所有水平空间。这是目前最好的解决方案,但这会导致水平中心对齐丢失。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

  

(在下面的代码中,我为了方便而重写了getPreferredSize方法,但我不想使用它

我同意。摆脱覆盖。

减小框架高度时的绘制问题是因为当没有足够的空间时,GridBagLayout将以最小尺寸绘制组件。

所以,虽然一般来说我不喜欢使用任何一套???硬编码大小的方法似乎有效:

scrollPane.setMinimumSize(scrollPane.getPreferredSize());

这将使滚动窗格宽度不会减小。

如果您不喜欢使用硬编码尺寸,可以使用Relative Layout。这很容易让您将组件居中。

然后基本代码是:

RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS);
rl.setFill( true );
setLayout(rl);

...

add(Box.createHorizontalGlue(), new Float(1));
add(scrollPane);
add(Box.createHorizontalGlue(), new Float(1));

答案 1 :(得分:1)

您的布局问题是由GridBagConstraints引起的(尤其是fillweightx) 这阻止了scrollPane使用可用的水平空间。

而不是

GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0.0;
c.weighty = 1.0;
add (scrollPane, c);

你应该使用

GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;  // !!
c.weightx = 1.0;                   // !!
c.weighty = 1.0;
add (scrollPane, c);

然后它会是这样的:

screenshot