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

481

Ich wurde mehrmals dafür kritisiert, dass ich die Verwendung der folgenden Methoden vorgeschlagen habe:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

auf SwingKomponenten. Ich sehe keine Alternative zu ihrer Verwendung, wenn ich Proportionen zwischen angezeigten Komponenten definieren möchte. Mir wurde folgendes gesagt:

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

Ich habe ein wenig im Internet gesucht, aber keine umfassende Analyse des Themas gefunden. Ich habe also folgende Fragen:

  1. Sollte ich die Verwendung dieser Methoden vollständig vermeiden?
  2. Die Methoden wurden aus einem bestimmten Grund definiert. Wann sollte ich sie verwenden? In welchem ​​Kontext? Für welche Zwecke?
  3. Was genau sind die negativen Folgen dieser Methoden? (Ich kann mir nur vorstellen, Portabilität zwischen Systemen mit unterschiedlicher Bildschirmauflösung hinzuzufügen).
  4. Ich glaube nicht, dass ein LayoutManager alle gewünschten Layoutanforderungen genau erfüllen kann. Muss ich wirklich für jede kleine Variation meines Layouts einen neuen LayoutManager implementieren?
  5. Wenn die Antwort auf 4 "Ja" lautet, führt dies dann nicht zu einer Zunahme von LayoutManager-Klassen, deren Wartung schwierig wird?
  6. Ist es in einer Situation, in der ich Proportionen zwischen untergeordneten Elementen einer Komponente definieren muss (z. B. sollte child1 10% des Speicherplatzes verwenden, child2 40%, child3 50%), möglich, dies zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren?
Heisenbug
quelle

Antworten:

236
  1. Sollte ich die Verwendung dieser Methoden vollständig vermeiden?

    Ja für den Anwendungscode.

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

    Ich weiß es nicht, ich persönlich betrachte es als einen API-Designunfall. Etwas gezwungen durch zusammengesetzte Komponenten, die spezielle Vorstellungen über Kindergrößen haben. "Leicht", weil sie ihre Anforderungen mit einem benutzerdefinierten LayoutManager hätten implementieren sollen.

  3. Was genau sind die negativen Folgen dieser Methoden? (Ich kann mir nur vorstellen, die Portabilität zwischen Systemen mit unterschiedlicher Bildschirmauflösung zu erhöhen.)

    Einige (unvollständige und leider aufgrund der Migration von SwingLabs zu java.net unterbrochene Links) technische Gründe werden beispielsweise in den Regeln (hehe) oder im Link @bendicott in seinem Kommentar zu meiner Antwort erwähnt . In sozialer Hinsicht müssen Sie Ihrem unglücklichen Kollegen, der den Code pflegen und ein kaputtes Layout aufspüren muss, eine Menge Arbeit auferlegen.

  4. Ich glaube nicht, dass ein LayoutManager alle gewünschten Layoutanforderungen genau 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. Nein, in der Praxis schreiben Sie LayoutManager nur selten, außer in einfachen hochspezialisierten Umgebungen.

  5. Wenn die Antwort auf 4 "Ja" lautet, führt dies dann nicht zu einer Zunahme von LayoutManager-Klassen, deren Wartung schwierig wird?

    (Die Antwort auf 4 lautet "nein".)

  6. Ist es in einer Situation, in der ich Proportionen zwischen untergeordneten Elementen einer Komponente definieren muss (z. B. sollte untergeordnetes Element 1 10% des Speicherplatzes verwenden, untergeordnetes Element 2 40%, untergeordnetes Element 3 50%), möglich, dies zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren?

    Jeder der Big-Three kann, kann nicht einmal GridBag (nie die Mühe gemacht, wirklich zu meistern, zu viel Ärger für zu wenig Power).

