Where is the right place to put this method?

By “right place”, I mean in terms of using Xojo as it’s meant to be used.

I have a method that writes messages into a textarea, for the user’s benefit. The textarea is part of a DesktopContainer of which there is a single instance in the main window. The method is at present in a module, is used from all over the app, and works a treat. But given where it is, it has to contain such as:

MainWindow.Logging.LogArea.AddText (msg)

But it feels like the method ought to be part of the DesktopContainer (Logging) or at least aMainWindow method. But if I move it to either, it becomes invisible to code in other windows. What is the right place to put this?

Your intention: having a method that can be used anywhere to write messages in textareas.
Where it needs to be: Some place, with global visibility, grouping such kind of functionality.

Suggestions: A “Logging module”, “Tools module”, etc

Let’s call it “Logging”, it does not need to be invoked as

MainWindow.Logging.LogArea.AddText (msg)

I would do something like MainWindow.AddLogMessage and let MainWindow worry about the details.

If I were starting from scratch, I probably wouldn’t couple it to MainWindow. But this change is a decent balance given the existing code.

As I said in my OP, it’s in such a module at the moment. The Q is, is that the best place for it?

It isn’t invoked like that, and I didn’t say that it was. That is the code the method has to contain. It’s invoked by:

mymethod (msg)

Well… I had the same logic for something I wrote. I did the same as you did with a small difference. I’ve put it into a module like “Logging” + other related utilities and extra functions related to logging tasks. The difference was that I chose to pass the TextArea as an optional parameter as VLog(msg As String, ta As TextArea = Nil)

So my VLog(“msg”) logged “msg” stored somewhere, and VLog(“msg”, TextArea1) did the same, but also appended it to the contents of the pointed TextArea.

Such place (a module) is a perfect place for such (as you want access to it from a global scope).

What I’ve sometimes done is put the Log method and string property (txtBuffer) in a module. When you call Log(s) it appends the string s to txtBuffer. Then, the actual logging text area is part of container control which also has a timer. In the timer event, it reads the txtBuffer string and appends it to the log textarea and clears the txtBuffer. The log method can then be called from anywhere in the application including a thread, and the container control automatically updates the log textarea no matter where it’s located.

maybe you could use a Interface with a Logging Method.
add this interface where it makes sense.

see also \Example Projects\Design Patterns\Observer.xojo_binary_project

because in Xojo you can’t inherit a base window, you need a class with all the common methods for your application which you instantiate in application open event, that’s the way I have done it, with a global pointer to MainWindow.

You are right to question your current approach. Code such as

MainWindow.Logging.LogArea.AddText (msg)

is rather brittle. Either have mymethod(msg) simply pass msg on to the window with

MainWindow.mymethod(msg)

and let the window handle the particulars, as @Thom_McGrath suggested. Or use @Robert_Weaver’s approach, which is the most flexible and future proof.

Can one guarantee that the timer clears the message fast enough?

This would be an improvement. The logging area has to go somewhere, though.

Yes. One event (such as Timer.Action) runs at a time, unless you have background tasks running, in which case you would use #Pragma BackgroundTasks False to disable task switching while you clear the the message.

But while the timer is timing (even at a 1 msec interval), seems to me several threads could try to post messages and end up overwriting each others message.

I assumed it would be a queue of messages that the timer would append to the textarea. The timer would halt the tasks via the pragma, empty the queue and then let the tasks continue.

Oddly enough, with a lot of the messages, that is what already happens, near enough. Threads have to use the UserInterfaceUpdate scheme, and I have a queue for all those actions.

The logging method appends to the text buffer string, and the timer appends the text buffer string to the text area. So, nothing gets lost.