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

481

Plusieurs fois, on m'a reproché d'avoir suggéré l'utilisation des méthodes suivantes:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

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

Avec les mises en page, la réponse est toujours la même: utilisez un LayoutManager approprié

J'ai cherché un peu sur le Web, mais je n'ai trouvé aucune analyse complète du 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 dois-je 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 peux que penser à ajouter de la portabilité entre des systèmes avec une résolution d'écran différente).
  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?
  5. Si la réponse à 4 est "oui", cela ne conduira-t-il pas à une prolifération de classes LayoutManager qui deviendra difficile à maintenir?
  6. Dans une situation où je dois définir des proportions entre les enfants d'un composant (par exemple, enfant1 doit utiliser 10% de l'espace, enfant2 40%, enfant3 50%), est-il possible d'y parvenir sans implémenter un LayoutManager personnalisé?
Heisenbug
la source

Réponses:

236
  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 dois-je les utiliser? Dans quel contexte? À quelles fins?

    Je ne sais pas, personnellement, je pense que c'est un accident de conception d'API. Légèrement forcé par des composants composés ayant des idées spéciales sur la taille des enfants. "Légèrement", car 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 que penser à ajouter la portabilité entre des systèmes avec 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 le règlement (hehe) ou dans le lien @bendicott trouvé dans son commentaire à ma réponse . Socialement, poser des tonnes de travail sur votre malheureux 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 grands sont JGoodies FormLayout, MigLayout, DesignGridLayout. Donc non, en pratique, vous écrivez rarement des LayoutManagers, sauf pour des environnements simples et hautement spécialisés.

  5. Si la réponse à 4 est "oui", cela ne conduira-t-il pas à une prolifération de classes LayoutManager qui deviendra difficile à maintenir?

    (La réponse à 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 implémenter un LayoutManager personnalisé?

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

kleopatra
la source
4
Je ne suis pas tout à fait sûr d'être d'accord avec ce conseil dans au moins deux situations. 1) Composants rendus personnalisés 2) Utilisation d'un JEditorPaneavec HTML qui ne suggère pas lui-même une largeur. OTOH Je ne sais pas si j'ai raté quelque chose. J'examinerai attentivement les réponses sur le fil, mais je serais intéressé si vous aviez des commentaires, en particulier sur ce dernier cas.
Andrew Thompson
2
@Andrew Thompson 1) compositions personnalisées: c'est la composition elle-même qui est chargée de renvoyer des conseils de mise en page utiles, si elles ne sont pas impliquées, la bogue 2) même les compositions de base sont boguées ;-) intentionnel cette fois, merci :-)
kleopatra
8
Je ne peux pas croire que la réponse acceptée soit celle qui dit d'éviter d'utiliser les méthodes setXXX (). Parfois, vous en avez simplement besoin pour fournir un indice au gestionnaire de mise en page. Si vous disposez d'un panneau, vous devez absolument vous sentir libre d'utiliser ces méthodes si nécessaire. En disant que je pense que si vous utilisez le gestionnaire de mise en page approprié, vous n'aurez pas besoin de ces méthodes très souvent, mais parfois vous en aurez simplement besoin. Essayez de placer un JComboBox ou JSpinner dans un BoxLayout X_AXIS et ne les utilisez pas, croyez que vous y trouverez besoin de setMaximumSize ().
Michael
5
@Michael non, je n'en ai absolument pas besoin - la réponse est toujours d'utiliser un LayoutManager décent et de faire des ajustements précis au niveau du gestionnaire (par rapport au niveau des composants)
kleopatra
5
Vous continuez à dire "utilisez un LayoutManager décent et dites-lui quelles tailles vous voulez" partout dans stackoverflow, mais vous ne donnez jamais d'exemples spécifiques d'un LayoutManager "décent". Et aucun des gestionnaires standard ne permet de contrôler directement les tailles.
Ti Strga
100

