Czy powinienem unikać korzystania z metod ustawiania (Preferowane | Maksymalne | Minimalne) Rozmiar w Java Swing?

481

Kilka razy byłem krytykowany za to, że zasugerowałem użycie następujących metod:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

na Swingkomponentach. Nie widzę żadnej alternatywy dla ich użycia, gdy chcę zdefiniować proporcje między wyświetlanymi komponentami. Powiedziano mi to:

W przypadku układów odpowiedź jest zawsze taka sama: użyj odpowiedniego narzędzia LayoutManager

Trochę przeszukałem Internet, ale nie znalazłem żadnej kompleksowej analizy tego tematu. Mam więc następujące pytania:

  1. Czy powinienem całkowicie unikać stosowania tych metod?
  2. Metody zostały zdefiniowane z jakiegoś powodu. Kiedy powinienem ich użyć? W jakim kontekście? Do jakich celów?
  3. Jakie dokładnie są negatywne konsekwencje stosowania tych metod? (Mogę tylko pomyśleć o dodaniu przenośności między systemami o różnej rozdzielczości ekranu).
  4. Nie sądzę, aby jakikolwiek LayoutManager mógł dokładnie zaspokoić wszystkie pożądane potrzeby układu. Czy naprawdę muszę wdrożyć nowy menedżer układów dla każdej małej odmiany mojego układu?
  5. Jeśli odpowiedź na 4 brzmi „tak”, czy nie doprowadzi to do mnożenia klas LayoutManager, które będą trudne do utrzymania?
  6. Czy w sytuacji, gdy muszę zdefiniować proporcje między elementami potomnymi komponentu (np. Dziecko 1 powinno zajmować 10% miejsca, dziecko 2 40%, dziecko 3 50%), czy można to osiągnąć bez implementacji niestandardowego menedżera układu?
Heisenbug
źródło

Odpowiedzi:

236
  1. Czy powinienem całkowicie unikać stosowania tych metod?

    Tak dla kodu aplikacji.

  2. Metody zostały zdefiniowane z jakiegoś powodu. Kiedy powinienem ich użyć? W jakim kontekście? Do jakich celów?

    Nie wiem, osobiście uważam to za wypadek przy projektowaniu API. Lekko wymuszone przez składniki złożone mające specjalne pomysły na temat rozmiarów dziecka. „Nieznacznie”, ponieważ powinni byli zaimplementować swoje potrzeby za pomocą niestandardowego menedżera LayoutManager.

  3. Jakie dokładnie są negatywne konsekwencje stosowania tych metod? (Mogę tylko pomyśleć o dodaniu przenośności między systemami o różnych rozdzielczościach ekranu).

    Niektóre (niekompletne i niestety linki są zerwane z powodu migracji SwingLabs do java.net) przyczyny techniczne są na przykład wymienione w Regułach (hehe) lub w linku @bendicott znalezionym w jego komentarzu do mojej odpowiedzi . Społecznie, nakładając mnóstwo pracy na twojego nieszczęśliwego faceta, który musi zachować kod i wyśledzić zepsuty układ.

  4. Nie sądzę, aby jakikolwiek LayoutManager mógł dokładnie zaspokoić wszystkie pożądane potrzeby układu. Czy naprawdę muszę wdrożyć nowy menedżer układów dla każdej małej odmiany mojego układu?

    Tak, istnieją narzędzia LayoutManagers wystarczająco mocne, aby spełnić bardzo dobre przybliżenie do „wszystkich potrzeb układu”. Wielka trójka to JGoodies FormLayout, MigLayout, DesignGridLayout. Więc nie, w praktyce rzadko piszesz LayoutManagers, z wyjątkiem prostych wysoce wyspecjalizowanych środowisk.

  5. Jeśli odpowiedź na 4 brzmi „tak”, czy nie doprowadzi to do mnożenia klas LayoutManager, które będą trudne do utrzymania?

    (Odpowiedź na 4 brzmi „nie”).

  6. Czy w sytuacji, w której muszę zdefiniować proporcje między elementami potomnymi komponentu (na przykład dziecko 1 powinno zajmować 10% miejsca, dziecko 2 40%, dziecko 3 50%), czy można to osiągnąć bez wdrożenia niestandardowego menedżera układu?

    Każda z Wielkiej Trójki może, nawet nie może GridBag (nigdy nie zadał sobie trudu, aby naprawdę opanować, zbyt wiele problemów za zbyt małą moc).

