2015-01-06 10 views
6

Sembra esserci un problema con l'allineamento di alcuni caratteri al centro di un BoxLayout lungo l'asse y in Java. Non so cosa potrebbe causare questo, & Ho creato un SSCCE per dimostrare l'effetto. Nell'esempio, utilizzo solo il carattere 'a', & Tracciamo una linea lungo il centro diretto di ciascun JPanel per dimostrare quanto lontano da ciascun caso provenga dal centro. Il caso con testo in grassetto sembra allineato bene, ma la formattazione normale in corsivo & è gravemente decentrata, nonostante l'utilizzo sia di setAlignmentX & setHorizontalAlignment. Qualsiasi aiuto sulla comprensione di questo effetto è apprezzato.L'allineamento di singoli caratteri in Java BoxLayout su asse Y è fuori centro

Nel caso in cui in qualche modo il problema sia con Java sul mio computer specifico, questa è un'immagine di ciò che viene visualizzato sullo schermo quando eseguo SSCCE, che carica tre diversi JPanel con BoxLayout lungo l'asse y & centrato JLabel con solo il carattere 'a' in ogni: enter image description here

& ecco il codice per lo 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

Per chiarezza, si usi 'style' [nomi] (http://docs.oracle.com/javase/8/docs/api/constant-values.html#java. awt.Font.BOLD). – trashgod

+0

Buon punto, non ci ho pensato. Ho cambiato il codice per usare i nomi 'style' ora. Grazie per l'input. –

risposta

4

Utilizzando JDK7 su Windows 7 nessuno dei personaggi sono il centro allineato.

Ho apportato alcune modifiche per visualizzare un campo JText e ho giocato con le colonne di JTextField (1, 3, 5). Man mano che le colonne aumentavano, il centro allineato migliorava ed era ragionevole alle colonne 5 e superiori. Quindi il problema è in qualche modo correlato alla larghezza del componente.

Suppongo che ci sia qualche strano errore di arrotondamento nel layout. Questo mi sembra un insetto.

Se si è interessati a un layout che fornisce alcune funzionalità simili a BoxLayout, è possibile controllare lo Relative Layout. Le modifiche al tuo esempio sono minori:

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

Il 'RelativeLayout' è sicuramente una soluzione adeguata. Non ne ho mai sentito parlare prima, ma è qualcosa che potrei usare qui e nelle future applicazioni. Tuttavia, dovevo andare online e copiare il codice sorgente di 'RelativeLayout' nel mio progetto per poterlo utilizzare. Ho Java versione 1.7.0_25. Devo aggiornare per avere la classe 'RelativeLayout' integrata in Java senza che io debba copiare manualmente il codice sorgente? –

+0

@ScottHetrick, RelativeLayout è solo un codice (non supportato) che ho scritto per fornire la funzionalità come descritto nel link. Non ci sono file jar o altro, quindi sì lo usi come qualsiasi classe che scrivi tu stesso. La classe non è dipendente dalla versione. – camickr

+0

Oh, ho capito. È impressionante. Grazie per la raccomandazione, probabilmente lo userò in futuro. –

4

L'effetto si osserva sembra essere un artefatto del modo BoxLayout opere. Interpolazione da How to Use BoxLayout: Box Layout Features, "Quando uno BoxLayout espone i componenti da sinistra a destra, ... Qualsiasi spazio aggiuntivo viene visualizzato a destra del contenitore." Quando la dimensione iniziale del contenitore che racchiude è un piccolo multiplo della dimensione (fissa) dell'etichetta, come mostrato di seguito, l'anomalia è minima; allunga orizzontalmente la cornice per vedere come cresce. Una soluzione sarebbe di minimizzare il grado in cui la dimensione preferita del contenitore che racchiude viene ingrandita artificialmente.

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

È una soluzione praticabile, ma per risolvere perfettamente il problema sarebbe necessaria una soluzione più diretta. –

5

Un altro modo per evitare di "dialogo Layout Caratteristiche: ... Ogni spazio viene visualizzata nella parte destra del contenitore", si avrebbe bisogno di sovrascrivere il metodo JLabel#getMinimumSize() per restituire la stessa Dimension come JLabel#getPreferredSize() .

Mi dispiace, ho frainteso.

Come @camickr ha già detto,

vorrei che ci sia un errore di arrotondamento strano nel layout. Questo mi sembra un insetto.

è abbastanza corretto.

fisso esempio:

//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

Molto interessante. Funziona bene, ma mi viene in mente un'altra domanda: non capisco perché Java stia usando il metodo 'getMinimumSize()' di 'JPanel' per capire come centrare' JLabel' per cominciare. Non dovrebbe usare la dimensione attuale di 'JPanel', non la dimensione minima? –

+0

In questo caso il metodo 'getMinimumSize()' di 'JPanel' è irrilevante. La parola chiave "this" si riferisce alla classe interna anonima ('JLabel') stessa. '@Override public Dimension getMinimumSize() {System.out.println (questa istanza di JLabel);/* ture */return this.getPreferredSize(); } ' – aterai

+0

Ah, ok. Suppongo che in tal caso la domanda rivista sarebbe: perché viene usato il metodo 'getMinimumSize()' di 'JLabel'? Per determinare la misura per il centraggio, immagino che la dimensione corrente venga utilizzata, non la dimensione minima. –