ActionListener w "addActionListener" - co robi, w jakim celu to

ActionListener w "addActionListener" - co robi, w jakim celu to
azalut
  • Rejestracja:około 12 lat
  • Ostatnio:ponad rok
  • Postów:1129
1

witam
Mam pytanie jak w temacie. Ucze sie Swing'a i do tej pory do obsługi zdarzen: implementowalem ActionListener, dodawałem metode z interfejsu i ona lapała zdarzenia i jak jakis np JButton miał cos robic to dodawałem w metodzie actionlistenera zrodlo i robiło.

Od jakiegos czasu spotykam sie z zapisem typu:

Kopiuj
winBtn.addActionListener(new ActionListener() {
					public void actionPerformed(ActionEvent evt) {
						try {
							javax.swing.UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
							updateUI();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});

Tzn: zamiast (this) w addActionListener jest jakby nowy obiekt actionlistenera.
Po co to, co to robi? Tutaj podałem przykład pierwszy jaki znalazłem, lookAndFeel'i jeszcze nie przerabiałem ;)

Co innego jeszcze mozna wpisac w nawiasy przy

Kopiuj
cos.addActionListener(**TUTAJ**);

?

Pozdrawiam!

edytowany 2x, ostatnio: azalut
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

Zamiast **TUTAJ** można wpisać referencję do dowolnego obiektu klasy, która implementuje ActionListenera. W podanym przykładzie, ten obiekt jest dopiero w tym momencie tworzony.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

@azalut opcja z "this" jest absolutnie błędna i zapomnij że kiedykolwiek ją widziałeś. Klasy powinny mieć bardzo konkretne funkcje i jak coś jest okienkiem czy panelem to NIE JEST action listenerem! Tworzenie anonimowych action listenerów też nie jest dobrym pomysłem bo potem jest problem z ich szukaniem (a i klasa która je zawiera puchnie).
Podsumowując: jesli robisz action listenera to stwórz nową klasę która implementuje taki interfejs


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
bogdans
@Shalom, grubo przesadziłeś z krytyką.
azalut
  • Rejestracja:około 12 lat
  • Ostatnio:ponad rok
  • Postów:1129
1

To znaczy, ze.. jesli mam klase "Ramka" i w niej mam implementowany ActionListener i metode actionPerformed to w innej klasie np. "Panel" moge stworzyc instancje klasy Ramka:

Kopiuj
Ramka r = new Ramka(); 

i potem dodać do np przycisku istniejacego w klasie "Panel" np tak:

Kopiuj
nazwaPrzycisku.addActionListener(r);

o to chodzi?

Ale prawde mówiąc wciaż nie rozumiem dlaczego w nawiasie addActionListener'a jest jakby.. tworzony nowy obiekt, ktory w dodatku w nawiasach klamrowych posiada kolejne metody? nie pojmuje, gdybys mogl szerzej wytlumaczyc bylbym wdzieczny ;)

EDIT: @Shalom
Jesli mam kod:

Kopiuj
public class Ramka extends JFrame implements ActionListener
{
JButton btn;
public Ramka()
{
[..dodaje layout i reszte do konstruktora..]
btn = new  JButton("KLIK");
btn.addActionListener(this);
add(btn);
}

@Override
	public void actionPerformed(ActionEvent e)
	{
           Object o = e.getSource();
            if(o==btn)
            {cos tam robi}
        }

public static void main(String[] args)
{
new Ramka();
}

To to jest źle stworzone? Do tej pory tak robiłem, bo w tutorialach tak pisali i działało niby wsyzstko :) powiedz co zmienic?

@@
Działam zgodnie z tym tutorialem:

edytowany 4x, ostatnio: azalut
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0
  1. Powinieneś mieć dwie osobne klasy. Jedna która jest action listenerem a druga która jest ramką. Czemu? Przykład banalny: zrób w swojej aplikacji 10 przycisków i każdy z inną akcją po kliknięciu. Good luck ;) Będziesz robił drabinkę if'ów? A jak guzików będzie 1000? :)
  2. Jeśli chodzi o "dziwny" zapis o który pytasz to nazywa się to klasą anonimową. Otóż ActionListener to jest tylko interfejs więc nie da się stworzyć obiektu takiej klasy bo brakuje implementacji metod. Java umożliwia tworzenie obiektów anonimowych klas implementujących taki interfejs w taki sposób jaki pokazałeś. Tzn tak jakby tworzysz obiekt ActionListener i od razu musisz zaimplementować jego metody i tyle.

"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
bogdans
Albo będziesz miał drabinkę if'ów w klasie, która jest listenerem, albo 1000 listenerów.
Shalom
No i chyba nie chcesz mi powiedzieć że drabinkę ifów uważasz tutaj za lepsze rozwiązanie? Szczególnie jeśli te guziki będą miały jakieś wspólne zachowanie i można by zastosować jakieś template method ;)
bogdans
Nie, ale pisanie o __jednej__klasie, która jest listenerem, i jednocześnie o drabince 1000 if'ów jest pewnego rodzaju manipulacją.
azalut
  • Rejestracja:około 12 lat
  • Ostatnio:ponad rok
  • Postów:1129