kleopatra
źródło
4
Nie jestem do końca pewien, czy zgadzam się z tą radą w co najmniej dwóch sytuacjach. 1) Komponenty renderowane na zamówienie 2) Używanie JEditorPanez HTML, który sam nie sugeruje szerokości. OTOH Nie jestem pewien, czy coś przeoczyłem. Dokładnie przejrzę odpowiedzi w wątku, ale byłem zainteresowany, jeśli masz jakieś uwagi, szczególnie w tym drugim przypadku.
Andrew Thompson,
2
@Andrew Thompson 1) kompozycje niestandardowe: to sama kompozycja jest odpowiedzialna za zwracanie użytecznych wskazówek dotyczących układu, jeśli nie są wadliwe 2) nawet kompozycje podstawowe są wadliwe ;-) 3) Nie mam nic przeciwko białej przestrzeni (chociaż nie była celowo tym razem, dzięki :-)
kleopatra
8
Nie mogę uwierzyć, że zaakceptowana odpowiedź mówi, że należy unikać używania metod setXXX (). Czasami po prostu potrzebujesz ich, aby przekazać wskazówkę menedżerowi układu. Jeśli układasz panel, powinieneś bezwzględnie swobodnie korzystać z tych metod w razie potrzeby. Mówiąc, że myślę, że jeśli użyjesz odpowiedniego menedżera układu, nie będziesz potrzebować tych metod bardzo często, ale czasami po prostu potrzebujesz ich. Spróbuj umieścić JComboBox lub JSpinner w X_AXIS BoxLayout i nie używaj ich, uważaj, że potrzebujesz tam setMaximumSize ().
Michael
5
@Michael nie, absolutnie tego nie potrzebuję - odpowiedzią jest zawsze użycie porządnego narzędzia LayoutManager i wykonanie drobnych poprawek na poziomie menedżera (w porównaniu z poziomem komponentu)
kleopatra
5
Cały czas mówisz „używaj porządnego LayoutManagera i mówisz mu, jakie chcesz rozmiary” w całym przepełnieniu stosu, ale nigdy nie podajesz żadnych konkretnych przykładów „porządnego” LayoutManagera. I żaden ze standardowych menedżerów nie pozwala bezpośrednio kontrolować rozmiarów.
Ti Strga
100

Kilka heurystyk:

  • Nie używaj, set[Preferred|Maximum|Minimum]Size()gdy naprawdę chcesz przesłonić get[Preferred|Maximum|Minimum]Size(), jak można to zrobić przy tworzeniu własnego komponentu, pokazanego tutaj .

  • Nie używaj, set[Preferred|Maximum|Minimum]Size()gdy możesz polegać na starannie przesłoniętym komponencie getPreferred|Maximum|Minimum]Size, jak pokazano tutaj i poniżej.

  • Użyj set[Preferred|Maximum|Minimum]Size()do uzyskania post- validate()geometrii, jak pokazano poniżej i tutaj .

  • Jeśli komponent nie ma preferowanego rozmiaru, np. JDesktopPaneMoże być konieczne określenie rozmiaru kontenera, ale każdy taki wybór jest dowolny. Komentarz może pomóc wyjaśnić zamiar.

  • Rozważ alternatywne lub niestandardowe układy, gdy okaże się, że będziesz musiał przejść przez wiele komponentów, aby uzyskać pochodne rozmiary, jak wspomniano w tych komentarzach .