Kleopatra
quelle
4
Ich bin mir nicht ganz sicher, ob ich diesem Rat in mindestens zwei Situationen zustimme. 1) Benutzerdefinierte gerenderte Komponenten 2) Verwenden von a JEditorPanemit HTML, das selbst keine Breite vorschlägt. OTOH Ich bin mir nicht sicher, ob ich etwas verpasst habe. Ich werde die Antworten auf den Thread sorgfältig prüfen, war aber interessiert, wenn Sie Kommentare hatten, insbesondere zu letzterem Fall.
Andrew Thompson
2
@ Andrew Thompson 1) Benutzerdefinierte Kompositionen: Es ist die Komposition selbst, die für die Rückgabe nützlicher Layout-Hinweise verantwortlich ist, wenn sie nicht fehlerhaft ist. 2) Sogar Kernkompositionen sind fehlerhaft diesmal absichtlich, danke :-)
kleopatra
8
Ich kann nicht glauben, dass die akzeptierte Antwort diejenige ist, die besagt, dass die Verwendung der setXXX () -Methoden vermieden werden soll. Manchmal benötigen Sie sie einfach, um dem Layout-Manager einen Hinweis zu geben. Wenn Sie ein Panel auslegen, sollten Sie diese Methoden bei Bedarf unbedingt anwenden können. Wenn Sie den entsprechenden Layout-Manager verwenden, werden Sie diese Methoden nicht sehr oft benötigen, aber gelegentlich brauchen Sie sie einfach. Versuchen Sie, eine JComboBox oder einen JSpinner in ein X_AXIS BoxLayout einzufügen, und verwenden Sie sie nicht. Sie werden dort wahrscheinlich setMaximumSize () benötigen.
Michael
5
@ Michael nein, ich brauche es absolut nicht - die Antwort ist immer, einen anständigen LayoutManager zu verwenden und auf Manager- Ebene (im
Vergleich
5
Sie sagen immer wieder "Verwenden Sie einen anständigen LayoutManager und teilen Sie ihm mit, welche Größen Sie möchten", aber Sie geben niemals konkrete Beispiele für einen "anständigen" LayoutManager. Und keiner der Standardmanager erlaubt die direkte Steuerung der Größen.
Ti Strga
100

Einige Heuristiken:

  • Verwenden Sie nicht , set[Preferred|Maximum|Minimum]Size()wenn Sie wirklich außer Kraft zu setzen bedeuten get[Preferred|Maximum|Minimum]Size(), wie es bei der Erstellung Ihre eigene Komponente erfolgen, gezeigt hier .

  • Nicht verwenden, set[Preferred|Maximum|Minimum]Size()wenn Sie sich darauf verlassen können, dass eine Komponente sorgfältig überschrieben wird getPreferred|Maximum|Minimum]Size, wie hier und unten gezeigt.

  • Verwenden Sie set[Preferred|Maximum|Minimum]Size()diese Option validate(), um die Postgeometrie abzuleiten , wie unten und hier gezeigt .

  • Wenn eine Komponente keine bevorzugte Größe hat JDesktopPane, müssen Sie möglicherweise den Container dimensionieren, aber eine solche Auswahl ist willkürlich. Ein Kommentar kann helfen, die Absicht zu verdeutlichen.

  • Ziehen Sie alternative oder benutzerdefinierte Layouts in Betracht, wenn Sie feststellen, dass Sie viele Komponenten durchlaufen müssen, um abgeleitete Größen zu erhalten, wie in diesen Kommentaren erwähnt .

Geben Sie hier die Bildbeschreibung ein

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());
            }
        }
    }
}
Müllgott
quelle
2
nicht einverstanden sein (wie Sie vielleicht erraten haben :-) mit Argumentation durch "externe Faktoren": Die XXSize-Eigenschaften sollen nur interne Bedürfnisse ausdrücken . Das Optimieren von außen ist missbräuchlich, auch bekannt als Hacking. Wenn Sie einen (internen oder J-) Rahmen mit einer bestimmten Größe im Verhältnis zu seiner bevorzugten Größe wünschen ... Größe des Rahmens, nicht des Inhalts
kleopatra
2
@kleopatra: nur um ein bisschen darauf zu bestehen: Wenn setXXSize-Methoden niemals von außen verwendet werden sollten, warum wurden sie nicht als privat oder geschützt deklariert? Ist das nicht ein Mangel an Design? Sagt der öffentliche Modifikator dem Benutzer nicht implizit, dass er diese Methoden verwenden kann?
Heisenbug
2
Ich muss @kleopatra zustimmen: Ersetzt setPreferredSize()immer die Berechnung der Komponente durch eine beliebige Auswahl.
Trashgod
1
@trashgod +100 für Sie Ich denke, es gibt kein Problem mit dem Überschreiben dieser Methoden, auch wenn sie aufgerufen werden (aber dies würde natürlich bedeuten, dass Sie eine benutzerdefinierte Komponente haben, daher wäre das Überschreiben besser)
David Kroukamp
5
@ DavidKroukamp: Danke. Ich verlasse mich auf Kleopatras größere Erfahrung, aber ich sehe den Wert darin, die gegenteilige Ansicht kritisch zu prüfen.
Trashgod
47

Sollte ich die Verwendung dieser Methoden vollständig vermeiden?

Nein, es gibt keine formalen Beweise dafür, dass das Aufrufen oder Überschreiben dieser Methoden nicht zulässig ist. Laut Oracle werden diese Methoden verwendet, um Größenhinweise zu geben: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment .

Sie können auch außer Kraft gesetzt werden (das ist die beste Praxis für Swing) , wenn Verlängerung eine Swing - Komponente (anstatt Aufruf der Methode auf dem benutzerdefinierten Komponenteninstanz)

Unabhängig davon, wie Sie die Größe Ihrer Komponente angeben, stellen Sie sicher, dass der Container Ihrer Komponente einen Layout-Manager verwendet, der die angeforderte Größe der Komponente berücksichtigt.

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

Wenn Sie dem Layout-Manager des Containers benutzerdefinierte Größenhinweise geben müssen, damit die Komponente gut angeordnet ist

Was genau sind die negativen Folgen dieser Methoden? (Ich kann nur daran denken, die Portabilität zwischen Systemen mit unterschiedlicher Bildschirmauflösung zu erhöhen).

  • Viele Layout-Manager achten nicht auf die angeforderte maximale Größe einer Komponente. Aber BoxLayoutund SpringLayouttun. Darüber hinaus GroupLayoutbietet die Möglichkeit , die minimalen, bevorzugte oder maximale Größe explizit zu setzen, ohne die Komponente zu berühren.

  • Stellen Sie sicher, dass Sie die genaue Größe der Komponente wirklich einstellen müssen. Jede Swing-Komponente hat eine andere bevorzugte Größe, abhängig von der verwendeten Schriftart und dem Erscheinungsbild. So hat eine festgelegte Größe variiert produzieren könnte Blicke auf verschiedene Systeme der UI

  • Manchmal können Probleme mit GridBagLayoutund Textfeldern auftreten. Wenn die Größe des Containers kleiner als die bevorzugte Größe ist, wird die Mindestgröße verwendet, was dazu führen kann, dass Textfelder erheblich verkleinert werden.

  • JFrameerzwingt keine Überschreibung getMinimumSize(), indem nur setMinimumSize(..)seine Werke aufgerufen werden

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

Wenn mit Implementierung gemeint ist, dann ja. Nicht jeder LayoutMangerkann mit allem umgehen, jeder LayoutManagerhat seine Vor- und Nachteile, so dass jeder zusammen verwendet werden kann, um das endgültige Layout zu erstellen.

Referenz:

David Kroukamp
quelle
3
Geben Sie benutzerdefinierte Größenhinweise an , die an sich schon ein Widerspruch sind: Das Bereitstellen von Größenhinweisen (in px!) ist die ausschließliche Aufgabe der Komponente. Sie berechnet sie auf der Grundlage interner Statusdetails, die keine andere Partei außer sich selbst kennen (und auch nicht verfolgen kann). Aus Client-Sicht kann das Anpassungsverfahren ein geeigneter LayoutManager sein und / oder eine API auf die Komponente spezialisieren, die es ermöglicht, Größenanforderungen in Bezug auf "semantische"
größenrelevante
3
@kleopatra Ich würde immer noch gerne wissen, warum Oracle uns dann sagt, wie man diese Methoden verwendet und wie man sie richtig verwendet. Wir haben vielleicht unsere eigenen Vorlieben, aber wir können nicht sagen, dass die Designer es nicht verwenden, wenn es keine Beweise dafür gibt. Aber das ist der Grund, warum ich das Kopfgeld aufstelle, um zu sehen, ob es andere anzieht, die Informationen aus einer glaubwürdigen Quelle liefern könnten, in der Orakel angibt, diese Methoden überhaupt nicht zu verwenden (was es zu einer schlechten Praxis macht, wenn Sie dies tun, zum Beispiel setMinimumSize) Dinge wie JSplitPane usw. aufgerufen. Dies ist im Oracle-Tutorial für geteilte Fenster zu sehen.
David Kroukamp
4
@ David: Ich bin gekommen, um die setXxxSizeMethoden als rote Fahne zu sehen, dass ich hier landen könnte , selbst wenn die Dokumente es vorschlagen. Ich hätte fast immer überschreiben sollen getXxxSize, wo man Zugriff auf die gewünschte Geometrie hat; und selbst kurze Beispiele werden mehr recycelt, als ich mir vorstellen möchte. +1 für die Erwähnung von Abweichungen zwischen Layout-Managern und das Zitieren des Tutorials.
Trashgod
1
D'oh, in meinem obigen Kommentar wollte ich die Antwort hier zitieren .
Trashgod
13
+1 "Nein, es gibt keine formalen Beweise dafür, dass das Aufrufen oder Überschreiben dieser Methoden nicht zulässig ist." Genau richtig. Der als Antwort getaggte Beitrag ist einfach BS.
TT.
25

