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

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:

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

cos.addActionListener(**TUTAJ**);

?

Pozdrawiam!

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.

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

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:

Ramka r = new Ramka(); 

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

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:

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:

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.
1

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

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

i niżej

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 :)?

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

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?

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ę ;]

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:

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:

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

0
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:

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...

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

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