前のページで示したように、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); } } }
上記を確認後、このボタンをクリックください。→