Hier gibt es viele gute Antworten, aber ich möchte etwas mehr über die Gründe hinzufügen, warum Sie diese normalerweise vermeiden sollten (die Frage wurde gerade in einem doppelten Thema erneut gestellt):

Mit wenigen Ausnahmen, wenn Sie diese Methoden verwenden, optimieren Sie wahrscheinlich Ihre GUI so, dass sie in einem bestimmten Erscheinungsbild gut aussieht (und mit Ihren systemspezifischen Einstellungen, z. B. Ihrer bevorzugten Desktop-Schriftart usw.). Die Methoden selbst sind nicht von Natur aus böse, aber die typischen Gründe für ihre Verwendung sind . Sobald Sie anfangen, Pixelpositionen und -größen in einem Layout zu optimieren, besteht die Gefahr, dass Ihre GUI auf anderen Plattformen beschädigt wird (oder zumindest schlecht aussieht).

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

Um Ihre GUI auf allen Plattformen funktionsfähig und ansprechend zu halten (denken Sie daran, einer der Hauptvorteile von Java ist die plattformübergreifende Funktionalität), sollten Sie sich auf Layout-Manager usw. verlassen, um die Größe von automatisch anzupassen Ihre Komponenten, damit sie außerhalb Ihrer spezifischen Entwicklungsumgebung korrekt gerendert werden.

Trotzdem können Sie sich durchaus Situationen vorstellen, in denen diese Methoden gerechtfertigt sind. Auch hier sind sie nicht von Natur aus böse, aber ihre Verwendung ist normalerweise eine große rote Fahne, die auf mögliche Probleme mit der Benutzeroberfläche hinweist. Stellen Sie einfach sicher, dass Sie sich des hohen Komplikationspotenzials bewusst sind, wenn / wenn Sie sie verwenden, und versuchen Sie immer zu überlegen, ob es eine andere Look-and-Feel-unabhängige Lösung für Ihre Probleme gibt - meistens werden Sie feststellen, dass diese auftreten Methoden sind nicht notwendig.

Übrigens, wenn Sie mit Standard-Layout-Managern frustriert sind, gibt es viele gute kostenlose Open-Source- Angebote vonFormLayout Drittanbietern, zum Beispiel JGoodies oder MigLayout. Einige GUI-Builder bieten sogar integrierte Unterstützung für Layout-Manager von Drittanbietern. Der WindowBuilder-GUI-Editor von Eclipse bietet beispielsweise Unterstützung für FormLayoutund MigLayout.

Jason C.
quelle
2
+1 eine rücksichtsvolle Antwort - stimmen Sie einfach nicht zu, dass sie nicht von Natur aus böse sind, nur weil sie es sind :-) In der Regel haben externe Kunden überhaupt keine Chance zu erraten - und bloße Annahmen sind so nah wie Außenstehende - halbwegs korrekte Layout-Hinweise: nur Die Komponenten selbst verfügen jederzeit über alle Informationen, um nützliche Informationen zurückzugeben. Und da sich Außenstehende einmischen, sind sie dafür verantwortlich, die Hinweise auf dem neuesten Stand zu halten, die sie nicht können.
Kleopatra
1
Weißt du, ich habe eine eher "Waffen töten keine Menschen, Menschen töten Menschen" -Ansicht über diese Art von Dingen. :) Wenn jemand diese Methoden verwendet, muss er sich der guten Punkte bewusst sein, die Sie zur unvorhersehbaren Verwendung von Layout-Hinweisen ansprechen (weshalb Situationen, in denen diese Methoden angemessen sind, in der Tat selten sind).
Jason C
Ich denke, die Einstellung der bevorzugten Größe ist überhaupt keine große rote Fahne. Wenn Sie es nicht setzen, wird stattdessen eine große rote Fahne angezeigt. Lassen Sie mich näher darauf eingehen. Der Layout-Manager - egal wie intelligent er ist - hat keine Ahnung von der logischen Funktion eines GUI-Widgets. Beispielsweise kann der Layout-Manager nicht zwischen einem JTextField zur Eingabe der Postleitzahl und einem JTextField zur Eingabe eines Namens unterscheiden. Ebenso kann nicht zwischen einer Werkzeugschaltfläche neben einem JTextField oder einer großen OK-Schaltfläche am unteren Rand eines Formulars unterschieden werden. Daher werden entweder ein besseres Widget-Set oder einige Größenhinweise benötigt, oder?
Gee Bee
@GeeBee Nein, das ist in der Tat ein Paradebeispiel für eine rote Fahne. Sie sollten lediglich JTextField.setColumnsdie Spaltenanzahl festlegen, um die bevorzugte Größe entsprechend anzupassen. Wenn Sie dies tun, setPreferredSizecodieren Sie eine Größe fest, wodurch Ihre Layouts abhängig von der Schriftgröße der Plattform beschädigt werden. Hier sind einige Textfelder in einem Grid-Bag-Layout mit setColumnsentsprechend aufgerufen . Verwenden Sie für Ihre Schaltflächen geeignete Layouts / Rastergewichte, um die Größen zu steuern.
Jason C
@GeeBee Und jetzt, wenn das richtig gemacht wurde, beachten Sie, wie die Textfeldbreiten verringert werden, wenn ich die Schriftgröße verkleinere: i.snag.gy/ZULulh.jpg . Selbst wenn Sie die Schriftgröße im laufenden Betrieb ändern, funktioniert dies jetzt automatisch, anstatt dass Sie beispielsweise alle Textfeldbreiten neu berechnen und setPreferredSize explizit erneut aufrufen müssen. Sie müssen lediglich das Layout ungültig machen und die Größe wird angepasst.
Jason C
20

