Window の Modal 処理

10.8 までの MacRuby では、Window にひも付けされた(?)別の Window や Panel を表示させる方法は、NSApplication の

beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:

を使って次のように処理していた。

def showPanel(sender)

NSApp.beginSheet(@panel,

modalForWindow: @window,

modalDelegate: self,

didEndSelector: "sheetDidEnd:returnCode:contextInfo:",

contextInfo: nil)

end

def sheetDidEnd(sheet, returnCode: returnCode, contextInfo: info)

sheet.close

end

def closePanelModal(sender)

NSApp.endSheet(@panel)

必要なら、ここにパネルを閉じた後の処理を書く。

end

ここでは、まず、showPanel(sender) というメソッドの中で @panel という outlet のパネルを @window にひも付けて表示させている。これで、@panel 上にボタンを配置して、closePanelModal(sender) (任意の名前)というメソッドを呼び出して、NSApplication の endSheet(panel) でパネルを閉じると、seetDidEnd:returnCode:contextInfo: というメソッドを呼び出して、modal が終わる、という感じ。seetDidEnd:returnCode:contextInfo: は、3 つ情報が返ってくるということで、名前を変えても多分動く。didEndSelector: で指定したものになる。ただ、細かいことはあまりよくわかっていないのだけれども。

ただ、このメソッドは、10.9 で deprecated になったためか、RubyMotion で、10.9 上ではエラーが出てちゃんと動かない(どうも、endSheet: あたりで問題があるようだが、はっきしない)。いずれはなおるのかもしれないが、これ以降のことも考えて、別の方法を探った方がいいだろうということで、代替手段を探した。

10.9 からは、NSWindow のメソッドに beginSheet:completionHandler: というのが追加された。10.9 の RubyMotion で、上の処理と同じことをしようとすると、次のような感じになる。

def showPanel(sender)

@window.beginSheet(@panel,completionHandler:Proc.new { |returnCode| })

end

def closePanelModal(sender)

@window.endSheet(@panel)

end

ここでも、表示させた @panel 上にボタンを配置して、closePanelModal(sender) (任意の名前)というメソッドを割り当てて、NSWindow の endSheet(panel) でパネルを閉じる。completionHandler のループの中か、closePanelModal(sender) に、パネルを閉じた後の処理を書く。ちなみに、returnCode には、-1000 が返ってきた。

ただ、問題は、この方法は 10.9 じゃないと動かない。10.8 以前でも動くようにするには、OS のバージョンを判別して別の処理をしないとだめそうだ。

現在は、あまりスマートな方法ではないけど、app フォルダの中に config というフォルダを作り、constants.rb というファイルで OS のバージョンをチェックして、グローバル変数を用意している。OS X 10.9 が KCFCoreFoundationVersionNumber で 855.00 なので、それ未満の場合をチェックしている。

if KCFCoreFoundationVersionNumber < 855.00

$VerCheck = false

else

$VerCheck = true

end


def openModalPanel(sender)

NSApp.runModalForWindow(@panel)

end


def closeModalPanel(sender)

NSApp.stopModal

@panel.orderOut(nil)

end

これは、OS のバージョンではなく、RubyMotion の問題のようなので、OS X 10.8 以前用には sheet ではなく、通常の modal window で対処している。panel を modal で開くには、NSApplication.sharedApplication (NSApp) の runModalForWindow(panel) で開き、処理した後にボタンなどで panel を閉じて実行するメソッドで stopModal で modal を終了させて、NSPanel/NSWindow の orderOut(sender) で panel を閉じている。