views:

79

answers:

2

I'm fairly new to GUI programming and I'm trying to write a plotting lib in D to use with some otherwise console-based scientific apps. I'm using DFL as my GUI library.

Assume my plot form has a method called showPlot() that's supposed to display the plot on the screen. I would like to be able to have any thread in my app throw up a plot window and either block until the plot is closed or continue working, without the caller of showPlot() having to know what any other thread is doing with regard to plotting, or what plots were created in the past and may still be on screen. (The internals of showPlot() may, of course, have this knowledge.)

I'm still trying to wrap my head around how GUI libs typically work under the hood. It seems like you're supposed to only have one GUI thread, and one main form. I'd appreciate answers at the language/library-agnostic design pattern level in addition to language/library-specific ones.

Edit: To emphasize, this app has no GUI besides the plots that it throws up at interesting points in its execution. It's basically a console app plus a few plots. Therefore, there's no well-defined "main" form.

A: 

GUI frameworks typically have their own own event-loop, and call the application code as callbacks in reaction to external events(button clicks, timers, redraw, ...). The main difference between a "typical" console application and a GUI application is that you give up the control about when a function is called to the GUI framework.

Threads are typically used when the application code contains some long-running process, which cannot be interrupted into smaller chunks(large computations, copying files, take control over the world, ...). Then one thread is used to keep the GUI responsive, while the work is done in a separate thread. The main problem is to keep both threads correct in sync, since most GUI toolkits are not capable to handle calls from more than one thread. When you have only small work parts, which don't block the GUI for long time (<0.1s), then it is better to stay without worker threads.

I also strongly suggest to separate the GUI code and the application logic apart from each other. Having GUI code and application code mixed together is a maintenance nightmare.

Rudi
I think you missed the point. The point is that this is not a "typical" GUI app. It's mostly a console scientific computing app, but one that happens to throw up a few plots during interesting parts of its execution. In this case there is no GUI besides these plots.
dsimcha
+2  A: 

What you're going to be able to do will likely rely on how DFL works. Typically, in a GUI app, there's an event thread which handles all the events in your app - be it repaint events, button click events, mouse click events or whatever. That thread calls the event handler which is registered to handle the event (that frequently being the widget which was clicked on or whatnot). The problem that you run into is that if you try and do too much in those event handlers, you lock up the event thread, so the other events (including repaint events) don't get processed in a timely manner. Some GUI toolkits even specifically limit what you're allowed to do in an event handler. Some also limit certain types of operations to that specific thread (like doing anything - especially object creation - with actual GUI-code like the various widget or window classes that the toolkit is bound to have).

Typically, the way to handle this is to have the event thread either fire off separate threads in the event handlers and let those other threads actually handle the events, or you set some amount of state in the event handler, a separate, already-running thread is alerted to this change in state (possibly using the observer pattern), and it handles things appropriately based on that state. In either case, what the event handlers themselves do is generally fairly limited.

How GUIs work is generally very event-based. The program handles events from the user and the system and doesn't tend to a do a lot without being signaled to do it. Frequently, GUI apps don't do anything until they're told to by an event (though there are plenty of cases where a background thread is doing some sort of work separate from the events). What you're trying to do doesn't sound particularly event based, so that complicates things a bit.

My guess would be that you would need to have your app create a new window every time that you want to throw a new plot up. That window would likely be a child window of the main window which would be hidden since you obviously don't need it, and presumably DFL requires you to have a main window of some kind. There's a decent chance that each thread which wanted to create a window would have to tell the main GUI window to do that, but it depends on DFL really. It's also possible that DFL allows any thread to create new GUI elements (such as a new window).

Regardless, it would almost certainly be the main event thread which actually handles the window. The thread which wants to create a window and populate it would likely have to create the window (either directly or indirectly), and then update the state of the window by updating a set of shared variables so that the event thread could appropriately repaint the window. The most that original thread would likely to do actually repaint the window is send a repaint event to window after it's updated the state of the shared variables that hold the data necessary to paint the window. It wouldn't handle the painting itself.

As for the thread blocking, it would likely have to do busy-waiting until the window closed event was received by the event thread, and some shared variable was updated, or you could make it go to sleep until the event thread woke it up after receiving the window closed event. In the case where you didn't want it to block, it just wouldn't care about waiting to be told about the window-closed event and would keep chugging along.

In any case, hopefully that's enough information to put you in the right direction. Usually events drive everything, with everything hanging off the GUI, so to speak. But in your case, your app is using the GUI more like stdout. So, you might do better to first work on some small, fairly stupid GUI apps that are actual, normal, event-based GUI apps (like a Tic-Tac-Toe game or something) in order to get a better handle on how the GUI stuff works before trying to get it to work in a somewhat less standard manner like you are.

Jonathan M Davis
The stdout analogy is a pretty good one--that's almost exactly how I would ideally like the GUI system to behave in this case.
dsimcha