Wenn Sie Probleme mit Layouts in Java Swing haben, kann ich die JGoodies, FormLayoutdie Karsten Lentzsch hier als Teil der Freeware-Bibliothek Forms zur Verfügung stellt, wärmstens empfehlen .

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

Sie finden Karsten Dokumentation in finden hier , und einige ziemlich gute Dokumentation von Eclipse hier .

Tom
quelle
16

Diese Methoden werden von den meisten Menschen kaum verstanden. Sie sollten diese Methoden auf keinen Fall ignorieren. Es ist Sache des Layout-Managers, diese Methoden einzuhalten. Diese Seite enthält eine Tabelle, die zeigt, welche Layout-Manager welche dieser Methoden einhalten:

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

Ich schreibe seit mehr als 8 Jahren Swing-Code und die im JDK enthaltenen Layout-Manager haben immer meine Bedürfnisse erfüllt. Ich habe noch nie einen Layout-Manager eines Drittanbieters benötigt, um meine Layouts zu erstellen.

Ich werde sagen, dass Sie nicht versuchen sollten, dem Layout-Manager mit diesen Methoden Hinweise zu geben, bis Sie sicher sind, dass Sie sie benötigen. Führen Sie Ihr Layout ohne Größenangaben aus (dh lassen Sie den Layout-Manager seine Arbeit erledigen), und nehmen Sie bei Bedarf kleinere Korrekturen vor.

Michael
quelle
1
Entweder gibt es ein leichtes Missverständnis (von Ihrer Seite) oder ein Missverständnis (von meiner Seite), treffen Sie Ihre Wahl :-) Sie wiederholen immer wieder (hier in Ihrem Blog, in Ihrer Antwort in Bezug auf BoxLayout) das Set XXSize als wichtig - eigentlich das Layoutmanager ist (oder nicht) interessiert in der XXSize, dass die ist Sizing Hinweis unabhängig, wie es dazu kam (interne Berechnung durch die Komponente oder manuell durch den Anwendungscode erzwungen)
kleopatra
1
Ich bin mir nicht sicher, ob ich verstehe, worauf du hier hinaus willst. Ich erwähne oben, dass die XXSize () -Methoden nur Hinweise sind. Ich sehe wirklich nichts Falsches daran, einem Layout-Manager bei Bedarf einen kleinen Hinweis zu geben. In meinem Swing-Code finden Sie gelegentlich eine setXXSize () -Methode. Nicht viele, aber hin und wieder finde ich, dass sie gebraucht werden. JComboBox und JSpinner benötigen häufig Hinweise. Insbesondere eine JComboBox, die nach ihrer Realisierung gefüllt wird. Sie scheinen gegen jede Anwendung dieser Methoden zu sein, und ich weiß nicht warum. (Vielleicht bin ich derjenige, dem das Boot fehlt, denke ich).
Michael
5
Nicht die Methoden sind die Hinweise, die Eigenschaften sind: Die Komponenten sollten für alle Hinweise etwas Vernünftiges melden, einige (wie z. B. JComboBox) nicht - bei der Rückgabe von maxInteger oder so. Das ist ein Fehler und sollte durch die Combo behoben werden. Was Ihre Gewohnheit betrifft: Seien Sie sicher, dass Sie weit weg sind, wenn der Betreuer-Kollege das bereinigen muss :) Hartcodierte Hinweise neigen dazu, das Layout bei der geringsten Änderung zu zerstören und sind als Grund für ein fehlerhaftes Layout schwer zu erkennen.
Kleopatra
15

