Home Technical Talk

Callback problem with visual interface

interpolator
Offline / Send Message
SimonT interpolator
THIS WORKS FINE
Every time i create a new object "hello world" is printed out.
callbacks.removeScripts id:#myscript;

fn myScript =
(
		print "hello world"
)

callbacks.addScript #nodeCreated "myScript()" id:#myscript;

THIS WON'T WORK
When i RESTART Max and try the same script but with an visual interface (a button which activates/deactivates the callback, in this exmple, it just activates the callback) it gives me this error message WHEN i try to create an object. Hitting the button works fine so that it seems that the callback is registered correct but when Max looks for the function "myscript" it just gets "undefined".
-- Type error: Call needs function of class, got: indefined
rollout AutoAddMat "AutoAddMat" width:168 height:64
(
	button bAutoAdd "Auto add sel. Material ON" pos:[8,8] width:152 height:48

	function myScript =
	(
			print "hello world";
	)
	
	on bAutoAdd pressed do
	(
			callbacks.addScript #nodeCreated "myScript()" id:#myscript;
	)
)

createDialog AutoAddMat;

Replies

  • SyncViewS
    Offline / Send Message
    SyncViewS polycounter lvl 13
    Yep it is a scope issue: in first case myScript() is in global scope and the callback knows how to find it. If you run the first case, then run the second without restarting Max, the second case calls myScript() defined in global scope and not the one inside the rollout.

    If you want to call a function inside a rollout from the outside scope, as the callback function mechanism do, you need to fully specify its scope to be reachable, in your case:
    callbacks.addScript #nodeCreated "AutoAddMat.myScript()" id:#myscript;
    

    Keep in mind that this will work if you create a rollout as you did in global scope, but it won't if you create a rollout in a MacroScript. The MacroScript introduces the concept of "private global" which means variables/rollouts/structures/... defined into its scope are unavailable from outside. In that case you need to declare the rollout as global, then define it, then set the callback pointing to the rollout.
    macroScript macroTest
    (
        global AutoAddMat
    
        rollout AutoAddMat "AutoAddMat" width:168 height:64
        (
            button bAutoAdd "Auto add sel. Material ON" pos:[8,8] width:152 height:48
    
            function myScript =
            (
                print "hello world";
            )
    	
            on bAutoAdd pressed do
            (
                 callbacks.addScript #nodeCreated "AutoAddMat.myScript()" id:#myscript;
            )
        )
    
        on execute
        (
            createDialog AutoAddMat;
        )
    ) -- Warning: untested code
    

    Or if you want a more conservative and clever way to code, define a struct in MacroScript with all and only the functions you need to access through a callback and make a global instance of it. Remember to use non trivial names when choosing them for global scope as they could easily collide.

    For more about scopes, take a look at: "What is Scope of variables?" in MaxScript reference and sub sections.
  • SimonT
    Offline / Send Message
    SimonT interpolator
    Thank you a lot for that explanation! It works! *wohoo*
Sign In or Register to comment.