Выравнивание одиночных символов в Java BoxLayout по оси Y не по центру

Кажется, есть проблема с выравниванием определенных символов к центру BoxLayout вдоль оси y в Java. Я не знаю, что может вызвать это, и я создал SSCCE, чтобы продемонстрировать эффект. В этом примере я использую только символ "a", и я рисую линию вниз по прямой середине каждой JPanel, чтобы показать, насколько далеко каждый случай от центра. Случай с полужирным текстом, кажется, выстраивается нормально, но нормальное форматирование и курсив оба сильно смещены от центра, несмотря на использование обоих setAlignmentX & setHorizontalAlignment. Любая помощь в понимании этого эффекта приветствуется.

в случае, если каким-то образом проблема связана с Java на моем конкретном компьютере, это изображение того, что отображается на моем экране, когда я запускаю SSCCE, который загружает три разных JPanels с BoxLayouts вдоль оси y и помещает центрированную JLabel только с символом " a " в каждом: enter image description here

& вот код для 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());
    }
}

3 ответов


использование JDK7 в Windows 7 ни один из символов не выровнен по центру.

Я внес некоторые изменения для отображения JTextField, и я играл со столбцами JTextField (1, 3, 5). По мере увеличения столбцов выравнивание по центру улучшалось и было разумным для столбцов 5 и выше. Таким образом, проблема каким-то образом связана с шириной компонента.

Я бы предположил, что есть какая-то странная ошибка округления в макете. Мне кажется, это жук.

в случае вас интересует макет, который предоставляет некоторые аналогичные функции BoxLayout вы можете проверить Относительная Разметка. Изменения в вашем примере незначительны:

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());
    }
}

другой способ избежать "особенности компоновки коробки: ... любое дополнительное пространство появляется справа от контейнера", вам нужно будет переопределить JLabel#getMinimumSize() метод для возврата того же Dimension as JLabel#getPreferredSize().

Извините, я неправильно понял.

как уже сказал @camickr,

Я бы предположил, что в макете есть какая-то странная ошибка округления. Мне кажется, это жук.

совершенно верно.

исправлено пример:

//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);
  }
}

эффект, который вы наблюдаете, кажется артефактом пути BoxLayout строительство. Интерполяция из как использовать BoxLayout: особенности компоновки коробки", когда BoxLayout выкладывает компоненты слева направо , ... любое дополнительное пространство появляется справа от контейнера."Когда начальный размер заключающего контейнера является небольшим кратным (фиксированному) размеру метки, как показано ниже, аномалия минимальна; растяните рамку по горизонтали, чтобы увидеть, как она растет. Одним из обходных путей было бы свести к минимуму степень, в которой предпочтительный размер заключающего контейнера искусственно увеличивается.

image

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());
    }
}