507 Stimmen

Sollte ich die Verwendung von set(Preferred|Maximum|Minimum)Size Methoden in Java Swing vermeiden?

Ich bin mehrfach dafür kritisiert worden, dass ich die Anwendung der folgenden Methoden vorgeschlagen habe:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

auf Swing Komponenten. Ich sehe keine Alternative zu ihrer Verwendung, wenn ich Proportionen zwischen angezeigten Komponenten festlegen möchte. Dies wurde mir gesagt:

Bei Layouts ist die Antwort immer die gleiche: Verwenden Sie einen geeigneten LayoutManager

Ich habe das Internet ein wenig durchsucht, aber ich habe keine umfassende Analyse zu diesem Thema gefunden. Daher habe ich die folgenden Fragen:

  1. Sollte ich die Anwendung dieser Methoden völlig vermeiden?
  2. Die Methoden sind nicht ohne Grund festgelegt worden. Wann sollte ich sie also verwenden? In welchem Zusammenhang? Für welche Zwecke?
  3. Was genau sind die negativen Folgen der Anwendung dieser Methoden? (Ich kann mir nur vorstellen, dass die Übertragbarkeit zwischen Systemen mit unterschiedlicher Bildschirmauflösung hinzukommt).
  4. Ich glaube nicht, dass irgendein LayoutManager alle gewünschten Layoutanforderungen erfüllen kann. Muss ich wirklich für jede kleine Variation in meinem Layout einen neuen LayoutManager implementieren?
  5. Wenn die Antwort auf Frage 4 "ja" lautet, führt dies dann nicht zu einer Vervielfachung der LayoutManager-Klassen, die nur noch schwer zu pflegen sind?
  6. In einer Situation, in der ich Proportionen zwischen Kindern einer Komponente definieren muss (z. B. Kind1 sollte 10 % des Platzes verwenden, Kind2 40 %, Kind3 50 %), ist es möglich, das zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren?

249voto

kleopatra Punkte 50122
  1. Sollte ich die Anwendung dieser Methoden völlig vermeiden?

    Ja für den Anwendungscode.

  2. Die Methoden wurden aus einem bestimmten Grund definiert. Wann sollte ich sie also verwenden? In welchem Zusammenhang? Für welche Zwecke?

    Ich weiß nicht, ich persönlich halte es für einen API-Design-Unfall. Ein wenig gezwungen durch zusammengesetzte Komponenten, die spezielle Vorstellungen von Kindgrößen haben. "Geringfügig", weil sie ihre Bedürfnisse mit einem benutzerdefinierten LayoutManager hätten umsetzen sollen.

  3. Was genau sind die negativen Folgen der Anwendung dieser Methoden? (Ich kann mir nur vorstellen, dass die Übertragbarkeit zwischen Systemen mit unterschiedlicher Bildschirmauflösung hinzukommt).

    Einige (unvollständige, und leider sind die Links aufgrund der Umstellung von SwingLabs auf java.net defekt) technische Gründe sind zum Beispiel in der Regeln (hehe) oder in der Link @bendicott fand in seinem/ihrem Kommentar zu meine Antwort . In sozialer Hinsicht bedeutet das eine Menge Arbeit für den unglücklichen Kollegen, der den Code pflegen und ein defektes Layout aufspüren muss.

  4. Ich glaube nicht, dass ein LayoutManager alle gewünschten Layoutanforderungen erfüllen kann. Muss ich wirklich für jede kleine Variation meines Layouts einen neuen LayoutManager implementieren?

    Ja, es gibt LayoutManager, die leistungsfähig genug sind, um eine sehr gute Annäherung an "alle Layoutanforderungen" zu erfüllen. Die großen drei sind JGoodies FormLayout, MigLayout, DesignGridLayout. Also nein, in der Praxis schreibt man selten LayoutManager, außer für einfache hochspezialisierte Umgebungen.

  5. Wenn die Antwort auf Frage 4 "ja" lautet, führt dies dann nicht zu einer Vermehrung der LayoutManager-Klassen, die schwer zu pflegen sind?

    (Die Antwort auf Frage 4 lautet "Nein".)

  6. In einer Situation, in der ich Proportionen zwischen Kindern einer Komponente definieren muss (z. B. Kind 1 sollte 10 % des Platzes, Kind 2 40 %, Kind 3 50 % verwenden), ist es möglich, das zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren?

    Jeder der Big-Three kann, kann nicht einmal GridBag (habe mir nie die Mühe gemacht, es wirklich zu beherrschen, zu viel Mühe für zu wenig Leistung).

