Y-Axis 上 Java BoxLayout 中单个字符的对齐方式是 Off-Center
Alignment of Single Characters in Java BoxLayout on Y-Axis Is Off-Center
将某些字符沿 Java 中的 y-axis 与 BoxLayout 的中心对齐似乎存在问题。我不知道是什么导致了这种情况,我已经创建了一个 SSCCE 来演示这种效果。在这个例子中,我只使用了字符 'a',并且我在每个 JPanel 的正中间画了一条线来展示每个案例离中心有多远。粗体文本的情况似乎排列得很好,但正常格式和斜体都非常 off-center,尽管同时使用了 setAlignmentX 和 setHorizontalAlignment。感谢任何帮助理解这种效果的帮助。
如果问题出在我的特定计算机上 Java,这是我 运行 SSCCE 时屏幕上显示的图像,它加载了三个不同的 JPanel BoxLayouts 沿着 y-axis & 放置一个居中的 JLabel,每个 JLabel 中只有字符 'a':
& 这是 SSCCE 的代码:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
public class AlignmentTest extends JPanel
{
public AlignmentTest(char label, int style)
{
JLabel l = new JLabel(Character.toString(label));
setBorder(BorderFactory.createLineBorder(Color.BLACK,1));
setBackground(Color.WHITE);
setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(300,50));
add(Box.createVerticalGlue());
add(l);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setHorizontalAlignment(JLabel.CENTER);
add(Box.createVerticalGlue());
}
public static void main(String[] args)
{
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1,0,5,5));
f.add(new AlignmentTest('a',Font.PLAIN));
f.add(new AlignmentTest('a',Font.BOLD));
f.add(new AlignmentTest('a',Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(getWidth()/2,0,getWidth()/2,getHeight());
}
}
在 Windows 7 none 个字符上使用 JDK7 居中对齐。
我进行了一些更改以显示 JTextField,并使用了 JTextField 的列 (1、3、5)。随着列的增加,中心对齐得到改善,并且在第 5 列及以上是合理的。
所以这个问题在某种程度上与组件的宽度有关。
我猜布局中存在一些奇怪的舍入错误。这对我来说似乎是一个错误。
如果您对提供与 BoxLayout 类似功能的布局感兴趣,您可以查看 Relative Layout。对您的示例所做的更改很小:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
public class AlignmentTest extends JPanel
{
public AlignmentTest(char label, int style)
{
JLabel l = new JLabel(Character.toString(label));
setBorder(BorderFactory.createLineBorder(Color.BLACK,1));
setBackground(Color.WHITE);
// setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
setLayout(new RelativeLayout(RelativeLayout.Y_AXIS));
setPreferredSize(new Dimension(300,50));
// add(Box.createVerticalGlue());
add(Box.createVerticalGlue(), new Float(1));
add(l);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setHorizontalAlignment(JLabel.CENTER);
// add(Box.createVerticalGlue());
add(Box.createVerticalGlue(), new Float(1));
}
public static void main(String[] args)
{
JFrame f = new JFrame("Alignment Test");
JScrollPane scroller = new JScrollPane();
JPanel panel = new JPanel(new GridLayout(1,0,5,5));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1,0,5,5));
f.add(new AlignmentTest('a',Font.PLAIN));
f.add(new AlignmentTest('a',Font.BOLD));
f.add(new AlignmentTest('a',Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(getWidth()/2,0,getWidth()/2,getHeight());
}
}
您观察到的效果似乎是 BoxLayout
works. Interpolating from How to Use BoxLayout: Box Layout Features、"When a BoxLayout
lays out components from left to right, … Any extra space appears at the right of the container." 当封闭容器的初始尺寸是标签(固定)尺寸的小倍数时,如下所示,异常是最小的;水平拉伸框架以查看其增长情况。一个 work-around 是最小化封闭容器的首选尺寸被人为放大的程度。
import javax.swing.*;
import java.awt.*;
public class AlignmentTest extends JPanel {
private final JLabel l;
public AlignmentTest(String label, int style) {
setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
setBackground(Color.WHITE);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
l = new JLabel(label, JLabel.CENTER);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setOpaque(true);
l.setBackground(Color.cyan);
add(Box.createVerticalGlue());
add(l);
add(Box.createVerticalGlue());
}
@Override
public Dimension getPreferredSize() {
int w = l.getPreferredSize().width;
int h = l.getPreferredSize().height;
return new Dimension(w * 3, h * 3);
}
public static void main(String[] args) {
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0, 5, 5));
f.add(new AlignmentTest("aMa", Font.PLAIN));
f.add(new AlignmentTest("aMa", Font.BOLD));
f.add(new AlignmentTest("aMa", Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
}
另一种避免 "Box Layout Features: … Any extra space appears at the right of the container" 的方法,您需要将 JLabel#getMinimumSize()
方法重写为 return 与 JLabel#getPreferredSize()
相同的 Dimension
].
对不起,我误会了。
正如@camickr 已经说过的,
I would guess there is some weird rounding error in the layout. This seems like a bug to me.
非常正确。
固定示例:
//MinimumSize checkbox
//selected true: set min width = 100px
//selected false: set min width = 7px(default "a" width)
//Here's my attempt(I am running JDK 1.7.0_72 on Windows 7):
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class AlignmentTest4 extends JPanel {
private static boolean FLAG = false;
@Override public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
@Override public Dimension getPreferredSize() {
return new Dimension(300, 80);
}
public static JLabel makeLabel(String label, int style) {
JLabel l = new JLabel(label) {
@Override public Dimension getPreferredSize() {
return new Dimension(120, 30);
}
@Override public Dimension getMinimumSize() {
Dimension d = super.getMinimumSize();
if (FLAG) {
d.width = 100;
} else {
d.width = 7;
}
return d;
//if (FLAG) {
// return this.getPreferredSize();
//} else {
// return super.getMinimumSize();
//}
}
};
l.setOpaque(true);
l.setBackground(Color.ORANGE);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(Component.CENTER_ALIGNMENT);
l.setAlignmentY(Component.CENTER_ALIGNMENT);
l.setVerticalAlignment(SwingConstants.CENTER);
l.setVerticalTextPosition(SwingConstants.CENTER);
l.setHorizontalAlignment(SwingConstants.CENTER);
l.setHorizontalTextPosition(SwingConstants.CENTER);
return l;
}
public static JComponent makePanel() {
JPanel p = new JPanel(new GridLayout(0, 1, 5, 5));
JPanel p1 = new AlignmentTest4();
p1.setBorder(BorderFactory.createTitledBorder("BoxLayout.X_AXIS"));
p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
p1.add(Box.createHorizontalGlue());
p1.add(makeLabel("a", Font.PLAIN));
p1.add(Box.createHorizontalGlue());
JPanel p2 = new AlignmentTest4();
p2.setBorder(BorderFactory.createTitledBorder("BoxLayout.Y_AXIS"));
p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
p2.add(Box.createVerticalGlue());
p2.add(makeLabel("a", Font.PLAIN));
p2.add(Box.createVerticalGlue());
for (JPanel c : Arrays.asList(p1, p2)) {
c.setBackground(Color.WHITE);
p.add(c);
}
return p;
}
public static JComponent makeUI() {
final JPanel p = new JPanel(new BorderLayout());
p.add(makePanel());
p.add(new JCheckBox(new AbstractAction("MinimumSize") {
@Override public void actionPerformed(ActionEvent e) {
FLAG = ((JCheckBox) e.getSource()).isSelected();
SwingUtilities.updateComponentTreeUI(p);
}
}), BorderLayout.SOUTH);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(makeUI());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
将某些字符沿 Java 中的 y-axis 与 BoxLayout 的中心对齐似乎存在问题。我不知道是什么导致了这种情况,我已经创建了一个 SSCCE 来演示这种效果。在这个例子中,我只使用了字符 'a',并且我在每个 JPanel 的正中间画了一条线来展示每个案例离中心有多远。粗体文本的情况似乎排列得很好,但正常格式和斜体都非常 off-center,尽管同时使用了 setAlignmentX 和 setHorizontalAlignment。感谢任何帮助理解这种效果的帮助。
如果问题出在我的特定计算机上 Java,这是我 运行 SSCCE 时屏幕上显示的图像,它加载了三个不同的 JPanel BoxLayouts 沿着 y-axis & 放置一个居中的 JLabel,每个 JLabel 中只有字符 'a':
& 这是 SSCCE 的代码:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
public class AlignmentTest extends JPanel
{
public AlignmentTest(char label, int style)
{
JLabel l = new JLabel(Character.toString(label));
setBorder(BorderFactory.createLineBorder(Color.BLACK,1));
setBackground(Color.WHITE);
setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(300,50));
add(Box.createVerticalGlue());
add(l);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setHorizontalAlignment(JLabel.CENTER);
add(Box.createVerticalGlue());
}
public static void main(String[] args)
{
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1,0,5,5));
f.add(new AlignmentTest('a',Font.PLAIN));
f.add(new AlignmentTest('a',Font.BOLD));
f.add(new AlignmentTest('a',Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(getWidth()/2,0,getWidth()/2,getHeight());
}
}
在 Windows 7 none 个字符上使用 JDK7 居中对齐。
我进行了一些更改以显示 JTextField,并使用了 JTextField 的列 (1、3、5)。随着列的增加,中心对齐得到改善,并且在第 5 列及以上是合理的。 所以这个问题在某种程度上与组件的宽度有关。
我猜布局中存在一些奇怪的舍入错误。这对我来说似乎是一个错误。
如果您对提供与 BoxLayout 类似功能的布局感兴趣,您可以查看 Relative Layout。对您的示例所做的更改很小:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
public class AlignmentTest extends JPanel
{
public AlignmentTest(char label, int style)
{
JLabel l = new JLabel(Character.toString(label));
setBorder(BorderFactory.createLineBorder(Color.BLACK,1));
setBackground(Color.WHITE);
// setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
setLayout(new RelativeLayout(RelativeLayout.Y_AXIS));
setPreferredSize(new Dimension(300,50));
// add(Box.createVerticalGlue());
add(Box.createVerticalGlue(), new Float(1));
add(l);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setHorizontalAlignment(JLabel.CENTER);
// add(Box.createVerticalGlue());
add(Box.createVerticalGlue(), new Float(1));
}
public static void main(String[] args)
{
JFrame f = new JFrame("Alignment Test");
JScrollPane scroller = new JScrollPane();
JPanel panel = new JPanel(new GridLayout(1,0,5,5));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1,0,5,5));
f.add(new AlignmentTest('a',Font.PLAIN));
f.add(new AlignmentTest('a',Font.BOLD));
f.add(new AlignmentTest('a',Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(getWidth()/2,0,getWidth()/2,getHeight());
}
}
您观察到的效果似乎是 BoxLayout
works. Interpolating from How to Use BoxLayout: Box Layout Features、"When a BoxLayout
lays out components from left to right, … Any extra space appears at the right of the container." 当封闭容器的初始尺寸是标签(固定)尺寸的小倍数时,如下所示,异常是最小的;水平拉伸框架以查看其增长情况。一个 work-around 是最小化封闭容器的首选尺寸被人为放大的程度。
import javax.swing.*;
import java.awt.*;
public class AlignmentTest extends JPanel {
private final JLabel l;
public AlignmentTest(String label, int style) {
setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
setBackground(Color.WHITE);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
l = new JLabel(label, JLabel.CENTER);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(CENTER_ALIGNMENT);
l.setOpaque(true);
l.setBackground(Color.cyan);
add(Box.createVerticalGlue());
add(l);
add(Box.createVerticalGlue());
}
@Override
public Dimension getPreferredSize() {
int w = l.getPreferredSize().width;
int h = l.getPreferredSize().height;
return new Dimension(w * 3, h * 3);
}
public static void main(String[] args) {
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridLayout(1, 0, 5, 5));
f.add(new AlignmentTest("aMa", Font.PLAIN));
f.add(new AlignmentTest("aMa", Font.BOLD));
f.add(new AlignmentTest("aMa", Font.ITALIC));
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
}
另一种避免 "Box Layout Features: … Any extra space appears at the right of the container" 的方法,您需要将 JLabel#getMinimumSize()
方法重写为 return 与 JLabel#getPreferredSize()
相同的 Dimension
].
对不起,我误会了。
正如@camickr 已经说过的,
I would guess there is some weird rounding error in the layout. This seems like a bug to me.
非常正确。
固定示例:
//MinimumSize checkbox
//selected true: set min width = 100px
//selected false: set min width = 7px(default "a" width)
//Here's my attempt(I am running JDK 1.7.0_72 on Windows 7):
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class AlignmentTest4 extends JPanel {
private static boolean FLAG = false;
@Override public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
}
@Override public Dimension getPreferredSize() {
return new Dimension(300, 80);
}
public static JLabel makeLabel(String label, int style) {
JLabel l = new JLabel(label) {
@Override public Dimension getPreferredSize() {
return new Dimension(120, 30);
}
@Override public Dimension getMinimumSize() {
Dimension d = super.getMinimumSize();
if (FLAG) {
d.width = 100;
} else {
d.width = 7;
}
return d;
//if (FLAG) {
// return this.getPreferredSize();
//} else {
// return super.getMinimumSize();
//}
}
};
l.setOpaque(true);
l.setBackground(Color.ORANGE);
l.setFont(l.getFont().deriveFont(style));
l.setAlignmentX(Component.CENTER_ALIGNMENT);
l.setAlignmentY(Component.CENTER_ALIGNMENT);
l.setVerticalAlignment(SwingConstants.CENTER);
l.setVerticalTextPosition(SwingConstants.CENTER);
l.setHorizontalAlignment(SwingConstants.CENTER);
l.setHorizontalTextPosition(SwingConstants.CENTER);
return l;
}
public static JComponent makePanel() {
JPanel p = new JPanel(new GridLayout(0, 1, 5, 5));
JPanel p1 = new AlignmentTest4();
p1.setBorder(BorderFactory.createTitledBorder("BoxLayout.X_AXIS"));
p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS));
p1.add(Box.createHorizontalGlue());
p1.add(makeLabel("a", Font.PLAIN));
p1.add(Box.createHorizontalGlue());
JPanel p2 = new AlignmentTest4();
p2.setBorder(BorderFactory.createTitledBorder("BoxLayout.Y_AXIS"));
p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
p2.add(Box.createVerticalGlue());
p2.add(makeLabel("a", Font.PLAIN));
p2.add(Box.createVerticalGlue());
for (JPanel c : Arrays.asList(p1, p2)) {
c.setBackground(Color.WHITE);
p.add(c);
}
return p;
}
public static JComponent makeUI() {
final JPanel p = new JPanel(new BorderLayout());
p.add(makePanel());
p.add(new JCheckBox(new AbstractAction("MinimumSize") {
@Override public void actionPerformed(ActionEvent e) {
FLAG = ((JCheckBox) e.getSource()).isSelected();
SwingUtilities.updateComponentTreeUI(p);
}
}), BorderLayout.SOUTH);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame("Alignment Test");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(makeUI());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}