Problem z powielaniem elementów

0

Mam problem z powielaniem się elementów graficznych.

Chodzi o to, że mam guzik1 powoduje wyświetlenie się guzika2.

Gdy klikam kilka razy na guzik1 mam kilka guzików2. Jak temu zapobiec ? Oto kod listenera

public class ButtonClientListener implements ActionListener {
    	public void actionPerformed(ActionEvent e) {
    		JLabel label = new JLabel("Zarządzanie klientami");

    		JButton showClientsButton = new JButton("Lista klinetów");
    		JButton showAddClientButton = new JButton("Dodaj klienta");
    		
    		showClientsButton.addActionListener(new ShowClientsButtonListener());
    		showAddClientButton.addActionListener(new ShowAddClientListener());
    		
    		topPanel.add(label);
    		rightPanel.add(showClientsButton);
    		rightPanel.add(showAddClientButton);

    		frame.getContentPane().add(topPanel, BorderLayout.NORTH);
    		frame.getContentPane().add(rightPanel, BorderLayout.EAST);
    		frame.validate();
    	}
    }

kod guzika1

JButton button = new JButton("guzik 1");
            leftPanel.add(button);
            frame.getContentPane().add(leftPanel, BorderLayout.WEST);
0

hmm rozwiązałem to tak. (szybko mnie naszło). powiedzcie czy to dobre rozwiązanie

public class ButtonClientListener implements ActionListener {
           private int flag = 0;
            public void actionPerformed(ActionEvent e) {
            if(flag == 0) {
                    JLabel label = new JLabel("Zarządzanie klientami");

                    JButton showClientsButton = new JButton("Lista klinetów");
                    JButton showAddClientButton = new JButton("Dodaj klienta");
                   
                    showClientsButton.addActionListener(new ShowClientsButtonListener());
                    showAddClientButton.addActionListener(new ShowAddClientListener());
                   
                    topPanel.add(label);
                    rightPanel.add(showClientsButton);
                    rightPanel.add(showAddClientButton);

                    frame.getContentPane().add(topPanel, BorderLayout.NORTH);
                    frame.getContentPane().add(rightPanel, BorderLayout.EAST);
                    frame.validate();
              } else {}
            }
    }
0
  1. Czy gdzieś zmieniasz wartość 'flag'?
  2. 'else' jest niepotrzebny
  3. Zamiast używać flagi możesz sprawdać np. czy label "Zarządzanie klientami" jest null-em
0

Możesz rozwinąć pkt. 3 ?

Generalnie zaraz po zastosowaniu tego rozwiązania zastanawiam się co się stanie jak zmienię widok, czy przypadkiem ta flaga nie zostanie i nie będzie trzeba jej jakoś zerować :) Więc pkt. 1 brzmi na na razie "nie"

Biorąc pod uwagę, że label jest tylko wewnątrz tej klasy to jak sprawdzić czy nie jest nulem skoro ona tam dopiero jest tworzona ?

0

możesz wyciągnąć label na zewnątrz klasy :) (razem z przyciskami)

0

fakt :) Na pewno sprawdzę ten sposób i zeorwanie flagi z zewnątrz

0

Po pierwsze zapomnij o jakichkolwiek new XXX() oraz add() w listenerze.
Jeżeli już chcesz pokazywać coś czego wcześniej nie było widać, to steruj pokazywaniem ukrywaniem już istniejących komponentów. Można w tym celu używać setVisible.
Listener służy do zmiany stanu programu, a do budowania interfejsu GUI.

Poza tym jeżeli już używasz jakiejś flagi, to nazwij ją porządnie aby oznaczała faktycznie to co ma oznaczać. Na przykład:
boolean babciaZjedzonaPrzezWilka = false;

0
Olamagato napisał(a)

Po pierwsze zapomnij o jakichkolwiek new XXX() oraz add() w listenerze.
Jeżeli już chcesz pokazywać coś czego wcześniej nie było widać, to steruj pokazywaniem ukrywaniem już istniejących komponentów. Można w tym celu używać setVisible.
Listener służy do zmiany stanu programu, a do budowania interfejsu GUI.

Poza tym jeżeli już używasz jakiejś flagi, to nazwij ją porządnie aby oznaczała faktycznie to co ma oznaczać. Na przykład:
boolean babciaZjedzonaPrzezWilka = false;

a możesz powiedzieć co jest złego w rozwiązaniu które zaprezentowałem ?

