Sunday, November 27, 2022

#1 2021-05-26 12:34:33 am

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

Textfield with a string, cancel and ok button as modal dialog

I have this simple script object running in Xcode

It has Textfield, cancel and ok button. I have set the cancel to action of terminate
and I use awakeForNib to set defaultValue for the Textfield. In Xcode I get a string
in log of the input string from Textfield.

So how could run the Nib as modal dialog in script bundle (scptd) or (scpt)...
I guess I will use NSBundle class and but the Nib inside the script bundle and load the
Nib from AppleScript.

What I like to do is... run the below code in Script Editor smile, any idea ??
And when I click the ok button the modal dialog will go away and return the value from textfield.
All this is new to me... smile

Applescript:

script AppDelegate
   property parent : class "NSObject"
   
   -- IBOutlets
   property theWindow : missing value
property theMessage : "" -- textField

(**
* Prepares the receiver for service after it has been loaded from an
* Interface Builder archive, or nib file.
*)

on awakeFromNib()
set defaultMessage to (long user name of (system info))
theMessage's setStringValue_(defaultMessage)
end awakeFromNib

on displayMessage_(sender)
set theMessageValue to (theMessage's stringValue()) as text
log theMessageValue
end displayMessage_

on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_

on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_

end script

Last edited by Fredrik71 (2021-05-26 12:49:04 am)


Node-RED makes it easy to automate IoT

Offline

 

#2 2021-05-26 07:05:27 am

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2583

Re: Textfield with a string, cancel and ok button as modal dialog

Fredrik71 wrote:


What I like to do is... run the below code in Script Editor smile, any idea ??


I wonder how you are going to run the code like this directly from the Script editor? I think this is not possible, since all these handlers are of on idle type. That is, they will only work as a stay-open application. (the application enters the main loop, and then reacts to user actions in the application interface.)

You can write AppleScript analog of Xcode stay-open application normal way, using on run, on idle, on quit handlers. But, once again, it will work only as stay-open application. Here is skeleton:

Applescript:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
property theMessage : "" -- textField

on run
   my applicationWillFinishLaunching:"Welcome to myApplication!"
   my awakeFromNib()
end run

on idle -- or on click (textfileld) handler
   -- put here some code which reads and returns current value of your text field
   -- if its old value was changed, then you can call on quit handler
   return 1
end idle

on applicationWillFinishLaunching:aNotification
   display dialog aNotification
end applicationWillFinishLaunching:

on awakeFromNib()
   -- create here window
   -- add some view (your textfield)
   set defaultMessage to (long user name of (system info))
   theMessage's setStringValue:defaultMessage
   -- set here value of your textfield to theMessage
end awakeFromNib

on applicationShouldTerminate:sender
   -- Insert code here to do any housekeeping before your application quits
   return current application's NSTerminateNow
end applicationShouldTerminate:

on quit
   my applicationShouldTerminate:me
end quit

Last edited by KniazidisR (2021-05-26 07:33:33 am)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 15.6.1
Ram: 4 GB

Offline

 

#3 2021-05-26 11:22:26 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

@KniazidisR, Thanks...
In other post I ask if its was possible to load Nib (Interface Builder) to be used in a script.
The respond from Shane was it was possible... maybe I did missunderstood.

My approach was to make a complex UI in Interface Builder to be used in AppleScript.
Same way Shane did with Myriad Tables Lib. And maybe the only way possible is to build a
framework to call a class, methods...

I thought it maybe was possible to load a Nib with AppleScriptObjC calls from Script applet (scptd)

I do know PyObjC could do this, but on other hand they are applets smile (.app)


Node-RED makes it easy to automate IoT

Offline

 

#4 2021-05-26 08:37:01 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6797

Re: Textfield with a string, cancel and ok button as modal dialog

Fredrik71 wrote:

The respond from Shane was it was possible... maybe I did missunderstood.



It is possible:

Applescript:

   set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
   set {theResult, theArray} to myBundle's loadNibNamed:"Window" owner:me topLevelObjects:(reference)

But then you have to deal with what's put in theArray, and any subviews. That means setting targets and possibly actions in code. Do-able but tedious.

My approach was to make a complex UI in Interface Builder to be used in AppleScript.
Same way Shane did with Myriad Tables Lib.



Myriad Tables does not use this approach. It's basically all written in Objective-C, with AppleScript used just to call the methods.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#5 2021-05-26 11:05:57 pm

KniazidisR
Member
From:: Greece
Registered: 2019-03-03
Posts: 2583

Re: Textfield with a string, cancel and ok button as modal dialog

Shane Stanley wrote:



Applescript:

   set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
   set {theResult, theArray} to myBundle's loadNibNamed:"Window" owner:me topLevelObjects:(reference)


Thanks for this. Somewhere I have already encountered this. Another thing is that how all this should be executed in the form of a script, not an application. After all, even xCode first creates an application and then executes it. I think this is impossible, even if you enclose all the code in an infinite repeat loop (analogous to the main loop). Or will it still work?

Last edited by KniazidisR (2021-05-26 11:06:49 pm)


Model: MacBook Pro
OS X: Catalina 10.15.7
Web Browser: Safari 15.6.1
Ram: 4 GB

Offline

 

#6 2021-05-26 11:39:31 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6797

Re: Textfield with a string, cancel and ok button as modal dialog

KniazidisR wrote:

Another thing is that how all this should be executed in the form of a script, not an application.



It needs to be a script bundle (.scptd file).


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#7 2021-05-26 11:54:38 pm

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

Re: Textfield with a string, cancel and ok button as modal dialog

@Shane
Thanks...

I did this and my dialog com to live... but I need to understand how I could bind the property
and actions... smile

Applescript:

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

property arguments : missing value

on run
   if current application's NSThread's isMainThread() as boolean then
       my performLoadNib:arguments
   else
       my performSelectorOnMainThread:"performLoadNib:" withObject:arguments waitUntilDone:true
   end if
end run

on performLoadNib:arguments
   set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
   set {theResult, theArray} to myBundle's loadNibNamed:"MainMenu" owner:me topLevelObjects:(reference)
end performLoadNib:


Node-RED makes it easy to automate IoT

Offline

 

#8 2021-05-27 12:08:28 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6797

Re: Textfield with a string, cancel and ok button as modal dialog

Fredrik71 wrote:

but I need to understand how I could bind the property
and actions...



First, don't use the term bind -- in cocoa, binding has a specific meaning.

You need to work out the relevant views from thisArray and any subviews, then use setAction: and setTarget:.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#9 2021-05-27 12:36:37 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

@Shane...
Thanks...

I will look into this methods, setAction: and setTarget:.
I do see from the log from theArray I have 5 objects.

I try to extract the names of this object

I use [applescript]log (theArray's objectAtIndex:0)'s |description|() as list[/AppleScript]

(*<NSMenu: 0x600001f1fd40>
    Title: Main Menu
    Open bounds: [t=900, l=2.1918e-314, b=900, r=6.95345e-310]
    Supermenu: 0x0 (None), autoenable: YES
    Items:     (
        "<NSMenuItem: 0x600002e227d0 Terminate, submenu: 0x600001f2ea80 (Terminate)>",
        "<NSMenuItem: 0x600002e21180 File, submenu: 0x600001f1cc40 (File)>",
        "<NSMenuItem: 0x600002e21110 Edit, submenu: 0x600001f2e0c0 (Edit)>",
        "<NSMenuItem: 0x600002e22610 Format, submenu: 0x600001f1e740 (Format)>",
        "<NSMenuItem: 0x600002e22450 View, submenu: 0x600001f2dd00 (View)>",
        "<NSMenuItem: 0x600002e224c0 Window, submenu: 0x600001f1e700 (Window)>",
        "<NSMenuItem: 0x600002e22530 Help, submenu: 0x600001f1dc80 (Help)>"
    )*)



It looks like this is the NSWindow log (theArray's objectAtIndex:2)'s |description|() as list

(*<NSWindow: 0x7fa873522910>*)

Last edited by Fredrik71 (2021-05-27 12:46:32 am)


Node-RED makes it easy to automate IoT

Offline

 

#10 2021-05-27 12:47:57 am

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6797

Re: Textfield with a string, cancel and ok button as modal dialog

You should make a nib with just the elements you want, and not use MainMenu.nib.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#11 2021-05-27 01:29:47 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

@Shane
That make sense, we do not need the MenuItems specially when the target dialog is modal.

This is a very interesting approach, why have I not seen this before smile
I have done similar things with PySide to print strings and load the python script from do shell script.

I guess it also are possible to have different Nib in same Script bundle there the main script
use different handlers to call them. In the end the main script will be shorter to make complex
UI with AppleScript. And that is the target for his approach.


Node-RED makes it easy to automate IoT

Offline

 

#12 2021-05-27 02:44:55 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

This is properly not the way to do it... but theArray's objectAtIndex change every time the
script is running. So in other words sometimes I get textField in my Window sometimes not.

The code was made to see if I could hardcode a textfield to be part of a load of Nib window.

I guess the solution here would be to always pick the right item in the theArray. smile

The log say: (*<NSFontManager: 0x6000025486e0>*) when the textfield is show in window.

Applescript:

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

property arguments : missing value

on run
   if current application's NSThread's isMainThread() as boolean then
       my performLoadNib:arguments
   else
       my performSelectorOnMainThread:"performLoadNib:" withObject:arguments waitUntilDone:true
   end if
end run

on performLoadNib:arguments
   set {theWidth, theHeight} to {600, 300}
   set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
   set {theResult, theArray} to myBundle's loadNibNamed:"MainMenu" owner:me topLevelObjects:(reference)
   
   set theTextfield to createTextfield("Textfield...", 20, 20, theWidth / 2, theHeight / 2)
   set theWindow to (theArray's objectAtIndex:0)
   theWindow's contentView()'s addSubview:theTextfield
   
   theWindow's |window|'s |center|()
   theWindow's |window|'s makeKeyAndOrderFront:me
   
end performLoadNib:

on createTextfield(theString, xMin, yMin, xLen, yLen)
   set textFieldSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
   set theTextfield to current application's NSTextField's alloc()'s initWithFrame:textFieldSize
   theTextfield's setEditable:false
   theTextfield's setStringValue:theString
   theTextfield's setTextColor:(current application's NSColor's whiteColor)
   theTextfield's setBezeled:true
   theTextfield's setBezelStyle:(current application's NSTextFieldSquareBezel)
   theTextfield's setBackgroundColor:(current application's NSColor's blackColor)
   return theTextfield
end createTextfield


Node-RED makes it easy to automate IoT

Offline

 

#13 2021-05-27 04:34:52 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

I find some code here on macscripter.net so I made a other script that always choose NSWindow.

[applescript]use framework "Foundation"
use framework "AppKit"
use scripting additions

property theWindow : missing value
property arguments : missing value

on run
    if current application's NSThread's isMainThread() as boolean then
        my performLoadNib:arguments
    else
        my performSelectorOnMainThread:"performLoadNib:" withObject:arguments waitUntilDone:true
    end if
end run

on performLoadNib:arguments
    set {theWidth, theHeight} to {600, 300}
    set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
    set {theResult, theArray} to myBundle's loadNibNamed:"MainMenu" owner:me topLevelObjects:(reference)
   
    set enumerator to theArray's objectEnumerator()
    repeat
        set nextObj to enumerator's nextObject()
        if (nextObj's isKindOfClass:(current application's NSWindow's |class|())) then
            set theWindow to nextObj
            exit repeat
        end if
    end repeat
   
    log theWindow's |description|() as text
    -- set theWindow to (theArray's objectAtIndex:0)
   
    set theTextfield to createTextfield("Textfield...", 20, 20, theWidth / 2, theHeight / 2)
    theWindow's contentView()'s addSubview:theTextfield
   
    theWindow's |window|'s |center|()
    theWindow's |window|'s makeKeyAndOrderFront:me
   
end performLoadNib:

on createTextfield(theString, xMin, yMin, xLen, yLen)
    set textFieldSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
    set theTextfield to current application's NSTextField's alloc()'s initWithFrame:textFieldSize
    theTextfield's setEditable:false
    theTextfield's setStringValue:theString
    theTextfield's setTextColor:(current application's NSColor's whiteColor)
    theTextfield's setBezeled:true
    theTextfield's setBezelStyle:(current application's NSTextFieldSquareBezel)
    theTextfield's setBackgroundColor:(current application's NSColor's blackColor)
    return theTextfield
end createTextfield[/AppleScript]

So I made a NSButton in Xcode for my NSWindow.

1. I bind the button to file's owner in binding inspector and name the 'buttonClicked:' in selector name field.

In my script above I add a handler

on buttonClicked:sender
    display dialog "Click me!"
end buttonClicked:

So what have I learn... its possible to make UI in Xcode that has elements we could access by
hardcoding but also with handlers. The code above include 3 things.

1. NSWindow and NSButton made from Xcode
2. NSTextfield hardcoded to be included.

It means we could mix code from Xcode and AppleScriptObjC methods to hardcode UI.

Last edited by Fredrik71 (2021-05-27 08:20:33 am)


Node-RED makes it easy to automate IoT

Offline

 

#14 2021-05-27 09:49:33 am

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

Re: Textfield with a string, cancel and ok button as modal dialog

This code is maybe easier to follow.

1) I made a NSWindow and NSButton in Xcode.
2) NSButton is binding to file's owner in binding inspector and named 'buttonClicked:' in selector name field.
3) NSTextfield is hardcoded in ASObjC and added to the NSWindow.

performDialog is the main handler to call elements to add to the window.
handler that begins with create is help handlers to build elements.
buttonClicked is action.


To try this code or doing something similar you need to copy the nib file from Xcode to
your script bundle (scptd) resources folder.


Applescript:

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

property arguments : missing value

on run
   if current application's NSThread's isMainThread() as boolean then
       my performDialog:arguments
   else
       my performSelectorOnMainThread:"performDialog:" withObject:arguments waitUntilDone:true
   end if
end run

on performDialog:arguments
   -- Call the window from the nib.
   set theWindow to createWindowFromNib("MainMenu")
   -- The frame size of the window
   set theFrame to theWindow's frame()
   set {theWidth, theHeight} to {item 1 of item 2 of theFrame, item 2 of item 2 of theFrame}
   
   -- Hardcode the textfield
   set theTextfield to createTextfield("This is a hardcoded textfield inside a NSWindow made from Xcode...", 20, 20, theWidth * 2 / 3, theHeight / 2)
   theWindow's contentView()'s addSubview:theTextfield
   
   theWindow's |center|()
   theWindow's makeKeyAndOrderFront:me
end performDialog:

on buttonClicked:sender
   display dialog "Click me!"
end buttonClicked:

on createWindowFromNib(theNibName)
   set theWindow to missing value
   set myBundle to my (NSBundle's bundleWithPath:(POSIX path of (path to me)))
   set {theResult, theArray} to myBundle's loadNibNamed:theNibName owner:me topLevelObjects:(reference)
   -- Get the class of NSWindow from the nib.
   set enumerator to theArray's objectEnumerator()
   repeat
       set nextObj to enumerator's nextObject()
       if (nextObj's isKindOfClass:(current application's NSWindow's |class|())) as boolean then
           set theWindow to nextObj
           exit repeat
       end if
   end repeat
   -- log theWindow's |description|() as text
   return theWindow
end createWindowFromNib

on createTextfield(theString, xMin, yMin, xLen, yLen)
   set textFieldSize to current application's NSMakeRect(xMin, yMin, xLen, yLen)
   set theTextfield to current application's NSTextField's alloc()'s initWithFrame:textFieldSize
   theTextfield's setEditable:false
   theTextfield's setStringValue:theString
   theTextfield's setTextColor:(current application's NSColor's whiteColor)
   theTextfield's setBezeled:true
   theTextfield's setBezelStyle:(current application's NSTextFieldSquareBezel)
   theTextfield's setBackgroundColor:(current application's NSColor's blackColor)
   return theTextfield
end createTextfield

Last edited by Fredrik71 (2021-05-27 09:54:13 am)


Node-RED makes it easy to automate IoT

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)