ここでは、NSSavePanel の使い方についてメモしていく。実際にファイルを保存するところは別の項目でメモする予定。
Save Panel は、Mac OS X 標準でついてる、ファイルを保存するときなどに出てくるウィンドウ(パネル)のこと。アプリケーションでファイルを保存するときに使う。
まずは、NSSavePanel オブジェクトを作る。
panel = NSSavePanel.savePanel
これ以外に、Ruby っぽく、
panel = NSSavePanel.new
でもいいはず。
これにいろいろと設定を加えていく。
setTitle(string) ウィンドウにタイトルをつける
panel.setTitle("Name the file and select a folder to save")
setPrompt(string) 通常 OK ボタンのある位置のボタンの文字を設定する
デフォルトでは、Save。
panel.setPrompt("Save as...")
setNameFieldLabel(string) 保存するファイル名の横の文字列をかえる
デフォルトでは、Save as:。
panel.setNameFieldLabel("Name of the saving file")
setMessage(string) 保存するファイル名を入力する欄の上にメッセージを加える
デフォルトでは何も表示がない。
panel.setMessage("Make sure to put an identifiable name.")
この3つの例。それぞれ、Prompt、Label、Message という表示にしてある。
setAccessoryView(view) Save Panel にカスタムビューを追加する。
panel.setAccessoryView(view)
Accessory View を追加するにいろいろなパーツを配置する方法を書いているので、詳しくはそちらを参照してください。
ちなみに、テキストとポップアップボタンを追加すると、次のような感じになる。
両方を表示したい場合は、popup と text の両方を subview として view に追加してから、setAccessoryView(view) を使う。
ここでの例を両方使うと、次のような表示になる。
setCanCreateDirectories(true/false) 新規フォルダを作るボタンを表示するかどうか設定する
デフォルトでは true。
panel.setCanCreateDirectories(true)
setCanSelectHiddenExtension(true/false) 拡張子を隠すかどうかのチェックボックスを表示するかどうかを設定する
デフォルトでは false。
panel.setCanSelectHiddenExtension(true)
setExtensionHidden(true/false) 拡張子を隠すかどうかのチェックボックスにチェックを入れるかどうか設定する
デフォルトでは false。
panel.setExtensionHidden(true)
setRequiredFileType(string) 拡張子がファイル名に含まれない場合に強制的につく拡張子を文字列で指定する
デフォルトでは nil。
panel.setRequiredFileType("txt")
setAllowedFileTypes(array) 付けてもいい拡張子を配列で指定する。[:txt,:pdf,:html] という形式か通常の ["txt","pdf","html"] で書く。
デフォルトでは nil。
panel.setAllowedFileTypes(["txt","pdf","html"])
setAllowsOtherFileTypes(true/false) 指定した以外の拡張子を付けてファイルを保存してもいいか設定する
panel.setAllowsOtherFileTypes(true)
setTreatsFilePackagesAsDirectories(true/false) パッケージになっているフォルダ(アプリケーションや一部のアプリケーションのファイル)
をフォルダとして扱うかどうかを設定する。デフォルトでは false。
panel.setTreatsFilePackagesAsDirectories(true)
パネルの設定が終わったら、パネルの動作の設定に入る。いろいろあるが、delegete method というのがよくわからないので、それ以外をここで見る。Open Panel のところで説明したものに対応している3つ。
runModal 普通のウィンドウで、何も指定しない。
runModalForDirectory_file(directory,file) 普通のウィンドウで、フォルダとファイル名が指定できる。
beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo(directory,file,window,modalDelegate,didEndSelector,contextInfo)
ウィンドウから現れるウィンドウ(Genie ウィンドウ?)で、ディレクトリ、ファイル、ファイルタイプ、現われるウィンドウが指定できる。
directory は、ウィンドウ(パネル)が開いたときに開くフォルダを指定する。絶対パスを文字列で書く。ただし、ホームフォルダは "~" でいい。だから、デスクトップを常に開くようにするには、"~/Desktop" とすればいい。日本語は通らないので "~/デスクトップ" ではいけない。指定しない場合は、nil と書く。
file は、あらかじめ指定したファイル名を使いたい場合に使う。もちろん、保存時に変更はできる。指定しない場合は nil と書く。
beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo には、この他に4つあるが、そのうち window と didEndSelector が重要なので(後の2つはよくわからないのもある)、その2つだけ説明する。
window は、その名の通り、ウィンドウ(パネル)が出てくるウィンドウを指定する。ib_outlet で指定したウィンドウの名前をクラス変数の形で書く(@ を付ける)。名前が window なら(ib_outlet :window)@window と書く。
didEndSelctor はよくわかっていないが、ここに、ウィンドウが開いたときに動作させたいスクリプトを書いたメソッド名を文字列としていれる。savePanelDidEnd_returnCode_contextInfo が標準のようなので、この後の例ではそうしてある。ファイルが選ばれると、ここで指定したメソッドが呼ばれる。
modalDelegate は、delegate をどれにするかの指定なので、self と入れておく。
contextInfo はポインタオブジェクトを入れると情報の受け渡しができるようだが、よくわからないので nil にしておく。
この3つのうち、runModal と runModalForDirectory_file はファイルを選んだ後の処理が同じだが、beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo は上で書いたように異なる。
いずれも、panel に対するインスタンスメソッドとして扱う。
panel.runModal
panel.runModalForDirectory_file(nil,nil)
panel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo(nil,nil,@window,self,"savePanelDidEnd_returnCode_contextInfo",nil)
runModal と runModalForDirectory_file では、この後、続けて filname でファイル名を取り出す。ファイルへのパスが NSCFString として取り出せる。Ruby で処理する場合は、to_s つけて Ruby の文字列に変換して処理する。変換しなくても扱えるが、正規表現など扱えない場合があるので注意する。RubyCocoa で扱う場合は、そのままでいい。
panel.filename.to_s
filename の代わりに URL を使うとパスが NSURL として得られる。NSURL のオブジェクトが得られる。これを to_s で Ruby の String オブジェクトにすると、パスが URL の書式で得られる。ローカルやネットワーク上だと file:// で URL になる。
panel.URL.to_s
また、directory でファイルの保存されるフォルダのパスが得られる。
panel.directory.to_s
panel.runModal と panel.runModalForDirectory_file(nil,nil) は、Save もしくはそれに対応するボタンがクリックされたかを返すので、結果を result などのオブジェクトとして扱えば、戻り値によって処理を選べる。例えば、
result = panel.runModalForDirectory_file(nil,nil)
if result == 1
fileName = panel.filename.to_s
else
return
end
などとして、ファイル名を付けて保存される場合だけファイル名を取り出す処理ができる。
panel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo(nil,nil,@window,self,"savePanelDidEnd_returnCode_contextInfo",nil) の場合は、この後の処理の仕方が違う。上で書いたように、"savePanelDidEnd_returnCode_contextInfo" というメソッドを、この SavePanel のメソッドと別に作り、それを実行させる。例えば、次のようなメソッドを書く。メソッド名は任意だと思う。ただ情報は3つ送られるようなので、それは得られるようにする。
この returnCode には、上の result と同じように戻り値が入る。あと、この方法だと、このメソッドでの処理が終わるまで、Open パネルが閉じない。複雑な処理をさせる場合などは、明示的に close で閉じる。
def savePanelDidEnd_returnCode_contextInfo(panel,returnCode,info)
if returnCode == 1
panel.close
fileName = panel.filename.to_s
else
return
end
end
最後にサンプルスクリプトを2つのせておく。これらは、Interface Builder で、ウィンドウに Text Field とボタン一つを配置して、savePath と Text Filed を結びつけておく。ボタンは、Received Action で openSavePanel と結びつける。これを実行すると、ファイル名を付けて Save を保存すると、.txt がついたパスが Text Filed に表示される。お試しあれ。
まずは結果から。両方とも同じなるはず。
runModalForDirectory_file を使ったスクリプト。
require 'osx/cocoa'
include OSX
class AppController < OSX::NSObject
def initialize
@output = []
end
def openSavePanel(sender)
panel = NSSavePanel.savePanel
panel.setTitle("Name the file and select a folder to save")
panel.setCanSelectHiddenExtension(true)
panel.setRequiredFileType("txt")
result = panel.runModalForDirectory_file("~",nil)
if result == 1
@savePath.setStringValue(panel.filename)
else
return
end
end
ib_action :openSavePanel
end
もう一つは、beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo を使ったもの。この長いメソッドは表示の都合で途中で改行されているが、実際はしなくてよい。
require 'osx/cocoa'
include OSX
class AppController < OSX::NSObject
def initialize
@output = []
end
def openSavePanel(sender)
panel = NSSavePanel.savePanel
panel.setTitle("Name the file and select a folder to save")
panel.setCanSelectHiddenExtension(true)
panel.setRequiredFileType("txt")
panel.beginSheetForDirectory_file_modalForWindow_modalDelegate_didEndSelector_contextInfo("~",
nil,
@window,
self,
"savePanelDidEnd_returnCode_contextInfo",
nil)
end
ib_action :openSavePanel
def savePanelDidEnd_returnCode_contextInfo(panel,returnCode,info)
if returnCode == 1
@savePath.setStringValue(panel.filename)
else
return
end
end
end