保存、開くダイアログ を使う

この作品はローカル作品であると同時にアプレット作品という位置付けで制作していますが、 アプレット作品は、保安上の理由からデフォルトでローカルデバイスのファイルを扱うこができません。
この作品では、そのポリシーに沿って作成します。
よってアプレットで動作する場合は、 制限で操作できないメニュー項目をsetEnabledメソッドで無効にします。
そして、ローカルで動作する場合だけファイル読み書きをできるようにします。
以下に、この作品のアプレットの実行を示します。
 作品ダウンロード

以下に、この作品の変更点(以前の作品:Painter.javaに対する)を示します。
まず、ローカル実行時のファイル操作や、イメージ読み書き用クラスを使うので、次のインポートを追加します。
import java.io.*; //FILE用パッケージ
import javax.imageio.*; //ImageIO用パッケージ
import java.awt.image.*;//BufferedImage用パッケージ

ローカル実行時にはダイアログ表示させます。その時に使うディレクトリとファイルの情報が必要になります。 しかしアプレット起動時は開くダイアログを表示させずに、サンプルを表示させます。そこで、 アプレット起動時が分かるようにフラグを設けます。
これら情報をインスタンス変数として、Painterクラスに追加します。(次の3項目です)
    File directory; //ファイルダイアログで使うのディレクトリ
    File file; //ファイルダイアログで使うファイル
    public boolean flagApplet; //アプレット起動時にtrueを設定

そして、上記directoryfileをJFileChooserに設定する次のメソッドを Painterクラスに追加します。(後で、ファイル操作ダイアログの表示時に利用します)

	public void setFileChooser(JFileChooser chooser){
		if (this.directory == null){//未設定の場合に、ユーザーディレクトリを記憶
			String s = System.getProperty("user.home") + "\\My Documents\\My Pictures";
			System.out.println(s);
			this.directory = new File(s);
		}
		if (this.file == null){//未設定の場合に使う初期のファイル名を記憶
			this.file = new File("temp.png");
		}
		chooser.setSelectedFile(this.file);//初期の選択ファイル名を指定
		chooser.setCurrentDirectory(this.directory);//chooserの初期ディレクトリを指定
	}

Painterのインスタンス変数flagAppletがtrueの時がアプレット起動とするわけですが、 その設定は次のようにinitメソッドを設けて そこで設定します。(Painterクラスに追加します。)
またここで、保存や終了のメニュー操作ができないようにメニュー項目を無効にしています。

	public void init()//アプレットをチェック
	{
		this.flagApplet = true;
		this.itemSave.setEnabled(false);
		this.itemExit.setEnabled(false);
	}

(なお、フレーム内に配置したAppletでは、 フレームをアプレットとして起動してもinitが実行されません。 またこの場合は、getParameterによるHTMLのアプレット用パラメタを取得することはできません。)


さて、ファイル選択ではJFileChooserを使いますが、 その時、Fileのどれを見せるかを指定するフィルタークラスを、 開くと保存の兼用に変更した次のMyFilterクラスをPainter.javaに追加します。

class MyFilter extends javax.swing.filechooser.FileFilter
{
	String description;//ファイル選択の説明のリスト用
	String extension;//ファイル選択の拡張子
	
	public MyFilter(String description, String extension){//コンストラクタ
		this.description = description;//ファイル選択の説明
		this.extension = extension;//ファイル選択の拡張子
	}
	public static MyFilter []getFilters(char op){
		// //扱える画像ファイルで、MyFilterの配列を生成して戻り値にする
		String[] formats;
		if(op == 'w') formats = javax.imageio.ImageIO.getWriterFormatNames();
		else formats = javax.imageio.ImageIO.getReaderFormatNames();
		java.util.ArrayList <MyFilter> lst = new java.util.ArrayList<MyFilter>();
		for(int i = 0; i < formats.length;i ++){
			//System.out.println(formats[i]);
			String ext = formats[i].toLowerCase();//小文字に変換して拡張子用文字列として記憶
			MyFilter myFilter = new MyFilter(ext+"の拡張子ファイル", ext);
			boolean existFlag = false; 
			for(MyFilter obj : lst){//lstのArrayListにextが記憶されているか調べる
				if(obj.extension.equals(ext)){
					existFlag = true;//既に存在している。
					break;
				}
			}
			if(existFlag == false){//記憶されていない?
				lst.add(myFilter);// ArrayListに追加記憶
			}
		}
		return lst.toArray(new MyFilter[0]); // ArrayListの内容を配列にして返す
	}
	public boolean accept(java.io.File f) {//fのファイルが見せるべきファイルならtrueを返す。
		if (f.isDirectory()) return true;//ディレクトリなら見せる
		String fname = f.getName();
		int idx = fname.lastIndexOf('.');//拡張子を求めるためのドット位置取得
		String ext = fname.substring(idx + 1);//拡張子の文字列取得
		if (idx != -1){
			return ext.equals(this.extension);//拡張子が合えば表示させる
		}
		return false;//fのファイルは表示させない
	}
	public String getDescription(){
		return this.description;//ファイルの説明のリスト用
	}
}