0

Przede wszystkim to, że taki program będzie w nieskończoność rozbudowywał swój interfejs o kolejne obiekty.
Tu żadne flagi nie pomogą.
Po prostu Twój program robi coś zupełnie innego niż napisałeś. A napisałeś "guzik1 powoduje wyświetlenie się guzika2", podczas gdy obecnie guzik1 powoduje utworzenie kolejnego nowego guzika2. Zgodnie z tym co napisałeś program powinien w listenerze jedynie "wyświetlić" guzika2. A wyświetlenie nie robi się za pomocą new, lecz przez setVisible(). Jakakolwiek operacja new w listenerze, to błąd ponieważ jeżeli utworzony obiekt żyje dłużej niż działa kod listenera, to powoduje to wyciek pamięci, a jeżeli krócej, to spowolnienie programu (bo utworzenie obiektu = przydział pamięci jest kosztowne czasowo).

Możesz oczywiście stworzyć potrzebne obiekty przy pierwszym użyciu listenera, zachować referencje do nich (np. w polach klasy), a następnie sprawdzać czy jest to kolejne wywołanie i wtedy tylko używać już utworzonych obiektów, ale daje to ten sam efekt, co utworzenie tych obiektów od razu i użycie ich za każdym razem.
Krótko mówiąc nieprzemyślana koncepcja tego co chcesz w ogóle osiągnąć przez takie zachowanie programu. Wygląda też mi na to, że nie odróżniasz klasy (wzoru dla obiektu) od instancji klasy, czyli samego obiektu.

0

@Olamagato: możesz wyjaśnić co miałeś na myśli pisząc

jeżeli utworzony obiekt żyje dłużej niż działa kod listenera, to powoduje to wyciek pamięci
?

0

Pewnie. Nawet przykładzie. Jeżeli kursor myszki umieścisz tak nieszczęśliwie, że będzie na Twoim feralnym buttonie, a następnie równie feralnie coś na przycisk myszki spadnie, to jak się zachowa program tworzący w listenerze coś nowego?
Otóż będzie on w nieskończoność produkował kolejne obiekty, których odśmiecacz nie zdąży usunąć tak szybko jak są tworzone, co oznacza, że w pewnym momencie nastąpi awaria. Na przykład przepełnienie stosu lub wyczerpanie sterty. Taki program nie będzie stabilny.

Dobrze napisany program stara się niczego w listenerach nie tworzyć dzięki czemu najgorsze, co może się zdarzyć, to połknięcie pewnej liczby zdarzeń, gdyby jakimś cudem system okienkowy (OS + JVM + Swing) nie zdążył przekazać ich do aplikacji.

Pisząc program okienkowy zawsze musisz zakładać nie tylko to, że nie zdążysz go obsłużyć zanim nadejdzie kolejne zdarzenie, ale nawet to, że może nadchodzić kolejne zanim w ogóle zaczniesz obsługiwać bieżące.
Stąd dobrze napisany kod listenera pierwsze co robi, to sprawdza czy właśnie nie obsługuje poprzedniego zdarzenia (co powinno spowodować odrzucenie bieżącego) oraz zablokowuje nadawcę zdarzeń, do czasu zakończenia obsługi bieżącego (np. powoduje wyszarzenie buttona), aby nic nowego nie nadeszło dopóki aplikacja nie będzie na to gotowa.
Wielu osobom wydaje się, że kod listenerów jest trywialny, ale jest tak dlatego, że nigdy nie widziały poprawnie napisanego kodu w takim odbiorniku.

0

a masz może jakieś przykłady takich aplikacji ? Chodzi mi o kod aplikacji GUI bo jak sam widzisz słabo mi z tym idzie :)

0

Najłatwiej po prostu pofatygować się do tutoriala Suna i porządnie przeglądnąć kod co większych przykładów. Dwa miesiące z życia, ale to minimum jeżeli chcesz porządnie poznać Javę i Swinga.

0

również w katalogu z jdk jest dużo przykładowych programów (wraz z kodem źródłowym i nie tylko związanych ze Swingiem):
$JDK_DIR/demo/jfc/SwingSet2

0

Tak, ale Swingset2 lub 3, to na takim etapie za duża rzecz do analizowania. Poza tym nie wszystko jest tam zaimplementowane z wykorzystaniem najlepszych możliwości Javy 6.

1 użytkowników online, w tym zalogowanych: 0, gości: 1