Quelques heuristiques:

  • Ne l'utilisez pas set[Preferred|Maximum|Minimum]Size()lorsque vous avez vraiment l' intention de remplacer get[Preferred|Maximum|Minimum]Size(), comme cela pourrait être fait lors de la création de votre propre composant, illustré ici .

  • Ne l'utilisez pas set[Preferred|Maximum|Minimum]Size()lorsque vous pouvez compter sur un composant soigneusement remplacé getPreferred|Maximum|Minimum]Size, comme illustré ici et ci-dessous.

  • Utilisez-le set[Preferred|Maximum|Minimum]Size()pour dériver la post- validate()géométrie, comme illustré ci-dessous et ici .

  • Si un composant n'a pas de taille préférée, par exemple JDesktopPane, vous devrez peut-être dimensionner le conteneur, mais un tel choix est arbitraire. Un commentaire peut aider à clarifier l'intention.

  • Envisagez des dispositions alternatives ou personnalisées lorsque vous constatez que vous devrez parcourir plusieurs composants pour obtenir des tailles dérivées, comme mentionné dans ces commentaires .

entrez la description de l'image ici

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 /programming/7229226
 * @see /programming/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());
            }
        }
    }
}
poubelle
la source
2
en désaccord (comme vous l'avez peut-être deviné :-) avec le raisonnement par "facteurs externes": les propriétés XXSize sont destinées à exprimer uniquement des besoins internes . Ajuster ceux de l'extérieur est une mauvaise utilisation, c'est-à-dire un piratage. Si vous voulez un cadre (interne ou J) avec une taille spécifique par rapport à ce qu'il préfère ... dimensionnez le cadre, pas le contenu
kleopatra
2
@kleopatra: juste pour insister un peu: 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 design? Le modificateur public ne dit-il pas implicitement à l'utilisateur qu'il peut utiliser ces méthodes?
Heisenbug
2
Je suis d'accord avec @kleopatra: setPreferredSize()remplace toujours le calcul du composant par un choix arbitraire.
trashgod
1
@trashgod +100 pour vous Je pense qu'il n'y a aucun problème à remplacer ces méthodes, même à les appeler (mais bien sûr, cela signifierait que vous avez un composant personnalisé, donc remplacer serait mieux)
David Kroukamp
5
@DavidKroukamp: Merci. Je m'en remets à la plus grande expérience de kleopatra, mais je vois l'intérêt d'examiner d'un œil critique le point de vue contraire.
trashgod
47

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

Non, il n'y a aucune preuve formelle suggérant que l'appel ou la substitution de ces méthodes n'est pas autorisé. En fait, Oracle dit 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) lors de l' extension d' un composant Swing (plutôt que d'appeler la méthode sur l'instance de composant personnalisé)

Plus important encore, 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 disposition qui respecte la taille demandée du composant.

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

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

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

  • De nombreux gestionnaires de mise en page ne prêtent pas attention à la taille maximale demandée d'un composant. Cependant, BoxLayoutet SpringLayoutfaites. En outre, GroupLayoutoffre la possibilité de définir explicitement la taille minimale, préférée ou maximale, sans toucher au composant.

  • Assurez-vous que vous devez vraiment 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 l'apparence. Ainsi, avoir une taille définie peut produire des looks variés de l'interface utilisateur sur différents systèmes

  • parfois, des problèmes peuvent être rencontrés avec les GridBagLayoutchamps 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 une réduction assez importante des champs de texte.

  • JFramen'applique pas outrepassé getMinimumSize()uniquement en faisant appel setMinimumSize(..)à ses œuvres

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?

Si en implémentant vous entendez utiliser alors oui. Personne ne LayoutMangerpeut tout gérer, chacun LayoutManagera ses avantages et ses inconvénients, chacun peut donc être utilisé ensemble pour produire la mise en page finale.

Référence:

David Kroukamp
la source
3
fournir des indices de taille personnalisés qui sont une contradiction en soi: fournir des indices de dimensionnement (en px!) est la tâche exclusive du composant. Il les calcule en fonction des détails de l'état interne qu'aucune autre partie sauf elle-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 pertinentes pour la taille "sémantique", le nombre de lignes / colonnes dans un composant texte
kleopatra
3
@kleopatra J'aimerais toujours savoir pourquoi Oracle nous dit alors comment utiliser ces méthodes et la bonne façon de les utiliser. Nous pourrions avoir nos propres préférences, mais nous ne pouvons pas dire que les concepteurs indiquent qu'il ne doit pas être utilisé lorsqu'il n'y a aucune preuve pour le suggérer. Mais c'est pourquoi j'ai mis en place la prime voir peut-être si cela attirerait d'autres personnes qui pourraient donner des informations d'une source crédible où Oracle déclare de ne pas utiliser ces méthodes du tout (ce qui en fait une mauvaise pratique si vous le faites, par exemple, setMinimumSize doit être appelé sur des choses comme JSplitPane, etc. cela peut être vu dans le tutoriel Oracle des volets divisés.
David Kroukamp
4
@David: J'en suis venu à voir les setXxxSizeméthodes comme un drapeau rouge que je pourrais finir ici , même lorsque les documents le suggèrent. J'aurais presque toujours dû passer outre getXxxSize, où l'on a accès à la géométrie requise; et même de courts exemples sont recyclés plus que je ne le pense. +1 pour mentionner les variations entre les gestionnaires de mise en page et citer le didacticiel.
trashgod
1
D'oh, dans mon commentaire ci-dessus, je voulais citer la réponse ici .
trashgod
13
+1 "Non, il n'y a aucune preuve formelle suggérant que l'appel ou la substitution de ces méthodes n'est pas autorisé." Repérez. Le message marqué comme réponse est simplement BS.
TT.
25

Il y a beaucoup de bonnes réponses ici, mais je veux ajouter un peu plus sur les raisons pour lesquelles vous devriez normalement les éviter (la question vient de se poser à nouveau dans un sujet en double):

À quelques exceptions près, si vous utilisez ces méthodes, vous ajustez probablement votre interface graphique pour bien paraître sur un aspect spécifique (et avec vos paramètres spécifiques au 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 le sont . Dès que vous commencez à régler la position et la taille des pixels dans une mise en page, vous risquez de casser votre interface graphique (ou, au minimum, de ne pas bien paraître) sur d'autres plates-formes.

Par exemple, essayez de changer l'apparence par défaut de votre application. Même avec les options disponibles sur votre plate-forme, vous serez peut-être surpris de la mauvaise qualité des résultats.

Donc, au nom de garder votre interface graphique fonctionnelle et agréable sur toutes les plates-formes (rappelez-vous, l'un des principaux avantages de Java est sa multiplicité), vous devez vous fier aux gestionnaires de mise en page, etc., pour ajuster automatiquement les tailles de vos composants afin qu'il s'affiche correctement en dehors de votre environnement de développement spécifique.

Cela dit, vous pouvez certainement concevoir des situations où ces méthodes sont justifiées. Encore une fois, ils ne sont pas intrinsèquement mauvais, mais leur utilisation est normalement un gros drapeau rouge indiquant des problèmes potentiels d'interface graphique. Assurez-vous simplement que vous êtes conscient du risque élevé de complications si / quand vous les utilisez, et essayez toujours de penser s'il existe une autre solution indépendante de l'apparence à vos problèmes - le plus souvent, vous constaterez que ces les méthodes ne sont pas nécessaires.

Soit dit en passant, si vous vous sentez frustré par les gestionnaires de mise en page standard, il y en a beaucoup de bons tiers gratuits et open source, par exemple JGoodiesFormLayout , ou MigLayout. Certains constructeurs d'interface graphique ont même une prise en charge intégrée des gestionnaires de disposition tiers - l'éditeur d'interface graphique WindowBuilder d'Eclipse, par exemple, est livré avec la prise en charge de FormLayoutet MigLayout.

Jason C
la source
2
+1 une réponse attentionnée - juste en désaccord avec le fait qu'ils ne sont pas intrinsèquement mauvais simplement parce qu'ils sont :-) En règle générale, les clients extérieurs n'ont aucune chance de deviner - et les simples hypothèses sont aussi proches que les étrangers peuvent le faire - des conseils de mise en page à mi-chemin corrects: seulement les composants eux-mêmes ont toutes les informations à tout moment pour renvoyer quelque chose d'utile. Et depuis le moment où des étrangers interfèrent, il est de leur responsabilité de maintenir à jour ces indices qu'ils ne peuvent pas.
kleopatra
1
Eh bien, vous savez, j'ai une vision plus «les armes à feu ne tuent pas les gens, les gens tuent les gens» de ce genre de choses. :) Si quelqu'un utilise ces méthodes, il doit ê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 en effet rares).
Jason C
Je pense que définir la taille préférée n'est pas du tout un gros drapeau rouge. Ne pas le régler est plutôt un gros drapeau rouge. Permettez-moi de développer. Le gestionnaire de disposition - aussi intelligent soit-il - n'a aucune idée de la fonction logique d'un widget gui. Par exemple, le gestionnaire de mise en page ne peut pas faire la distinction entre un JTextField pour entrer le code postal et un JTextField pour entrer un nom. De même, il ne peut pas faire la distinction entre un bouton d'outil à côté d'un JTextField ou un gros bouton OK au bas d'un formulaire. Par conséquent, soit un meilleur ensemble de widgets, soit quelques conseils de dimensionnement sont nécessaires, non?
Gee Bee
@GeeBee Nope, c'est un excellent exemple de drapeau rouge, en fait. Ce que vous devez faire est d' utiliser JTextField.setColumnspour définir le nombre de colonnes, qui ajuste la taille préférée en conséquence. Si vous le faites, setPreferredSizevous codez en dur une taille, ce qui cassera vos dispositions en fonction de la taille de la police de la plate-forme. Voici quelques champs de texte dans une disposition de sac de grille avec setColumnsappelé de manière appropriée . Pour vos boutons, utilisez les dispositions / poids de grille appropriés pour contrôler les tailles.
Jason C
@GeeBee Et maintenant, avec cela fait correctement, remarquez comment les largeurs des champs de texte sont diminuées lorsque je diminue la taille de la police: i.snag.gy/ZULulh.jpg . Même changer la taille de la police à la volée fonctionne désormais automatiquement, plutôt que vous devez, par exemple, recalculer toutes les largeurs de champ de texte et appeler explicitement à nouveau setPreferredSize pour chacune, tout ce que vous avez à faire est d'invalider la mise en page et leurs tailles s'ajusteront.
Jason C
20

Si vous rencontrez des problèmes avec les mises en page dans Java Swing, je peux fortement recommander les JGoodies FormLayoutfournis gratuitement dans le cadre de la bibliothèque de logiciels gratuits Forms par Karsten Lentzsch ici .

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

Vous trouverez la documentation de Karsten ici , et une assez bonne documentation d'Eclipse ici .

À M
la source
16

Ces méthodes sont mal comprises par la plupart des gens. Vous ne devez absolument pas ignorer ces méthodes. Il appartient au gestionnaire de mise en page s'il respecte ces méthodes. Cette page contient un tableau qui indique quels gestionnaires de mise en page honorent laquelle de ces méthodes:

http://thebadprogrammer.com/swing-layout-manager-sizing/

J'écris du code Swing depuis plus de 8 ans et les gestionnaires de mise en page inclus dans le JDK ont toujours répondu à mes besoins. Je n'ai jamais eu besoin d'un gestionnaire de mise en page tiers pour réaliser mes mises en page.

Je dirai que vous ne devriez pas essayer de donner des conseils au gestionnaire de disposition avec ces méthodes tant que vous n'êtes pas sûr d'en avoir besoin. Faites votre mise en page sans donner de conseils de dimensionnement (c.-à-d. Laissez le gestionnaire de mise en page faire son travail) et vous pourrez ensuite apporter des corrections mineures si vous en avez besoin.

Michael
la source
1
soit il y a une légère idée fausse (de votre part) ou un malentendu (de ma part), faites votre choix :-) Vous continuez à répéter (ici, dans votre blog, dans votre réponse relative à BoxLayout) l' ensemble XXSize comme étant important - en fait le LayoutManager s'intéresse (ou non) à la XXSize, c'est-à-dire l' indice de dimensionnement indépendant de la façon dont il a été créé (calcul interne par le composant ou forcé manuellement par le code d'application)
kleopatra
1
Je ne suis pas sûr de comprendre ce que vous voulez dire ici. Je mentionne ci-dessus que les méthodes XXSize () ne sont que des indices. Je ne vois vraiment rien de mal à donner un petit indice à un gestionnaire de mise en page, si nécessaire. Dans mon code swing, vous trouverez une méthode setXXSize () occasionnelle. Pas beaucoup, mais de temps en temps, je trouve qu'ils sont nécessaires. JComboBox et JSpinner ont souvent besoin d'indices. Surtout un JComboBox qui est rempli après sa réalisation. Vous semblez être contre toute utilisation de ces méthodes et je ne sais pas pourquoi. (je suis peut-être celui qui manque le bateau à ce sujet, je suppose).
Michael
5
ce ne sont pas les méthodes qui sont les conseils, les propriétés sont: les composants doivent rapporter quelque chose de raisonnable pour tous les conseils, certains (comme fi JComboBox) ne le font pas - en retournant maxInteger ou plus. C'est un bug et devrait être corrigé par le combo. Quant à votre habitude: assurez-vous d'être loin lorsque le collègue responsable du nettoyage doit nettoyer cela :) Les indices codés en dur ont tendance à détruire la mise en page au moindre changement et sont difficiles à détecter comme la raison d'une mise en page cassée.
kleopatra
15

Dans une situation où je dois définir des proportions entre les enfants d'un composant (l'enfant 1 doit utiliser 10% de l'espace, l'enfant2 40%, l'enfant3 50%), est-il possible d'y parvenir sans implémenter un gestionnaire de disposition personnalisé?

Peut GridBagLayout- être satisferait vos besoins. En plus de cela, il y a une tonne de gestionnaires de mise en page sur le Web, et je parie qu'il y en a un qui correspond à vos besoins.

Thomas
la source
Merci d'avoir répondu. Je dois supposer que vous vouliez aussi dire: "n'utilisez pas du tout setPreferredSize", non?
Heisenbug
1
GridBagLayout utilise des contraintes, où vous pouvez spécifier le "poids" à la fois en X et Y pour un composant donné, afin que le LayoutManager puisse décider quoi faire avec l'espace supplémentaire sur un redimensionnement. MAIS vous avez toujours besoin / pouvez utiliser setPreferredSize pour déterminer la taille préférée de chaque composant, notez que "préféré" ne signifie pas qu'il sera toujours respecté. Pour des cas particuliers, vous pouvez également avoir besoin de setMinimumSize et setMaximumSize. Ils ne sont pas mauvais , n'adhérez pas à cela. docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
マ ル ち ゃ ん だ よ
5

Je vois cela différemment de la réponse acceptée.

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

N'évitez jamais! Ils sont là pour exprimer les contraintes de taille de vos composants au gestionnaire de disposition. Vous pouvez éviter de les utiliser si vous n'utilisez aucun gestionnaire de mise en page et essayez de gérer la mise en page visuelle par vous-même.

Malheureusement, Swing ne vient pas avec des dimensions par défaut raisonnables. Cependant, au lieu de définir les dimensions d'un composant, il est préférable d'utiliser la POO pour descendre votre propre composant avec des valeurs par défaut raisonnables. (Dans ce cas, vous appelez setXXX dans votre classe descendante.) Vous pouvez également remplacer les méthodes getXXX pour le même effet.

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

Toujours. Lorsque vous créez un composant, définissez sa taille réaliste min / préférée / max en fonction de l'utilisation de ce composant. Par exemple, si vous avez un JTextField pour saisir des symboles de pays tels que le Royaume-Uni, sa taille préférée doit être aussi large pour contenir deux caractères (avec la police actuelle, etc.), mais il est probablement inutile de le laisser grossir. Après tout, les symboles de pays sont deux caractères. Comme ci-contre, si vous avez un JTextField pour entrer par exemple un nom de client, il peut avoir une taille préférée comme la taille de pixel pour 20 caractères, mais peut devenir plus grand si la mise en page est redimensionnée, alors définissez la taille maximale sur plus. Dans le même temps, avoir un JTextField large de 0px est inutile, alors définissez une taille minimale réaliste (je dirais la taille de pixel de 2 caractères).

3) Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes?