109voto

trashgod Punkte 199887

Ein paar Heuristiken:

  • Verwenden Sie nicht set[Preferred|Maximum|Minimum]Size() wenn Sie wirklich die Absicht haben, sich außer Kraft zu setzen get[Preferred|Maximum|Minimum]Size() wie es bei der Erstellung eines eigenen Bauteils der Fall sein könnte, gezeigt aquí .

  • Verwenden Sie nicht set[Preferred|Maximum|Minimum]Size() wenn Sie sich auf die sorgfältig überschriebene Funktion einer Komponente verlassen können getPreferred|Maximum|Minimum]Size wie gezeigt aquí und darunter.

  • Verwenden Sie set[Preferred|Maximum|Minimum]Size() zur Ableitung von Post- validate() Geometrie, wie unten dargestellt und aquí .

  • Wenn eine Komponente keine bevorzugte Größe hat, z. B. JDesktopPane müssen Sie möglicherweise die Größe des Behälters anpassen, nach Aufruf von pack() aber eine solche Wahl ist willkürlich. Ein Kommentar kann helfen, die Absicht zu klären.

  • Ziehen Sie alternative oder benutzerdefinierte Layouts in Betracht, wenn Sie feststellen, dass Sie sich durch viele Komponenten durcharbeiten müssen, um abgeleitete Größen zu erhalten, wie in diesen Kommentare .

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

53voto

David Kroukamp Punkte 35897

Sollte ich die Anwendung dieser Methoden völlig vermeiden?

Nein, es gibt keine formalen Beweise dafür, dass der Aufruf oder das Überschreiben dieser Methoden nicht erlaubt ist. Oracle sagt sogar, dass diese Methoden dazu verwendet werden, Größenhinweise zu geben: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment .

Sie können auch außer Kraft gesetzt werden (was für Swing die beste Praxis ist), wenn Erweiterung eine Swing-Komponente (anstatt die Methode für die benutzerdefinierte Komponenteninstanz aufzurufen)

Unabhängig davon, wie Sie die Größe Ihrer Komponente angeben, sollten Sie darauf achten, dass der Container Ihrer Komponente einen Layout-Manager verwendet, der die gewünschte Größe der Komponente berücksichtigt.

Die Methoden sind nicht ohne Grund festgelegt worden. Wann sollte ich sie also verwenden? In welchem Zusammenhang? Für welche Zwecke?

Wenn Sie dem Container-Layout-Manager benutzerdefinierte Größenangaben zur Verfügung stellen müssen, damit die Komponente gut angeordnet wird

Was genau sind die negativen Folgen der Anwendung dieser Methoden? (I kann nur daran denken, die Übertragbarkeit zwischen Systemen mit unterschiedlicher Bildschirmauflösung).

  • Viele Layout-Manager achten nicht auf die von einer Komponente geforderte maximale Größe. Wie auch immer, BoxLayout y SpringLayout tun. Außerdem, GroupLayout bietet die Möglichkeit, die minimale, bevorzugte oder maximale Größe explizit festzulegen, ohne die Komponente zu berühren.

  • Vergewissern Sie sich, dass Sie wirklich die genaue Größe der Komponente festlegen müssen. Jede Swing-Komponente hat eine andere bevorzugte Größe, abhängig von der verwendeten Schriftart und dem Look and Feel. Eine festgelegte Größe kann daher zu unterschiedlichen siehe der UI auf verschiedenen Systemen

  • manchmal können Probleme auftreten bei GridBagLayout und Textfelder, wobei, wenn die Größe des Behälters kleiner als die bevorzugte Größe ist, die Mindestgröße verwendet wird, was dazu führen kann, dass Textfelder ganz erheblich schrumpfen.

  • JFrame erzwingt keine Aufhebung der getMinimumSize() Nur Anrufe setMinimumSize(..) über seine Werke

