Programowanie zdarzeniowe III. Zaawansowana obsługa zdarzeń Małgorzata Prolejko ZDA JA16Z03
Plan Hierarchia zdarzeń Typy zdarzeń niskiego poziomu Zdarzenia okna Obsługa kliknięcia myszy Adaptery Zdarzenia dotyczące myszki Zdarzenia klawiatury Multicasting Kolejka zdarzeń
Hierarchia zdarzeń Event Object AWT Event Action E Adjustment E Component E Item E Focus E Input E Paint E Window E Key E Mouse E MouseWheel E
Typy zdarzeń niskiego poziomu Zdarzenia niskiego poziomu to te, które dziedziczą po ComponentEvent. Zdarzenie FocusEvent PaintEvent WindowEvent InputEvent KeyEvent MouseEvent MouseWheelEvent Zdarzenie dotyczące fokusu Zdarzenie informujące o potrzebie odmalowania komponentu Zdarzenia okna Zdarzenia urządzeń wejścia Zdarzenia klawiatury Zdarzenia myszki Zdarzenia kółka myszki Źródłami tych zdarzeń mogą być dowolne komponenty GUI.
Zdarzenia okna Zdefiniowane są trzy interfejsy nasłuchu zdarzeń okna: WindowFocusListener słuchacz zdarzeń fokusu okna WINDOW_GAINED_FOCUS okno zyskało fokus (bycie aktywnym) windowgainedfocus WINDOW_LOST_FOCUS okno straciło fokus windowlostfocus WindowListener słuchacz zdarzeń widoczności okna WINDOW_ACTIVATED - okno aktywowano windowactivated WINDOW_DEACTIVATED okno dezaktywowano windowdeactivated WINDOW_ICONIFIED okno zminimalizowano windowiconified WINDOW_DEICONIFIED okno przywrócono windowdeiconified WINDOW_OPENED okno zostało otwarte windowopened WINDOW_CLOSING okno zostanie zamknięte windowclosin WINDOW_CLOSED okno zostało zamknięte windowclosed WindowStateListener słuchacz zdarzeń stanu okna WINDOW_STATE_CHANGED stan okna się zmienił - windowstatechanged
Zdarzenia okna Podstawowe działanie i odmalowywanie ramki okna JFrame jest już wstępnie zaimplementowane. Można jednak wybrać jedną z predefiniowanych operacji, która zostanie wykonana podczas zamykania okna. Metoda setdefaultcloseoperation przyjmuje jeden z wcześniej zadeklarowanych parametrów zdefiniowanych w WindowConstants: DO_NOTHING_ON_CLOSE : Nic nie robi, a operacja zamknięcia obsługiwana jest tylko przez odpowiednią implementację zdarzenia windowclosing HIDE_ON_CLOSE : tylko chowa ramkę DISPOSE_ON_CLOSE : chowa i niszczy ramkę (ale nie kończy działania aplikacji) EXIT_ON_CLOSE : Zamyka aplikację. setdefaultcloseoperation(windowconstants.exit_on_close);
Obsługa kliknięcia myszy Jeżeli interesuje nas fizyczne kliknięcie, a nie obsługa przycisku lub elementu GUI, należy zaimplementować zdarzenie niskiego poziomu dotyczące myszki MouseEvent. Interfejs słuchacza tego zdarzenia zawiera pięć metod: mousepressed klawisz myszki został wciśnięty mousereleased klawisz myszki został zwolniony mouseclicked nastąpiło kliknięcie: wciśnięcie i zwolnienie przycisku w tym samym miejscu ekranu mouseentered kursor najechał na element mouseexited kursor opuścił element Źródłem tego zdarzenia, tak jak i innych niskopoziomowych mogą być dowolne komponenty GUI np. JButton, lub JPanel.
Obsługa kliknięcia myszy b.addmouselistener(new MouseListener(){ public void mouseclicked(mouseevent e) { System.out.println("klik " + e.getclickcount() + " raz"); public void mouseentered(mouseevent e) { System.out.println("wejście - wsp. el :x=["+ e.getx()+";"+e.gety()+"]"); public void mouseexited(mouseevent e) { System.out.println("zejście - wsp X ekranu: x=["+ e.getxonscreen()+"]"); public void mousepressed(mouseevent e) { System.out.println("wciśnięcie przycisku w punkcie "+ e.getpoint().tostring()); public void mousereleased(mouseevent e) { System.out.println("puszczenie przycisku"); ); Package test5
Adaptery Wykorzystanie interfejsu słuchacza wymaga od programisty zaimplementowania wszystkich metod jakie ten interfejs deklaruje. Czasami chcemy obsłużyć tylko jedną z metod (np. mouseclicked). W takim przypadku pozostałe implementacje będą puste. b.addmouselistener(new MouseListener(){ public void mouseclicked(mouseevent e) { System.out.println("klik " + e.getclickcount() + " raz"); ); public void mouseentered(mouseevent e) { public void mouseexited(mouseevent e) { public void mousepressed(mouseevent e) { public void mousereleased(mouseevent e) {
Adaptery Aby zapobiec pustym implementacjom i co za tym idzie nadmiernemu kodowi, wprowadzono klasy adaptacyjne. Są to klasy implementujące interfejsy słuchaczy, ale z samymi pustymi ciałami metod. class MouseAdapter implements MouseListener{ public void mouseclicked(mouseevent e) { public void mouseentered(mouseevent e) { public void mouseexited(mouseevent e) { public void mousepressed(mouseevent e) { public void mousereleased(mouseevent e) { ); Teraz skonstruowanie słuchacza z obsłużoną jedną metodą będzie wymagało jedynie przeładowania tej metody. b.addmouselistener(new MouseAdapter(){ public void mouseclicked(mouseevent e) {System.out.println("klik); ); Package test6
Adaptery Klasy adaptacyjne zostały zaimplementowane dla siedmiu słuchaczy (tych, które mają więcej niż jedną metodę). ComponentAdapter ContainerAdapter FocusAdapter KeyAdapter MouseAdapter MouseMotionAdapter WindowAdapter implements ComponentListener ContainerListener FocusListener KeyListener MouseListener MouseMotionListener WindowListener
Zdarzenia dotyczące myszki Zdarzeniom myszki przypisane są trzy rodzaje słuchaczy: MouseListener, MouseMotionListener oraz MouseWheelListener. MouseListener MouseMotionListener MouseWheelListener mouseclicked mousemoved mousewheelmoved mouseentered mouseexited mousepressed mousereleased mousedragged Klasa MouseEvent posiada metody zwracające pozycję kursora na ekranie bądź na elemencie, numer wciśniętego przycisku myszy, liczbę kliknięć. int getxonscreen() int getyonscreen() Point getlocationonscreen() int getx() int gety() Point getpoint() int getbutton() int getclickcount()
Zdarzenia klawiatury Zdarzeniom klawiatury przypisany jest tylko jeden słuchacz: KeyListener. KeyListener keytyped keypressed keyreleased Pojawia się kiedy wpisano zdefiniowaną kombinację znaków Wciśnięcie klawisza Puszczenie klawisza Klasa KeyEvent posiada metody pozwalające na sprawdzenie jakiego rodzaju klawisz został wciśnięty. getextendedkeycode() getkeychar() getkeycode() isactionkey() zwraca rozszerzony kod zdarzenia zwraca znak klawisza zwraca kod klawisza sprawdza czy klawisz jest funkcyjny
Zdarzenia wejścia Zdarzenia wejścia dotyczą zarówno myszki jak i klawiatury. Przechowywane są w ich nadklasie InputEvents. Metody tej nadklasy pozwalają na sprawdzenie wystąpienia wciśniętych klawiszy funkcyjnych consume() zużywa zdarzenie zapobiegając jego propagacji dalej isconsumed() sprawdza czy zdarzenie zostało zużyte getmodifiers()- zwraca rozszerzoną maskę modyfikatorów wciśniętych podczas wystąpienia zdarzenia getmodifiersex() zwraca rozszerzoną maskę modyfikatorów getwhen() zwraca czas w ms od początku epoki kiedy nastąpiło zdarzenie isaltdown() isaltgraphdown() iscontroldown() ismetadown() isshiftdown()
Multicasting Istnieje czasem potrzeba wykonania pewnych akcji równocześnie na wielu komponentach, gdy zdarzenie wystąpi na jednym z nich. Np. zamknięcie wszystkich okien jednym przyciskiem. Kiedy jedno zdarzenie wysyłane jest wielu słuchaczom, mówimy o multicastingu. Słuchacze rejestrowani są w źródle i umieszczani na liście słuchaczy. Gdy następuje zdarzenie, każdy słuchacz z listy zostaje o nim poinformowany. Sluchacz s1 = new Sluchacz(); Sluchacz s2 = new Sluchacz(); Sluchacz s3 = new Sluchacz(); trzy różne obiekty słuchaczy Zrodlo z = new Zrodlo(); z.dodajsluchacza(s1); z.dodajsluchacza(s2); z.dodajsluchacza(s3); jedno źródło zdarzenia rejestracja każdego ze słuchaczy
Multicasting JButton jb1 = new JButton("Poszerz"); JButton jb2 = new JButton("Zwęź"); ActionListener slposzerz1 = new ActionListener(){ @Override public void actionperformed(actionevent e) { jb1.setsize(jb1.getwidth()+10,jb1.getheight()); ; ActionListener slposzerz2 = new ActionListener(){ @Override public void actionperformed(actionevent e) { jb2.setsize(jb2.getwidth()+20,jb2.getheight()); ; jb1.addactionlistener(slposzerz1); jb1.addactionlistener(slposzerz2); Package test6 dwa różne obiekty słuchaczy jedno źródło zdarzenia rejestracja każdego ze słuchaczy
Kolejka zdarzeń W bibliotece AWT zaimplementowano kolejkę zdarzeń dla komponentów z niej korzystających. Gdy jakieś zdarzenie ma miejsce, zostaje wstawione do kolejki i oczekuje na przetworzenie void postevent(awtevent). Następnie narzędzie obsługujące kolejkę pobiera zdarzenie AWTEvent getnextevent(), znajduje jego słuchaczy i wywołuje odpowiednią metodę obsługi zdarzenia u słuchacza. Można także zdarzenie w kolejce podejrzeć (bez usuwania go z kolejki) metodą AWTEvent peekevent(). Ponieważ niektóre zdarzenia zdarzają się bardzo często, ale są krótkie(jak poruszenia myszką) a inne wymagają dłuższego czasu na wykonanie(np. odmalowywanie komponentów), narzędzie AWT może dzielić i łączyć zadania tak, by optymalizować czas i zasoby procesora.
Główna kolejka zdarzeń Główna Kolejka Zdarzeń (wątek dystrybucji zdarzeń, Event Dispatch Thread EDT) zajmuje się synchronizacją wątków i zdarzeń. Aby dobrze obsługiwać zdarzenia GUI program powinien tworzyć własny wątek dodany do tej kolejki. public static void main(string[] args) { SwingUtilities.invokeLater(new Runnable(){ @Override public void run(){... ); kod programu, który zwykle był w main ie Własne zdarzenia także muszą być wygenerowane i wstawione do kolejki w osobnym wątku.