Question Devrais-je éviter l'utilisation de méthodes de taille définies (Preferred | Maximum | Minimum) dans Java Swing?


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

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

sur Swing Composants. Je ne vois aucune alternative à leur utilisation lorsque je souhaite 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   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. Dois-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 à ajouter 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 va-t-il pas entraîner une prolifération de classes LayoutManager qui deviendront difficiles à maintenir?
  6. Dans une situation où j'ai besoin de définir des proportions entre les enfants d'un composant (par exemple, child1 doit utiliser 10% d'espace, child2 40%, child3 50%), est-il possible d'y parvenir sans implémenter un LayoutManager personnalisé?

J'espère avoir été clair.


436
2017-08-29 11:02


origine


Réponses:


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

    Oui pour le code de l'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 pense à 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 devraient avoir implémenté leurs besoins avec un LayoutManager personnalisé.

  3. Quelles sont 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.)

    Certaines raisons (incomplètes, et malheureusement les liens sont rompus suite à la migration de SwingLabs vers java.net) sont mentionnées dans le Règles (hehe) ou dans le lien @bendicott a trouvé dans son / ses commentaire (s) à ma réponse. Socialement, posant des tonnes de travail sur votre malheureux qui doit maintenir le code et doit traquer une mise en page cassée.

  4. Je ne pense pas qu'un LayoutManager puisse répondre exactement à tous les besoins de mise en page souhaités. Ai-je vraiment besoin d'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 LayoutManagers, sauf dans des environnements simples et hautement spécialisés.

  5. Si la réponse à 4 est "oui", cela ne va-t-il pas entraîner une prolifération de classes LayoutManager qui deviendront difficiles à 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 devrait utiliser 10% d'espace, l'enfant 2 40%, l'enfant 3 50%), est-il possible de réaliser cela sans mettre en place un LayoutManager personnalisé?

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


224
2017-08-29 11:33



Quelques heuristiques:

  • Ne pas utiliser set[Preferred|Maximum|Minimum]Size() quand vous voulez vraiment passer outre get[Preferred|Maximum|Minimum]Size(), comme cela pourrait être fait en créant votre propre composant, montré ici.

  • Ne pas utiliser set[Preferred|Maximum|Minimum]Size() quand vous pouvez compter sur un composant soigneusement remplacé getPreferred|Maximum|Minimum]Size, comme montré ici et plus bas.

  • Utiliser set[Preferred|Maximum|Minimum]Size() dériver aprèsvalidate() géométrie, comme indiqué ci-dessous et ici.

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

  • Envisagez des mises en page alternatives ou personnalisées lorsque vous devez parcourir plusieurs composants pour obtenir des tailles dérivées, comme indiqué dans ces pages. 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());
            }
        }
    }
}

92
2017-08-29 11:48



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

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

Plus important encore, peu importe comment 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 indications de taille personnalisées au gestionnaire de mise en page des conteneurs afin que le composant soit bien structuré

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

  • De nombreux gestionnaires de mise en page ne font pas attention à la taille maximale requise d'un composant. cependant, BoxLayout et SpringLayout faire. En outre, GroupLayout permet 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 l'apparence. Ainsi, avoir une taille définie peut produire divers regards de l'interface utilisateur sur différents systèmes

  • parfois des problèmes peuvent être rencontrés avec GridBagLayout et des champs de texte, 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 un rétrécissement substantiel des champs de texte.

  • JFramen'impose pas de dépassement getMinimumSize() appelant seulement setMinimumSize(..) sur ses œuvres

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

Si en mettant en œuvre vous voulez dire en utilisant alors oui. Pas une LayoutManger peut gérer tout, chaque LayoutManager a ses avantages et ses inconvénients ainsi chacun peut être utilisé ensemble pour produire la mise en page finale.

Référence:


41
2017-09-30 22:50



Il y a beaucoup de bonnes réponses ici mais je veux en ajouter un peu plus sur les raisons Pourquoi Normalement, vous devriez les éviter (la question vient de se répéter dans un sujet en double):

À quelques exceptions près, si vous utilisez ces méthodes, vous affinez probablement votre interface graphique pour la rendre bien sur un look-and-feel 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 sont. Dès que vous commencez à ajuster les positions et les tailles des pixels dans une mise en page, vous courez le risque de voir votre interface graphique se briser (ou, au moins, paraître mauvaise) sur d'autres plateformes.

À titre d'exemple, essayez de modifier le look-and-feel par défaut de votre application. Même avec les options disponibles sur votre plate-forme, vous pouvez être surpris de voir à quel point les résultats peuvent être médiocres.

Donc, au nom de garder votre interface graphique fonctionnelle et agréable sur toutes les plateformes (rappelez-vous, l'un des principaux avantages de Java est son multiplicité), vous devriez compter sur les gestionnaires de disposition, etc., pour ajuster automatiquement les tailles de vos composants afin qu'ils soient correctement rendus 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 gros drapeau rouge indiquant les problèmes d'interface graphique potentiels. 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 de look-and-feel indépendante de vos problèmes - le plus souvent vous constaterez que ces les méthodes ne sont pas nécessaires.

En passant, si vous vous trouvez frustré par les gestionnaires de mise en page standard, il y a beaucoup de bons tiers gratuits et open-source, par exemple JGoodies ' FormLayout, ou MigLayout. Certains constructeurs d'interface graphique prennent même en charge les gestionnaires de disposition tiers: l'éditeur de GUI WindowBuilder d'Eclipse, par exemple, est compatible avec FormLayout et MigLayout.


23
2018-03-10 17:02



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

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

Vous trouverez la documentation de Karsten dans ici, et une assez bonne documentation de l'éclipse ici.


18
2017-08-29 11:22



Dans une situation où je dois définir des proportions entre les enfants d'un composant (1 enfant devrait utiliser 10% de l'espace, CHILD2 40%, enfant3 50%), est-il possible d'y parvenir sans mettre en oeuvre un gestionnaire de mise en page personnalisée?

Peut être GridBagLayout satisferait vos besoins. En plus de cela, il y a une tonne de gestionnaires de disposition sur le web, et je parie qu'il y en a un qui répond à vos besoins.


15
2017-08-29 11:08



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 disposition s'ils honorent ces méthodes. Cette page contient un tableau qui indique quels gestionnaires de mise en page honorent les méthodes suivantes:

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

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

Je vais vous dire que vous ne devriez pas essayer de donner les conseils du gestionnaire de disposition avec ces méthodes jusqu'à ce que vous soyez sûr que vous en avez 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 alors apporter des corrections mineures si nécessaire.


14
2018-03-25 18:23



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

1) Devrais-je complètement éviter 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 aucun gestionnaire de disposition et essayer 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 de définir OOP pour que votre propre composant soit doté de 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 min / preferred / max réaliste en fonction de l'utilisation de ce composant. Par exemple, si vous avez un JTextField pour entrer des symboles de pays tels que Royaume-Uni, sa taille préférée doit être aussi large pour tenir deux caractères (avec la police en cours, etc.), mais sans doute il est inutile de le laisser grandir une plus grande. Après tout, les symboles de pays sont deux caractères. Comme ci-contre, si vous avez un JTextField pour entrer par ex. un nom de client, il peut avoir une taille préférée pour comme la taille des pixels pour 20 caractères, mais peut atteindre plus si la mise en page est redimensionnée, afin de définir la taille maximale plus. En même temps, ayant un JTextField large 0px est inutile, donc définir une taille minimum réaliste (je dirais que 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 les systèmes avec une résolution d'écran différente).

Pas de conséquences négatives. Ce sont des conseils 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 de mise en page de base tels que la disposition horizontale et verticale.

Par exemple, la disposition ci-dessous:

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

est en deux parties. Les parties gauche et droite sont horizontales. 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 difficile avec une mise en page réelle. Par conséquent, les gestionnaires de disposition basés sur la grille tels que MigLayout sont bien mieux si vous êtes sur le point de développer quelque chose de sérieux.

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

Non, vous ne devez certainement pas développer des gestionnaires de disposition, sauf si vous avez besoin de quelque chose de très spécial.

6) Dans une situation où j'ai besoin de définir des proportions ...

entre les enfants d'un composant (par exemple, child1 devrait utiliser 10% de l'espace, child2 40%, child3 50%), est-il possible de réaliser cela 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. Simplement, parce que les pourcentages sont inutiles (par exemple, il est inutile d'avoir un JTextField de 10% de la taille de la fenêtre - car on peut réduire la fenêtre de sorte que JTextField devienne 0px large, ou étendre la fenêtre de sorte que JTextField soit sur deux écrans sur un configuration multi-affichage).

Mais, parfois, vous pouvez utiliser les pourcentages pour contrôler les tailles des plus grands blocs de construction de votre gui (panneaux, par exemple).

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


5
2018-02-16 20:08