(Je ne peux que penser à ajouter de la portabilité entre des systèmes avec une résolution d'écran différente).

Pas de conséquences négatives. Ce sont des conseils pour le gestionnaire de mise en page.

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?

Non, absolument pas. L'approche habituelle consiste à mettre en cascade différents gestionnaires de mise en page de base tels que la mise en page horizontale et verticale.

Par exemple, la disposition ci-dessous:

<pre>
+--------------+--------+
| ###JTABLE### | [Add]  | 
| ...data...   |[Remove]|
| ...data...   |        |
| ...data...   |        |
+--------------+--------+
</pre>

est d'avoir deux parties. Les parties gauche et droite sont une disposition horizontale. La partie droite est un JPanel ajouté à la disposition horizontale, et ce JPanel a une disposition verticale qui dispose les boutons verticalement.

Bien sûr, cela peut devenir délicat avec une mise en page réelle. Par conséquent, les gestionnaires de disposition basés sur une grille tels que MigLayout sont bien meilleurs si vous êtes sur le point de développer quelque chose de sérieux.

5) Si la réponse à 4 est "oui", cela ne conduira-t-il pas à une prolifération de classes LayoutManager qui deviendra difficile à maintenir?

Non, vous ne développerez certainement pas de gestionnaires de mise en page, sauf si vous avez besoin de quelque chose de très spécial.