Ist es in einer Situation, in der ich Proportionen zwischen Kindern einer Komponente definieren muss (Kind 1 sollte 10% des Speicherplatzes verwenden, Kind2 40%, Kind3 50%), möglich, dies zu erreichen, ohne einen benutzerdefinierten Layout-Manager zu implementieren?

Vielleicht GridBagLayoutwürde Ihre Bedürfnisse befriedigen. Außerdem gibt es im Web eine Menge Layout-Manager, und ich wette, es gibt einen, der Ihren Anforderungen entspricht.

Thomas
quelle
Danke für die Antwort. Ich muss davon ausgehen, dass Sie auch gemeint haben: "Verwenden Sie setPreferredSize überhaupt nicht", oder?
Heisenbug
1
GridBagLayout verwendet Einschränkungen, bei denen Sie das "Gewicht" sowohl in X als auch in Y für eine bestimmte Komponente angeben können, damit der LayoutManager entscheiden kann, was mit dem zusätzlichen Speicherplatz für eine Größenänderung geschehen soll. ABER Sie benötigen / können setPreferredSize weiterhin verwenden, um die bevorzugte Größe jeder Komponente zu bestimmen. Beachten Sie, dass "bevorzugt" nicht bedeutet, dass es immer berücksichtigt wird. In besonderen Fällen benötigen Sie möglicherweise auch setMinimumSize und setMaximumSize. Sie sind nicht böse , kaufen Sie sich das nicht ein . docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
よ ル ち. ん ん
5

Ich sehe es anders als die akzeptierte Antwort.

1) Sollte ich die Verwendung dieser Methoden vollständig vermeiden?

Niemals meiden! Sie dienen dazu, dem Layout-Manager die Größenbeschränkungen Ihrer Komponenten auszudrücken. Sie können sie vermeiden, wenn Sie keinen Layout-Manager verwenden, und versuchen, das visuelle Layout selbst zu verwalten.

Leider wird Swing nicht mit angemessenen Standardabmessungen geliefert. Anstatt die Abmessungen einer Komponente festzulegen, ist es jedoch besser, die eigene Komponente mit angemessenen Standardeinstellungen herabzusetzen. (In diesem Fall rufen Sie setXXX in Ihrer Nachkommenklasse auf.) Alternativ können Sie die getXXX-Methoden für denselben Effekt überschreiben.

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

Immer. Wenn Sie eine Komponente erstellen, legen Sie ihre realistische minimale / bevorzugte / maximale Größe entsprechend der Verwendung dieser Komponente fest. Wenn Sie beispielsweise ein JTextField für die Eingabe von Ländersymbolen wie UK haben, muss seine bevorzugte Größe so breit sein, dass zwei Zeichen (mit der aktuellen Schriftart usw.) passen. Wahrscheinlich ist es jedoch bedeutungslos, es größer werden zu lassen. Ländersymbole sind schließlich zwei Zeichen. Wenn Sie dagegen ein JTextField zur Eingabe eines Kundennamens haben, kann es eine bevorzugte Größe wie die Pixelgröße für 20 Zeichen haben, kann jedoch größer werden, wenn die Größe des Layouts geändert wird. Stellen Sie daher die maximale Größe auf mehr ein. Gleichzeitig ist es sinnlos, ein 0px breites JTextField zu haben. Legen Sie daher eine realistische Mindestgröße fest (ich würde sagen, die Pixelgröße beträgt 2 Zeichen).

3) Was genau sind die negativen Folgen dieser Methoden?

(Ich kann mir nur vorstellen, Portabilität zwischen Systemen mit unterschiedlicher Bildschirmauflösung hinzuzufügen).

Keine negativen Folgen. Dies sind Hinweise für den Layout-Manager.

4) Ich glaube nicht, dass ein LayoutManager alle gewünschten Layoutanforderungen genau erfüllen kann.

Muss ich wirklich für jede kleine Variation meines Layouts einen neuen LayoutManager implementieren?

Nein, definitiv nicht. Der übliche Ansatz besteht darin, verschiedene grundlegende Layoutmanager wie das horizontale und das vertikale Layout zu kaskadieren.

Zum Beispiel das folgende Layout:

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

hat zwei Teile. Der linke und der rechte Teil sind horizontal angeordnet. Der rechte Teil ist ein JPanel, das dem horizontalen Layout hinzugefügt wurde, und dieses JPanel hat ein vertikales Layout, das die Schaltflächen vertikal anordnet.

