昨日の部分は細部が間違っていたので修正した。
Swing部品の標準Look & Feelのときの処理 (ボタン部品のアクションイベントについて) は以下のようになっている。
JDK のソースをいくら見てもわからず、結局、JBuilder Personal 9 日本語版 と添付のJDK 1.4.1_02-b06 でイベント処理用メソッドにデバッガのブレークをかけて調べた結果である。
だだし、以下の文中で参照しているJDKのソースは 1.4.2_11-b06 のものである。
Swingのイベント処理はAWTの低レベルなイベント処理の上に構成されており
非常にややこしいが、何というか勉強になった気がする。
[処理の概要説明]
Swingの部品は多くが見かけ(view)と動作内容(model)を分離する形で記述されており、ボタンも内部に動作を規定するモデルを持っている。イベント処理にはモデルが密接に関っている。
ボタン構築時に
javax.swing.plaf.basic.BasicButtonUI
クラスで、メソッドが
public void installUI(JComponent c)
protected void installListeners(AbstractButton b)
と呼び出され、そこで
javax.swing.plaf.basic.BasicButtonListener
クラスのインスタンスが、ボタンの MouseListener, MouseMotionListener, FocusListener, ChangeListener, PropertyChangeListener として登録されているようだ。(メソッドinstallUI()呼び出しコード等は未確認)
ボタンクリックのマウスイベントは、 java.awt.Component の protected void processEvent(AWTEvent e) から protected void processMouseEvent(MouseEvent e) で処理されるが、その中でリスナとして
javax.swing.plaf.basic.BasicButtonListener
クラスのインスタンスの該当メソッドが呼び出されることになる。
ボタンクリック時には、このリスナの
mouseReleased()
から、ボタンの getModel() によって得られるモデル ButtonModel の setPressed(true) が呼び出される。
JButton の場合は、
javax.swing.DefaultButtonModel の setPressed()
が呼ばれ、そこで
javax.swing.DefaultButtonModel の protected void fireActionPerformed(ActionEvent e)
が呼ばれる。
(JCheckBox など JToggleButton の場合は、
javax.swing.JToggleButton.ToggleButtonModel (内部staticクラス。DefaultButtonModelのサブクラス) の setPressed()
が呼ばれ、そこでトグルチェックをやった後
javax.swing.DefaultButtonModel の protected void fireActionPerformed(ActionEvent e)
が呼ばれる。)
モデル (DefaultButtonModel や ToggleButtonModel 等のインスタンス) の fireActionPerformed() では、 インスタンス変数である
protected EventListenerList listenerList (java.util.EventListener クラス)
を参照し、登録されている ActionListener を順次検索し、それぞれの
public void ationPerformed(ActionEvent e)
を順次呼び出している。
ところで、ボタンのコンストラクタの中の
setModel(new DefaultButtonModel());
や
setModel(new ToggleButtonModel());
によって呼ばれる
AbstractButton の public void setModel(ButtonModel newModel)
の中で、モデル (DefaultButtonModel や ToggleButtonModel 等のインスタンス) の ChangeListener, ActionListener, ItemListener として以下のようなリスナが登録されている。
アクションイベントではモデルのリスナは ForwardActionEvents であり、イベント処理はその
public void actionPerformed(ActionEvent event)
にて行われる。その中味は
fireActionPerformed(event);
であるため、結局
AbstractButton の protected void fireActionPerformed(ActionEvent event)
メソッドに処理が移る。
ここで AbstractButton は JComponent のサブクラスなので、JComponent に用意されているインスタンス変数
protected EventListenerList listenerList
を参照し、そこに登録されているアクションリスナの actionPerformed(ActionEvent e) を順次呼び出す。
JComponent に用意されているインスタンス変数 listenerList はボタンの addActionListener() 等で利用されているため、ここでようやく登録されたリスナのメソッドが呼び出されることになる。
[ボタンクリックからイベント処理用メソッドに至るまでのスタックトレース]
以下は (A) JButtonnクリック時 (B) JCheckBoxクリック時 のイベント処理用メソッドに至るまでのスタックトレースである。
(A) JButtonをクリックしたとき
処理用メソッド
jButton1_actionPerformed() : 104, フレームクラス, ソース.java
登録してあるリスナのイベントハンドラ
actionPerformed() : 177, アダプタクラス, ソース.java
fireActionPerformed() : 1764, javax.swing.AbstractButton, AbstractButton.java
actionPerformed() : 1817, javax.swing.AbstractButton$ForwardActionEvents, AbstractButton.java
fireActionPerformed() : 419, javax.swing.DefaultButtonModel, DefaultButtonModel.java
setPressed() : 257, javax.swing.DefaultButtonModel, DefaultButtonModel.java
mouseReleased() : 245, javax.swing.plaf.basic.BasicButtonListener, BasicButtonListener.java
processMouseEvent() : 5134, java.awt.Component, Component.java
processEvent() : 4931, java.awt.Component, Component.java
processEvent() : 1566, java.awt.Container, Container.java
dispatchEventImpl() : 3639, java.awt.Component, Component.java
dispatchEventImpl() : 1623, java.awt.Container, Container.java
dispatchEvent() : 3480, java.awt.Component, Component.java
retargetMouseEvent() : 3450, java.awt.LightweightDispatcher, Container.java
processMouseEvent() : 3165, java.awt.LightweightDispatcher, Container.java
dispatchEvent() : 3095, java.awt.LightweightDispatcher, Container.java
dispatchEventImpl() : 1609, java.awt.Container, Container.java
dispatchEventImpl() : 1590, java.awt.Window, Window.java
dispatchEvent() : 3480, java.awt.Component, Component.java
dispatchEvent() : 450, java.awt.EventQueue, EventQueue.java
pumpOneEventForHierarchy() : 197, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEventsForHierarchy() : 150, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 144, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 136, java.awt.EventDispatchThread, EventDispatchThread.java
run() : 99, java.awt.EventDispatchThread, EventDispatchThread.java
(B) JCheckBox (JToggleButtonの一種) をクリックしたとき
処理用メソッド
jCheckBox1_actionPerformed() : 156, フレームクラス, ソース.java
登録してあるリスナのイベントハンドラ
actionPerformed() : 216, アダプタクラス, ソース.java
fireActionPerformed() : 1764, javax.swing.AbstractButton, AbstractButton.java
actionPerformed() : 1817, javax.swing.AbstractButton$ForwardActionEvents, AbstractButton.java
fireActionPerformed() : 419, javax.swing.DefaultButtonModel, DefaultButtonModel.java
setPressed() : 273, javax.swing.JToggleButton$ToggleButtonModel, JToggleButton.java
mouseReleased() : 245, javax.swing.plaf.basic.BasicButtonListener, BasicButtonListener.java
processMouseEvent() : 5134, java.awt.Component, Component.java
processEvent() : 4931, java.awt.Component, Component.java
processEvent() : 1566, java.awt.Container, Container.java
dispatchEventImpl() : 3639, java.awt.Component, Component.java
dispatchEventImpl() : 1623, java.awt.Container, Container.java
dispatchEvent() : 3480, java.awt.Component, Component.java
retargetMouseEvent() : 3450, java.awt.LightweightDispatcher, Container.java
processMouseEvent() : 3165, java.awt.LightweightDispatcher, Container.java
dispatchEvent() : 3095, java.awt.LightweightDispatcher, Container.java
dispatchEventImpl() : 1609, java.awt.Container, Container.java
dispatchEventImpl() : 1590, java.awt.Window, Window.java
dispatchEvent() : 3480, java.awt.Component, Component.java
dispatchEvent() : 450, java.awt.EventQueue, EventQueue.java
pumpOneEventForHierarchy() : 197, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEventsForHierarchy() : 150, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 144, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 136, java.awt.EventDispatchThread, EventDispatchThread.java
run() : 99, java.awt.EventDispatchThread, EventDispatchThread.java
Swing部品の標準Look & Feelのときの処理 (ボタン部品のアクションイベントについて) は以下のようになっている。
JDK のソースをいくら見てもわからず、結局、JBuilder Personal 9 日本語版 と添付のJDK 1.4.1_02-b06 でイベント処理用メソッドにデバッガのブレークをかけて調べた結果である。
だだし、以下の文中で参照しているJDKのソースは 1.4.2_11-b06 のものである。
Swingのイベント処理はAWTの低レベルなイベント処理の上に構成されており
非常にややこしいが、何というか勉強になった気がする。
[処理の概要説明]
Swingの部品は多くが見かけ(view)と動作内容(model)を分離する形で記述されており、ボタンも内部に動作を規定するモデルを持っている。イベント処理にはモデルが密接に関っている。
ボタン構築時に
javax.swing.plaf.basic.BasicButtonUI
クラスで、メソッドが
public void installUI(JComponent c)
protected void installListeners(AbstractButton b)
と呼び出され、そこで
javax.swing.plaf.basic.BasicButtonListener
クラスのインスタンスが、ボタンの MouseListener, MouseMotionListener, FocusListener, ChangeListener, PropertyChangeListener として登録されているようだ。(メソッドinstallUI()呼び出しコード等は未確認)
ボタンクリックのマウスイベントは、 java.awt.Component の protected void processEvent(AWTEvent e) から protected void processMouseEvent(MouseEvent e) で処理されるが、その中でリスナとして
javax.swing.plaf.basic.BasicButtonListener
クラスのインスタンスの該当メソッドが呼び出されることになる。
ボタンクリック時には、このリスナの
mouseReleased()
から、ボタンの getModel() によって得られるモデル ButtonModel の setPressed(true) が呼び出される。
JButton の場合は、
javax.swing.DefaultButtonModel の setPressed()
が呼ばれ、そこで
javax.swing.DefaultButtonModel の protected void fireActionPerformed(ActionEvent e)
が呼ばれる。
(JCheckBox など JToggleButton の場合は、
javax.swing.JToggleButton.ToggleButtonModel (内部staticクラス。DefaultButtonModelのサブクラス) の setPressed()
が呼ばれ、そこでトグルチェックをやった後
javax.swing.DefaultButtonModel の protected void fireActionPerformed(ActionEvent e)
が呼ばれる。)
モデル (DefaultButtonModel や ToggleButtonModel 等のインスタンス) の fireActionPerformed() では、 インスタンス変数である
protected EventListenerList listenerList (java.util.EventListener クラス)
を参照し、登録されている ActionListener を順次検索し、それぞれの
public void ationPerformed(ActionEvent e)
を順次呼び出している。
ところで、ボタンのコンストラクタの中の
setModel(new DefaultButtonModel());
や
setModel(new ToggleButtonModel());
によって呼ばれる
AbstractButton の public void setModel(ButtonModel newModel)
の中で、モデル (DefaultButtonModel や ToggleButtonModel 等のインスタンス) の ChangeListener, ActionListener, ItemListener として以下のようなリスナが登録されている。
登録コード
changeListener = createChangeListener(); actionListener = createActionListener(); itemListener = createItemListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); newModel.addItemListener(itemListener);
登録リスナクラス
protected ChangeListener createChangeListener() { return (ChangeListener) new ButtonChangeListener(); } protected class ButtonChangeListener implements ChangeListener, Serializable { ButtonChangeListener() { } public void stateChanged(ChangeEvent e) { Object source = e.getSource(); updateMnemonicProperties(); fireStateChanged(); repaint(); } } private class ForwardActionEvents implements ActionListener, Serializable { public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected ActionListener createActionListener() { return new ForwardActionEvents(); } private class ForwardItemEvents implements ItemListener, Serializable { public void itemStateChanged(ItemEvent event) { fireItemStateChanged(event); } } protected ItemListener createItemListener() { return new ForwardItemEvents(); }
アクションイベントではモデルのリスナは ForwardActionEvents であり、イベント処理はその
public void actionPerformed(ActionEvent event)
にて行われる。その中味は
fireActionPerformed(event);
であるため、結局
AbstractButton の protected void fireActionPerformed(ActionEvent event)
メソッドに処理が移る。
ここで AbstractButton は JComponent のサブクラスなので、JComponent に用意されているインスタンス変数
protected EventListenerList listenerList
を参照し、そこに登録されているアクションリスナの actionPerformed(ActionEvent e) を順次呼び出す。
JComponent に用意されているインスタンス変数 listenerList はボタンの addActionListener() 等で利用されているため、ここでようやく登録されたリスナのメソッドが呼び出されることになる。
[ボタンクリックからイベント処理用メソッドに至るまでのスタックトレース]
以下は (A) JButtonnクリック時 (B) JCheckBoxクリック時 のイベント処理用メソッドに至るまでのスタックトレースである。
(A) JButtonをクリックしたとき
処理用メソッド
jButton1_actionPerformed() : 104, フレームクラス, ソース.java
登録してあるリスナのイベントハンドラ
actionPerformed() : 177, アダプタクラス, ソース.java
fireActionPerformed() : 1764, javax.swing.AbstractButton, AbstractButton.java
actionPerformed() : 1817, javax.swing.AbstractButton$ForwardActionEvents, AbstractButton.java
fireActionPerformed() : 419, javax.swing.DefaultButtonModel, DefaultButtonModel.java
setPressed() : 257, javax.swing.DefaultButtonModel, DefaultButtonModel.java
mouseReleased() : 245, javax.swing.plaf.basic.BasicButtonListener, BasicButtonListener.java
processMouseEvent() : 5134, java.awt.Component, Component.java
processEvent() : 4931, java.awt.Component, Component.java
processEvent() : 1566, java.awt.Container, Container.java
dispatchEventImpl() : 3639, java.awt.Component, Component.java
dispatchEventImpl() : 1623, java.awt.Container, Container.java
dispatchEvent() : 3480, java.awt.Component, Component.java
retargetMouseEvent() : 3450, java.awt.LightweightDispatcher, Container.java
processMouseEvent() : 3165, java.awt.LightweightDispatcher, Container.java
dispatchEvent() : 3095, java.awt.LightweightDispatcher, Container.java
dispatchEventImpl() : 1609, java.awt.Container, Container.java
dispatchEventImpl() : 1590, java.awt.Window, Window.java
dispatchEvent() : 3480, java.awt.Component, Component.java
dispatchEvent() : 450, java.awt.EventQueue, EventQueue.java
pumpOneEventForHierarchy() : 197, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEventsForHierarchy() : 150, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 144, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 136, java.awt.EventDispatchThread, EventDispatchThread.java
run() : 99, java.awt.EventDispatchThread, EventDispatchThread.java
(B) JCheckBox (JToggleButtonの一種) をクリックしたとき
処理用メソッド
jCheckBox1_actionPerformed() : 156, フレームクラス, ソース.java
登録してあるリスナのイベントハンドラ
actionPerformed() : 216, アダプタクラス, ソース.java
fireActionPerformed() : 1764, javax.swing.AbstractButton, AbstractButton.java
actionPerformed() : 1817, javax.swing.AbstractButton$ForwardActionEvents, AbstractButton.java
fireActionPerformed() : 419, javax.swing.DefaultButtonModel, DefaultButtonModel.java
setPressed() : 273, javax.swing.JToggleButton$ToggleButtonModel, JToggleButton.java
mouseReleased() : 245, javax.swing.plaf.basic.BasicButtonListener, BasicButtonListener.java
processMouseEvent() : 5134, java.awt.Component, Component.java
processEvent() : 4931, java.awt.Component, Component.java
processEvent() : 1566, java.awt.Container, Container.java
dispatchEventImpl() : 3639, java.awt.Component, Component.java
dispatchEventImpl() : 1623, java.awt.Container, Container.java
dispatchEvent() : 3480, java.awt.Component, Component.java
retargetMouseEvent() : 3450, java.awt.LightweightDispatcher, Container.java
processMouseEvent() : 3165, java.awt.LightweightDispatcher, Container.java
dispatchEvent() : 3095, java.awt.LightweightDispatcher, Container.java
dispatchEventImpl() : 1609, java.awt.Container, Container.java
dispatchEventImpl() : 1590, java.awt.Window, Window.java
dispatchEvent() : 3480, java.awt.Component, Component.java
dispatchEvent() : 450, java.awt.EventQueue, EventQueue.java
pumpOneEventForHierarchy() : 197, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEventsForHierarchy() : 150, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 144, java.awt.EventDispatchThread, EventDispatchThread.java
pumpEvents() : 136, java.awt.EventDispatchThread, EventDispatchThread.java
run() : 99, java.awt.EventDispatchThread, EventDispatchThread.java