wprowadź opis zdjęcia tutaj

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());
            }
        }
    }
}
trashgod
źródło
2
nie zgadzam się (jak można się domyślać :-) z rozumowaniem przez „czynniki zewnętrzne”: właściwości XXSize mają wyrażać wyłącznie potrzeby wewnętrzne . Ulepszanie tych z zewnątrz jest niewłaściwe, czyli hakowanie. Jeśli chcesz mieć ramkę (wewnętrzną lub J) o określonym rozmiarze w stosunku do jej preferowanego ...
zmień
2
@kleopatra: aby być trochę natarczywym: jeśli nigdy nie należy używać metod setXXSize z zewnątrz, dlaczego nie zostałby ogłoszony prywatnym lub chronionym? Czy to nie jest brak projektu? Czy publiczny modyfikator domyślnie nie informuje użytkownika, że ​​może korzystać z tych metod?
Heisenbug
2
Muszę się zgodzić z @kleopatra: setPreferredSize()zawsze zastępuje obliczenia komponentu arbitralnym wyborem.
trashgod
1
@trashgod +100 do ciebie Myślę, że nie ma problemu z przesłonięciem tych metod, nawet ich wywołaniem (ale oczywiście oznaczałoby to, że masz niestandardowy komponent, więc
przesłonięcie
5
@DavidKroukamp: Dziękuję. Opieram się na większym doświadczeniu kleopatry, ale widzę wartość krytycznego badania odmiennego poglądu.
trashgod
47

Czy powinienem całkowicie unikać stosowania tych metod?

Nie, nie ma formalnych dowodów sugerujących, że wywołanie lub zastąpienie tych metod jest niedozwolone. W rzeczywistości Oracle twierdzi, że te metody są używane do podawania wskazówek dotyczących rozmiaru: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment .

Można je również przesłonić (co jest najlepszą praktyką dla Swing) podczas rozszerzania komponentu Swing (zamiast wywoływania metody na niestandardowej instancji komponentu)

Co najważniejsze, bez względu na to, jak określisz rozmiar komponentu, upewnij się, że kontener komponentu używa menedżera układu, który przestrzega żądanego rozmiaru komponentu.

Metody zostały zdefiniowane z jakiegoś powodu. Kiedy powinienem ich użyć? W jakim kontekście? Do jakich celów?

Gdy trzeba podać niestandardowe wskazówki dotyczące rozmiaru menedżerowi układu kontenerów, aby komponent był dobrze rozplanowany

Jakie dokładnie są negatywne konsekwencje stosowania tych metod? (Mogę tylko pomyśleć o dodaniu przenośności między systemami o różnej rozdzielczości ekranu).

  • Wielu menedżerów układu nie zwraca uwagi na żądany maksymalny rozmiar komponentu. Jednak BoxLayouti SpringLayouttak. Ponadto GroupLayoutzapewnia możliwość jawnego ustawienia minimalnego, preferowanego lub maksymalnego rozmiaru bez dotykania komponentu.

  • Upewnij się, że naprawdę musisz ustawić dokładny rozmiar komponentu. Każdy komponent Swing ma inny preferowany rozmiar, w zależności od używanej czcionki oraz wyglądu i stylu. Zatem posiadanie ustawionego rozmiaru może powodować zróżnicowany wygląd interfejsu użytkownika w różnych systemach

  • czasami można napotkać problemy z GridBagLayoutpolami tekstowymi i, w których jeśli rozmiar kontenera jest mniejszy niż rozmiar preferowany, wykorzystywany jest rozmiar minimalny, co może powodować znaczne zmniejszenie pól tekstowych.

  • JFramenie wymusza nadpisania getMinimumSize()tylko przywoływania setMinimumSize(..)swoich dzieł

Nie sądzę, aby jakikolwiek LayoutManager mógł dokładnie zaspokoić wszystkie pożądane potrzeby układu. Czy naprawdę muszę wdrożyć nowy menedżer układów dla każdej małej odmiany mojego układu?

Jeśli przez wdrożenie masz na myśli użycie, to tak. Nie LayoutMangerda się obsłużyć wszystkiego, każdy LayoutManagerma swoje zalety i wady, dzięki czemu każdy z nich może być użyty razem w celu uzyskania ostatecznego układu.

Odniesienie:

David Kroukamp
źródło
3
dostarczanie niestandardowych wskazówek dotyczących rozmiaru, które same w sobie są sprzecznością: dostarczanie wskazówek dotyczących rozmiaru (w px!) jest wyłącznym zadaniem komponentu. Oblicza je na podstawie wewnętrznych informacji o stanie, których żadna inna strona oprócz siebie nie może wiedzieć (ani nie może śledzić). Z perspektywy klienta środkiem dostosowywania może być odpowiedni LayoutManager i / lub specjalizowany interfejs API w komponencie, który umożliwia konfigurowanie wymagań dotyczących wielkości pod względem właściwości „semantycznych” związanych z rozmiarem, liczby wierszy / kolumn w komponencie tekstowym
Kleopatra
3
@kleopatra Nadal chciałbym wiedzieć, dlaczego Oracle mówi nam, jak korzystać z tych metod i jak z nich korzystać. Możemy mieć własne preferencje, ale nie możemy powiedzieć, że projektanci twierdzą, że nie należy go używać, gdy nie ma na to dowodów. Ale dlatego wystawiłem nagrodę, by przekonać innych, którzy mogliby przekazać informacje z wiarygodnego źródła, w którym wyrocznia twierdzi, że w ogóle nie używa tych metod (co czyni z tego niewłaściwą praktykę, na przykład setMinimumSize musi być zwrócił się do takich rzeczy jak JSplitPane itp. Można to zobaczyć w samouczku Oracle dotyczącym podzielonych okien
David Kroukamp 1'12
4
@David: Widziałem setXxxSizemetody jako czerwoną flagę, że mogę tu skończyć , nawet jeśli sugerują to dokumenty. I prawie zawsze powinien nadpisane getXxxSize, gdzie ma dostęp do wymaganej geometrii; a nawet krótkie przykłady są poddawane recyklingowi bardziej, niż chcę myśleć. +1 za wzmiankę o różnicach między menedżerami układu i cytowanie samouczka.
trashgod
1
Nie, w moim komentarzu powyżej chciałem zacytować odpowiedź tutaj .
trashgod
13
+1 „Nie, nie ma formalnych dowodów sugerujących, że wywołanie lub zastąpienie tych metod jest niedozwolone”. Spot on. Post oznaczony jako odpowiedź jest zwykły BS.
TT.
25

Jest tutaj wiele dobrych odpowiedzi, ale chcę dodać trochę więcej o powodach, dla których powinieneś ich unikać (pytanie pojawiło się ponownie w zduplikowanym temacie):

Z kilkoma wyjątkami, jeśli używasz tych metod, prawdopodobnie dopracowujesz GUI, aby dobrze wyglądać w określonym wyglądzie (i przy ustawieniach specyficznych dla systemu, np. Preferowanej czcionki pulpitu itp.). Same metody nie są z natury złe, ale typowe powody ich używania to . Gdy tylko zaczniesz dostrajać pozycje i rozmiary pikseli w układzie, ryzykujesz uszkodzenie swojego GUI (lub przynajmniej źle wyglądającego) na innych platformach.

Jako przykład tego spróbuj zmienić domyślny wygląd aplikacji. Nawet z opcjami dostępnymi na twojej platformie możesz być zaskoczony, jak słabo można renderować wyniki.

Tak więc, w imię utrzymania GUI funkcjonalnego i ładnego na wszystkich platformach (pamiętaj, jedną z głównych zalet Javy jest jego wieloplatformowość), powinieneś polegać na menedżerach układu itp., Aby automatycznie dostosowywać rozmiary komponenty, aby renderowało się poprawnie poza określonym środowiskiem programistycznym.

To powiedziawszy, z pewnością możesz wyobrazić sobie sytuacje, w których metody te są uzasadnione. Ponownie, nie są z natury źli, ale ich użycie jest zwykle dużą czerwoną flagą wskazującą na potencjalne problemy z GUI. Upewnij się tylko, że zdajesz sobie sprawę z wysokiego potencjału powikłań, jeśli / kiedy ich używasz, i zawsze staraj się zastanowić, czy istnieje inne niezależne od wyglądu rozwiązanie swoich problemów - najczęściej okazuje się, że metody nie są konieczne.

Nawiasem mówiąc, jeśli czujesz się sfrustrowany standardowymi menedżerami układu, istnieje wiele dobrych darmowych, otwartych programów zewnętrznych, na przykład JGoodiesFormLayout lub MigLayout. Niektóre konstruktory GUI mają nawet wbudowaną obsługę zewnętrznych menedżerów układu - na przykład edytor GUI WindowBuilder firmy Eclipse jest dostarczany z obsługą FormLayouti MigLayout.

Jason C.
źródło
2
+1 przemyślaną odpowiedź - po prostu nie zgadzaj się z tym, że z natury nie są źli, ponieważ są :-) Zazwyczaj klienci zewnętrzni nie mają żadnych szans na odgadnięcie - a same założenia są tak bliskie, jak to możliwe, przez osoby postronne - w połowie poprawne wskazówki dotyczące układu: tylko same komponenty mają zawsze wszystkie informacje, aby zwrócić cokolwiek przydatnego. A ponieważ w chwili ingerencji osób postronnych ich obowiązkiem jest aktualizowanie tych wskazówek, których nie mogą.
kleopatra
1
Cóż, wiesz, mam więcej „poglądów, że ludzie nie zabijają ludzi, ludzie zabijają ludzi” tego rodzaju poglądów. :) Jeśli ktoś korzysta z tych metod, musi zdawać sobie sprawę z takich rzeczy, jak podniesione przez ciebie zalety nieprzewidywalnego użycia wskazówek dotyczących układu (dlatego sytuacje, w których te metody są odpowiednie, są naprawdę rzadkie).
Jason C
Myślę, że ustawienie preferowanego rozmiaru wcale nie jest dużą czerwoną flagą. Zamiast tego nie jest to duża czerwona flaga. Pozwól mi rozwinąć. Menedżer układu - bez względu na to, jak inteligentny jest - nie ma pojęcia o logicznej funkcji widżetu GUI. Na przykład menedżer układu nie może odróżnić pola JTextField do wprowadzania kodu pocztowego od pola JTextField do wprowadzania nazwy. Podobnie nie można odróżnić przycisku narzędzia obok pola JTextField lub dużego przycisku OK na dole formularza. Dlatego potrzebny jest albo lepszy zestaw widżetów, albo wskazówki dotyczące zmiany rozmiaru, nie?
Gee Bee,
@GeeBee Nie, to w rzeczywistości doskonały przykład czerwonej flagi. Co należy zrobić, to JTextField.setColumnsustawić liczbę kolumn, która odpowiednio dostosuje preferowany rozmiar. Jeśli to zrobisz setPreferredSize, programujesz na stałe rozmiar, który spowoduje uszkodzenie układów w zależności od rozmiaru czcionki platformy. Oto kilka pól tekstowych w układzie siatki siatki z setColumnsodpowiednio wywoływanymi . Do przycisków używaj odpowiednich układów / ciężarów siatki, aby kontrolować rozmiary.
Jason C
@GeeBee A teraz, po prawidłowym wykonaniu, zauważ, jak zmniejszają się szerokości pola tekstowego, gdy zmniejszam rozmiar czcionki: i.snag.gy/ZULulh.jpg . Nawet zmiana rozmiaru czcionki w locie działa teraz automatycznie, zamiast, powiedzmy, konieczności ponownego obliczenia wszystkich szerokości pól tekstowych i jawnego wywołania setPreferredSize ponownie dla każdego, wszystko co musisz zrobić, to unieważnić układ, a ich rozmiary się dostosują.
Jason C
20