1

@Shalom :
2. Aaa! to takie cuś ;) a jak chce to moge tworzyc ile chce takich implementacji? tzn np:

Kopiuj
button1.addActionListener(new ActionListener [..]); 

i niżej

Kopiuj
button2.addActionListener(new ActionListener [..]);

tak? i jesli mam racje, da rade odnieść się np przy "button2.addActionListener();" do tego obiektu ktory zaimplementowalismy w "button1.addActionListener(new ActionListener [..]);" ? Z tego co mi sie wydaje nie - bo przeciez nie jest on zapisany pod żadną zmienna, dlatego nie mozna sie do niego odniesc. racja?

1.A co mi da stworzenie nowej klasy, ktora implementuje ActionListener? Przeciez tam tez bedzie actionPerformed i tez bede musiał łapac źródło i dawac drabine ifów.
Co to zmienia :)?

edytowany 3x, ostatnio: azalut
airborn
  • Rejestracja:prawie 16 lat
  • Ostatnio:prawie 7 lat
  • Postów:274
0
azalut napisał(a):

1.A co mi da stworzenie nowej klasy, ktora implementuje ActionListener? Przeciez tam tez bedzie actionPerformed i tez bede musiał łapac źródło i dawac drabine ifów.
Co to zmienia :)?

Metoda actionPerformed zostanie wywołana tylko dla źródeł w których dany ActionListener jest zarejestrowany. Czyli źródłem zawsze będzie obiekt na rzecz którego wywołałeś metodę addActionListener

azalut
  • Rejestracja:około 12 lat
  • Ostatnio:ponad rok
  • Postów:1129
1

Metoda actionPerformed zostanie wywołana tylko dla źródeł w których dany ActionListener jest zarejestrowany. Czyli źródłem zawsze będzie obiekt na rzecz którego wywołałeś metodę addActionListener

No tak myslalem @airborn , ale jesli Shalom mówi o tworzeniu osobno: klasy ramki (o nazwie np: Ramka) i klasy z implementowanym actionlistenerem (np nowa klasa o nazwie Sluchacz) to w czym to ułatwia zadanie :)? Przecież i tak bede musiał wyłapywać tą nową klasą zdarzenie i ifem sprawdzac źródło, co w dodatku jeszcze bardziej bedzie utrudnione, bo trzeba bedzie sprawdzać pola klasy "Ramka" (tzn np. który przycisk albo ktory JTextField wywolal zdarzenie)
Albo mi sie pogmatwało, albo to ułatwia dopiero w pewnym momencie, bo obecnie wydaje sie utrudnieniem :D pewnie nie mam racji, poprawcie mnie

A jesli jak mówisz, zarejestruje dla jakiegos przycisku ActionListenera - to musze tam wpisac cała formułke: new ActionListener, potem nadpisac metode actionPerformed i teraz dac jej implementacje. Nie krócej i mniej zawile jest dodac klasie: "implements ActionListener" i faktycznie dodawac po prostu te ify w actionPerformed?

edytowany 4x, ostatnio: azalut
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@azalut rly? Jak zarejestrujesz tego action listenera tylko w jednym konkretnym buttonie to wcale nie musisz nic "sprawdzać" bo wiesz kto go wywołał. W ogóle zabawy w sprawdzanie ifem co wywołało action listenera wskazuje na błąd w implementacji...
I nie, nigdy lepszym rozwiązaniem nie jest dodanie implementacji tego interfejsu. Klasy powinny być małe, metody też. Jeśli masz metodę która ma więcej niż 20 linijek to na 99% jest to źle napisane.
Jak chcesz mieć dwa buttony podpięte do tego samego listenera to wtedy bez sensu byłoby robić dwa anonimowe listenery i wtedy lepiej mieć normalną klasę ;]


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
bogdans
Masz rację, ale korzystanie z anonimowych listenerów w żaden sposób nie zmniejsza klasy, wprost przeciwnie, nieco zwiększa.
Shalom
Tak, ale można tą klasę "ekstraktować" jednym klikiem kiedy tylko chcemy. Wyciągnąć tak ifa z metody może być trudniej, szczególnie jak ify są zagnieżdżone ;)
bogdans
E tam, zazwyczaj obsługa przycisku korzysta z pól klasy, "ekstrakcja" wymaga dopisania w klasie listenera konstruktora i pola przechowującego referencję do klasy okna. Nigdy nie zagnieżdżam if'ów w actionPerformed: if(source == ..) {zrób coś; return;} A zrób coś to zazwyczaj wywołanie metody.
azalut
  • Rejestracja:około 12 lat
  • Ostatnio:ponad rok
  • Postów:1129