Natürlich kann dies mit einem realen Layout schwierig werden. Daher sind gitterbasierte Layout-Manager wie MigLayout viel besser, wenn Sie etwas Ernstes entwickeln möchten.

5) Wenn die Antwort auf 4 "Ja" lautet, führt dies dann nicht zu einer Zunahme von LayoutManager-Klassen, deren Wartung schwierig wird?

Nein, Sie sollten definitiv keine Layout-Manager entwickeln, es sei denn, Sie benötigen etwas ganz Besonderes.

6) In einer Situation, in der ich Proportionen definieren muss ...

Ist es zwischen Kindern einer Komponente (z. B. Kind1 sollte 10% des Speicherplatzes verwenden, Kind2 40%, Kind3 50%) möglich, dies zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren?

Sobald die bevorzugten Größen richtig eingestellt sind, möchten Sie möglicherweise nichts mehr in Prozent tun. Einfach, weil Prozentsätze sinnlos sind (z. B. ist es sinnlos, ein JTextField zu haben, das 10% der Fenstergröße beträgt - da man das Fenster verkleinern kann, sodass JTextField 0 Pixel breit wird, oder das Fenster so erweitern kann, dass sich das JTextField über zwei Anzeigen auf einem befindet Multi-Display-Setup).

Möglicherweise verwenden Sie die Prozentsätze jedoch, um die Größe größerer Bausteine ​​Ihrer GUI (z. B. Panels) zu steuern.

Sie können JSplitPane verwenden, wo Sie das Verhältnis der beiden Seiten voreingestellt haben. Sie können auch MigLayout verwenden, mit dem Sie solche Einschränkungen in Prozent, Pixeln und anderen Einheiten festlegen können.

Gee Bee
quelle
"Ja wirklich?" Das war bei 0? Dies ist besser als die akzeptierte Antwort mit mehr als 100 Ups. Das heißt im Grunde: "Du sollst nie setPreferredSize verwenden!" Das ist schrecklich. In meiner Arbeit gibt es eine Menge spezifischer Größenanforderungen, z. B. "Schaltflächen auf Touchscreens müssen [X] mal [Y] mit einem Abstand von [M] x [N] zwischen" Sicherheitsanforderungen sein. btnBar.setPreferredSize( dimTouchBtn );ist der beste Weg, das zu tun. Einfach, kein benutzerdefinierter Layout-Manager erforderlich. Ich benutze meistens GridBagLayoutmit einigen BorderLayoutund BoxLayoutniste, wenn es mir passt. Dies ist eine starke Kombination und einfach zu bedienen.
Loduwijk
Ich war in meinem obigen Kommentar voreilig. Dies war die erste Antwort, die ich nach der akzeptierten Antwort sah. Warum zählt SO nicht mehr nach Stimmen? Ich dachte, das war ursprünglich einer der Hauptgründe für die Stimmenzahl. Ich stehe trotzdem zu dem ursprünglichen Kommentar; Dies ist eine der besseren Antworten. Abgesehen von Punkt 6 - der nicht so toll ist. Es gibt viele Gründe (die Minderheit kann immer noch eine große Anzahl sein), die Größe zu ändern, und GridBagLayout unterstützt dies in den meisten Fällen, die ich hatte.
Loduwijk
Ich denke, Größenänderung vs. Nicht-Größenänderung wird nicht als religiöse Entscheidung behandelt. Es gibt Anwendungsfälle, in denen niemand die Größe ändern möchte, z. B. wenn Sie eine grafische Benutzeroberfläche für einen Kiosk mit einer voreingestellten festen Auflösung entwickeln. Wenn Sie unterschiedliche Ziele haben, wie z. B. industrielle HMI-Displays und den Fall von "Tasten", müssen Sie mindestens 1 x 1 cm für eine Taste auf einem Touchscreen haben. In diesem Fall legt die DPI des Bildschirms fest, wie Sie die Größe ändern. Andere Eingaben wie Textfelder werden möglicherweise überhaupt nicht vertikal in der Größe geändert, und manchmal (z. B. eine Postleitzahl) ist die horizontale Größenänderung ebenfalls sinnlos.
Gee Bee
0