Jeśli masz problemy z układami w Java Swing, mogę gorąco polecić JGoodies FormLayoutdostarczone bezpłatnie jako część darmowej biblioteki Forms autorstwa Karstena Lentzscha tutaj .

Ten bardzo popularny menedżer układu jest niezwykle elastyczny, dzięki czemu można opracowywać bardzo dopracowane interfejsy Java.

Znajdziesz tutaj dokumentację Karstena , a trochę dobrej dokumentacji z zaćmienia tutaj .

Tomek
źródło
16

Metody te są słabo rozumiane przez większość ludzi. Absolutnie nie powinieneś ignorować tych metod. Od menedżera układu zależy, czy zastosują się do tych metod. Ta strona zawiera tabelę, która pokazuje, którzy menedżerowie układu honorują, które z tych metod:

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

Piszę kod Swing od ponad 8 lat, a menedżerowie układu znajdujący się w JDK zawsze spełniali moje potrzeby. Nigdy nie potrzebowałem zewnętrznego menedżera układu, aby uzyskać moje układy.

Powiem, że nie powinieneś próbować udzielać wskazówek menedżerowi układu tymi metodami, dopóki nie będziesz pewien, że ich potrzebujesz. Wykonaj swój układ bez żadnych wskazówek dotyczących zmiany rozmiaru (tj. Pozwól menedżerowi układu wykonać swoją pracę), a następnie możesz wprowadzić niewielkie poprawki, jeśli zajdzie taka potrzeba.

