カスタムダイアログ (アプレットでも使う)

前のページでフレームで色を変更するプログラムを示しました。 しかし、フレーム(JFrame継承)を使うと、起動フレームと対等ウィンドウになるので、 操作性に欠けます。
このような場合はダイアログ(JDialog継承クラス)を使うのがよいでしょう。
JDialog継承クラスのダイアログを使うと、閉じる操作が所有者のウィンドウに連動したり、 所有者のウィンドウの背面に回りこむ表示がないなどの操作性が向上します。
しかし、アプレットを所有者にすることはできませんでした。参考
この場合の簡単な解決策として、ダイアログを管理する専用フレームを設ける方法がありました。  直接にアプレットからダイアログを生成するのではなく、 専用フレームを介して、それを所有者として生成する方法です。(eJ1443m0.htm)
これを応用した次のダイアログ(JDialog継承クラス)タイプのブラシを 使う作品を示します。

以下で、(eJ1443m0.htm)のOwnerBrushFrameクラスに対応するクラスとして BrushFrameを定義します。これが、ダイアログを管理する専用フレームです。
管理するのは、JDialogを継承したBrushDialogのオブジェクトです。
(eJ1443m0.htm)のBrushDialog用コンストラクタでは 任意部品(Component)を引数にしていましたが、 ここでは、この作品のパネル(PaintPanel)に対して 表示位置が決定されるように、PaintPanelを引数するように変更し、 それをインスタンス変数paintPanelに記憶する変更がなされています。
またWindowListenerを実装し、ダイアログがアクティブになった時に作品をブラシを this.paintPanel.brushImg = bufImg;と変更する記述が追加されています。
そのBrushFrame.javaのコードを以下に示します。この色の箇所がeJ1443m0.htmに対する変更点です。

package paint;
import java.awt.*;//Point、Color Graphicsなどのパッケージ
import javax.swing.*;//JPanelのパッケージ
import java.awt.event.*;//MouseMotionListenerなどのリスナーや、MouseEventなどのイベント用
import java.awt.image.BufferedImage;//編集可能なメモリイメージ用

//ブラシ用フレーム
public class BrushFrame extends JFrame implements WindowListener
{
	public static JFrame frame;	//ダイアログのOwnerフレーム 
	public static BrushDialog createDialog(PaintPanel panel, Dimension size){
		// component の位置を取得(componentのスクリーン座標で)
		Point pt = new Point(0, 0);
		javax.swing.SwingUtilities.convertPointToScreen(pt, panel);
		if (frame == null){//ダイアログ管理用フレームがなければ生成
			try {
				frame = new BrushFrame();//ダイアログ管理用で、自身のフレーム生成
			}
			catch(Exception e){
				return null;//重複エラー(プログラムが正しければ、実行されません)
			}
			frame.setLocation(pt.x-150, pt.y);//座標スクリーン座標で位置指定
		}
		BrushDialog dialog = new BrushDialog(frame, panel, size);//ダイアログ生成
		dialog.setLocation(pt.x, pt.y);//座標スクリーン座標で位置指定
		return dialog;
	}
	public BrushFrame()throws Exception{
		if(frame != null) throw new Exception("複数の生成は、できません");
		if(frame == null) frame = this;
		this.setTitle("Owner Brushes Frame");
		this.pack();
		this.setVisible(true);
		this.addWindowListener(this);
	}
	//Window がアクティブに変化した時、呼び出されます。
	public void windowActivated(WindowEvent e){
	}
	//dispose の呼び出し結果で、ウィンドウクローズ処理終了時に呼び出されます。
	public void windowClosed(WindowEvent e){
		this.frame = null;
	}
	//ユーザによる閉じるボタン操作などで、閉じる処理直前に呼び出されます。
	public void windowClosing(WindowEvent e){
		this.dispose();//このオブジェクトを破棄する
	}
	//Window がアクティブでなくなったときに呼び出されます。
	public void windowDeactivated(WindowEvent e){
	}
	//最小化状態から通常の状態に変更された時、呼び出されます。
	public void windowDeiconified(WindowEvent e){
	}
	//通常の状態から最小化された状態に変更された時、呼び出されます。
	public void windowIconified(WindowEvent e){
	}
	//ウィンドウが最初に可視になった時、呼び出されます。
	public void windowOpened(WindowEvent e){
	}
}

//ブラシ用ダイアログ
class BrushDialog extends JDialog implements WindowListener
{
	PaintPanel paintPanel;//作品の描画パネル
	BufferedImage bufImg;//使用するメモリイメージ
	Dimension imgSize;	//上記イメージのサイズ

