Subclassing with AppleScriptObjC

Hi, I’m quite a beginner to scripting so be patient, please. Can somebody explain why does my attempt to call drawRect from the custom NSView is not working. “Sort of NSView” instance is created but coloured square is not there. The script is run in Script Editor. Is it possible to use subclassed Cocoa objects in vanilla SE?

use framework "AppKit"
use scripting additions

on run
	if current application's NSThread's isMainThread() as boolean then
		my prepareWindow:me
	else
		my performSelectorOnMainThread:"prepareWindow:" withObject:(missing value) waitUntilDone:true
	end if
end run

on prepareWindow:sender
	set theWindow to current application's NSWindow's new()
	tell theWindow
		its setDelegate:me
		its setStyleMask:(3)
		its setContentSize:{400, 220}
		its |center|()
	end tell
	
	set aView to (my MYView)'s alloc's initWithFrame:{{10, 10}, {200, 100}}
	log aView's |description|() as text
	theWindow's contentView's addSubview:aView
	
	theWindow's makeKeyAndOrderFront:me
end prepareWindow:

script MYView
	property parent : class "NSView"
	property NSColor : class "NSColor"
	
	on initWithFrame:frame
		continue initWithFrame:frame
		log "init"
		return me
	end initWithFrame:
	
	on drawRect:dirtyRect
		continue drawRect:dirtyRect
		NSColor's redColor()'s setFill()
		current application's NSRectFill(dirtyRect)
		log "drawRect"
	end drawRect:
end script

You can’t subclass like that. You need to use a script bundle, and the subclass needs to be a separate file in its Resources folder, preferably in its own folder. Then your script has to load it, like this:

set theBundle to current application's NSBundle's bundleWithPath:pathToFolderWithScripts
theBundle's loadAppleScriptObjectiveCScripts()
1 Like

Thank you very much Shane for pointing me out to the solution! You are a genius.
I also added “AppleScriptObjC” framework reference on top of the main script. Now it all works.

Now it’s missing only block objects support. At least to me.

I noticed though that “AppleScriptObjC” reference isn’t necessary.

You should probably include it anyway.

Thanks, I will do it. The only problem for now that Script Editor crashes when I try to edit subclass script within the bundle script. I bet it’s all about Apple’s file autosaving process in SE.

1 Like

Is there a code sample coming out of this?

Something like that, this is for the main script:

use framework "AppKit"
use framework "AppleScriptObjC"
use scripting additions

on run
 set resourcePath to POSIX path of (path to me) & "Contents/Resources/Classes"
 set theBundle to current application's NSBundle's bundleWithPath:resourcePath
 theBundle's loadAppleScriptObjectiveCScripts()
 theBundle's |description|() as text
 if current application's NSThread's isMainThread() as boolean then
 	my prepareWindow:me
 else
 	my performSelectorOnMainThread:"prepareWindow:" withObject:(missing value) waitUntilDone:true
 end if
end run

on prepareWindow:sender
 set theWindow to current application's NSWindow's new()
 tell theWindow
 	its setDelegate:me
 	its setStyleMask:(3)
 	its setContentSize:{400, 220}
 	its |center|()
 end tell
 
 set aView to current application's MYView's alloc()'s initWithFrame:{{10, 10}, {380, 200}}
 theWindow's contentView's addSubview:aView
 theWindow's makeKeyAndOrderFront:me
end prepareWindow:

… and that is for your custom class:

script MYView
 property parent : class "NSView"
 property NSColor : class "NSColor"
 
 on initWithFrame:frame
 	me is equal to (continue initWithFrame:frame)
 	return me
 end initWithFrame:
 
 on drawRect:dirtyRect
 	continue drawRect:dirtyRect
 	NSColor's brownColor()'s setFill()
 	current application's NSRectFill(dirtyRect)
 end drawRect:
end script

You need to use a script bundle, as Shane said

1 Like