Michał
źródło
1
albo istnieje niewielkie nieporozumienie (z twojej strony), albo nieporozumienie (z mojej strony), wybierz swój wybór :-) Powtarzasz (tutaj, na blogu, w odpowiedzi dotyczącej BoxLayout) zestaw XXSize jako ważny - w rzeczywistości LayoutManager jest (lub nie) interesuje się XXSize, czyli wielkości wskazówka niezależnie od tego, jak to się stało (obliczenia wewnętrznej przez komponent lub ręcznie wymuszonej przez kod aplikacji)
Kleopatra
1
Nie jestem pewien, czy rozumiem, o co tu chodzi. Wspominam powyżej, że metody XXSize () to tylko wskazówki. Naprawdę nie widzę nic złego w udzielaniu menedżerowi układu podpowiedzi, jeśli to konieczne. W moim huśtawce znajduje się okazjonalna metoda setXXSize (). Nie wielu, ale od czasu do czasu uważam, że są potrzebne. JComboBox i JSpinner często potrzebują wskazówek. Zwłaszcza JComboBox, który jest wypełniany po jego realizacji. Wygląda na to, że sprzeciwiasz się jakiemukolwiek użyciu tych metod i nie wiem dlaczego. (chyba chyba tęsknię za łodzią).
Michael
5
nie metody są podpowiedziami, właściwości są: składniki powinny zgłaszać coś sensownego dla wszystkich podpowiedzi, niektóre (jak fi JComboBox) nie - zwracając maxInteger lub coś takiego. To błąd, który powinien zostać naprawiony przez kombinację. Jeśli chodzi o twój nawyk: pamiętaj, aby być daleko, gdy kolega opiekuńczy musi to wyczyścić :) Zakodowane wskazówki mają tendencję do niszczenia układu przy najmniejszej zmianie i są trudne do wykrycia jako przyczynę zepsutego układu.
kleopatra,
15

