web-dev-qa-db-fra.com

Devrais-je éviter l'utilisation de méthodes set (Preferred | Maximum | Minimum) Size dans Java Swing?

On m'a reproché à plusieurs reprises d'avoir suggéré d'utiliser les méthodes suivantes:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

sur les composants Swing. 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 dispositions, la réponse est toujours la même: utilisez un .__ approprié. LayoutManager

J'ai un peu cherché sur le Web, mais je n'ai trouvé aucune analyse complète du sujet. J'ai donc les questions suivantes:

  1. Devrais-je éviter complètement l'utilisation de ces méthodes?
  2. Les méthodes ont été définies pour une raison. Alors, quand devrais-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 à l’ajout de la portabilité entre les systèmes avec une résolution d’écran différente).
  4. Je ne pense pas que 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 à 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 les proportions entre les enfants d'un composant (par exemple, l'enfant1 devrait utiliser 10% d'espace, l'enfant2 à 40%, l'enfant3 à 50%), est-il possible d'y parvenir sans implémenter un gestionnaire LayoutManager personnalisé?
457
Heisenbug
  1. Devrais-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 devrais-je les utiliser? Dans quel contexte? À quelles fins?

    Je ne sais pas, personnellement, je le considère comme un accident de conception d'API. Légèrement contraint par les 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 à l'ajout de 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 les Rules (hehe) ou dans le link @bendicott trouvé dans ses/son commentaire à ma réponse . Sur le plan social, faire des tonnes de travail pour votre malheureux qui doit gérer le code et retrouver une mise en page endommagée.

  4. Je ne pense pas que 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?

    Oui, il existe des gestionnaires de mises en page assez puissants pour répondre à une très bonne approximation de "tous les besoins en mise en page". Les trois grands sont JGoodies FormLayout, MigLayout, DesignGridLayout. Donc non, en pratique, vous écrivez rarement 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 les proportions entre les enfants d'un composant (par exemple, l'enfant 1 doit utiliser 10% d'espace, l'enfant 2 40%, l'enfant 3 50%), est-il possible d'y parvenir sans implémenter un gestionnaire LayoutManager personnalisé?

    Aucun des Trois Grands ne peut, même pas GridBag (ne jamais se donner la peine de vraiment maîtriser, trop de problèmes pour trop peu d'énergie).

231
kleopatra

Quelques heuristiques:

  • N'utilisez pas set[Preferred|Maximum|Minimum]Size() lorsque vous voulez réellement remplacer le get[Preferred|Maximum|Minimum]Size(), comme cela pourrait être le cas lors de la création de votre propre composant, affiché ici .

  • N'utilisez pas set[Preferred|Maximum|Minimum]Size() si vous pouviez vous fier au getPreferred|Maximum|Minimum]Size soigneusement remplacé par un composant, comme indiqué ici et ci-dessous.

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

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

  • Envisagez des dispositions alternatives ou personnalisées lorsque vous vous trouvez dans l'obligation de parcourir plusieurs composants pour obtenir des tailles dérivées, comme indiqué dans ces comments .

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());
            }
        }
    }
}
97
trashgod

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

Non, aucune preuve formelle ne suggère que l'appel ou le remplacement de ces méthodes n'est pas autorisé. En fait, Oracle indique que ces méthodes sont utilisées pour donner des conseils 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) lorsque extension un composant Swing (plutôt que d'appeler la méthode sur l'instance du composant personnalisé).

Plus important encore, quelle que soit la manière 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 devrais-je les utiliser? Dans quel contexte? À quelles fins?

Lorsque vous devez fournir des conseils de taille personnalisés aux conteneurs Gestionnaire de disposition afin que le composant soit bien agencé

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

  • De nombreux gestionnaires de disposition ne font pas attention à la taille maximale demandée par un composant. Cependant, BoxLayout et SpringLayout le font. De plus, 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 vraiment 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 utilisée et de son apparence. Ainsi, avoir une taille définie peut produire des regards de l'interface utilisateur différents sur différents systèmes.

  • des problèmes peuvent parfois survenir avec les champs GridBagLayout et text, dans lesquels, 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 importante des champs de texte.

  • JFrame n'applique pas getMinimumSize() surchargée en appelant seulement setMinimumSize(..) sur ses travaux

