JXA からの Objective-c バインディングを再勉強。
Building OS X Apps with JavaScript by Tyler Gaw
今回はボタンを押した時のハンドラ指定でも。
target にインスタンス化したデリゲートを指定。
action にハンドラ名を文字列にて指定。
でいいみたい、何だか変な指定方法だけど従うしかない。
ところで現在の JXA は ES6 が使えるので var より let のほうがいい。
ただ全部グローバル変数だとコードが長くなった時にワケワカメになるのよね。
やっぱり class にしたいなぁ。
ObjC.import("Cocoa");
class ButtonWindow extends $.NSWindow {
}
//TypeError: The value of the superclass's
//prototype property is not an object. (-2700)
駄目だ。
ぶっちゃけ Cocoa の API はこう継承するメリットは無さそうだし。
this.window みたいな感じで class にくっつけておけばいいかなと。
それと忘れていたけどアプリにするなら起動パラメーターも得ないと。
まあ少しづつやっていくつもり。
#!/usr/bin/osascript
ObjC.import("Cocoa");
class ButtonWindow {
constructor(app) {
ObjC.registerSubclass({
name: 'WinDelegate',
protocols: ['NSWindowDelegate'],
methods: {
'windowWillClose:': {
types: ['void', ['id']],
implementation: function(notification) {
return app.terminate(0);
}
}
}
});
ObjC.registerSubclass({
name: 'AppDelegate',
methods: {
'onButtonClicked': {
types: ['void', ['id']],
implementation: (button)=> {
// parameter ?
button.title = "Click!Click!Click!Click!Click!";
// this ?
this.window.title = "Click!";
}
}
}
});
let appDelegate = $.AppDelegate.new;
// NSButton
this.button = $.NSButton.alloc.initWithFrame($.NSMakeRect(10, 10, 150, 50));
this.button.title = "Click!";
this.button.bezelStyle = $.NSRoundedBezelStyle;
this.button.buttonType = $.NSMomentaryLightButton;
this.button.target = appDelegate;
this.button.action = "onButtonClicked";
// NSWindow
this.window = $.NSWindow.alloc.initWithContentRectStyleMaskBackingDefer(
$.NSMakeRect(0, 0, 320, 120),
$.NSTitledWindowMask
| $.NSClosableWindowMask
| $.NSMiniaturizableWindowMask
| $.NSResizableWindowMask,
$.NSBackingStoreBuffered,
false
);
this.window.title = $("JXA NSButton");
this.window.orderFrontRegardless;
this.window.delegate = $.WinDelegate.new;
this.window.contentView.addSubview(this.button);
this.window.makeKeyAndOrderFront(this.window);
}
}
function run(argv) {
let app = $.NSApplication.sharedApplication;
app.setActivationPolicy($.NSApplicationActivationPolicyRegular);
app.mainMenu = function() {
function newMenu(title, action, key) {
return $.NSMenuItem.alloc.initWithTitleActionKeyEquivalent(title, action, key);
}
const mainMenu = $.NSMenu.alloc.initWithTitle("Test");
const itemApp = $.NSMenuItem.new;
const menuApp = $.NSMenu.alloc.initWithTitle("Test2");
itemApp.submenu = menuApp;
mainMenu.addItem(itemApp);
menuApp.addItem(newMenu('Quit', 'terminate:', 'q') );
return mainMenu;
}();
let window = new ButtonWindow(app);
app.run;
}
で
ボタンをクリックするとタイトルバーとボタンの文字が変わります。
よしハンドラ指定方法はコレでいいようだ。
で、やはり絶対位置配置なのでボタン文字列のはみ出しが起こります。
macOS って見た目は洗練されているけど API は古臭いな。
constructor(app) の app ポインタは保持されるようです。
app.terminate(0) をどうしようかと思ったけど試してみるもんです。
class と run を使ったらいかにもアプリのコードって感じになった。
アロー関数で this が保持され一般的な class のように使える。
やっぱり class にしたほうが理解しやすい、this だらけになってもーたけど。