Czy w sytuacji, gdy muszę zdefiniować proporcje między elementami potomnymi komponentu (dziecko 1 powinno zajmować 10% miejsca, dziecko 2 40%, dziecko 3 50%), czy można to osiągnąć bez wdrożenia niestandardowego menedżera układu?

Może GridBagLayoutzaspokoi twoje potrzeby. Poza tym w sieci jest mnóstwo menedżerów układu i założę się, że jest taki, który pasuje do twoich wymagań.

Tomasz
źródło
Dziękuję za odpowiedź. Muszę założyć, że miałeś na myśli także: „w ogóle nie używaj setPreferredSize”, prawda?
Heisenbug
1
GridBagLayout wykorzystuje ograniczenia, w których można określić „wagę” zarówno w X, jak i Y dla danego komponentu, dzięki czemu LayoutManager może zdecydować, co zrobić z dodatkową przestrzenią przy zmianie rozmiaru. ALE nadal potrzebujesz / możesz użyć setPreferredSize, aby określić preferowany rozmiar każdego komponentu, zwróć uwagę, że „preferowane” nie oznacza, że ​​będzie on zawsze honorowany. W szczególnych przypadkach możesz także potrzebować setMinimumSize i setMaximumSize. Nie są źli , nie kupujcie tego. docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
マ ル ち ゃ ん だ よ
5

Widzę to inaczej niż zaakceptowana odpowiedź.

1) Czy powinienem całkowicie unikać stosowania tych metod?

Nigdy nie unikaj! Są one po to, aby wyrazić ograniczenia wielkości komponentów dla menedżera układu. Możesz uniknąć ich używania, jeśli nie korzystasz z żadnego menedżera układu i spróbuj samodzielnie zarządzać układem wizualnym.

Niestety, Swing nie ma rozsądnych domyślnych wymiarów. Jednak zamiast ustawiać wymiary komponentu, lepiej OOP schodzić z własnego komponentu z rozsądnymi wartościami domyślnymi. (W takim przypadku wywołujesz setXXX w klasie potomnej.) Alternatywnie możesz zastąpić metody getXXX dla tego samego efektu.

2) Metody zostały zdefiniowane z konkretnego powodu. Kiedy powinienem ich użyć? W jakim kontekście? Do jakich celów?

Zawsze. Podczas tworzenia komponentu ustaw jego realistyczny minimalny / preferowany / maksymalny rozmiar zgodnie z użyciem tego komponentu. Na przykład, jeśli masz JTextField do wprowadzania symboli kraju, takich jak Wielka Brytania, jego preferowany rozmiar powinien być tak szeroki, aby zmieścił się w dwóch znakach (z bieżącą czcionką itp.), Ale prawdopodobnie nie ma sensu pozwolić, aby urósł. W końcu symbole kraju to dwa znaki. Przeciwnie, jeśli masz JTextField do wprowadzania np. Nazwy klienta, może on mieć preferowany rozmiar podobny do rozmiaru piksela dla 20 znaków, ale może wzrosnąć do większego, jeśli zmieni się rozmiar układu, więc ustaw maksymalny rozmiar na więcej. Jednocześnie posiadanie JTextField o szerokości 0 pikseli jest bezcelowe, więc ustaw realistyczny minimalny rozmiar (powiedziałbym, że piksel to 2 znaki).

3) Jakie dokładnie są negatywne konsekwencje stosowania tych metod?

(Mogę tylko pomyśleć o dodaniu przenośności między systemami o różnej rozdzielczości ekranu).

Bez negatywnych konsekwencji. Są to wskazówki dla menedżera układu.

4) Nie sądzę, aby jakikolwiek LayoutManager mógł dokładnie zaspokoić wszystkie pożądane potrzeby układu.

Czy naprawdę muszę wdrożyć nowy menedżer układów dla każdej małej odmiany mojego układu?