	//内部使うパネル---------------------------------------
	class BrushPanel extends JPanel
	{
		public BrushPanel(Dimension size){
			imgSize = size;
			this.setPreferredSize(size); //適切なサイズを設定
			//メモリーイメージを作成
			bufImg = new BufferedImage(size.width, size.height, BufferedImage.TYPE_4BYTE_ABGR);
		}
		//描画すべきタイミングで、呼び出されるメソッド
		public void paintComponent(Graphics g){
			super.paintComponent(g);
			g.drawImage(bufImg, 0, 0, this);//メモリイメージをパネルへ描画する追加
		}
	}//----インナー(内部)クラスの終端--------------------
	BrushPanel brushPanel;// 上記インナークラスを管理するインスタンス変数

	//コンストラクタ
	public BrushDialog(JFrame owner, PaintPanel  panel, Dimension size){
		super(owner);
		this.paintPanel = panel;//作品のパネルを管理
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		brushPanel = new BrushPanel(size);//内部
		this.getContentPane().add(brushPanel);
		this.pack();//サブコンポーネントの推奨サイズおよびレイアウトに合わせたサイズ変更
		this.setVisible(true);//表示する
		this.addWindowListener(this);
	}

	//メモリイメージ中央に、/4サイズの楕円を描画して、PaintPanelのブラシを指定する。
	public void drawOval(Color color){
		this.setTitle(Integer.toHexString(color.getRGB()));//色の16進数値へ変換し、タイトル設定
		Graphics g = bufImg.getGraphics();
		g.setColor(color);
		g.fillOval(0, 0, imgSize.width, imgSize.height);
		this.paintPanel.brushImg = bufImg;//PaintPanelのブラシを変更
		this.repaint();
	}

	//Window がアクティブに変化した時、呼び出されます。
	public void windowActivated(WindowEvent e){
		this.paintPanel.brushImg = bufImg;//PaintPanelのブラシを変更
	}
	//dispose の呼び出し結果で、ウィンドウクローズ処理終了時に呼び出されます。
	public void windowClosed(WindowEvent e){
	}
	//ユーザによる閉じるボタン操作などで、閉じる処理直前に呼び出されます。
	public void windowClosing(WindowEvent e){
	}
	//Window がアクティブでなくなったときに呼び出されます。
	public void windowDeactivated(WindowEvent e){
	}
	//最小化状態から通常の状態に変更された時、呼び出されます。
	public void windowDeiconified(WindowEvent e){
	}
	//通常の状態から最小化された状態に変更された時、呼び出されます。
	public void windowIconified(WindowEvent e){
	}
	//ウィンドウが最初に可視になった時、呼び出されます。
	public void windowOpened(WindowEvent e){
	}
}

以上の変更により、BrushFrame.createDialogメソッドで、 ブラシ用ダイアログが生成できるようになります。
PaintPanel.javaのメニュー処理用actionPerformedを、これを使うように変更したコードを 以下に示します。

	public void actionPerformed(ActionEvent e){// メニュー処理
		Object obj = e.getSource();
		if (obj == itemOval){//円
			JColorChooser chooser = new JColorChooser();//カラー選択ダイアログ生成
			Color intColor = new Color(0, 0, 255); //初期の色
			Color color = chooser.showDialog(this, "色を選択ください", intColor);
			if (color != null)	{
				BrushDialog dialog = BrushFrame.createDialog(this.paintPanel, new Dimension(25, 25));
				dialog.drawOval(color);//選択した色の楕円ブラシにする。
			}
		} else if (obj == itemImg){//イメージ
			//【3】	
		} else if (obj == itemOpen){//開く
			//【2】		
		} else if (obj == itemSave){//保存
			//【1】	
		} else if (obj == itemExit){//終了
			System.exit(0);//終了
		}
	}

また、ローカル作品として動作させる場合は、そのフレームを ブラシ用ダイアログの所有者にする変更を行います。
それは、ブラシ用ダイアログの所有者用になっているBrushFrame.frameに 作品用のフレームオブジェクトを設定することで可能です。(PaintPanel.java内の変更です。)

class PainterFrame extends JFrame
{
	Painter painter;//上記のアプレットパネルを管理する

	PainterFrame(){	//コンストラクタ
		if(BrushFrame.frame == null) BrushFrame.frame = this;
		this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);//閉じるボタンで終了
		this.painter = new Painter();//上記Painterを生成配置
		this.setContentPane(painter);
		this.setTitle("Painter");
		this.setBounds(0, 0, 300, 300);//サイズ指定
		this.setVisible(true);
	}
}

上記を確認後、このボタンをクリックください。→