6) Dans une situation où je dois définir des proportions ...

entre les enfants d'un composant (par exemple, enfant1 doit utiliser 10% de l'espace, enfant2 40%, enfant3 50%), est-il possible d'y parvenir sans implémenter un LayoutManager personnalisé?

Fondamentalement, une fois que les tailles préférées sont définies correctement, vous ne voudrez peut-être rien faire en pourcentage. Tout simplement, parce que les pourcentages sont inutiles (par exemple, il est inutile d'avoir un JTextField 10% de la taille de la fenêtre - car on peut réduire la fenêtre pour que JTextField ait une largeur de 0px, ou peut agrandir la fenêtre pour que le JTextField soit sur deux affichages sur un écran). configuration multi-affichage).

Mais, parfois, vous pouvez utiliser les pourcentages pour contrôler la taille des blocs de construction plus gros de votre interface graphique (panneaux, par exemple).

Vous pouvez utiliser JSplitPane où vous pouvez prédéfinir le rapport des deux côtés. Ou, vous pouvez utiliser MigLayout qui vous permet de définir ces contraintes en pourcentage, pixels et autres unités.

Gee Bee
la source
Vraiment? C'était à 0? C'est mieux que la réponse acceptée qui a plus de 100 ups. Cela dit en gros "Tu utiliseras névar setPreferredSize!" ce qui est TERRIBLE. Dans ma ligne de travail, il y a BEAUCOUP d'exigences de taille spécifiques, telles que "Les boutons sur les écrans tactiles doivent être [X] par [Y] avec un espacement de [M] x [N] entre" l'exigence de sécurité. btnBar.setPreferredSize( dimTouchBtn );est la meilleure façon de le faire. Simple, pas besoin de gestionnaire de mise en page personnalisé. J'utilise principalement GridBagLayoutavec certains BorderLayoutet BoxLayout, emboîtant quand c'est pratique. Il s'agit d'une combinaison solide et facile à utiliser.
Loduwijk
J'étais précipité dans mon commentaire ci-dessus. Ce fut la première réponse que j'ai vue après la réponse acceptée. Pourquoi SO ne trie-t-il plus par nombre de voix? Je pensais que c'était à l'origine l'une des principales raisons du décompte des voix. Je maintiens néanmoins le commentaire original; c'est l'une des meilleures réponses. Sauf pour son point n ° 6 - celui-là n'est pas aussi génial. Il existe de nombreuses raisons (une minorité peut encore être un grand nombre) de redimensionner, et GridBagLayout le supporte bien dans la plupart des cas.
Loduwijk
Je pense que redimensionner vs ne pas redimensionner ne doit pas être traité comme une décision religieuse. Il existe des cas d'utilisation où personne ne veut redimensionner quoi que ce soit, par exemple si vous développez une interface graphique pour un kiosque, avec une résolution fixe prédéfinie. Si vous avez des cibles différentes, comme des écrans IHM industriels et le cas des "boutons", alors oui, vous devez avoir au moins 1 cm par 1 cm pour un bouton sur un écran tactile. Dans ce cas, le DPI de l'écran définit la façon dont vous redimensionnez. D'autres entrées telles que les champs de texte peuvent ne pas être redimensionnées verticalement du tout, et parfois (comme un code postal) le redimensionnement horizontal est également inutile.
Gee Bee
0

Dois-je éviter complètement l'utilisation de ces méthodes? Je ne dirais pas "les éviter". Je dirais que si vous pensez en avoir besoin, vous faites probablement quelque chose de mal. Les tailles des composants sont déterminées en fonction du contexte. Par exemple, la taille des composants de texte est déterminée par le nombre de lignes et de colonnes que vous spécifiez, combiné à la police que vous avez choisie. La taille de votre bouton et de votre étiquette sera la taille du graphique, si vous en avez défini un, ou l'espace nécessaire pour afficher le texte que vous avez défini. Chaque composant a une taille naturelle et les gestionnaires de disposition les utiliseront pour tout disposer sans que vous ayez à spécifier de tailles. La principale exception est le JScrollPane, qui a une taille indépendante de ce qu'il contient. Pour ceux-là, je vais parfois appeler setSize(), et laisser cette taille déterminer la taille initiale de la fenêtre, en appelantJFrame.pack(). Habituellement, je laisse la taille de la fenêtre déterminer la taille de JScrollPane. L'utilisateur déterminera la taille de la fenêtre. De nombreux gestionnaires de mise en page ignorent de toute façon les tailles que vous définissez, donc ils ne font souvent pas grand-chose.

Les méthodes ont été définies pour une raison. Alors, quand dois-je les utiliser? Dans quel contexte? À quelles fins? Je pense qu'ils ont été ajoutés pour fournir des conseils aux gestionnaires de mise en page. Ils peuvent avoir été écrits pour des raisons historiques, car les gestionnaires de mise en page étaient nouveaux et les gens ne leur faisaient pas entièrement confiance. Je connais quelques développeurs qui ont évité les gestionnaires de mise en page et ont tout placé manuellement, simplement parce qu'ils ne voulaient pas se soucier d'apprendre un nouveau paradigme. C'est une terrible idée.

Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes? (Je ne peux que penser à ajouter la portabilité entre des systèmes avec une résolution d'écran différente). Ils sont inefficaces et produisent de mauvaises dispositions, les objets étant serrés ou étirés à des tailles non naturelles. Et les dispositions seront fragiles. Les modifications de la taille de la fenêtre cassent parfois la disposition et mettent les choses aux mauvais endroits.

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? Vous ne devez pas "implémenter" un nouveau LayoutManager. Vous devez instancier ceux qui existent déjà. J'utilise souvent plusieurs gestionnaires de mise en page dans une seule fenêtre. Chaque JPanel aura son propre gestionnaire de mise en page. Certaines personnes rechignent aux dispositions imbriquées, car elles sont difficiles à maintenir. Lorsque je les utilise, je donne à chacun sa propre méthode de création pour qu'il soit plus facile de voir ce que chacun fait. Mais je n'implémente jamais un gestionnaire de mise en page. Je les instancie juste.

Si la réponse à 4 est "oui", cela ne conduira-t-il pas à une prolifération de classes LayoutManager qui deviendra difficile à maintenir? Si vous implémentez de nouvelles classes de gestionnaire de disposition pour de légères variations de disposition, vous les utilisez mal. Si vous implémentez simplement de nouveaux gestionnaires de disposition, vous faites probablement quelque chose de mal. La seule fois où j'ai étendu une classe LayoutManager, c'était pour ajouter un curseur de zoom à un JScrollPane.

Dans une situation où je dois définir des proportions entre les enfants d'un composant (par exemple, enfant1 doit utiliser 10% de l'espace, enfant2 40%, enfant3 50%), est-il possible d'y parvenir sans implémenter un LayoutManager personnalisé? Le JSplitPane a un moyen de spécifier le pourcentage que chaque composant doit obtenir. Le séparateur est mobile par défaut, mais vous pouvez le désactiver si vous le souhaitez. Je n'utilise pas beaucoup cette fonctionnalité. J'ai généralement certains composants qui prennent une taille définie, et le reste de l'espace est occupé par un volet de défilement. La taille du volet de défilement s'ajustera à la taille de la fenêtre. Si vous avez deux volets de défilement côte à côte, vous pouvez les placer dans un JSplitPane et spécifier le pourcentage de nouvel espace donné à chacun à mesure que l'utilisateur agrandit et contracte les fenêtres.

MiguelMunoz
la source