我有一个情况,我正在添加jpanel到FlowLayout,他们没有对齐到布局的底部。我使用这个layout.setAlignOnBaseline(true)
,它正确地将JLabels对齐到面板的底部。然而,一旦这些标签被包裹在面板中,它就不再起作用了。这里有一个例子,上面和下面有两个面板。
import javax.swing.*;
import java.awt.*;
public class BadLayout {
private static final Font font1 = new Font("Arial", Font.BOLD, 14);
private static final Font font2 = new Font("Arial", Font.BOLD, 30);
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Bad layout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 0, 0);
layout.setAlignOnBaseline(true);
JPanel topPanel = new JPanel();
topPanel.setLayout(layout);
topPanel.setBackground(Color.BLACK);
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Foo");
label.setForeground(Color.WHITE);
label.setBackground(Color.RED);
label.setOpaque(true);
label.setFont(i % 2 == 0 ? font1 : font2);
JPanel subPanel = new JPanel();
subPanel.setLayout(layout);
subPanel.setBackground(Color.RED);
subPanel.add(label);
subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT);
topPanel.add(subPanel);
}
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(layout);
bottomPanel.setBackground(Color.DARK_GRAY);
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Foo");
label.setForeground(Color.WHITE);
label.setBackground(Color.RED);
label.setOpaque(true);
label.setFont(i % 2 == 0 ? font1 : font2);
bottomPanel.add(label);
}
JPanel parentPanel = new JPanel();
parentPanel.setLayout(new BorderLayout());
parentPanel.add(topPanel, BorderLayout.NORTH);
parentPanel.add(bottomPanel, BorderLayout.SOUTH);
frame.getContentPane().add(parentPanel);
frame.pack();
frame.setVisible(true);
});
}
}
如果你运行这段代码,你会注意到顶部的面板有较小的"Foo"在面板的中心,而底部的面板有我希望的"底部对齐"行为。任何想法如何让子jpanel的行为相同?
setAlignOnBaseline(...)
方法的API状态:
没有基线的组件将居中
JPanel没有合理的基线,因为组件可以在多行上,这取决于所使用的布局管理器。它是居中的。
从你的问题中,我看不出你是真的想把所有的文本都放在基线的中心,不受字体大小的影响,还是只是想让所有的组件都画在面板的底部。
如果你想让文本居中,那么你可以用下面的代码覆盖面板的基线:
JPanel subPanel = new JPanel()
{
@Override
public int getBaseline(int width, int height)
{
Component c = getComponent(0);
return c.getBaseline(width, height);
}
};
当然,只有当面板上的所有组件具有相同的基线时,这才会起作用。
或者如果你只是想把所有的组件都放在面板的底部,那么你需要使用一个不同的布局管理器。
你可以使用相对布局来对齐所有的组件到底部。
它可以直接替换你现有的代码:
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 0);
rl.setAlignment( RelativeLayout.TRAILING );
JPanel topPanel = new JPanel(rl);
或者如果您不想使用非JDK类,那么BoxLayout
或GridBagLayout
将是您的选择。
如果你使用BoxLayout
,那么你需要使用每个组件的setAlignmentY(...)
属性。
如果您使用GridBagLayout
,那么您将需要使用每个组件的约束。
我自己,我会使用比FlowLayout更有"魅力"的布局,比如GridBagLayout。如果你使用它,你可以设置锚为SOUTH
,重量为0.0,这应该防止组件拉伸其高度,并将其放置在底部。例如:
JPanel topPanel = new JPanel();
// topPanel.setLayout(layout);
topPanel.setLayout(new GridBagLayout());
topPanel.setBackground(Color.BLACK);
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Foo");
label.setForeground(Color.WHITE);
label.setBackground(Color.RED);
label.setOpaque(true);
label.setFont(i % 2 == 0 ? font1 : font2);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = i;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 0.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.SOUTH;
JPanel subPanel = new JPanel();
subPanel.setLayout(new BorderLayout());
subPanel.setBackground(Color.RED);
subPanel.add(label);
subPanel.setPreferredSize(subPanel.getMinimumSize());
// subPanel.setAlignmentY(Component.BOTTOM_ALIGNMENT);
topPanel.add(subPanel, gbc);
}
在考虑了如何在没有griddbaglayout的情况下做到这一点之后,我想到了这个,尽管它有点"hackish":
JPanel topPanel = new JPanel();
((FlowLayout) topPanel.getLayout()).setAlignOnBaseline(true);
topPanel.setBackground(Color.BLACK);
int h = 0;
for (int i = 0; i < 10; i++) {
JLabel label = new JLabel("Foo");
label.setForeground(Color.WHITE);
label.setBackground(Color.GREEN);
label.setOpaque(true);
label.setFont(i % 2 == 0 ? font1 : font2);
JPanel wrapBorder = new JPanel(new BorderLayout());
JPanel subPanel = new JPanel();
subPanel.setBackground(Color.RED);
subPanel.add(label);
subPanel.setBackground(Color.GREEN);
wrapBorder.setOpaque(false);
wrapBorder.add(BorderLayout.SOUTH, subPanel);
if(wrapBorder.getPreferredSize().height > h) {
h = wrapBorder.getPreferredSize().height;
}
topPanel.add(wrapBorder);
}
for(Component component : topPanel.getComponents()) {
component.setPreferredSize(new Dimension(component.getPreferredSize().width, h));
}
我这样做的唯一原因是我个人从来没有使用过GridBagLayout
,但它有它的优点(可以看出;))。
我可能只是错过了一个方法,使JPanel
的垂直扩展,我过于复杂的东西很多。