MAXScript Tools and Interaction with 3ds Max > Change Handlers and Callbacks >

# Viewport Redraw Callback Mechanism

| Callback Notifications - Quick Navigation

You can register one or more functions to be called whenever the 3ds Max viewports are redrawn.

In addition, with the introduction of the Nitrous Graphics Manager in 3ds Max 2012, any MAXScript Graphics Window (gw.) Viewport Drawing Methods must be wrapped in a Viewport Redraw Callback function to produce any results due to the progressive refinement nature of the drawing process.

The following methods let you register and unregister these callbacks:

    registerRedrawViewsCallback <fn>
    unRegisterRedrawViewsCallback <fn>

You can register as many functions as you like. Each one is individually called whenever the viewports are redrawn. The functions you register must take no arguments.

EXAMPLE:
    fn redrawviews_p = print "Viewports Redrawn"
    registerRedrawViewsCallback redrawviews_p
In the above example, the registered function causes the string "Viewports Redrawn" to be printed in the Listener window whenever the 3ds Max viewports are redrawn.

Special Considerations

- If a runtime error occurs in a callback function while it is being executed, an error message is displayed and that callback function is permanently disabled.

- The registered function is executed in a special context and not in the context of the code that created it. This means that the function cannot contain references to local variables in outer code nestings surrounding the function definition since those variables are on an execution stack that does not exist at the time the function is called. An important exception to this is utility and rollout panel locals, such as local functions, rollout variables and nested rollouts. You can refer to them in change handler code inside rollout code as they are associated directly with their rollout or utility object.

- Note that it is the function value that is being registered, not the function name or global variable. This means that redefining the same-named function after registering it will not change the callback automatically, but register another function value to be called resulting in two separate callbacks. You either need to unregister the old callback function, then redefine the function and register it again (see further on this page), or make the registered function an intermediary which calls another function,

EXAMPLE:
    fn redrawviews_cb = print currentTime
    fn rvcb = redrawviews_cb()
    registerRedrawViewsCallback rvcb
In this case, the registered callback function, rvcb , calls the real call back, redrawviews_cb , (by referencing the global variable it is defined in), meaning you can redefine redrawviews_cb() as often as you need and the callback will always invoke the latest definition. This is a useful technique to employ while you are developing and debugging a callback. Note that you may only redefine the redrawviews_cb() function but NOT evaluate the other two lines again, otherwise you would end up with multiple callbacks calling the same function on each redraw.

- Due to the fact that the function value is being registered, it is absolutely important to unregister any previous value using the unregisterRedrawViewsCallback() method before redefining the function and registering a new callback.The method can be called with an undefined argument, so it can be safely placed just before the function definition without the need to ensure the function already exists. This will ensure that a previous definition of the function will not remain registered without any means to unregister it (short of restarting 3ds Max).

EXAMPLE:
    unregisterRedrawViewsCallback redrawviews_callback_function
    fn redrawviews_callback_function = print "Viewport Redraw 1"
    registerRedrawViewsCallbackredrawviews_callback_function
Evaluating the above will first attempt to unregister the callback function. If it was not registered, nothing will happen. Then the function will be defined and its value will be registered as callback. Orbiting in the viewport for example will cause the string to be printed to the listener. If you would change the string to "Viewport Redraw 2" and evaluate the same code, the old function will be unregistered, the new function will be defined and the new callback will be registered. Orbiting the viewport will print the new string only.
BAD EXAMPLE:
    fn redrawviews_callback_function = print "Viewport Redraw2"
    unregisterRedrawViewsCallback redrawviews_callback_function
    registerRedrawViewsCallback redrawviews_callback_function
If the unregister function call were the second line and not the first, the new function would be defined first, then the unregister attempt would fail silently because the new function would be used and the old one's value would be inaccessible. This would result in both the old and the new functions being executed on viewport redraws, thus printing both "Viewport Redraw 1" and "Viewport Redraw 2" to the Listener.
LOCAL SCOPE EXAMPLE:
    (--open a local scope
    global redrawviews_cb_function --ensure variable visibility
    unregisterRedrawViewsCallback redrawviews_cb_function
    fn redrawviews_cb_function= print "Redraw Test1"
    registerRedrawViewsCallback redrawviews_cb_function
    )--end local scope
If the function definition and the callback unregistering and registering are performed in local scope, it is paramount to ensure the callback function's visibility to the code in either global scope or a "private local" scope such as the top-level local scope of a MacroScript that would protect the function value during the current session. Evaluating the above code without a global declaration would create a function value inside the LOCAL scope defined by the outer-most brackets and the attempt to call unregisterRedrawViewsCallback() in a second evaluation of the script would NOT see the original function value in the variable since the variable would have ceased to exist after the first run. Thus, the variable storing the function value must be declared as global to allow a second run of the script to successfully unregister the previous function value. Changing the printed string to "Redraw Test 2" and evaluating the code again would correctly unregister the old value stored in the global variable, then overwrite it with the new value and register it as a redraw views callback.

- Callback functions remain registered after loading a new file or performing a 3ds Max reset.

| Callback Notifications - Quick Navigation

#### See Also

- Change Handlers and Callbacks

- Change Handlers and When Constructs

- Time Change Callback Mechanism

- General Event Callback Mechanism