2010-10-14 13 views
8

Kilka razy przeczytałem określony tutorial na temat key bindings, ale pamięć podręczna mojego mózgu nie wydaje się wystarczająco duża, aby pomieścić skomplikowane procesy.W jaki sposób Java wysyła KeyEvents?

byłem debugowania Kluczowym problemem wiązania (okazało się, używałem złego JComponent.WHEN_* warunek), i natknąłem się na zwięzły i wesołym javadoc dla pakietu prywatnej javax.swing.KeyboardManager przez (niestety) inżynier anonimowy Java.

Moje pytanie brzmi następująco: z wyjątkiem KeyEventDispatcher, które jest sprawdzane na samym początku, czy w opisie brakuje czegoś i/lub coś pomyłkowo?

Klasa KeyboardManager służy do pomocy działań wysyłka klawiaturowych dla WHEN_IN_FOCUSED_WINDOW actions stylu. Akcje z innymi warunkami są obsługiwane bezpośrednio w JComponent.

Oto opis symantics [sic], w jaki klawiatura wysyłki powinien pracować conajmniej [sic!], Jak ja go rozumiem.

KeyEvents są wysyłane do komponentu fokusowanego . Menedżer focusów dostaje pierwsze pęknięcie podczas przetwarzania tego zdarzenia . Jeśli menedżer fokusowania nie chce tego, wówczas JComponent wywołuje super.processKeyEvent(), co umożliwia słuchaczom przetworzenie zdarzenia .

Jeśli żaden ze słuchaczy nie "zużyje" zdarzenia, to klawisze dostaną strzał . Tutaj zaczynają się interesować rzeczy zaczynające się od . Po pierwsze, KeyStokes [sic] zdefiniowane za pomocą warunku WHEN_FOCUSED mają szansę. Jeśli żaden z nich nie chce tego zdarzenia, komponent przechodzi, chociaż jego rodzice przeglądali akcje typu WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.

Jeśli nikt jeszcze go nie zajął, oznacza to, że podciąga się tutaj . Następnie wyszukujemy komponenty zarejestrowane dla zdarzeń WHEN_IN_FOCUSED_WINDOW i wywołujemy dla nich . Zauważ, że jeśli nie znajdziemy żadnego z tych , przekazujemy to wydarzenie na w paskach i niech mają na sobie pęknięcie . Są traktowane inaczej.

Na koniec sprawdzamy, czy patrzymy na wewnętrzną ramkę . Jeśli jesteśmy i nie ma potrzeby, aby wydarzenie miało miejsce, wówczas podnosimy się do twórcy InternalFrame i widzimy , jeśli ktoś chce tego zdarzenia (i tak dalej: itd.).


(AKTUALIZACJA) Jeśli kiedykolwiek zastanawialiście się o tym śmiałym ostrzeżenia w klawiszy przewodniku:

Ponieważ kolejność przeszukiwania elementów jest nieprzewidywalny, uniknąć powielania WHEN_IN_FOCUSED_WINDOW wiązania!

To z powodu tego segmentu w KeyboardManager#fireKeyboardAction:

 Object tmp = keyMap.get(ks); 
    if (tmp == null) { 
     // don't do anything 
    } else if (tmp instanceof JComponent) { 
      ... 
    } else if (tmp instanceof Vector) { //more than one comp registered for this 
     Vector v = (Vector)tmp; 
      // There is no well defined order for WHEN_IN_FOCUSED_WINDOW 
      // bindings, but we give precedence to those bindings just 
      // added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW 
      // bindings are accessed before those of the JRootPane (they 
      // both have a WHEN_IN_FOCUSED_WINDOW binding for enter). 
      for (int counter = v.size() - 1; counter >= 0; counter--) { 
     JComponent c = (JComponent)v.elementAt(counter); 
     //System.out.println("Trying collision: " + c + " vector = "+ v.size()); 
     if (c.isShowing() && c.isEnabled()) { // don't want to give these out 
      fireBinding(c, ks, e, pressed); 
     if (e.isConsumed()) 
      return true; 
     } 
    } 

Więc kolejność przeszukiwania jest faktycznie przewidywalne, ale oczywiście zależy od tej konkretnej implementacji, więc lepiej nie polegać na to w ogóle. Niech to będzie nieprzewidywalne.

(Javadoc i kod jest od jdk1.6.0_b105 na WinXP).

+0

To jest miła analiza obsługi KeyEvent ... ale nie wiem, czy to właściwie pytanie, na które można odpowiedzieć. – BoffinbraiN

+0

@BoffinbraiN: Miałem nadzieję, że ktoś z kilkoma huśtawkowymi znaczkami mówi coś w stylu "według mojej najlepszej wiedzy" :) –

+1

Tak, zdecydowanie byłoby lepiej! Ale myślę, że w przypadku czegoś tak głębokiego, to naprawdę jest specyficzne dla implementacji, i przeanalizowałeś tę implementację znacznie ostrożniej niż najdrożsi programiści. ;) Najlepiej nie uzależniać kodu od tych szczegółów. – BoffinbraiN

Odpowiedz

1

Musimy rozpocząć debugowanie z Component.dispatchEventImpl.
Samo przeczytanie źródłowych komentarzy metody powinno dać ci doskonałe wyobrażenie o tym, jak wydarzenia płyną w Swingu (możesz także zacząć o jeden poziom wyżej od EventQueue.pumpEventsForHeirarchy).

Dla jasności podam tylko wyciąg z kodem:

  1. Set datownik oraz modyfikatory bieżącego zdarzenia .; Pre-dispatchers. Wykonaj niezbędne ponowne retargeting/reordering tutaj, zanim powiadomimy AWTEventListeners.
  2. Pozwól narzędziu Toolkit przekazać to zdarzenie do AWTEventListeners.
  3. Jeśli nikt nie zużył kluczowego wydarzenia, zezwól, aby KeyboardFocusManager je przetworzył.
  4. Pozwól metody wprowadzania do przetworzenia zdarzenia
  5. wstępne przetworzenie jakieś specjalne wydarzenia przed dostawą
  6. Dostarcz zdarzenie dla normalnego przetwarzania
  7. specjalnego traktowania dla 4061116. Zaczep przeglądarka zamknąć modalnych okien dialogowych :)
  8. Zezwalaj peerowi na przetwarzanie zdarzenia. Z wyjątkiem KeyEvents, będą przetwarzane przez każdy z każdym po wszystkich KeyEventPostProcessors (patrz DefaultKeyboardFocusManager.dispatchKeyEvent())

Teraz można dopasować powyższy przepływ ze swoim opisem, aby ustalić, czy jego prawo czy nie. Ale chodzi o to, że naprawdę nie powinieneś polegać na javadocs klas prywatnych, powodem jest to, że programiści zwykle nie dbają o aktualizowanie komentarzy klas prywatnych podczas zmian kodu, więc dokumenty mogą stać się przestarzałe.

Powiązane problemy