Je ne pense pas que LayoutManager puisse satisfaire exactement toutes les mises en page souhaitées Besoins. Dois-je vraiment implémenter un nouveau LayoutManager pour chaque peu de variation sur ma mise en page?

Si par implémentation, vous entendez utiliser, alors oui. Aucune LayoutManger ne peut tout gérer, chaque LayoutManager a ses avantages et ses inconvénients, de sorte que chacun peut être utilisé ensemble pour produire la mise en page finale.

Référence:

46
David Kroukamp

Il y a beaucoup de bonnes réponses ici, mais je voudrais ajouter un peu plus de détails sur les raisons pour lesquelles vous devriez normalement éviter cespourquoi (la question vient d'être posée à nouveau dans un sujet dupliqué):

À quelques exceptions près, si vous utilisez ces méthodes, vous ajustez probablement votre interface graphique afin de lui donner une apparence précise (et avec les paramètres spécifiques de 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 are _. Dès que vous commencez à ajuster les positions et les tailles de pixel dans une présentation, vous courez le risque de voir votre interface graphique se briser (ou au moins, avoir l'air mauvaise), sur d'autres plates-formes.

Par exemple, essayez de modifier l'aspect et la convivialité par défaut de votre application. Même avec les options disponibles sur votre plate-forme, vous serez peut-être surpris de la qualité médiocre du rendu des résultats.

Ainsi, afin de garder votre interface graphique fonctionnelle et de belle apparence sur toutes les plateformes (rappelez-vous, l'un des principaux avantages de Java est son multiplicité de plateformes), vous devez vous fier aux gestionnaires de disposition, etc., pour ajuster automatiquement la taille des fichiers. vos composants afin qu’ils s'affichent 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 diaboliques, mais leur utilisation est normalement un big drapeau rouge indiquant des problèmes potentiels d’interface graphique. Assurez-vous simplement que vous êtes conscient du risque élevé de complications que vous rencontrez si vous les utilisez, et essayez toujours de penser s’il existe une autre solution indépendante de vos problèmes - vous constaterez plus souvent que ces problèmes les méthodes ne sont pas nécessaires.

En passant, si vous vous sentez frustré par les gestionnaires de disposition standard, il existe de nombreux bons logiciels tiers gratuits, tels que JGoodies 'FormLayout , 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 fourni avec le support de FormLayout et MigLayout.

25
Jason C

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

Ce gestionnaire de disposition très populaire est extrêmement flexible et permet de développer des interfaces utilisateur Java très sophistiquées.

Vous trouverez la documentation de Karsten dans ici , et quelques informations plutôt bonnes d'Eclipse ici .

19
Tom

Ces méthodes sont mal comprises par la plupart des gens. Vous ne devez absolument pas ignorer ces méthodes. C'est au responsable de la mise en page s'il respecte ces méthodes. Cette page contient un tableau qui indique quel gestionnaire de disposition honore 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 disposition 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 indications 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 d’indices de dimensionnement (c’est-à-dire laissez le gestionnaire de mise en page faire son travail) et vous pourrez ensuite apporter des corrections mineures si besoin est.

16
Michael

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

Peut-être que GridBagLayout satisferait vos besoins. En plus de cela, il existe une tonne de gestionnaires de disposition sur le Web, et je parie qu’un seul répond à vos besoins.

15
Thomas

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

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

Ne jamais éviter! 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 pas de gestionnaire de présentation et essayez de gérer vous-même la présentation visuelle.

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 OOP de 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 devrais-je les utiliser? Dans quel contexte? À quelles fins?

Toujours. Lorsque vous créez un composant, définissez sa taille réaliste/minimale/maximale en fonction de l'utilisation de ce composant. Par exemple, si vous avez un JTextField pour entrer des symboles de pays tels que le Royaume-Uni, sa taille préférée doit être aussi large que 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 peut avoir une taille préférée, par exemple 20 pixels, mais peut s'agrandir si la mise en page est redimensionnée. Réglez donc la taille maximale davantage. En même temps, avoir un JTextField 0px large n'a pas de sens, alors définissez une taille minimale réaliste (je dirais une 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 à l’ajout de la portabilité entre les systèmes avec une résolution d’écran différente).

Aucune conséquence négative. Ce sont des astuces pour le gestionnaire de disposition.

4) Je ne pense pas que 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 d’agencement de base tels que l’agencement horizontal et vertical.

Par exemple, la mise en page ci-dessous:

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

est d'avoir deux parties. Les parties gauche et droite ont une disposition horizontale. La partie droite est un JPanel ajouté à la disposition horizontale, et ce JPanel a une disposition verticale qui positionne 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 devez absolument pas développer 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, l'enfant1 doit utiliser 10% de l'espace, l'enfant2, 40%, l'enfant3, 50%), est-il possible d'y parvenir sans implémenter un gestionnaire LayoutManager personnalisé?

En gros, une fois que les tailles préférées sont bien définies, vous pouvez ne rien faire en pourcentage. Simplement parce que les pourcentages sont inutiles (par exemple, il est inutile de disposer d’un JTextField de 10% de la taille de la fenêtre, car on peut réduire la fenêtre de sorte que JTextField ait une largeur de 0px ou élargir la fenêtre de sorte que JTextField soit sur deux configuration multi-écrans).

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

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

6
Gee Bee

Dois-je éviter complètement l'utilisation de ces méthodes? Je ne dirais pas "évite". Je dirais que si vous pensez en avoir besoin, vous faites probablement quelque chose de mal. La taille des composants est déterminée dans le contexte. Par exemple, les tailles des composants de texte sont déterminées par le nombre de lignes et de colonnes que vous spécifiez, associé à la police que vous avez éventuellement choisie. La taille de votre bouton et de votre étiquette correspondra à 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 utilisent pour tout disposer sans que vous ayez à spécifier de taille. La principale exception est JScrollPane, dont la taille est indépendante de ce qu’il contient. Pour ceux-là, j’appellerai parfois setSize(), et laisser cette taille déterminer la taille initiale de la fenêtre, en appelant JFrame.pack(). En général, 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 disposition ignorent de toute façon les tailles que vous définissez et ne font souvent pas beaucoup de bien.

Les méthodes ont été définies pour une raison. Alors, quand devrais-je les utiliser? Dans quel contexte? À quelles fins? Je pense qu’ils ont été ajoutés pour fournir des astuces aux gestionnaires de disposition. Ils ont peut-être été écrits pour des raisons historiques, parce que les gestionnaires de disposition étaient nouveaux et que les utilisateurs ne leur faisaient pas entièrement confiance. Je connais quelques développeurs qui ont évité les gestionnaires de disposition et ont tout placé manuellement, simplement parce qu'ils ne voulaient pas se préoccuper d'apprendre un nouveau paradigme. C'est une idée terrible.

Quelles sont exactement les conséquences négatives de l'utilisation de ces méthodes? (Je ne peux que penser à l’ajout de la portabilité entre les systèmes avec une résolution d’écran différente). Ils sont inefficaces et produisent de mauvaises mises en page, des objets étant compressés ou étirés à des tailles non naturelles. Et les dispositions seront fragiles. Des modifications de la taille de la fenêtre peuvent parfois endommager la mise en page et placer des éléments au mauvais endroit.

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? Vous ne devriez pas "implémenter" un nouveau LayoutManager. Vous devriez instancier ceux qui existent déjà. J'utilise souvent plusieurs gestionnaires de disposition dans une seule fenêtre. Chaque JPanel aura son propre gestionnaire de disposition. Certaines personnes hésitent devant les dispositions imbriquées, car elles sont difficiles à maintenir. Quand 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'ai jamais "implémenté" un gestionnaire de disposition. Je viens de les instancier. 

Si la réponse à 4 est "oui", cela ne mènera-t-il pas à une prolifération de classes LayoutManager qui deviendra difficile à maintenir? Si vous implémentez de nouvelles classes du gestionnaire de disposition pour de légères variations de disposition, vous les utilisez mal. Si vous ne faites que mettre en place 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 les proportions entre les enfants d'un composant (par exemple, l'enfant1 devrait utiliser 10% de l'espace, l'enfant2 40%, l'enfant3 50%), est-il possible d'y parvenir sans implémenter un gestionnaire LayoutManager personnalisé? Le composant JSplitPane permet de spécifier le pourcentage que chaque composant doit obtenir. Le diviseur est déplaçable 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 des composants qui prennent une taille définie, et le reste de l'espace est occupé par un panneau de défilement. La taille du volet de défilement sera ajustée à 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 attribué à chacun d'eux au fur et à mesure que l'utilisateur agrandit et contracte les fenêtres.

0
MiguelMunoz