AppKit Equivalent to Choose From List

I’ve been mainly programming in Objective-C lately and come across situations where I want to present a TableView to the user to confirm data.

I know how to customize NSAlert and have create an extension on it to provide many option I need… custom text editing, check boxes, buttons etc. But inserting a NSTableView and providing it data has failed.
I want to keep this in a extension and not have to load any nib’s.

I’m thinking I my have to use good old AppleScript via osascript to do this,
Unless someone can provide other suggestions!


Here is one example. The script was originally developed by user @Takaaki Naganoya. Slightly modified by me for execution on the main thread.

use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |⌘| : a reference to current application
property aList : {3, "None", "Apple", 3, 4, "Chick", "Gyouza", "Snagi also", "Apple", "Peaches"}
property aSubMessage : "Please select the appropriate one from the following"
property theAlert : missing value
property theResult : 0
property returnCode : 0
property theDataSource : {}

my performSelectorOnMainThread:"createAlert" withObject:(missing value) waitUntilDone:true
my performSelectorOnMainThread:"displayAlert" withObject:(missing value) waitUntilDone:true
if theResult = (|⌘|'s NSAlertSecondButtonReturn) then error number -128
set aResult to my chooseItemByTableView()

on createAlert()
	set my theAlert to |⌘|'s NSAlert's alloc()'s init()
	my performSelectorOnMainThread:"displayAlert:" withObject:theAlert waitUntilDone:true
end createAlert

on chooseItemByTableView()
	-- define the matrix size where you’ll put the radio buttons
	set aScrollWithTable to makeTableView(300, 150) of me
	-- set up alert
	tell theAlert
		its setMessageText:aMainMessage
		its setInformativeText:aSubMessage
		its addButtonWithTitle:"OK"
		its addButtonWithTitle:"Cancel"
		its setAccessoryView:aScrollWithTable
	end tell
	-- show alert in modal loop
	|⌘|'s NSRunningApplication's currentApplication()'s activateWithOptions:0
	my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
	if (my returnCode as number) = 1001 then error number -128
	return (aScrollWithTable's documentView's selectedRow()) + 1
end chooseItemByTableView

on doModal:aParam
	set (my returnCode) to aParam's runModal()
end doModal:

on makeTableView(aWidth as number, aHeight as number)
	set aOffset to 40
	set sourceList to {}
	repeat with i in aList
		set the end of sourceList to {dataItem:(contents of i)}
	end repeat
	set theDataSource to |⌘|'s NSMutableArray's alloc()'s init()
	theDataSource's addObjectsFromArray:sourceList
	set aScroll to |⌘|'s NSScrollView's alloc()'s initWithFrame:(|⌘|'s NSMakeRect(0, aOffset, aWidth, aHeight))
	set aView to |⌘|'s NSTableView's alloc()'s initWithFrame:(|⌘|'s NSMakeRect(0, aOffset, aWidth, aHeight))
	set aColumn to (|⌘|'s NSTableColumn's alloc()'s initWithIdentifier:"dataItem")
	(aColumn's setWidth:aWidth)
	(aColumn's headerCell()'s setStringValue:"dataItem")
	(aView's addTableColumn:aColumn)
	aView's setDelegate:me
	aView's setDataSource:me
	aView's reloadData()
	aScroll's setDocumentView:aView
	aView's enclosingScrollView()'s setHasVerticalScroller:true
	-- Select line
	set aIndexSet to |⌘|'s NSIndexSet's indexSetWithIndex:0
	aView's selectRowIndexes:aIndexSet byExtendingSelection:false
	-- Force scroll to top
	-- set maxHeight to aScroll’s documentView()’s |bounds|()’s |size|()’s height
	set aDBounds to aScroll's documentView()'s |bounds|()
	if class of aDBounds = list then
		-- macOS 10.13 or later
		set maxHeight to item 2 of item 1 of aDBounds
		-- macOS 10.10….10.12
		set maxHeight to height of |size| of aDBounds
	end if
	set aPoint to |⌘|'s NSMakePoint(0.0, -40.0)
	aScroll's documentView()'s scrollPoint:aPoint
	return aScroll
end makeTableView

-- TableView Event Handlers
on numberOfRowsInTableView:aView
	return my theDataSource's |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
	set aRecord to (my theDataSource)'s objectAtIndex:(aRow as number)
	set aTitle to (aColumn's headerCell()'s title()) as string
	set aResult to (aRecord's valueForKey:aTitle)
	return aResult
end tableView:objectValueForTableColumn:row:


Yes but the problem is the delegate methods of supply data or selection. Kinda hard to make the NSAlert class extension the delegate

We can extend NSAlert class by using AppleScriptObjC framework maybe like this.

1 Like

Is think I need to creat my own Class that will — accepted my sourceData.

  • follow the NSTableView delegate protocols
  • create the Alert with TableView
  • run the Alert and return the selected items

I may even create a TableView in InterfaceBuilder and have my custom class load nib file.