Notifications
Clear all

[Closed] Structs?

I want to start coding using structs cause I read that structs handle scope better. (Is this statement right?) Here’s my first attempt, which keeps throwing an “expected while” error from the listener.

struct tstStruct
          	(
          	countVAR = 1,
          	fn timerTest =
          		(
          		timer clock "testClock" interval:1000
          		on clock tick do
          			(
          			countVAR = countVAR+1
          			print countVAR
          			)
          		)
          	) --error "expected while"
          tstStruct = tstStruct()
          tstStruct.timerTest()
          
     I don't understand why the error is occurring, and I've had this error happen before and somehow solved it, but wasn't really sure of what solved it.  It's probably bad syntax, and it has something to do with the "[i]on... do...[/i]".  Is Max looking for a [b][i]while[/i][/b] because of the [b][i]do[/i][/b]?  I even added in a while(), but the listener threw the same error at me again.  Halp! :blush:
6 Replies

It is not the struct that is the problem, but the timer.

If you look in the Help, you might notice that the timer is a User Interface Control and can thus only “live” inside a rollout or utility. It is NOT a stand-alone object you can construct and store in a struct. For that, you can create a DotNet timer which will do exactly what you want, but does not have to “live” in a User Interface.

The error message is confusing because MAXScript itself is confused what is going on there.
It sees a DO statement in the line ‘on clock tick do’ and when the body of the handler ends, it complains it could not find a matching WHILE statement. This is because it does not expect an event handler inside the struct and when it sees a DO, it assumes you are DOing a ‘do… while’ loop.

Thanks Bobo, the ‘timer’ makes much more sense now!
I just ordered your DVD “The Matrix Explained” from CG Academy.

Glad to hear

Note that you can use a DotNet timer to do the same without the need for a UI.
It just ticks in the background since the DotNet Timer is an actual object in memory.
Look here:
http://www.scriptspot.com/bobo/mxs9/dotNet/Timer.html

I’ve taken the dotnet timer and used it inside of a struct, controlled by buttons on a floating rollout.
The timer starts ok, but I can’t seem to stop it. I think the issue is due to scope, as the function that tells the timer to stop can’t see the timer because it was created in the scope of the startTimer function. How can I make this work? Here is code using Bobo’s timer dotNet code:

struct testSt
   	(	
   		myVariable = 56879.7,
   		function myFunction theNumIn: = 
   		(
   			if (theNumIn == unsupplied) do
   			theNumIn = myVariable
   		),
   		function startTimer =
   		(
   			--Bobo's code
   			theTimer = dotNetObject  "System.Windows.Forms.Timer"
   			fn printTime = (print localTime)
   			dotnet.addEventHandler theTimer "tick" printTime
   			theTimer.interval = 1000
   			theTimer.start()
   		),
   		function stopTimer =
   		(
   			theTimer.stop()
   		)
   	)
   rollout myRollout "MyRollout 1" category:1
   	(
   	button _BTN1 "start timer" width:150 pos:[20,10]
   	on _BTN1 pressed do 
   		(
   		local theStruct = testSt()
   		theStruct.startTimer()
   		)	
   	button _BTN2 "stop timer" width:150 pos:[20,35]
   	on _BTN2 pressed do 
   		(
   		local theStruct = testSt()
   		theStruct.stopTimer()
   		)
   	)
   myFloater = newRolloutFloater "My Floater" 200 200
   addRollout myRollout myFloater rolledUp:false

There are two issues here:

  1. The variable holding the timer should be local to the struct, not to the function (as you mentioned correctly).
  2. When you call the stop() function, you should NOT create a new struct right before that, because this makes the call work on a completely different instance that has nothing to do with the original struct you created in the start event handler!

To make both event handlers “see” the same struct, you have to pre-declare the variable storing the struct instance in the scope of the rollout (higher than both event handlers).

struct testSt
	   (	
		   myVariable = 56879.7,
		theTimer, --the timer is now a property of the struct and all functions can "see" it
		   function myFunction theNumIn: = 
		   (
			   if (theNumIn == unsupplied) do
			   theNumIn = myVariable
		   ),
		   function startTimer =
		   (
			   theTimer = dotNetObject  "System.Windows.Forms.Timer"
			   fn printTime = (print localTime)
			   dotnet.addEventHandler theTimer "tick" printTime
			   theTimer.interval = 1000
			   theTimer.start()
		   ),
		   function stopTimer =
		   (
			   theTimer.stop()
		   )
	   )
   rollout myRollout "MyRollout 1" category:1
	   (
	local theStruct  --pre-declare the variable to store the struct instance into
	   button _BTN1 "start timer" width:150 pos:[20,10]
	   on _BTN1 pressed do 
		   (
		   theStruct = testSt() --create the instance using the existing higher scope variable
		   theStruct.startTimer()
		   )	
	   button _BTN2 "stop timer" width:150 pos:[20,35]
	   on _BTN2 pressed do 
		   (
		   --local theStruct = testSt() --don't need this, as it would mask the other variable
		   theStruct.stopTimer()
		   )
	   )
   myFloater = newRolloutFloater "My Floater" 200 200
   addRollout myRollout myFloater rolledUp:false

Thank you Bobo! You’re awesome!