C言語の関数ポインタを java で実装するパターン備忘録。
親ウィンドウからダイアログを呼び出し、ダイアログから親ウィンドウへ値を返す、よくあるシチュエーション。
FrameMain.jar 15,218kB(ソース含む)
下記 どのSTEPでも同じ動作。...▼
●STEP1 最初は 1クラスファイルだけの無名クラスで構成した実装例。
FrameMain.java
呼び先 DialogSample が呼び元 FrameMain の label を直接操作。呼び先が呼び元の操作対象を知っていなければならないので、呼び先を汎用的に再利用しにくい。
FrameMain.java
呼び先 DialogSample のインターフェース CallBack の関数 onChange() を、 呼び元 FrameMain に実装(implements)させ これを呼び出すことで情報を返す。
FrameMain.java
FrameMain.java
import java.awt.*;
class FrameMain extends Frame{
Label label= new Label( "Label of FrameMain", Label.CENTER );
class DialogSample extends Dialog{
class ScrollbarSample extends Scrollbar{
ScrollbarSample(){
super( Scrollbar.HORIZONTAL );
addAdjustmentListener( new java.awt.event.AdjustmentListener(){
@Override
public void adjustmentValueChanged( java.awt.event.AdjustmentEvent e ){
label.setText( String.valueOf( ScrollbarSample.this.getValue() ) );
}
} );
}
}
DialogSample( Frame fOwner ){
super( fOwner, true );//modal
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
setVisible( false );
}
} );
add( "Center", new ScrollbarSample() );
setSize( 200, 60 );
setVisible( true );
}
}
class ButtonMain extends Button{
ButtonMain( String s ){
super( s );
addActionListener( new java.awt.event.ActionListener(){
@Override
public void actionPerformed( java.awt.event.ActionEvent e ){
new DialogSample( FrameMain.this );
}
} );
}
}
FrameMain(){
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
System.exit( 0 );
}
} );
add( label );
add( "South", new ButtonMain( "Dialog Sample Button" ) );
setSize( 400 , 300 );
setVisible( true );
}
public static void main( String[] args ){
new FrameMain();
}
}
●STEP2 ダイアログクラスファイルを分離した実装例。
呼び先 DialogSample が呼び元 FrameMain の label を直接操作。呼び先が呼び元の操作対象を知っていなければならないので、呼び先を汎用的に再利用しにくい。
FrameMain.java
import java.awt.*;
class FrameMain extends Frame{
public Label label= new Label( "Label of FrameMain", Label.CENTER );
class ButtonMain extends Button{
ButtonMain( String s ){
super( s );
addActionListener( new java.awt.event.ActionListener(){
@Override
public void actionPerformed( java.awt.event.ActionEvent e ){
new DialogSample( FrameMain.this );
}
} );
}
}
FrameMain(){
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
System.exit( 0 );
}
} );
add( label );
add( "South", new ButtonMain( "Dialog Sample Button" ) );
setSize( 400 , 300 );
setVisible( true );
}
public static void main( String[] args ){
new FrameMain();
}
}
DialogSample.java
import java.awt.*;
class DialogSample extends Dialog{
Frame fOwner;
class ScrollbarSample extends Scrollbar{
ScrollbarSample(){
super( Scrollbar.HORIZONTAL );
addAdjustmentListener( new java.awt.event.AdjustmentListener(){
@Override
public void adjustmentValueChanged( java.awt.event.AdjustmentEvent e ){
//▼▼▼
((FrameMain)DialogSample.this.fOwner).label.setText( String.valueOf( ScrollbarSample.this.getValue() ) );
//▲▲▲
}
} );
}
}
DialogSample( Frame fOwner ){
super( fOwner, true );//modal
//▼▼▼
this.fOwner= fOwner;
//▲▲▲
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
setVisible( false );
}
} );
//▼▼▼
add( "Center", new ScrollbarSample() );
//▲▲▲
setSize( 200, 60 );
setVisible( true );
}
}
●STEP3 java の インターフェース(interface) を使った コールバック(callback)実装例。
呼び先 DialogSample のインターフェース CallBack の関数 onChange() を、 呼び元 FrameMain に実装(implements)させ これを呼び出すことで情報を返す。
FrameMain.java
import java.awt.*;
//▼▼▼
class FrameMain extends Frame implements DialogSample.CallBack{
public void onChange( DialogSample dialogSample ){
label.setText( String.valueOf( dialogSample.scrollbarSample.getValue() ) );
}
//▲▲▲
public Label label= new Label( "Label of FrameMain", Label.CENTER );
class ButtonMain extends Button{
ButtonMain( String s ){
super( s );
addActionListener( new java.awt.event.ActionListener(){
public void actionPerformed( java.awt.event.ActionEvent e ){
new DialogSample( FrameMain.this );
}
} );
}
}
FrameMain(){
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
System.exit( 0 );
}
} );
add( label );
add( "South", new ButtonMain( "Dialog Sample Button" ) );
setSize( 400 , 300 );
setVisible( true );
}
public static void main( String[] args ){
new FrameMain();
}
}
DialogSample.java
import java.awt.*;
class DialogSample extends Dialog{
//▼▼▼
public interface CallBack{
abstract void onChange( DialogSample d );
}
CallBack callBack= null;
//▲▲▲
//▼▼▼
ScrollbarSample scrollbarSample= new ScrollbarSample();//呼び元から参照させる
//▲▲▲
class ScrollbarSample extends Scrollbar{
ScrollbarSample(){
super( Scrollbar.HORIZONTAL );
addAdjustmentListener( new java.awt.event.AdjustmentListener(){
public void adjustmentValueChanged( java.awt.event.AdjustmentEvent e ){
//▼▼▼
callBack.onChange( DialogSample.this );
//▲▲▲
}
} );
}
}
DialogSample( Frame fOwner ){
super( fOwner, true );//modal
//▼▼▼
callBack= (CallBack)fOwner;//CallBack implemented Frame
//▲▲▲
addWindowListener( new java.awt.event.WindowAdapter(){
public void windowClosing( java.awt.event.WindowEvent e ){
setVisible( false );
}
} );
//▼▼▼
add( "Center", scrollbarSample );
//▲▲▲
setSize( 200, 60 );
setVisible( true );
}
}
呼び先 DialogSample は、呼び元 FrameMain の label を参照せず(知らなくとも)情報を返すことを実現。DialogSample のインターフェースを実装さえすれば DialogSample を再利用可能に。lambda expression(ラムダ式)、annotation()アノテーション、swing(スウィング) すら使っていない基本形。