2015-01-06 13 views
6

JavaのY軸に沿って特定の文字をBoxLayoutの中心に揃える際に問題があるようです。私はこれを引き起こす原因を知りません。&私はその効果を実証するためにSSCCEを作成しました。この例では、文字「a」のみを使用しています。&各JPanelの真ん中を線で描き、各ケースが中心からどのくらい離れているかを示します。太字の場合は整列しているようですが、通常の書式設定の&は、setAlignmentX & setHorizo​​ntalAlignmentの両方を使用していますが、イタリック体はどちらも大きく外れています。この効果を理解する上での助けに感謝します。Javaでの単一文字の配置Y軸上のBoxLayoutが中央にない

特定のコンピュータのJavaで何らかの問題が発生している場合、これは、y軸に沿ってBoxLayoutsを持つ3つの異なるJPanelをロードするSSCCEを実行すると、画面に表示される画像です&文字のみでのJLabelを中心に「」それぞれに:ここ enter image description here

&はSSCCEのコードです:文字のWindows 7のいずれも中心を整列さにJDK7を使用して

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

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がコンポーネントを左から右にレイアウトすると、余分なスペースがコンテナの右側に表示されます。以下に示すように、囲みコンテナの初期サイズがラベルの(固定)サイズの小さな倍数である場合、異常は最小です。それがどのように成長するかを見るためにフレームを水平に伸ばす。 1つの回避策は、囲みコンテナの好ましいサイズが人為的に拡大される程度を最小にすることである。

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

回避するための別の方法として、「ボックスレイアウトの特長:...余分なスペースは、コンテナの右側に表示されます」、あなたはJLabel#getPreferredSize()と同じDimensionを返すようにJLabel#getMinimumSize()メソッドをオーバーライドする必要があります。

申し訳ありませんが、私は誤解しました。 @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が 'Janel'の' getMinimumSize() 'メソッドを使って' JLabel'をどのように中心に置くのか理解できないのです。最小サイズではなく、 'JPanel'の現在のサイズを使用するべきではありませんか? –

+0

この場合、 'JPanel'の' getMinimumSize() 'メソッドは無関係です。 "this"キーワードは、匿名の内部クラス( 'JLabel')自体を参照します。 '@Override public Dimension getMinimumSize(){System.out.println(このインスタンスのJLabel);/* ture */return this.getPreferredSize(); } ' – aterai

+0

ああ、大丈夫です。その場合、改訂された質問は、 'JLabel'の' getMinimumSize() 'メソッドが使われている理由でしょうか?センタリングの測定を決定するために、最小サイズではなく、現在のサイズが使用されると思います。 –