GridBagLayout:如何使用首选宽度水平垂直填充
GridBagLayout: how to fill vertically using preferred width horizontally
我在尝试在 JPanel
中垂直填充 JScrollPane
(其中包含 JTable
)时遇到问题:不应水平填充面板,相反,JScrollPane
应该只取 "necessary" space.
我正在使用在 SO 上找到的一些代码根据其内容设置 table 首选宽度(我也覆盖了 JTable
的 getPreferredScrollableViewportSize
方法)。
这是我想要实现的截图:
JPanel
更宽,因为在我的应用程序中它将成为 CardLayout
的一部分,因此其他卡片的宽度和高度将决定此面板的大小(在下面的代码中我覆盖了getPreferredSize
方便的方法,但我不想使用它)。
这个结果可以用下面的代码实现,你只需要改变这行代码:
Object [][] data = new Object [100][1];
至:
Object [][] data = new Object [10][1];
问题是当JTable
有更多行时,在这种情况下会出现垂直滚动条,但滚动窗格会"shrink":
这是我正在使用的代码:
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
大小的情况下使用 table 的首选宽度?
编辑
我的代码非常少,因为我发现我的问题与 table 列的数量无关。但是我的真实程序必须处理更多列和大量行(在许多情况下为一百万或更多)。
A JList
是我的第一次尝试,因为我喜欢我可以使用原型值的方式,但是加载数据太慢(也可以在运行时更新),所有 GUI冻结了超过 200 000 行,这也是因为我使用的是自定义渲染器。
此外,我已经尝试使用 BorderLayout
,但我真的希望滚动窗格的高度能够填满我的面板,我尝试了不同的解决方案,但仍然无法解决。
EDIT2
正如@camickr 所建议的,我可以为我的面板使用 BorderLayout,在 BorderLayout.WEST 处添加滚动窗格以垂直填充面板,而不占用所有水平 space。这是目前最好的解决方案,但这会导致水平居中对齐丢失。有什么想法吗?
(in the code below i'm overriding getPreferredSize method for convenience, but i don't want to use it
我同意。摆脱覆盖。
降低框架高度时出现的绘制问题是因为 GridBagLayout 会在组件不足时以其最小尺寸绘制组件 space。
所以,虽然一般来说我不喜欢使用任何一套???硬编码大小的方法如下:
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));
你的排版问题是你的GridBagConstraints
(尤其是fill
and weightx
)造成的
这阻止了 scrollPane
使用可用的水平 space.
而不是
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);
然后它看起来像这样:
我在尝试在 JPanel
中垂直填充 JScrollPane
(其中包含 JTable
)时遇到问题:不应水平填充面板,相反,JScrollPane
应该只取 "necessary" space.
我正在使用在 SO 上找到的一些代码根据其内容设置 table 首选宽度(我也覆盖了 JTable
的 getPreferredScrollableViewportSize
方法)。
这是我想要实现的截图:
JPanel
更宽,因为在我的应用程序中它将成为 CardLayout
的一部分,因此其他卡片的宽度和高度将决定此面板的大小(在下面的代码中我覆盖了getPreferredSize
方便的方法,但我不想使用它)。
这个结果可以用下面的代码实现,你只需要改变这行代码:
Object [][] data = new Object [100][1];
至:
Object [][] data = new Object [10][1];
问题是当JTable
有更多行时,在这种情况下会出现垂直滚动条,但滚动窗格会"shrink":
这是我正在使用的代码:
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
大小的情况下使用 table 的首选宽度?
编辑
我的代码非常少,因为我发现我的问题与 table 列的数量无关。但是我的真实程序必须处理更多列和大量行(在许多情况下为一百万或更多)。
A JList
是我的第一次尝试,因为我喜欢我可以使用原型值的方式,但是加载数据太慢(也可以在运行时更新),所有 GUI冻结了超过 200 000 行,这也是因为我使用的是自定义渲染器。
此外,我已经尝试使用 BorderLayout
,但我真的希望滚动窗格的高度能够填满我的面板,我尝试了不同的解决方案,但仍然无法解决。
EDIT2
正如@camickr 所建议的,我可以为我的面板使用 BorderLayout,在 BorderLayout.WEST 处添加滚动窗格以垂直填充面板,而不占用所有水平 space。这是目前最好的解决方案,但这会导致水平居中对齐丢失。有什么想法吗?
(in the code below i'm overriding getPreferredSize method for convenience, but i don't want to use it
我同意。摆脱覆盖。
降低框架高度时出现的绘制问题是因为 GridBagLayout 会在组件不足时以其最小尺寸绘制组件 space。
所以,虽然一般来说我不喜欢使用任何一套???硬编码大小的方法如下:
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));
你的排版问题是你的GridBagConstraints
(尤其是fill
and weightx
)造成的
这阻止了 scrollPane
使用可用的水平 space.
而不是
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);
然后它看起来像这样: