¿Debo evitar el uso de métodos de tamaño set(Preferred|Maximum|Minimum) en Java Swing?

Resuelto Heisenbug asked hace 13 años • 9 respuestas

Varias veces me han criticado por haber sugerido el uso de los siguientes métodos:

  1. setPreferredSize()
  2. setMinimumSize()
  3. setMaximumSize()

sobre Swingcomponentes. No veo ninguna alternativa a su uso cuando quiero definir proporciones entre los componentes mostrados. Me han dicho esto:

Con los diseños, la respuesta es siempre la misma: utilice un LayoutManager adecuado .

He buscado en la web, pero no he encontrado ningún análisis completo del tema. Entonces tengo las siguientes preguntas:

  1. ¿Debo evitar por completo el uso de esos métodos?
  2. Los métodos se han definido por una razón. Entonces, ¿cuándo debo usarlos? ¿En qué contexto? ¿Con qué fines?
  3. ¿Cuáles son exactamente las consecuencias negativas del uso de esos métodos? (Sólo puedo pensar en agregar portabilidad entre sistemas con diferente resolución de pantalla).
  4. No creo que ningún LayoutManager pueda satisfacer exactamente todas las necesidades de diseño deseadas. ¿Realmente necesito implementar un nuevo LayoutManager para cada pequeña variación en mi diseño?
  5. Si la respuesta a 4 es "sí", ¿no conducirá esto a una proliferación de clases de LayoutManager que serán difíciles de mantener?
  6. En una situación en la que necesito definir proporciones entre los elementos secundarios de un Componente (por ejemplo, el niño1 debe usar el 10% del espacio, el niño2 el 40%, el niño3 el 50%), ¿es posible lograrlo sin implementar un LayoutManager personalizado?
Heisenbug avatar Aug 29 '11 18:08 Heisenbug
Aceptado
  1. ¿Debo evitar por completo el uso de esos métodos?

    Sí para el código de aplicación.

  2. Los métodos se han definido por una razón. Entonces, ¿cuándo debo usarlos? ¿En qué contexto? ¿Con qué fines?

    No lo sé, personalmente lo considero un accidente de diseño de API. Ligeramente forzado por componentes compuestos que tienen ideas especiales sobre el tamaño de los niños. "Un poco", porque deberían haber implementado sus necesidades con un LayoutManager personalizado.

  3. ¿Cuáles son exactamente las consecuencias negativas del uso de esos métodos? (Solo puedo pensar en agregar portabilidad entre sistemas con diferente resolución de pantalla).

    Algunas razones técnicas (incompletas y desafortunadamente los enlaces están rotos debido a la migración de SwingLabs a java.net) se mencionan, por ejemplo, en las Reglas (jeje) o en el enlace que @bendicott encontró en su comentario a mi respuesta . Socialmente, suponer un montón de trabajo para el desafortunado compañero que tiene que mantener el código y localizar un diseño roto.

  4. No creo que ningún LayoutManager pueda satisfacer exactamente todas las necesidades de diseño deseadas. ¿Realmente necesito implementar un nuevo LayoutManager para cada pequeña variación en mi diseño?

    Sí, existen LayoutManagers lo suficientemente potentes como para satisfacer una muy buena aproximación a "todas las necesidades de diseño". Los tres grandes son JGoodies FormLayout, MigLayout y DesignGridLayout. Entonces no, en la práctica, rara vez se escriben LayoutManagers, excepto para entornos simples y altamente especializados.

  5. Si la respuesta a 4 es "sí", ¿no conducirá esto a una proliferación de clases de LayoutManager que serán difíciles de mantener?

    (La respuesta a 4 es "no".)

  6. En una situación en la que necesito definir proporciones entre los hijos de un Componente (por ejemplo, el hijo 1 debe usar el 10% del espacio, el hijo 2 el 40%, el hijo 3 el 50%), ¿es posible lograrlo sin implementar un LayoutManager personalizado?

    Cualquiera de los Tres Grandes puede, ni siquiera GridBag (nunca se molestó en dominarlo realmente, demasiados problemas para muy poca potencia).

kleopatra avatar Aug 29 '2011 11:08 kleopatra

Algunas heurísticas:

  • No lo use set[Preferred|Maximum|Minimum]Size()cuando realmente quiera anular get[Preferred|Maximum|Minimum]Size(), como se podría hacer al crear su propio componente, como se muestra aquí .

  • No lo use set[Preferred|Maximum|Minimum]Size()cuando pueda confiar en la anulación cuidadosa de un componente getPreferred|Maximum|Minimum]Size, como se muestra aquí y a continuación.

  • Úselo set[Preferred|Maximum|Minimum]Size()para derivar la post- validate()geometría, como se muestra a continuación y aquí .

  • Si un componente no tiene un tamaño preferido, por ejemplo JDesktopPane, es posible que tenga que dimensionar el contenedor, después de invocar pack(), pero dicha elección es arbitraria. Un comentario puede ayudar a aclarar la intención.

  • Considere diseños alternativos o personalizados cuando descubra que tendría que recorrer muchos componentes para obtener tamaños derivados, como se menciona en estos comentarios .

ingrese la descripción de la imagen aquí

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());
            }
        }
    }
}
trashgod avatar Aug 29 '2011 11:08 trashgod

¿Debo evitar por completo el uso de esos métodos?

No, no hay evidencia formal que sugiera que no se permite llamar o anular estos métodos. De hecho, Oracle dice que estos métodos se utilizan para dar sugerencias de tamaño: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment .

También pueden anularse (que es la mejor práctica para Swing) al extender un componente Swing (en lugar de llamar al método en la instancia del componente personalizado).

Lo más importante es que, independientemente de cómo especifique el tamaño de su componente, asegúrese de que el contenedor de su componente utilice un administrador de diseño que respete el tamaño solicitado del componente.

Los métodos se han definido por una razón. Entonces, ¿cuándo debo usarlos? ¿En qué contexto? ¿Con qué fines?

Cuando necesite proporcionar sugerencias de tamaño personalizadas al administrador de diseño de contenedores para que el componente se distribuya bien

¿Cuáles son exactamente las consecuencias negativas del uso de esos métodos? (Sólo se me ocurre añadir portabilidad entre sistemas con diferente resolución de pantalla).

  • Muchos administradores de diseño no prestan atención al tamaño máximo solicitado de un componente. Sin embargo, BoxLayouty SpringLayouthazlo. Además, GroupLayoutofrece la posibilidad de establecer explícitamente el tamaño mínimo, preferido o máximo, sin tocar el componente.

  • Asegúrese de que realmente necesita establecer el tamaño exacto del componente. Cada componente Swing tiene un tamaño preferido diferente, según la fuente que utiliza y la apariencia. Por lo tanto, tener un tamaño establecido puede producir apariencias variadas de la interfaz de usuario en diferentes sistemas.

  • A veces se pueden encontrar problemas con GridBagLayoutlos campos de texto, en los que si el tamaño del contenedor es menor que el tamaño preferido, se utiliza el tamaño mínimo, lo que puede hacer que los campos de texto se reduzcan considerablemente.

  • JFrameno hace cumplir la anulación getMinimumSize()sólo llamando setMinimumSize(..)a sus obras

No creo que ningún LayoutManager pueda satisfacer exactamente todas las necesidades de diseño deseadas. ¿Realmente necesito implementar un nuevo LayoutManager para cada pequeña variación en mi diseño?

Si por implementar te refieres a usar, entonces sí. Ninguno LayoutMangerpuede manejarlo todo, cada uno LayoutManagertiene sus pros y sus contras, por lo que cada uno puede usarse en conjunto para producir el diseño final.

Referencia:

  • http://docs.oracle.com/javase/tutorial/uiswing/layout/problems.html
David Kroukamp avatar Sep 30 '2012 22:09 David Kroukamp

Hay muchas buenas respuestas aquí, pero quiero agregar un poco más sobre las razones por las que normalmente deberías evitarlas (la pregunta volvió a surgir en un tema duplicado):

Con pocas excepciones, si está utilizando estos métodos, probablemente esté ajustando su GUI para que se vea bien con una apariencia específica (y con la configuración específica de su sistema, por ejemplo, su fuente de escritorio preferida, etc.). Los métodos en sí no son intrínsecamente malos, pero las razones típicas para usarlos sí lo son . Tan pronto como comience a ajustar las posiciones y tamaños de los píxeles en un diseño, corre el riesgo de que su GUI se rompa (o, como mínimo, se vea mal) en otras plataformas.

Como ejemplo de esto, intente cambiar la apariencia predeterminada de su aplicación. Incluso sólo con las opciones disponibles en su plataforma, es posible que se sorprenda de lo deficientes que se pueden generar los resultados.

Entonces, en nombre de mantener su GUI funcional y atractiva en todas las plataformas (recuerde, uno de los principales beneficios de Java es su multiplataforma), debe confiar en los administradores de diseño, etc., para ajustar automáticamente los tamaños de sus componentes para que se procesen correctamente fuera de su entorno de desarrollo específico.

Dicho todo esto, ciertamente se pueden concebir situaciones en las que estos métodos estén justificados. Nuevamente, no son intrínsecamente malos, pero su uso normalmente es una gran señal de alerta que indica posibles problemas con la GUI. Sólo asegúrese de ser consciente del alto potencial de complicaciones si los usa y cuando los use, y siempre trate de pensar si existe otra solución independiente de apariencia para sus problemas; la mayoría de las veces encontrará que estas Los métodos no son necesarios.

Por cierto, si se siente frustrado con los administradores de diseño estándar, existen muchos buenos programas de terceros gratuitos y de código abierto, por ejemplo JGoodiesFormLayout o MigLayout. Algunos creadores de GUI incluso tienen soporte integrado para administradores de diseño de terceros: el editor de GUI WindowBuilder de Eclipse, por ejemplo, incluye soporte para FormLayouty MigLayout.

Jason C avatar Mar 10 '2014 17:03 Jason C

Si tiene problemas con los diseños en Java Swing, le recomiendo encarecidamente los JGoodies que FormLayoutKarsten Lentzsch proporciona gratuitamente como parte de la biblioteca gratuita Forms aquí .

Este administrador de diseño muy popular es extremadamente flexible y permite desarrollar interfaces de usuario Java muy pulidas.

Encontrará la documentación de Karsten aquí y alguna documentación bastante buena de eclipse aquí .

Tom avatar Aug 29 '2011 11:08 Tom

La mayoría de la gente no comprende bien estos métodos. No debes ignorar estos métodos en absoluto. Depende del administrador de diseño si respeta estos métodos. Esta página tiene una tabla que muestra qué administradores de diseño respetan cuál de esos métodos:

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

He estado escribiendo código Swing durante más de 8 años y los administradores de diseño incluidos en el JDK siempre han satisfecho mis necesidades. Nunca he necesitado un administrador de diseño de terceros para realizar mis diseños.

Diré que no deberías intentar darle sugerencias al administrador de diseño con estos métodos hasta que estés seguro de que los necesitas. Realice su diseño sin dar sugerencias sobre el tamaño (es decir, deje que el administrador de diseño haga su trabajo) y luego podrá hacer correcciones menores si es necesario.

Michael avatar Mar 25 '2013 18:03 Michael