498 votes

Dois-je éviter d'utiliser les méthodes set(Preferred|Maximum|Minimum)Size dans Java Swing ?

J'ai été plusieurs fois critiqué pour avoir suggéré l'utilisation des méthodes suivantes :

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

sur Swing composants. Je ne vois pas d'alternative à leur utilisation lorsque je veux définir des proportions entre les composants affichés. On m'a dit ceci :

En ce qui concerne les mises en page, la réponse est toujours la même : utilisez un gestionnaire de mise en page approprié. LayoutManager

J'ai fait quelques recherches sur le web, mais je n'ai pas trouvé d'analyse complète sur le sujet. J'ai donc les questions suivantes :

  1. Dois-je éviter complètement l'utilisation de ces méthodes ?
  2. Les méthodes ont été définies pour une raison. Alors, quand faut-il les utiliser ? Dans quel contexte ? À quelles fins ?
  3. Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes ? (Je ne pense qu'à ajouter la portabilité entre des systèmes ayant une résolution d'écran différente).
  4. Je ne pense pas qu'un LayoutManager puisse répondre exactement à tous les besoins de mise en page souhaités. Dois-je vraiment implémenter un nouveau LayoutManager pour chaque petite variation de ma mise en page ?
  5. Si la réponse à la question 4 est "oui", cela ne va-t-il pas conduire à une prolifération de classes LayoutManager qui deviendront difficiles à maintenir ?
  6. Dans une situation où j'ai besoin de définir les proportions entre les enfants d'un composant (par exemple, child1 doit utiliser 10% de l'espace, child2 40% ,child3 50%), est-il possible d'y parvenir sans mettre en œuvre un LayoutManager personnalisé ?

245voto

kleopatra Points 31585
  1. Dois-je éviter complètement l'utilisation de ces méthodes ?

    Oui pour le code d'application.

  2. Les méthodes ont été définies pour une raison. Alors, quand faut-il les utiliser ? Dans quel contexte ? À quelles fins ?

    Je ne sais pas, personnellement je pense que c'est un accident de conception de l'API. Légèrement forcé par les composants composés ayant des idées spéciales sur les tailles des enfants. "Légèrement", parce qu'ils auraient dû implémenter leurs besoins avec un LayoutManager personnalisé.

  3. Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes ? (Je ne peux penser qu'à ajouter la portabilité entre des systèmes ayant une résolution d'écran différente).

    Certaines raisons techniques (incomplètes, et malheureusement les liens sont rompus en raison de la migration de SwingLabs vers java.net) sont par exemple mentionnées dans l'article suivant Règles (hehe) ou dans le enlace @bendicott a trouvé dans son commentaire à ma réponse . D'un point de vue social, cela impose des tonnes de travail à votre malheureux compagnon qui doit maintenir le code et retrouver une mise en page cassée.

  4. Je ne pense pas qu'un LayoutManager puisse satisfaire exactement tous les besoins de mise en page souhaités. Dois-je vraiment implémenter un nouveau LayoutManager pour chaque petite variation de ma mise en page ?

    Oui, il existe des LayoutManagers suffisamment puissants pour satisfaire une très bonne approximation de "tous les besoins de mise en page". Les trois principaux sont FormLayout, MigLayout et DesignGridLayout de JGoodies. Donc non, en pratique, vous écrivez rarement des LayoutManagers sauf pour des environnements simples et hautement spécialisés.

  5. Si la réponse à la question 4 est "oui", cela ne va-t-il pas conduire à une prolifération de classes LayoutManager qui deviendront difficiles à maintenir ?

    (La réponse à la question 4 est "non").

  6. Dans une situation où je dois définir des proportions entre les enfants d'un composant (par exemple, l'enfant 1 doit utiliser 10 % de l'espace, l'enfant 2 40 %, l'enfant 3 50 %), est-il possible d'y parvenir sans mettre en œuvre un LayoutManager personnalisé ?

    N'importe lequel des Big-Three peut, ne peut même pas GridBag (je n'ai jamais pris la peine de vraiment le maîtriser, trop de problèmes pour trop peu de pouvoir).

5 votes

Je ne suis pas tout à fait sûr d'être d'accord avec ce conseil dans au moins deux situations. 1) Les composants rendus personnalisés 2) L'utilisation d'un JEditorPane avec un HTML qui ne suggère pas lui-même une largeur. Par contre, je ne suis pas sûr d'avoir manqué quelque chose. Je vais examiner attentivement les réponses au fil de discussion, mais j'aimerais savoir si vous avez des commentaires, en particulier sur le dernier cas.

2 votes

