前のページで示したように、JDialog継承クラスを
モーダルで使う場合、所有者を指定すると使い勝手が良くなります。
JFrameまたはJDialogは所有者に指定できますが、アプレットを所有者にできません。
しかもJDialogの所有者なしで使った場合、タスクバーにも表示されないので、
ブラウザの背面に隠れると操作が行い難くなります。
この場合の簡単な解決策として、ダイアログを管理する専用フレームを設ける方法があります。
つまり、直接にアプレットからダイアログを生成するのではなく、
専用フレームを介して、それを所有者として生成する訳です。
以下で、その例のアプレットを示します。
まず、上記各ボタンで生成するダイアログクラス(BrushDialog)をのコードを示します。
コンストラクタで、オーナー用のフレーム、ダイアログ表示位置指定用のコンポーネント、
ダイアログ内のパネルサイズを指定しています。
また、BrushPanelの名前でパネルを継承した
内部クラスを作って、
そこで、外側のbufImgが管理するイメージを描画しています。
package paint;
import java.awt.*;//Point、Color Graphicsなどのパッケージ
import javax.swing.*;//JPanelのパッケージ
import java.awt.event.*;//MouseMotionListenerなどのリスナーや、MouseEventなどのイベント用
import java.awt.image.BufferedImage;//編集可能なメモリイメージ用
//ブラシ用ダイアログ
class BrushDialog extends JDialog
{
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);
Graphics2D g2 = (Graphics2D)g;//これでGraphics2Dの機能も使える
g2.drawImage(bufImg, 0, 0, this);//メモリイメージをパネルへ描画する追加
}
}//----インナー(内部)クラスの終端--------------------
BrushPanel brushPanel;// 上記インナークラスを管理するインスタンス変数
//コンストラクタ
public BrushDialog(JFrame owner, Component panel, Dimension size){
super(owner);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
brushPanel = new BrushPanel(size);//内部
this.getContentPane().add(brushPanel);
this.pack();//サブコンポーネントの推奨サイズおよびレイアウトに合わせたサイズ変更
this.setVisible(true);//表示する
}
//メモリイメージ中央に、/4サイズの楕円を描画して、PaintPanelのブラシを指定する。
public void drawOval(Color color){
Graphics2D g2 = (Graphics2D)bufImg.getGraphics();
this.setTitle(Integer.toHexString(color.getRGB()));//色の16進数値へ変換し、タイトル設定
g2.setColor(color);
g2.fillOval(0, 0, imgSize.width, imgSize.height);
this.repaint();
}
}
次に上記ダイアログの所有者になるフレーム(OwnerBrushFrame)を示しします。
上記コンストラクタの第1引数で指定するのが、このOwnerBrushFrameオブジェクトです。
このOwnerBrushFrameオブジェクトは、一つしか生成できないように細工しています。
その制御は、クラス変数のframeで行っています。最初の生成時に自身のオブジェクトを
frameに管理しています。
よって、frameがnullでなければ既にオブジェクトが存在するとして例外を投げて
生成できなくしています。
また、フレームを閉じる時に、frameをnullに戻しています。その処理を行うために、
フレームを閉じる時の『自動的破棄 』を行う次の命令が存在しません。
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
この代わりにWindowListenerインターフェイスを実装し、
windowClosingのオーバライドで、this.dispose();を実行し、廃棄するタイミングを
明示的に指示するコードにしています。
そして、この閉じる所でframeをnullに戻しています。
なお、this.dispose();の実行で、ウィンドウが閉じられる処理が
継続され、最終的にwindowClosedが呼び出される流れになっています。
上記ダイアログBrushDialogを生成する場合は、
必ず以下のOwnerBrushFrameフレームを介して行われるように、
BrushDialogにダイアログを生成するcreateDialogのstaticメソッドを用意します。
//ダイアログを管理するパネル
class OwnerBrushFrame extends JFrame implements WindowListener
{
public static JFrame frame; //ダイアログのOwnerフレーム
public static BrushDialog createDialog(Component component, Dimension size)
{
// component の位置を取得(componentのスクリーン座標で)
Point pt = new Point(0, 0);
javax.swing.SwingUtilities.convertPointToScreen(pt, component);
if (frame == null){//ダイアログ管理用フレームがなければ生成
try {
frame = new OwnerBrushFrame();//ダイアログ管理用で、自身のフレーム生成
}
catch(Exception e){
return null;
}
frame.setLocation(pt.x-150, pt.y);//座標スクリーン座標で位置指定
}
BrushDialog dialog = new BrushDialog(frame,component, size);//ダイアログ生成
dialog.setLocation(pt.x, pt.y);//座標スクリーン座標で位置指定
return dialog;
}
public OwnerBrushFrame()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){
}
}
上記のOwnerBrushFrame.createDialog(位置の基準となる部品,サイズ)
を呼び出せば、BrushDialogのダイアログオブジェクト生成し、戻り値で得られるわけです。
これを利用したページ先頭のアプレットコードを以下に示します。
public class OwnerFrameApplet extends JApplet implements ActionListener {
JButton btnRed = new JButton("赤");
JButton btnBlue = new JButton("青");
JButton btnGreen = new JButton("緑");
public OwnerFrameApplet(){//コンストラクタ
this.setLayout(new java.awt.FlowLayout());
this.getContentPane().add(btnRed);
this.getContentPane().add(btnBlue);
this.getContentPane().add(btnGreen);
btnRed.addActionListener(this);
btnBlue.addActionListener(this);
btnGreen.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
if (e.getSource() instanceof JButton == false) return;
JButton btn = (JButton)e.getSource();
if (btn == this.btnRed){
BrushDialog dialog = OwnerBrushFrame.createDialog(btn, new Dimension(25, 25));
dialog.drawOval(Color.red);
} else if (btn == this.btnBlue){
BrushDialog dialog = OwnerBrushFrame.createDialog(btn, new Dimension(25, 25));
dialog.drawOval(Color.blue);
} else if (btn == this.btnGreen){
BrushDialog dialog = OwnerBrushFrame.createDialog(btn, new Dimension(25, 25));
dialog.drawOval(Color.green);
}
}
}
上記を確認後、このボタンをクリックください。→