Nie definitywnie nie. Zwykle stosuje się kaskadowanie różnych podstawowych menedżerów układu, takich jak układ poziomy i pionowy.

Na przykład poniższy układ:

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

ma dwie części. Lewa i prawa część mają układ poziomy. Prawa część to JPanel dodany do układu poziomego, a ten JPanel ma układ pionowy, który układa przyciski pionowo.

Oczywiście może to stać się trudne z układem w prawdziwym życiu. Dlatego menedżery układu oparte na siatce, takie jak MigLayout, są znacznie lepsze, jeśli masz zamiar opracować coś poważnego.

5) Jeśli odpowiedź na 4 brzmi „tak”, czy nie doprowadzi to do mnożenia klas LayoutManager, które będą trudne do utrzymania?

Nie, zdecydowanie nie powinieneś tworzyć menedżerów układu, chyba że potrzebujesz czegoś bardzo specjalnego.

6) W sytuacji, gdy muszę zdefiniować proporcje ...

między dziećmi elementu (np. dziecko1 powinno zajmować 10% miejsca, dziecko2 40%, dziecko3 50%), czy można to osiągnąć bez implementacji niestandardowego menedżera LayoutManager?

Zasadniczo po prawidłowym ustawieniu preferowanych rozmiarów możesz nie chcieć nic robić procentowo. Po prostu, ponieważ wartości procentowe są bezcelowe (np. Nie ma sensu mieć JTextField 10% rozmiaru okna - ponieważ można zmniejszyć okno, aby JTextField stał się 0px szeroki, lub można rozwinąć okno, aby JTextField znajdował się na dwóch ekranach na konfiguracja wielu wyświetlaczy).

Ale może się zdarzyć, że użyjesz wartości procentowych do kontrolowania rozmiarów większych elementów konstrukcyjnych twojego GUI (na przykład paneli).

Możesz użyć JSplitPane, gdzie możesz wstępnie ustawić stosunek dwóch stron. Lub możesz użyć MigLayout, który pozwala ustawić takie ograniczenia w procentach, pikselach i innych jednostkach.

Gee Bee
źródło
Naprawdę? To było na 0? To jest lepsze niż zaakceptowana odpowiedź, która ma ponad 100 poprawek. To w zasadzie mówi: „Nigdy nie będziesz używać setPreferredSize!” co jest straszne. W mojej pracy jest wiele specyficznych wymagań dotyczących wielkości, takich jak „wymagania dotyczące przycisków na ekranach dotykowych muszą być [X] do [Y] z odstępami [M] x [N]”. btnBar.setPreferredSize( dimTouchBtn );jest najlepszym sposobem na to. Prosto, nie ma potrzeby tworzenia niestandardowego menedżera układu. Używam głównie GridBagLayoutz niektórymi BorderLayouti BoxLayoutzagnieżdżanie, gdy jest to wygodne. Jest to mocna kombinacja i łatwa w użyciu.
Loduwijk,
W moim powyższym komentarzu spieszyłem się szybko. To była pierwsza odpowiedź, jaką zobaczyłem po zaakceptowaniu odpowiedzi. Dlaczego SO już nie sortuje według głosów? Myślałem, że to był jeden z głównych powodów, dla których głosowanie się liczy. Mimo to podtrzymuję oryginalny komentarz; to jedna z lepszych odpowiedzi. Z wyjątkiem punktu 6 - ten nie jest tak świetny. Istnieje wiele (mniejszość nadal może być duża) powodów, dla których warto zmienić rozmiar, a GridBagLayout dobrze to obsługuje w większości przypadków, które miałem.
Loduwijk,
Myślę, że zmiana rozmiaru kontra brak zmiany rozmiaru nie będą traktowane jako decyzja religijna. Zdarzają się przypadki użycia, w których nikt nigdy nie chce zmieniać rozmiaru, np. Jeśli tworzysz GUI dla kiosku, z ustaloną z góry ustaloną rozdzielczością. Jeśli masz różne cele, takie jak przemysłowe wyświetlacze HMI i przypadek „przycisków”, to tak, musisz mieć co najmniej 1 cm na 1 cm dla przycisku na ekranie dotykowym. W takim przypadku DPI ekranu określa sposób zmiany rozmiaru. Inne dane wejściowe, takie jak pola tekstowe, mogą w ogóle nie być zmieniane w pionie, a czasami (np. Kod pocztowy) zmiana rozmiaru w poziomie również nie ma sensu.
Gee Bee,
0