@Andrew Thompson 1) les comps personnalisées : c'est la comp elle-même qui est responsable de renvoyer des indications de mise en page utiles, si elle ne le fait pas, l'impl est boguée 2) même les comps de base sont boguées ;-) 3) Les espaces blancs ne me dérangent pas (même si ce n'était pas intentionnel cette fois-ci, merci :-)

0 votes

Le fait de passer par des bibliothèques internes pour faire ce qu'une méthode de 5 lignes peut faire juste au cas où quelqu'un ferait le changement exact qui casse votre mise en page sans lire votre code ne viole-t-il pas YAGNI ?

106voto

trashgod Points 136305

Quelques heuristiques :

  • N'utilisez pas set[Preferred|Maximum|Minimum]Size() quand vous voulez vraiment passer outre get[Preferred|Maximum|Minimum]Size() comme on pourrait le faire en créant son propre composant, montré aquí .

  • N'utilisez pas set[Preferred|Maximum|Minimum]Size() quand vous pouviez compter sur un composant soigneusement surchargé getPreferred|Maximum|Minimum]Size comme indiqué aquí et ci-dessous.

  • Utilisez set[Preferred|Maximum|Minimum]Size() pour dériver des post- validate() géométrie, comme indiqué ci-dessous et aquí .

  • Si un composant n'a pas de taille préférée, par exemple JDesktopPane il se peut que vous deviez dimensionner le conteneur, mais ce choix est arbitraire. Un commentaire peut aider à clarifier l'intention.

  • Envisagez des mises en page alternatives ou personnalisées lorsque vous constatez que vous devez passer en boucle par de nombreux composants pour obtenir des tailles dérivées, comme indiqué dans les exemples suivants commentaires .

enter image description here

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @see https://stackoverflow.com/questions/7229226
 * @see https://stackoverflow.com/questions/7228843
 */
public class DesignTest {

    private List<JTextField> list = new ArrayList<JTextField>();
    private JPanel panel = new JPanel();
    private JScrollPane sp = new JScrollPane(panel);

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                DesignTest id = new DesignTest();
                id.create("My Project");
            }
        });
    }

    private void addField(String name) {
        JTextField jtf = new JTextField(16);
        panel.add(new JLabel(name, JLabel.LEFT));
        panel.add(jtf);
        list.add(jtf);
    }

    private void create(String strProjectName) {
        panel.setLayout(new GridLayout(0, 1));
        addField("First Name:");
        addField("Last Name:");
        addField("Address:");
        addField("City:");
        addField("Zip Code:");
        addField("Phone:");
        addField("Email Id:");
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("permanentFocusOwner",
            new FocusDrivenScroller(panel));
        // Show half the fields
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.validate();
        Dimension d = sp.getPreferredSize();
        d.setSize(d.width, d.height / 2);
        sp.setPreferredSize(d);

        JInternalFrame internaFrame = new JInternalFrame();
        internaFrame.add(sp);
        internaFrame.pack();
        internaFrame.setVisible(true);

        JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.add(internaFrame);

        JFrame frmtest = new JFrame();
        frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmtest.add(desktopPane);
        frmtest.pack();
        // User's preference should be read from java.util.prefs.Preferences
        frmtest.setSize(400, 300);
        frmtest.setLocationRelativeTo(null);
        frmtest.setVisible(true);
        list.get(0).requestFocusInWindow();
    }

    private static class FocusDrivenScroller implements PropertyChangeListener {

        private JComponent parent;

        public FocusDrivenScroller(JComponent parent) {
            this.parent = parent;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Component focused = (Component) evt.getNewValue();
            if (focused != null
                && SwingUtilities.isDescendingFrom(focused, parent)) {
                parent.scrollRectToVisible(focused.getBounds());
            }
        }
    }
}

2 votes

Je ne suis pas d'accord (vous l'aurez deviné :-) avec le raisonnement par "facteurs externes" : les propriétés XXSize sont censées exprimer interne uniquement besoins. Les modifier de l'extérieur est une mauvaise utilisation, c'est-à-dire du piratage. Si vous voulez un cadre (interne ou J) d'une taille spécifique par rapport à son contenu préféré, dimensionnez le cadre, pas le contenu.

2 votes

@kleopatra : juste pour être un peu insistant : si les méthodes setXXSize ne doivent jamais être utilisées de l'extérieur, pourquoi n'ont-elles pas été déclarées privées ou protégées ? N'est-ce pas un manque de conception ? Le modificateur public n'indique-t-il pas implicitement à l'utilisateur qui peut utiliser ces méthodes ?

3 votes

