2010-09-18 3 views
7

est-il un moyen look-and-feel-indépendant d'aligner un composant (par exemple un JLabel) horizontalement avec le texte d'un JCheckBox?Aligner un JLabel avec le texte d'une JCheckBox

J'essaie d'utiliser les valeurs du UIDefaults pour prédire l'emplacement du texte par rapport au coin supérieur gauche du JCheckBox. J'ai trouvé une combinaison qui donne le bon résultat pour le métal, Windows, Motif et Aqua Look-et-Sent:
Example: Metal (correctly-aligned)

Mais pas Nimbus:
Example: Nimbus (incorrectly-aligned)

Y at-il une méthode utilitaire quelque part Cela donnera de manière fiable X, Y offsets pour le texte dans tous Look-and-Feels?


code

(note: pour éviter les effets secondaires mise en page j'ai utilisé une disposition nulle pour ce test):

import java.awt.Insets; 

import javax.swing.JApplet; 
import javax.swing.JCheckBox; 
import javax.swing.JLabel; 
import javax.swing.UIManager; 
import javax.swing.border.Border; 

public class AlignCheckBoxText extends JApplet { 

    public AlignCheckBoxText() { 
     setLayout(null); 
     checkBox = new JCheckBox("Hello, World!"); 
     label = new JLabel("Hello, World!"); 
     add(checkBox); 
     add(label); 
    } 

    @Override 
    protected void validateTree() { 
     checkBox.setLocation(0, 0); 
     checkBox.setSize(checkBox.getPreferredSize()); 
     int labelX = UIManager.getIcon("CheckBox.icon").getIconWidth(); 
     Insets cbInsets = UIManager.getInsets("CheckBox.margin"); 
     if (cbInsets != null) labelX += cbInsets.left + cbInsets.right; 
     Border cbBorder = UIManager.getBorder("CheckBox.border"); 
     if (cbBorder != null) { 
      Insets borderInsets = cbBorder.getBorderInsets(checkBox); 
      if (borderInsets != null) { 
       labelX += borderInsets.left; 
      } 
     } 
     label.setLocation(labelX, checkBox.getHeight()); 
     label.setSize(label.getPreferredSize()); 
     super.validateTree(); 
    } 

    private JCheckBox checkBox; 
    private JLabel label; 

} 
+1

Dans ce cas, il serait plus simple de créer une case à cocher sans texte, et un JLabel séparé qui contient le texte de la case d'origine. – barjak

+0

@barjak, cela va jouer avec l'affichage de la mise au point. Normalement, il y a une bordure autour de la case à cocher (icône et texte) pour montrer quand elle est focalisée. Si vous cliquez également sur le texte, la sélection de la case ne sera plus activée. – finnw

Répondre

3

(OP: s'il vous plaît ma mauvaise réponse non acceptable plus tôt, et je vais le supprimer Désolé.!)

Vous pouvez utiliser une case à cocher qui ne peint pas la case à cocher pour vos étiquettes. Cela fonctionne pour tous les LAF dans Windows JDK6, y compris Nimbus. Je n'ai pas de mac donc je ne peux pas tester Aqua.

class CheckBoxLabel extends JCheckBox 
{ 
    public CheckBoxLabel(String string) 
    { 
     super(string); 
    } 

    public void updateUI() 
    { 
     setUI(new CheckBoxLabelUI()); 
    } 
} 

class CheckBoxLabelUI extends BasicCheckBoxUI 
{ 
    public void installUI(JComponent c) 
    { 
     super.installUI(c); 
     Icon i = super.getDefaultIcon(); 
     icon_ = new EmptyIcon(i.getIconWidth(), i.getIconHeight()); 
    } 

    public Icon getDefaultIcon() 
    { 
     return icon_; 
    } 

    private Icon icon_; 
} 

class EmptyIcon implements Icon 
{ 
    public EmptyIcon() 
    { 
     this(0, 0); 
    } 

    public EmptyIcon(int width, int height) 
    { 
     width_ = width; 
     height_ = height; 
    } 

    public int getIconHeight() 
    { 
     return height_; 
    } 

    public int getIconWidth() 
    { 
     return width_; 
    } 

    public void paintIcon(Component c, Graphics g, int x, int y) 
    { 
    } 

    private int width_; 
    private int height_; 
} 
1

Ce n'est pas une réponse complète, mais il peut vous aider à:

Si vous ajoutez checkBox.getIconTextGap() à la valeur de labelX, l'alignement semble être OK avec Nimbus, mais pas avec le métal ou GTK.

+0

Intéressant. 'checkBox.getIconTextGap' donne un résultat utile (peut-être une coïncidence) dans Nimbus mais un résultat non-utile dans d'autres L & F. 'UIManager.getInt (" CheckBox.textIconGap ")' retourne toujours zéro. – finnw

+0

C'était la solution que j'allais suggérer, bien que vous devriez noter que les LAF ne sont pas forcés d'utiliser l'une des valeurs par défaut d'UIManager. De plus, j'obtiens une valeur non nulle pour les LAF par défaut. Consultez le programme UIManager Defaults (http://tips4java.wordpress.com/2008/10/09/uimanager-defaults/). Tous les exemples que j'ai jamais vus dans le tutoriel Swing remplacent la méthode init() pour créer l'interface graphique. Peut-être que le problème est avec la méthode que vous utilisez et que le LAF n'est pas encore installé? Essayez la méthode normale ou essayez de créer une JFrame pour votre démo pour voir s'il y a une différence. – camickr

1

Si vous utilisez GroupLayout, le générateur d'interface graphique Netbeans peut aligner le texte d'une case à cocher et d'une étiquette sur la ligne suivante .... en quelque sorte.

Cela semble bien fonctionner pour Nimbus, mais dans l'autre LAF, le texte de l'étiquette est trop éloigné d'un pixel vers la droite. En regardant le code généré pour le GroupLayout dans le générateur GUI, il fait un écart de 22x22 devant le label. Pour Nimbus, 22 semble correct, mais pour les autres LAF, il semble être 21.

Le code généré ressemble à ceci.

GroupLayout layout = new GroupLayout(getContentPane()); 
getContentPane().setLayout(layout); 
layout.setHortizontalGroup(
    layout.createParallelGroup(Alignment.LEADING) 
    .addGroup(layout.createSequentialGroup() 
     .addContainerGap() 
     .addGroup(layout.createParallelGroup(Alignment.LEADING) 
     .addGroup(layout.createSequentialGroup() 
      .addGap(22,22,22) 
      .addComponent(label) 
     ) 
     .addComponent(checkBox) 
    ) 
    ) 
); 

layout.setVerticalGroup(
    layout.createParallelGroup(Alignment.LEADING) 
    .addGroup(layout.createSequentialGroup() 
     .addContainerGap() 
     .addComponent(checkBox) 
     .addPreferredGap(ComponentPlacement.RELATED) 
     .addComponent(label) 
    ) 
); 

Ce code irait dans le constructeur de la classe d'échantillons après les affectations de label et checkBox. En outre, supprimez setLayout (null);

Tout cela étant dit, en fonction de ce que je l'ai vu à l'aide du constructeur de GUI, je recommande ce qui suit pour de vrai:

  1. retirer le bit Border cbBorder de l'échantillon
  2. ajouter le checkBox.getIconTextGap() à l'étiquetteX.
  3. Si le LAF est nimbus, ajoutez 4 à labelX. :)
2

Vous pouvez aligner à droite l'étiquette et définir sa largeur comme étant la largeur de la case à cocher moins la bordure droite. Cela fonctionne pour tous les LAF avec Windows JDK1.6.0_21, y compris Nimbus. Je n'ai pas de Mac donc je ne peux pas tester Aqua.

Voici votre code très légèrement modifié:

class AlignCheckBoxText extends JApplet { 

    public AlignCheckBoxText() { 
     setLayout(null); 
     checkBox = new JCheckBox("Hello, World!"); 
     label = new JLabel("Hello, World!"); 
     add(checkBox); 
     add(label);   
     label.setHorizontalAlignment(JLabel.TRAILING); 
    } 

    @Override 
    protected void validateTree() { 
     checkBox.setLocation(0, 0); 
     checkBox.setSize(checkBox.getPreferredSize()); 
     int x = 0; 
     Border cbBorder = UIManager.getBorder("CheckBox.border"); 
     if (cbBorder != null) { 
      Insets borderInsets = cbBorder.getBorderInsets(checkBox); 
      if (borderInsets != null) { 
       x += borderInsets.right; 
      } 
     } 
     label.setLocation(0, checkBox.getHeight()); 
     label.setSize(new Dimension(checkBox.getPreferredSize().width - x, label.getPreferredSize().height)); 
     super.validateTree(); 
    } 

    private JCheckBox checkBox; 
    private JLabel label; 

} 
+1

J'aimerais pouvoir supprimer ou rejeter ma réponse. C'est vraiment mort de cerveau (pas d'offense à OP, tout est de ma faute). Cela ne fonctionne que lorsque la case à cocher et l'étiquette ont le même texte. Vous pouvez le pirater en définissant le texte réel de la case à cocher après avoir défini la taille de l'étiquette, mais vous devrez le faire chaque fois que le texte de l'étiquette change. En outre, il échoue pour les paramètres régionaux de droite à gauche. Une vraie réponse aurait probablement besoin de se plonger dans l'interface utilisateur de la case à cocher, que je ne connais pas. Pardon. –

+0

Même si cette réponse a des inconvénients, je pense que cela devrait rester. Ne le supprime pas. Bien que peut-être le PO pourrait le décliner. –

Questions connexes