2015-01-06 5 views
6

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

В случае, если проблема связана с Java на моем конкретном компьютере, это изображение того, что отображается на моем экране при запуске SSCCE, который загружает три разных JPanel с помощью BoxLayouts по оси y. & ставит в центре JLabel только с символом «а» в каждой: 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()); 
    } 
} 
+1

Для ясности, используйте 'style' [имена] (http://docs.oracle.com/javase/8/docs/api/constant-values.html#java. awt.Font.BOLD). – trashgod

+0

Хорошо, я об этом не думал. Я изменил код, чтобы использовать имена 'style'. Спасибо за вход. –

ответ

4

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

Я сделал некоторые изменения, чтобы отобразить 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()); 
    } 
} 
+0

«RelativeLayout» определенно является адекватным обходным решением. Я не слышал об этом раньше, но это то, что я мог бы использовать здесь и в будущих приложениях. Тем не менее, мне пришлось перейти в онлайн-копию и скопировать исходный код для «RelativeLayout» в мой проект, чтобы использовать его. У меня есть версия Java 1.7.0_25. Нужно ли обновлять, чтобы класс 'RelativeLayout' был встроен в Java без необходимости скопировать исходный код вручную? –

+0

@ScottHetrick, RelativeLayout - это просто какой-то (неподдерживаемый) код, который я написал для обеспечения функциональности, описанной в ссылке. Для него нет файла jar или чего-то еще, поэтому да, вы используете его, как любой класс, который вы пишете сами. Класс не зависит от версии. – camickr

+0

О, я получил. Это поразительно. Спасибо за рекомендацию, я, скорее всего, буду использовать это в будущем. –

4

Эффект вы наблюдаете, как представляется, является артефактом пути BoxLayout работ. Интерполяция от How to Use BoxLayout: Box Layout Features: «Когда 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()); 
    } 
} 
+0

Это жизнеспособное обходное решение, но для того, чтобы полностью «решить» проблему, потребуется более прямое решение. –

5

Другой способ избежать «Box Layout Особенности: ... Любое дополнительное пространство появляется в правой части контейнера», вам нужно будет переопределить метод JLabel#getMinimumSize() вернуть тот же Dimension, как 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); 
    } 
} 
+0

Очень интересно. Это хорошо работает, но для меня возникает еще один вопрос: я не понимаю, почему Java использует метод getMinimumSize() 'JPanel', чтобы выяснить, как сосредоточиться на' JLabel' для начала. Разве он не должен использовать текущий размер «JPanel», а не минимальный размер? –

+0

Метод 'getMinimumSize()' 'JPanel' в этом случае не имеет значения. Ключевое слово this относится к анонимному внутреннему классу ('JLabel'). '@Override public Dimension getMinimumSize() {System.out.println (этот экземпляр JLabel);/* ture */return this.getPreferredSize(); } ' – aterai

+0

А, ладно. Я предполагаю, что в этом случае пересмотренный вопрос будет: почему используется метод getMinimumSize() 'из' JLabel'? Чтобы определить измерение для центрирования, я бы предположил, что будет использоваться текущий размер, а не минимальный размер. –