Ich glaube nicht, dass ein LayoutManager alle gewünschten Layouts exakt erfüllen kann. Bedürfnisse erfüllen kann. Muss ich wirklich für jede kleine Variation meines Layouts einen neuen LayoutManager implementieren? kleine Variation meines Layouts implementieren?

Wenn Sie mit Umsetzung die Verwendung meinen, dann ja. Nicht eine LayoutManger alles bewältigen kann, jeder LayoutManager hat seine Vor- und Nachteile, so dass beide zusammen verwendet werden können, um das endgültige Layout zu erstellen.

Referenz:

26voto

Jason C Punkte 35780

Es gibt hier viele gute Antworten, aber ich möchte noch ein wenig mehr über die Gründe sagen pourquoi sollten Sie diese normalerweise vermeiden (die Frage wurde gerade in einem doppelten Thema erneut gestellt):

Von wenigen Ausnahmen abgesehen, verwenden Sie diese Methoden wahrscheinlich zur Feinabstimmung Ihrer grafischen Benutzeroberfläche, damit diese in einem bestimmten Look-and-Feel gut aussieht (und mit Ihren systemspezifischen Einstellungen, z. B. Ihrer bevorzugten Desktop-Schriftart usw.). Die Methoden selbst sind nicht per se schlecht, aber die typischen Gründe für ihre Verwendung sind sind . Sobald Sie anfangen, Pixelpositionen und -größen in einem Layout zu verändern, besteht die Gefahr, dass Ihre Benutzeroberfläche auf anderen Plattformen nicht mehr funktioniert (oder zumindest schlecht aussieht).

Versuchen Sie beispielsweise, das Standard-Look-and-Feel Ihrer Anwendung zu ändern. Selbst mit den Optionen, die auf Ihrer Plattform verfügbar sind, werden Sie vielleicht überrascht sein, wie schlecht die Ergebnisse wiedergegeben werden können.

Damit Ihre grafische Benutzeroberfläche auf allen Plattformen funktioniert und gut aussieht (einer der größten Vorteile von Java ist seine Plattformunabhängigkeit), sollten Sie sich auf Layout-Manager usw. verlassen, um die Größen Ihrer Komponenten automatisch anzupassen, damit sie außerhalb Ihrer spezifischen Entwicklungsumgebung korrekt dargestellt werden.

Dennoch kann man sich durchaus Situationen vorstellen, in denen diese Methoden gerechtfertigt sind. Nochmals: Sie sind nicht von Natur aus böse, aber ihr Einsatz ist normalerweise ein groß rote Flagge, die auf mögliche GUI-Probleme hinweist. Stellen Sie sicher, dass Sie sich des hohen Potenzials für Komplikationen bewusst sind, wenn Sie sie verwenden, und versuchen Sie immer zu überlegen, ob es eine andere, vom Aussehen und der Handhabung unabhängige Lösung für Ihre Probleme gibt - in den meisten Fällen werden Sie feststellen, dass diese Methoden nicht notwendig sind.

Übrigens, wenn Sie mit den Standard-Layout-Managern nicht mehr zurechtkommen, gibt es viele gute kostenlose, quelloffene Programme von Drittanbietern, zum Beispiel JGoodies' FormLayout , oder MigLayout . Einige GUI-Builder haben sogar eine eingebaute Unterstützung für Layout-Manager von Drittanbietern - Eclipse's WindowBuilder GUI-Editor, zum Beispiel, wird mit Unterstützung für FormLayout y MigLayout .

22voto

Tom Punkte 4662

Wenn Sie Probleme mit Layouts in Java Swing haben, dann kann ich Ihnen die JGoodies FormLayout frei zur Verfügung gestellt als Teil der Forms-Freeware-Bibliothek von Karsten Lentzsch aquí .

Dieser sehr beliebte Layout-Manager ist äußerst flexibel und ermöglicht die Entwicklung sehr ausgefeilter Java-Oberflächen.

Die Dokumentation von Karsten finden Sie unter aquí und eine recht gute Dokumentation von eclipse aquí .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X