Sharing a Timer between multiple windows

I’m trying to reduce code in an older project that has copies of the same code on multiple windows. The code updates certain elements and displays sheet windows on the parent that are the same regardless of the parent window. I’m reworking the code to use threads, and therefore I’m updating the UI steps via timers and I’m a bit lost on the processes that would be required to share a timer between multiple windows.

Or, would the best design be to create a timer for each window and just share the callback method code via a global module?

You could share a timer between windows if you created the timer in a module or something NOT on the window.
But is that really worth it since then you have to worry about when to destroy it etc.
Sharing the callback code is probably simpler.

That’s what my tests have proven as well. I’m now moving to a timer on each window that sets the parameters and then calls the shared method.

He’s baaaack …

The coding to deal with this in multiple windows is getting twisted.

Is there no way to create a general, shared timer and handle the window involved in a select … case:

GlobalTimer.Action:

Select Case ParentWindow
Case WMain:
Case WLTFSManager:
Case WQuickArchive:
End Select

I can’t figure out how to achieve this with a global timer. I know that we’ve had discussions about this, but it’s all a mush right now.

Help, I’m drowning in timers…

Shouldn’t that be

Select Case ParentWindow
Case ISA WMain:
Case ISA WLTFSManager:
Case ISA WQuickArchive:
End Select

Tim, your select case should work. Where are you getting stuck?

Norman said:

[quote]Shouldn’t that be

Select Case ParentWindow
Case ISA WMain:
[/quote]
Actually, it should have been “TopWindow” and the actual Window is assigned to that property depending on the parent window of the calling method.

Tim said:

Creating the shared timer and being able to invoke it in global methods.

There is an old project called “Delegating Timer” from Charles Yeomans. In the project the timer is subclassed and with a simple call to a delegate you can use the timer everywhere. Since the §$%& thread-accessing-ui-exception I use the timer more and more.

TopWindow as in front most ?
That’s Window(0)

If we don’t throw an exception the OS will just kill your app very unceremoniously.
No crash log, no warning - it just disappears.
Which would you prefer ?

@Norman: I’ve had my app working in Cocoa when Lion came out (RS2011r4). Even then I had to do some hairy contortions. With the thread-ui-exception mandatory I now have some nice spaghetti code. And I still trip over the lovely problem with the threads. Like today where I found out that a quit just makes a beep and does nothing when called in a thread.

I’ll dig that up (Charles, you there???)

Yes, some of my windows now have 15 to 20 timers. I thought that this would reduce the code, but to trap each possible case, it’s added around 10% (1,100 lines) to the project I’m currently working on.

It almost makes me want to stay in Carbon…

Not to harp on class interfaces, but why not just have your windows implement an interface? Then the timer doesn’t care what kind of window it is, it just calls the methods.
Create an interface called, for example, timerUpdateable with a method DoUpdate()
The timer.action code could look like

If TopWindow isa TimerUpdateable then timerUpdateable(TopWindow).DoUpdate()

Any time a thread needs to post an update, it would set timer.mode=1
Each window could have code to set the UI based on properties in the window. Any code in DoUpdate is thread safe if you only ever call it from the timer. If you have generic code, the DoUpdate could call a global method with a reference to self…
Seems like one way to de-spaghettify a bit. Just my 2 cents.

Jim - That’s not the hard part and it really only saves a few lines because you have to create the Interface and associated method(s).

The hard part is having a single, persistent Timer that can be called from outside of a window. The general mechanism is to place a timer on each window and then call the timer associated with the window. I’ve seen discussions of persistent, non-window-based Timers, but didn’t pay close attention because it wasn’t apropos to my work at the time.

Trixie - I also found this class:
Persistent Timer Subclass

I was thinking the timer would exist in a module and exist for the life of the app. That way it could be started from anywhere and run updates in windows without regard to what sort of window it is or where it was called from. The window would handle it’s own updates (called by the timer) . And if there is global code (like to show a sheet), it could exist in the module and be called from inside the window’s update method. You could reasonably run all UI updating code from one global timer. No need for complex select-case code to decipher the window type etc…

Or maybe I completely misunderstood the original question…?

You understand the question - the issue is the creation and calling of the share, persistent global timer. That’s where my confusion exists.

Darned good luck that it worked - really

Why not create and destroy the timer(s) on the fly? Add a method to the window that updates the UI. Have your thread create a new timer and AddHandler the method to the Action event. The thread starts the timer whenever it needs to update the UI and destroys the timer when the thread completes. See the UpdatingUIFromThread examples that come with Xojo.

But again, your select case should work fine. You’ll probably have to cast ParentWindow to the correct type to use it:

Select Case ParentWindow
Case WMain
    WMain(ParentWindow).DoSomething
...

Sometimes it’s easier to throw together an example than explain what I’m thinking…

UITimer.xojo_binary_project.zip

This is a very simple module that creates and destroys a timer on the fly and uses a class interface to do the updating. I’ll be using this in my apps :wink: Seems more stable and readable than other more convoluted techniques (that I have used)…