Sunday, June 13, 2021

#1 2021-06-11 02:57:03 am

Fredrik71
Member
Registered: 2019-10-23
Posts: 798

NSAlert example with 3 inputs

Today, I got everything working for my Alert Dialog to be running in main thread.
The difficulty I had was to return the values from textFields but later I realised it got whose values before the runModal was running, and that is not correct. That was the main reason setTag and viewWithTag didn't work for me. That is also one of the reason to build handlers with code. Its easier to debug.

Here is the final result.

Applescript:

use scripting additions
use framework "Foundation"
use framework "AppKit"
-- use scripting additions

property cancelButton : "Cancel"
property returnCode : missing value

on run
   set {labels, placeholders} to {{"Name", "Address", "Country"}, {"Your name", "Your address", " Your country"}}
   set theView to my accessoryViewWithLabels:labels andPlaceholders:placeholders
   
   set theAlert to showAlert given arguments:{title:"Title of Alert", message:"My message...", info:"My info...", labels:labels, placeholders:placeholders, buttons:{"Cancel", "Contine", "Info", "Maybe", "OK"}, accessory:theView}
   
   set {theName, theAddress, theCountry} to values of theAlert
end run

on showAlert given arguments:arguments
   try
       if my NSThread's isMainThread() as boolean then
           -- if we run in main thread set the arguments to dictionary.
           set arguments to current application's NSDictionary's dictionaryWithDictionary:arguments
           my performAlert:arguments
       else
           my performSelectorOnMainThread:"performAlert:" withObject:arguments waitUntilDone:true
       end if
       
       if button returned of returnCode is cancelButton then error number -128
       return returnCode
   on error the error_message number the error_number
       set the error_text to "Error: " & the error_number & ". " & the error_message
       return the error_text
   end try
end showAlert

on performAlert:arguments
   set theAlert to createAlert(arguments's title, arguments's message, arguments's info, arguments's labels, arguments's placeholders, arguments's buttons, arguments's accessory)
   
   -- Get the accessoryView
   set theView to arguments's accessory -- NSView
   
   set button to theAlert's runModal()
   set buttonsArray to (buttons of arguments)'s reverseObjectEnumerator()'s allObjects()
   set button to item (button mod 1000 + 1) of buttonsArray
   
   -- Get the input from textfields
   set theAnswers to {}
   repeat with i from 1 to count (arguments's labels)
       set end of theAnswers to (my textFromView:theView withTag:i)
   end repeat
   
   -- Return the modal
   set my returnCode to {values:theAnswers as list, button returned:button as text, labels:arguments's labels as list, placeholders:arguments's placeholders as list}
end performAlert:

on createAlert(title, message, info, labels, placeholders, buttons, theView)
   set theAlert to current application's NSAlert's alloc()'s init()
   -- Set the dialog windows title
   theAlert's |window|'s setTitle:title
   -- Set the a custom image to the dialog
   theAlert's setIcon:(my createImageWithName(current application's NSImageNameActionTemplate))
   -- Set the title message
   theAlert's setMessageText:message
   -- Set the informative text
   theAlert's setInformativeText:info
   
   -- Reverse the order of button so same order as input.
   repeat with anItem in reverse of (buttons as list)
       (theAlert's addButtonWithTitle:anItem)
   end repeat
   
   -- Set the accessoryView to the alert.
   theAlert's setAccessoryView:theView
   return theAlert
end createAlert

on createImageWithName(theImageName)
   set theImage to current application's NSImage's imageNamed:theImageName
end createImageWithName

on accessoryViewWithLabels:labels andPlaceholders:placeholders
   set labelCount to count of labels
   set totalDepth to labelCount * 55 -- each label plus entry field needs 55pts
   set accessoryViewList to {}
   repeat with i from 1 to labelCount
       set theLabel to (current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, totalDepth - 30 - (i - 1) * 55, 400, 17)))
       (theLabel's setStringValue:(item i of labels))
       (theLabel's setEditable:false)
       (theLabel's setBordered:false)
       (theLabel's setDrawsBackground:false)
       copy theLabel to end of accessoryViewList
       
       set theInput to (current application's NSTextField's alloc()'s initWithFrame:(current application's NSMakeRect(0, totalDepth - 55 - (i - 1) * 55, 400, 22)))
       (theInput's setEditable:true)
       (theInput's setBordered:true)
       (theInput's setPlaceholderString:(item i of placeholders))
       (theInput's setTag:i)
       copy theInput to end of accessoryViewList
   end repeat
   
   -- Set the accessoryView to the view
   set viewSize to current application's NSMakeRect(0, 0, 400, totalDepth)
   set theView to current application's NSView's alloc()'s initWithFrame:viewSize
   theView's setSubviews:accessoryViewList
   return theView
end accessoryViewWithLabels:andPlaceholders:

on textFromView:theView withTag:theTag
   return (theView's viewWithTag:theTag)'s stringValue() as text
end textFromView:withTag:

Last edited by Fredrik71 (2021-06-11 04:31:14 am)


if you are the expert, who will you call if its not your imagination.

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)