Je suis d'accord avec @kleopatra : setPreferredSize() remplace toujours le calcul du composant par un choix arbitraire.

52voto

David Kroukamp Points 23503

Dois-je éviter complètement l'utilisation de ces méthodes ?

Non, il n'y a aucune preuve formelle qui suggère que l'appel ou le remplacement de ces méthodes n'est pas autorisé. En fait, Oracle affirme que ces méthodes sont utilisées pour donner des indications de taille : http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment .

Ils peuvent également être remplacés (ce qui est la meilleure pratique pour Swing) quand extension de un composant Swing (plutôt que d'appeler la méthode sur l'instance du composant personnalisé)

Surtout, quelle que soit la façon dont vous spécifiez la taille de votre composant, assurez-vous que le conteneur de votre composant utilise un gestionnaire de mise en page qui respecte la taille demandée du composant.

Les méthodes ont été définies pour une raison précise. Alors quand faut-il les utiliser ? Dans quel contexte ? À quelles fins ?

Lorsque vous devez fournir des indications de taille personnalisées au gestionnaire de mise en page des conteneurs afin que le composant soit bien disposé.

Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes ? (I pense seulement à ajouter de la portabilité entre des systèmes avec différentes résolution d'écran).

  • De nombreux responsables de la mise en page ne prêtent pas attention à la taille maximale requise pour un composant. Cependant, BoxLayout y SpringLayout faire. En outre, GroupLayout offre la possibilité de définir explicitement la taille minimale, préférée ou maximale, sans toucher au composant.

  • Assurez-vous que vous avez réellement besoin de définir la taille exacte du composant. Chaque composant Swing a une taille préférée différente, en fonction de la police qu'il utilise et de son apparence. Ainsi, le fait de définir une taille précise peut produire des regarde de l'interface utilisateur sur différents systèmes

  • parfois des problèmes peuvent être rencontrés avec GridBagLayout et des champs de texte, où si la taille du conteneur est inférieure à la taille préférée, la taille minimale est utilisée, ce qui peut entraîner un rétrécissement assez important des champs de texte.

  • JFrame n'applique pas le principe de la surcharge getMinimumSize() uniquement la vocation setMinimumSize(..) sur ses travaux

Je ne pense pas qu'un LayoutManager puisse répondre exactement à tous les besoins. Ai-je vraiment besoin d'implémenter un nouveau LayoutManager pour chaque petite variation de ma mise en page ?

Si par mise en œuvre vous voulez dire utilisation, alors oui. Pas un LayoutManger peut tout gérer, chaque LayoutManager a ses avantages et ses inconvénients ; ainsi, chacune peut être utilisée conjointement pour produire la mise en page finale.

Référence :

3 votes

fournir des conseils de taille personnalisés C'est une contradiction en soi : fournir des indications de taille (en px !) est la meilleure façon de faire. exclusif tâche de la composante. Il les calcule sur la base de détails d'état internes que personne d'autre que lui-même ne peut connaître (ni suivre). Du point de vue du client, le moyen de personnalisation peut être un LayoutManager approprié et/ou une API spécialisée sur le composant qui permet de configurer les exigences de taille en termes de propriétés "sémantiques" relatives à la taille, par exemple le nombre de lignes/colonnes dans un composant texte.

4 votes

@kleopatra J'aimerais quand même savoir pourquoi Oracle nous dit ensuite comment utiliser ces méthodes et la manière correcte de les utiliser. Nous pouvons avoir nos propres préférences, mais nous ne pouvons pas dire que les concepteurs ont voulu qu'elles ne soient pas utilisées alors qu'il n'y a aucune preuve qui le suggère. Mais c'est pour cela que j'ai mis en place une prime, pour voir si cela pourrait attirer d'autres personnes qui pourraient donner une information d'une source crédible où Oracle déclare ne pas utiliser ces méthodes du tout (ce qui fait que c'est une mauvaise pratique si vous le faites, par exemple setMinimumSize doit être appelé sur des choses comme JSplitPane, etc, ce qui peut être vu dans le tutoriel Oracle sur les panneaux divisés.

4 votes

@David : Je suis venu pour voir le setXxxSize méthodes comme un drapeau rouge que je pourrais finir par aquí même quand les docteurs le suggèrent. I presque toujours aurait dû remplacer getXxxSize Même les exemples les plus courts sont recyclés plus souvent que je ne veux le penser. +1 pour avoir mentionné la variation entre les gestionnaires de mise en page et avoir cité le tutoriel.

25voto

Jason C Points 14927

Il y a beaucoup de bonnes réponses ici, mais je veux ajouter un peu plus de raisons. pourquoi vous devriez normalement les éviter (la question vient de revenir dans un sujet en double) :

À quelques exceptions près, si vous utilisez ces méthodes, vous êtes probablement en train de peaufiner votre interface graphique pour qu'elle ait un aspect et une apparence spécifiques (et avec les paramètres propres à votre système, par exemple votre police de bureau préférée, etc.) Les méthodes elles-mêmes ne sont pas intrinsèquement mauvaises, mais les raisons typiques de leur utilisation sont les suivantes sont . Dès que vous commencez à régler la position et la taille des pixels dans une mise en page, vous courez le risque de voir votre interface graphique se briser (ou au minimum, avoir une mauvaise apparence) sur d'autres plateformes.

À titre d'exemple, essayez de modifier l'aspect et la convivialité par défaut de votre application. Même avec les seules options disponibles sur votre plate-forme, vous pourriez être surpris de la médiocrité du rendu.

Ainsi, pour que votre interface graphique reste fonctionnelle et agréable à regarder sur toutes les plates-formes (n'oubliez pas que l'un des principaux avantages de Java est son caractère multiplateforme), vous devez vous fier aux gestionnaires de mise en page, etc., pour ajuster automatiquement la taille de vos composants afin d'obtenir un rendu correct en dehors de votre environnement de développement spécifique.

Tout cela dit, on peut certainement concevoir des situations où ces méthodes sont justifiées. Encore une fois, elles ne sont pas intrinsèquement mauvaises, mais leur utilisation est normalement une grand drapeau rouge indiquant des problèmes potentiels d'interface graphique. Assurez-vous simplement d'être conscient du potentiel élevé de complications si/quand vous les utilisez, et essayez toujours de voir s'il existe une autre solution indépendante de l'apparence et de la sensation à vos problèmes -- le plus souvent, vous trouverez que ces méthodes ne sont pas nécessaires.

À propos, si vous vous sentez frustré par les gestionnaires de mise en page standard, il existe un grand nombre de bons gestionnaires tiers gratuits et à code source ouvert, par exemple JGoodies' FormLayout ou MigLayout . Certains éditeurs d'interface graphique ont même un support intégré pour les gestionnaires de mise en page tiers -- l'éditeur d'interface graphique WindowBuilder d'Eclipse, par exemple, est livré avec un support pour les gestionnaires de mise en page suivants FormLayout y MigLayout .

2 votes

+1 une réponse attentionnée - juste en désaccord avec ils ne sont pas intrinsèquement mauvais simplement parce qu'ils le sont :-) En règle générale, les clients extérieurs n'ont aucune chance de deviner - et les simples suppositions sont ce qui se rapproche le plus des indications de mise en page à mi-chemin : seuls les composants eux-mêmes disposent de toutes les informations à tout moment pour renvoyer quelque chose d'utile. Et à partir du moment où des personnes extérieures interviennent, il est de leur responsabilité de maintenir ces indications à jour, ce qu'elles ne peuvent pas faire.

2 votes

Eh bien, vous savez, j'ai une vision plus "les armes ne tuent pas les gens, les gens tuent les gens" de ce genre de choses. :) Si quelqu'un utilise ces méthodes, ils besoin de d'être conscient de choses comme les bons points que vous soulevez à propos de l'utilisation imprévisible des conseils de mise en page (c'est pourquoi les situations où ces méthodes sont appropriées sont rares en effet).

0 votes

Je pense que le fait de fixer la taille préférée n'est pas du tout un gros drapeau rouge. Ne pas la définir est un grand drapeau rouge à la place. Laissez-moi développer. Le gestionnaire de mise en page - aussi intelligent soit-il - n'a aucune idée de la fonction logique d'un widget de GUI. Par exemple, le gestionnaire de mise en page ne peut pas faire la distinction entre un JTextField pour saisir un code postal et un JTextField pour saisir un nom. De même, il ne peut pas faire la différence entre un bouton d'outil à côté d'un JTextField et un gros bouton OK au bas d'un formulaire. Par conséquent, il faut soit un meilleur ensemble de widgets, soit des indications de taille, non ?

21voto

Tom Points 2773

Si vous rencontrez des difficultés avec les mises en page dans Java Swing, je vous recommande vivement le logiciel JGoodies FormLayout fourni gratuitement dans le cadre de la bibliothèque freeware Forms par Karsten Lentzsch aquí .

Ce gestionnaire de mise en page très populaire est extrêmement flexible et permet de développer des interfaces utilisateur Java très soignées.

Vous trouverez la documentation de Karsten dans aquí et une bonne documentation sur eclipse aquí .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X