このクラスのstaticメソッドgetFiltersで、JFileChooserに必要なFileFilterの継承オブジェクトの配列を 取得します。そこでは、このコンピュータが取り扱えるファイル拡張子を ImageIOクラスの getWriterFormatNamesまたはgetReaderFormatNamesメソッド(→参考)で取得し、使っています。

あとは、これらを使ってメニュー項目を選択した時に実行する各操作をプログラミングします。 まず、『ファイル』の『保存』を選択した場合に、this.paintPanel.offscrImgを保存する処理を、 Painterクラスのメニュー処理【1】へ次のように追加します。

		} else if (obj == itemSave){//保存
			javax.swing.JFileChooser chooser = new javax.swing.JFileChooser();
			//書き込み用フィルターの取得
			javax.swing.filechooser.FileFilter[] filters = MyFilter.getFilters('w');
			for (int i = 0; i < filters.length; i++){
				chooser.addChoosableFileFilter(filters[i]);//フィルターの追加
			}
			setFileChooser(chooser);//chooserに対するファイル、ディレクトリ設定
			int returnVal = chooser.showSaveDialog(this);//ファイルオープンダイアログ表示

			if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION){
				this.file = chooser.getSelectedFile();//入力または選択ファイル
				this.directory = chooser.getCurrentDirectory();
				String path = file.getName();
				int idx = path.lastIndexOf("."); //拡張子直前のドット位置を取得
				String ext = path.substring(idx + 1); //拡張子のみ取得
				try{
					ImageIO.write((BufferedImage)this.paintPanel.offscrImg, ext, file);
				}
				catch (Exception err){
					JOptionPane.showMessageDialog(this, "ファイル保存に失敗しました。");
					return;
				}
			}
		} else if (obj == itemExit){//終了

同様に 『ファイル』の『開く』を選択した場合、this.paintPanel.offscrImgに画像を読み取って再描画する処理を、 Painterクラスのメニュー処理【2】へ次のように追加します。 ここでは、アプレット実行時にダイアログを表示しないでサンプル画像()をロードする処理に なっています。

		} else if (obj == itemOpen){//開く
			if(this.flagApplet){//アプレット実行時
				java.net.URL url = getClass().getResource("sample.png");
				try {
					this.paintPanel.offscrImg = ImageIO.read(url);
				}
				catch (Exception err){
					System.out.println("Error:" + err.toString());
				}
				paintPanel.repaint();//再描画を要求
				return;
			}
			javax.swing.JFileChooser chooser = new javax.swing.JFileChooser();
			//読み込み用フィルターの取得
			javax.swing.filechooser.FileFilter[] filters = MyFilter.getFilters('r');
			for (int i = 0; i < filters.length; i++){
				chooser.addChoosableFileFilter(filters[i]);//フィルターの追加
			}
			setFileChooser(chooser);//chooserに対するファイル、ディレクトリ設定
			int returnVal = chooser.showOpenDialog(this);//ファイルオープンダイアログ表示

			if (returnVal == javax.swing.JFileChooser.APPROVE_OPTION){
				this.file = chooser.getSelectedFile();//入力または選択ファイル
				this.directory = chooser.getCurrentDirectory();
				this.file = chooser.getSelectedFile();//入力または選択ファイル
				try{
					this.paintPanel.offscrImg = ImageIO.read(this.file);
				}
				catch (Exception err){
					JOptionPane.showMessageDialog(this, "ファイルオープンに失敗しました。");
					return;
				}
			}
			paintPanel.repaint();//再描画を要求
		} else if (obj == itemSave){//保存

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