NSTextField action sent on changed value

So I have a text field that I would like to run the following code when the text changes (you can tell it’s a workaround for not being able to figure out drop areas for files but maybe I’m on the right path):

        set single_string to (stringValue() of files_drop) as string
        set AppleScript's text item delimiters to {return, linefeed, return & linefeed, linefeed & return}
        set pre_list to text items of single_string as list
        set AppleScript's text item delimiters to {}
        
        set list_text to ""
        
        repeat with i from 1 to number of items in pre_list
            set this_item to item i of pre_list
            set Applescript's text item delimiters to "/"
            set text_item to last text item of this_item as text
            set Applescript's text item delimiters to ""
            set list_text to list_text & text_item & return & return
        end repeat
        
        files_list's setStringValue_(list_text)
        files_drop's setHidden:1
        files_list's setHidden:0
        files_drop's displayIfNeeded()
        files_list's displayIfNeeded()

The problem is in the interface builder the only options are sent on end editing and sent on enter only. Is there a way to make it so that this routine runs once the text changes (like altering the properties of the NSTextField on application launch for instance?) I tried with an NSTimer forcing a tab/return, but I can’t think of a good condition to be present to make sure it doesn’t keep running.

Thanks for anyone’s help!

Do a search here and you will find code for handling drag-and-drop of files – that’s what you really need.

In the meantime:

Just use:

set pre_list to paragraphs of single_string

Use:

set pre_list to current application's NSArray's arrayWithArray:pre_list
set list_text to (pre_list's valueForKey:"lastPathComponent") as list

You can use controlTextDidChange and NSNotificationCenter with your NSTextField to detect string changes in the text field.

Thanks for the help!

Hi! Me again… can you please elaborate on the above?

My app isn’t updating textfield values unless a user clicks another element or presses enter.

The above sounds like the solution i’m looking for.

FWIW, this seemingly echo’s my issue: http://stackoverflow.com/questions/19649484/updating-a-label-as-a-user-is-typing-using-cocoa-applescript

Hi,

It’s pretty easy to set up. In Interface Builder, just set the delegate of your NSTextField(s) to your App Delegate object, and then add something like this to your AppDelegate.applescript file:


    property aTextField : missing value
    property aTextField2 : missing value

property aTextLabel : missing value


on controlTextDidChange_(aNotification)
	
	if aNotification's object() is aTextField then
		-- run whatever you want to,
		--  but here is an example of setting a label's string to the field's new string
		set newText to aTextField's stringValue()
		aTextLabel's setStringValue_(newText)
	end if


	if aNotification's object() is aTextField2 then
		-- run whatever you want to,
		--  but here is an example of setting a label's string to the field's new string
		set newText to aTextField2's stringValue()
		aTextLabel's setStringValue_(newText)
	end if

end controlTextDidChange_

Thanks… but I think i’m missing some steps, the textfields value is bound to netBootNameTextfield’s value.

On send (which is on end editing) the below action is run:

Changing from (sender) to (aNotification) didn’t work… So what are the steps to register aNotification?

    
-- Make sure a name is specified for the NetBoot Image, error if not.
    on netBootName_(sender)
        
        -- If textfield is empty
        if netBootNameTextField is missing value then
            
            -- Set netBoot Name
            set my netBootNameTextField to selectedOSdmgVersion & " AutoCasperNBI"
        
            -- Display error to user
            display dialog "Please select a Name for the NetBoot Image" with icon 0 buttons {"OK"}
            
            --Log Action
            set logMe to "Error: Name required for NetBoot Image"
            
            -- Log To file
            logToFile_(me)
            
        else
        
            --Log Action
            set logMe to "Name: " & netBootNameTextField
            
            -- Log To file
            logToFile_(me)
        
        end if
        
    end netBootName_

I’ve found a workaround that works for me.

The app i’m writing has various textfield options in the XIB’s, to close there are buttons.

I’ve created an action for the button that re-runs the sender actions for each textfield, this then has logic to alert the user or proceed… seems to work for me.

As an example, here’s the Time Server action:

    -- Bound to Time Server Text field
    on timeServerCheck_(sender)
        
        -- If textfield is empty
        if timeServerSelected is missing value then
            
            -- Set netBoot Name
            set my timeServerSelected to "time.apple.com"
            
            -- Display error to user
            display dialog "Please enter a Time Server" with icon 0 buttons {"OK"}
            
            --Log Action
            set logMe to "Error: Please enter a Time Server"
            
            -- Log To file
            logToFile_(me)
            
            -- Update plist with selection
            tell defaults to setObject_forKey_(timeServerSelected, "timeServerSelected")
            
            -- Set to false so we don't proceed
            set closeButtonPreCheckPassed to false
            
        else
            
            --Log Action
            set logMe to "Time Server: " & timeServerSelected
            
            -- Log To file
            logToFile_(me)
            
            -- Update plist with selection
            tell defaults to setObject_forKey_(timeServerSelected, "timeServerSelected")
            
        end if
        
    end timeServerCheck_

That would trigger when enter was pressed or another text filed, but not on clicking the XIB’s “Close” push button.

That now has an action that does the below, therefore rechecking where values are needed they are set.

    -- Make sure all variables are set if enabled, if passed close options window
    on closeOptionsWindowCheck_(sender)
        
        -- reset value
        set closeButtonPreCheckPassed to true
        
        -- Verify that the description field has a value & reset & prompt if not
        netBootDescriptionCheck_(me)
        
        -- Bound to NetBoot Image Resize value
        netBootImageExpandEnteredValue_(me)
        
        -- Check the value entered in the ARD Username textfield
        checkardUsername_(me)
               
        -- Check the value entered in the ARD Password textfield
        checkardPassword_(me)
            
        -- Check the value entered in the vnc Password textfield
        checkvncPassword_(me)
        
        -- Check that a custom desktop image has been selected
        checkcustomDesktopImagePath_(me)
        
        -- Bound to Time Server Text field
        timeServerCheck_(me)

        -- Set to boolean of value
        set closeButtonPreCheckPassed to closeButtonPreCheckPassed as boolean

        -- Proceed if we've passed precheck
        if closeButtonPreCheckPassed is true then
            
            -- reload options from plist
            retrieveDefaults_(me)
        
            -- close options window
            optionsWindow's orderOut_(null)

            -- enable options
            set my optionWindowEnabled to true
                
        end if

    end closeOptionsWindowCheck_

There’s nothing special you need to do to get controlTextDidChange working. I’ll list the steps in order, starting from scratch…

  1. Create a new Cocoa-AppleScript application. Name it whatever you want
  2. Under the IBOutlets comment, Add this to your AppDelegate.applescript file (without quotes): “property testTextField : missing value”
  3. Open your MainMenu.xib file, add a new NSTextField from the object library to your NSWindow
  4. Right-click on the NSTextField you just added to the NSWindow.
  5. Click and drag a connection from the little circle next to “New Referencing Outlet” to the App Delegate (blue cube) object
  6. Choose “testTextField” for the Referencing Outlet for the NSTextField
  7. Right-click the NSTextField again and click and drag the little circle next to “delegate” (under Outlets) to the App Delegate (blue cube) object
  8. Add the following handler to your AppDelegate.applescript file (after applicationWillFinishLaunching and before applicationShouldTerminate):

on controlTextDidChange_(aNotification)
	
	if aNotification's object() is testTextField then
		log "Handler is being called every time the string changes"
	end if
	
end controlTextDidChange_

  1. Run your project, edit the contents of the text field (either by typing something in there or by dragging and dropping a file from Finder into it).
  2. Check your Debug panel in Xcode to confirm that the handler is called every time a change occurs

Thanks x74353.

I’ll bear that in mind with my next app!

Hi, there!

I try to do a sample project with this example, but don’t get an property object:


script AppDelegate
	property parent : class "NSObject"
	
	-- IBOutlets
	property theWindow : missing value
	property myText : missing value
	property textEntered : ""
	
	on applicationWillFinishLaunching:aNotification
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching:
	
	on controlTextDidChange:aNotification
		if aNotification's object() is myText then
			log "Handler is being called every time the string changes"
			set newText to myText's stringValue()
			textEntered's setStringValue:newText
		else
			log "Do nothing"
		end if
	end controlTextDidChange:
	
	on applicationShouldTerminate:sender
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate:
	
end script

always got a message “Do nothing”.

I have connected my text field in IB section “Outlets/delegate” to blue cube “Delegate”, and section “Referencing Outlets/New referencing outlet” to blue cube “Delegate/Referencing Outlets/myText” (whose declared as “property myText : missing value”).

What wrong?

You have also to connect the delegate of the text field to the AppDelegate object

Hi, Stefan

Yes, i have 2 connections “ one with property Outlet, and one delegate with blue cube Delegate.

if i try to log my object

set theObject to aNotification's object()
		log theObject

i got a message “<NSTextField: 0x6000001e0600>”

If you have only one text field you don’t have to perform a type check, otherwise try the Cocoa equation method


if aNotification's object()'s isEqual:myText then

Thank’s, Stefan it works well :slight_smile:

FWIW, you can also use:

       if aNotification's object() is myText() then

No idea why…:expressionless:

Hi, All.

Why

if aNotification's object() is myText() then

don’t worked?

It works here…