macOS Monterey の JXA は NSRect のバグが無くなった。
ということで、今の知識で NSWindow を作ってみたらどうなるか。
いや PyObjC のほうが簡単なんだけど、デフォルトで入っていないのが。
JXA ならどんな Mac でもそのまま動かせるという利点があるので捨て難い。
ただ JXA では PyObjC みたいに class にできないんだよなぁ。
ネットで簡単に見つかる方法では全部グローバル変数にするしかないのが。
そもそも JavaScript の class は他の言語の class とは違うし。
なので GNOME の Gjs もアクロバットな手段で class っぽくしている。
ObjC.registerSubclass を上手く利用してソレっぽくやってみよう。
追加メソッドはどう書けばいいのかな?とか。
#!/usr/bin/osascript ObjC.import('Cocoa'); //let wins = []; ObjC.registerSubclass({ name: 'AppDelegate', protocols: ['NSApplicationDelegate'], methods: { 'applicationDidFinishLaunching:': function (notification) { let window = $.MyWindow.alloc.initWithContentRectStyleMaskBackingDefer( $.NSMakeRect(0, 0, 300, 100), $.NSTitledWindowMask | $.NSClosableWindowMask | $.NSMiniaturizableWindowMask | $.NSResizableWindowMask, $.NSBackingStoreBuffered, false ); window.makeKeyAndOrderFront(window); $.NSApp.activateIgnoringOtherApps(true); //wins.push(window); } } }); ObjC.registerSubclass({ name: 'WinDelegate', protocols: ['NSWindowDelegate'], methods: { 'windowWillClose:': function(notification) { console.log('MyApp Close !'); return $.NSApp.terminate(0); } } }); ObjC.registerSubclass({ name: 'MyWindow', superclass: 'NSWindow', propertyies: {}, methods: { 'initWithContentRect:styleMask:backing:defer:': function (contentRect, style, backingStoreType, flag) { let _this = ObjC.super(this).initWithContentRectStyleMaskBackingDefer( contentRect, style, backingStoreType, flag); _this.title = $('JXA NSWindow'); _this.delegate = $.WinDelegate.new; // Button let button = $.NSButton.buttonWithTitleTargetAction('button', this, 'onButtonClick:'); button.setFrame($.NSMakeRect(10, 10, 200, 36)); _this.contentView.addSubview(button); // return return _this; }, 'onButtonClick:': { types: ['void', ['id']], implementation: function(sender) { sender.setTitle('Clicked!'); } } } }); /** * Application */ $.NSApplication.sharedApplication; $.NSApp.setActivationPolicy($.NSApplicationActivationPolicyRegular); $.NSApp.mainMenu = function() { let mainMenu = $.NSMenu.new; let itemApp = $.NSMenuItem.new; mainMenu.addItem(itemApp); let menuApp = $.NSMenu.new; itemApp.setSubmenu(menuApp); // quit menu let itemQuit = $.NSMenuItem.new; itemQuit.initWithTitleActionKeyEquivalent('Quit App', 'terminate:', 'q'); menuApp.addItem(itemQuit); return mainMenu; }(); $.NSApp.setDelegate($.AppDelegate.new); $.NSApp.run;
こんな感じになった、
ボタンのハンドラは delegate ではなく this に届くようだ。
オーバーライドは types 指定不要なのね、ふむふむ。
これだけ解れば応用でなんとかなりそう。
ただ PyObjC と違って NSWindow がガベージコレクションされないんだが。
let 指定ならばハンドラを抜けたら破棄されるはずなんだけど、何故だ?
Python とは破棄対象の選定方法が違うんだろう、知らんけど。
ところで Monterey で今頃気がついたんだけど。
iOS みたいに充電の保留機能が付いたんだね。
筆者は滅多に持ち歩かないんで意味はないかもだがけど。