1

@bogdans @Shalom Nie wiem czy dobrze rozumiem, wiec pozwoliłem sobie napisać mała klase, zeby mozna bylo ocenic czy jestem na dobrej drodze :D
Otoz tak: mam 3 buttony, pierwszy ma miec zarejestrowany actionlistener ktory wykona sie zawsze dla niego(przycisk: b1)
Nastepne dwa mają mieć tego samego ActionListenera(b2 i b3).

I zrobiłem tak:
klasa Ramka:

Kopiuj
public class Ramka extends JFrame
{
	JButton b1, b2, b3;
	
	public Ramka()
	{
		setSize(400,400);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		b1 = new JButton("klik1");
		b2 = new JButton("klik2");
		b3 = new JButton("klik3");
		
		b1.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e)
			{
				System.out.println("CZESC");
			}
		});
		Sluchacz sl2 = new Sluchacz(b2,b3);
		b2.addActionListener(sl2);
		b3.addActionListener(sl2);
                add(b1);
                add(b2);
                add(b3);
	}
	
	public static void main(String[] args)
	{
		new Ramka();
	}
}

i klasa Sluchacz:

Kopiuj
public class Sluchacz implements ActionListener
{
	private Ramka b2;
	private Ramka b3;

	public Sluchacz(Ramka b2, Ramka b3)
	{
		this.b2 = b2;
		this.b3 = b3;
	}
	
	@Override
	public void actionPerformed(ActionEvent e)
	{
		Object o = e.getSource();
		if(o == b2)
		{costam}
		else if(o == b3)
		{costam}
	}
}

W ogóle zabawy w sprawdzanie ifem co wywołało action listenera wskazuje na błąd w implementacji...

Możliwe, w tutorialach zawsze piszą zeby tak robic ;) dlatego tak robiłem, poprawcie mnie tak, zebym robił dobrze ;p

edytowany 5x, ostatnio: azalut
bogdans
Nie należy być dogmatykiem, przy jednym przycisku w oknie na pewno nie korzystałbym z dodatkowej klasy słuchacza. Przy dwóch zapewne też.
azalut
tak tak, ale to tylko szybki przykład :) pewnie polecałbys zrobic w listenerach (this) i ifem sprawdzac, jesli klasa ma mało buttonow czy tam ogólnie "zdarzen" generowanych?
airborn
  • Rejestracja:prawie 16 lat
  • Ostatnio:prawie 7 lat
  • Postów:274
0
Kopiuj
public class Ramka extends JFrame {
        JButton b1, b2, b3;
 
        public Ramka() {
                setSize(400,400);
                setVisible(true);
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setLayout(new FlowLayout());
 
                b1 = new JButton("klik1");
                b2 = new JButton("klik2");
                b3 = new JButton("klik3");
 
                b1.addActionListener(new ActionListener(){
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                System.out.println("b1");
                        }
                });
                b2.addActionListener(new ActionListener(){
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                System.out.println("b2");
                        }
                });
                b3.addActionListener(new ActionListener(){
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                System.out.println("b3");
                        }
                });
        }

Oczywiście prócz klas anonimowych można zastosować normalne klasy jeżeli np. kod obsługi kliknięcia jest podobny i tylko stosować inne parametry np:

Kopiuj
public class Ramka extends JFrame {
        JButton b1, b2, b3;
 
        public Ramka() {
                setSize(400,400);
                setVisible(true);
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setLayout(new FlowLayout());
 
                b1 = new JButton("klik1");
                b2 = new JButton("klik2");
                b3 = new JButton("klik3");
 
                b1.addActionListener(new Act("b1"));
                b2.addActionListener(new Act("b2"));
                b3.addActionListener(new Act("b3"));
        }
class Act implements ActionListener {
    private final String msg;
    public Act(String msg){
        this.msg = msg;
    }
    public void actionPerformed(ActionEvent e) {
        System.out.println(msg);
    }
}

Możliwe, w tutorialach zawsze piszą zeby tak robic dlatego tak robiłem, poprawcie mnie tak, zebym robił dobrze ;p
Dlatego tutoriale przeważnie są g. warte...

edytowany 2x, ostatnio: airborn
azalut
na samym koncu miało nie miało byc: System.out.println(msg); zamiast System.out.println("b3"); ? bo w tym wypadku czy wpisze przy b2/b3.addActionListener("b2"/"b3") zawsze pokaze sie "b3" hmm?
airborn
Tak, oczywiście.
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0
azalut napisał(a):

Możliwe, w tutorialach zawsze piszą zeby tak robic ;) dlatego tak robiłem, poprawcie mnie tak, zebym robił dobrze ;p

Jeśli poważnie tak piszą w tutorialu z którego korzystasz to proponuje poszukać lepszego ;)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.