Sollte ich die Verwendung dieser Methoden vollständig vermeiden? Ich würde nicht sagen "meide" sie. Ich würde sagen, wenn du denkst, dass du sie brauchst, machst du wahrscheinlich etwas falsch. Komponentengrößen werden im Kontext bestimmt. Die Größe von Textkomponenten wird beispielsweise durch die Anzahl der von Ihnen angegebenen Zeilen und Spalten in Kombination mit der von Ihnen ausgewählten Schriftart bestimmt. Ihre Schaltflächen- und Beschriftungsgröße entspricht der Größe der Grafik, falls Sie eine festlegen, oder dem Platz, der zum Anzeigen des von Ihnen festgelegten Texts erforderlich ist. Jede Komponente hat eine natürliche Größe, und die Layout-Manager verwenden diese, um alles zu gestalten, ohne dass Sie Größen angeben müssen. Die Hauptausnahme ist das JScrollPane, dessen Größe unabhängig von dem ist, was es enthält. Für diese werde ich manchmal anrufen setSize()und diese Größe die anfängliche Fenstergröße durch Aufrufen bestimmen lassenJFrame.pack(). Normalerweise lasse ich die Fenstergröße die JScrollPane-Größe bestimmen. Der Benutzer bestimmt die Größe des Fensters. Viele Layout-Manager ignorieren die von Ihnen festgelegten Größen ohnehin und tun daher oft nicht viel Gutes.

Die Methoden wurden aus einem bestimmten Grund definiert. Wann sollte ich sie verwenden? In welchem ​​Kontext? Für welche Zwecke? Ich glaube, sie wurden hinzugefügt, um den Layout-Managern Hinweise zu geben. Sie wurden möglicherweise aus historischen Gründen geschrieben, weil Layout-Manager neu waren und die Leute ihnen nicht voll vertrauten. Ich kenne einige Entwickler, die Layout-Manager vermieden und alles manuell platziert haben, nur weil sie sich nicht mit dem Erlernen eines neuen Paradigmas beschäftigen wollten. Es ist eine schreckliche Idee.

Was genau sind die negativen Folgen dieser Methoden? (Ich kann mir nur vorstellen, Portabilität zwischen Systemen mit unterschiedlicher Bildschirmauflösung hinzuzufügen). Sie sind ineffektiv und erzeugen schlechte Layouts, wobei Objekte zusammengedrückt oder auf nicht natürliche Größen gedehnt werden. Und die Layouts werden spröde. Änderungen an der Fenstergröße führen manchmal zu einer Unterbrechung des Layouts und zu falschen Positionen.

Ich glaube nicht, dass ein LayoutManager alle gewünschten Layoutanforderungen genau erfüllen kann. Muss ich wirklich für jede kleine Variation meines Layouts einen neuen LayoutManager implementieren? Sie sollten keinen neuen LayoutManager "implementieren". Sie sollten vorhandene instanziieren. Ich verwende oft mehrere Layout-Manager in einem einzigen Fenster. Jedes JPanel verfügt über einen eigenen Layout-Manager. Einige Leute scheuen verschachtelte Layouts, weil sie schwer zu pflegen sind. Wenn ich sie benutze, gebe ich jedem seine eigene Erstellungsmethode, damit ich leichter sehen kann, was jeder tut. Aber ich "implementiere" niemals einen Layout-Manager. Ich instanziiere sie einfach.

Wenn die Antwort auf 4 "Ja" lautet, führt dies dann nicht zu einer Zunahme von LayoutManager-Klassen, deren Wartung schwierig wird? Wenn Sie neue Layout-Manager-Klassen für geringfügige Abweichungen im Layout implementieren, verwenden Sie diese falsch. Wenn Sie nur neue Layout-Manager implementieren, machen Sie wahrscheinlich etwas falsch. Das einzige Mal, dass ich eine LayoutManager-Klasse erweitert habe, war das Hinzufügen eines Zoom-Schiebereglers zu einem JScrollPane.

Ist es in einer Situation, in der ich Proportionen zwischen untergeordneten Elementen einer Komponente definieren muss (z. B. sollte child1 10% des Speicherplatzes verwenden, child2 40%, child3 50%), möglich, dies zu erreichen, ohne einen benutzerdefinierten LayoutManager zu implementieren? Im JSplitPane kann der Prozentsatz angegeben werden, den jede Komponente erhalten soll. Der Teiler ist standardmäßig beweglich, aber Sie können ihn deaktivieren, wenn Sie möchten. Ich benutze diese Funktion nicht viel. Normalerweise habe ich einige Komponenten, die eine festgelegte Größe einnehmen, und der Rest des Speicherplatzes wird von einem Bildlauffenster eingenommen. Die Größe des Bildlauffensters wird mit der Fenstergröße angepasst. Wenn Sie zwei Bildlauffenster nebeneinander haben, können Sie sie in ein JSplitPane einfügen und den Prozentsatz des neuen Speicherplatzes angeben, der jedem Fenster zugewiesen wird, wenn der Benutzer die Fenster erweitert und verkleinert.

MiguelMunoz
quelle