Czy powinienem całkowicie unikać stosowania tych metod? Nie powiedziałbym „unikaj” ich. Powiedziałbym, że jeśli uważasz, że ich potrzebujesz, prawdopodobnie robisz coś złego. Rozmiary komponentów są określane w kontekście. Na przykład rozmiary komponentów tekstowych są określane przez liczbę określonych wierszy i kolumn w połączeniu z wybraną czcionką. Rozmiar przycisku i etykiety będzie odpowiadał rozmiarowi grafiki, jeśli ją ustawisz, lub przestrzeni potrzebnej do wyświetlenia ustawionego tekstu. Każdy komponent ma naturalny rozmiar, a menedżerowie układu użyją go do rozłożenia wszystkiego bez konieczności określania rozmiarów. Głównym wyjątkiem jest JScrollPane, który ma rozmiar niezależny od wszystkiego, co zawiera. Dla tych czasami dzwonię setSize()i pozwalam temu rozmiarowi określić początkowy rozmiar okna, dzwoniącJFrame.pack(). Zazwyczaj pozwalam rozmiarowi okna określać rozmiar JScrollPane. Użytkownik określi rozmiar okna. Wielu menedżerów układu i tak ignoruje ustawione przez ciebie rozmiary, więc często nie robią nic dobrego.

Metody zostały zdefiniowane z jakiegoś powodu. Kiedy powinienem ich użyć? W jakim kontekście? Do jakich celów? Wierzę, że zostały dodane, aby zapewnić wskazówki dla menedżerów układu. Być może zostały napisane z przyczyn historycznych, ponieważ menedżerowie układów byli nowi, a ludzie nie ufali im w pełni. Znam kilku programistów, którzy unikali menedżerów układu i umieszczali wszystko ręcznie, tylko dlatego, że nie chcieli zawracać sobie głowy poznawaniem nowego paradygmatu. To okropny pomysł.

Jakie dokładnie są negatywne konsekwencje stosowania tych metod? (Mogę tylko pomyśleć o dodaniu przenośności między systemami o różnej rozdzielczości ekranu). Są nieskuteczne i wytwarzają złe układy, a obiekty są ściskane lub rozciągane do nienaturalnych rozmiarów. A układy będą kruche. Zmiany rozmiaru okna czasami psują układ i umieszczają rzeczy w niewłaściwych miejscach.

Nie sądzę, aby jakikolwiek LayoutManager mógł dokładnie zaspokoić wszystkie pożądane potrzeby układu. Czy naprawdę muszę wdrożyć nowy menedżer układów dla każdej małej odmiany mojego układu? Nie powinieneś „wdrażać” nowego menedżera układów. Powinieneś utworzyć instancję istniejących. Często używam kilku menedżerów układu w jednym oknie. Każdy JPanel będzie miał własnego menedżera układu. Niektóre osoby boją się układów zagnieżdżonych, ponieważ są trudne do utrzymania. Kiedy ich używam, daję każdemu własną metodę tworzenia, aby łatwiej było zobaczyć, co każdy z nich robi. Ale nigdy nie „wdrażam” menedżera układu. Po prostu je tworzę.

Jeśli odpowiedź na 4 brzmi „tak”, czy nie doprowadzi to do mnożenia klas LayoutManager, które będą trudne do utrzymania? Jeśli wdrażasz nowe klasy menedżera układu dla niewielkich różnic w układzie, używasz ich źle. Jeśli tylko wdrażasz nowe menedżery układu, prawdopodobnie robisz coś złego. Jedyny raz, kiedy rozszerzyłem klasę LayoutManager, było dodanie suwaka powiększenia do JScrollPane.

Czy w sytuacji, gdy muszę zdefiniować proporcje między elementami potomnymi komponentu (np. Dziecko 1 powinno zajmować 10% miejsca, dziecko 2 40%, dziecko 3 50%), czy można to osiągnąć bez implementacji niestandardowego menedżera układu? JSplitPane ma sposób określania procentu, jaki powinien otrzymać każdy składnik. Rozdzielacz jest domyślnie ruchomy, ale możesz go wyłączyć, jeśli chcesz. Nie używam tej funkcji dużo. Zwykle mam niektóre elementy, które zajmują ustalony rozmiar, a resztę miejsca zajmuje okienko przewijania. Rozmiar panelu przewijania będzie dostosowywany do rozmiaru okna. Jeśli masz dwa panele przewijania obok siebie, możesz umieścić je w JSplitPane i określić procent nowego miejsca przydzielonego każdemu, gdy użytkownik rozszerza i kurczy okna.

MiguelMunoz
źródło