On 20.09.2010, at 16:39, paul wrote:
Given what i've read today and how it differs from my traditional idea of event
handling, i think this be accomplished just with the native event structures as
descirbed and a single thread.
but, given this CPU usage issue (i may block or warn users at certain settings)
then would a second thread be the best option?
I don't think that CPU usage should be an argument here. It depends on
the complexity of your work - unless you need to use more than one core
on a multi-core CPU, as Ian explained. Also, debugging and portability
might be an issue...
The attached program is a more extended version w/o threads and
timeouts. It works in a way that splits the long callback in some
short slices of about 10 ms each (simulated by sleeping). This might
be more difficult to do in a real world programming problem, but I
hope that it shows the idea how to integrate a long-running callback
with FLTK's event handling and a responsive GUI to let the user stop
the calculation and/or do anything else.
As a bonus, there's also a window callback that shows how to handle
the user's request to close the window. If you want to deny it, it
is as simple as not to call hide() - then the window stays open.
Note that you must notify the worker (callback) that the user wants
to stop it...
Albrecht
/* long-running callback demo
compile and run using:
fltk-config --compile long-callback.cxx && ./long-callback
This demo shows how you can manage a long-running callback that does
its work but is still interruptible w/o threads. Communication with
the GUI works through a simple flag. This is really basic and would
probably need to be more sophisticated for real GUI and callback
synchronization, but it shows the idea.
After clicking the start button, the callback can't be interrupted
for 2 seconds (initialization phase), but then it can be interrupted
by resetting the state flag to 0. This is done by pressing the button
again. Note that this is a recursive callback, but it is designed to
work this way. Closing the window triggers the callback win_cb() that
resets the state flag as well and then closes (hides) the window.
*/
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
// simulate working (code 'stolen' from Ian's example ;-)
#ifdef WIN32
# include <Windows.h>
# define wait_here(x) Sleep(x)
#else /* for *nix and OSX */
# define wait_here(x) usleep((x)*1000)
#endif
static int state = 0; // 0 = stopping, 1 = running
/*
This is the "long-running" callback function. This callback runs for
about 8 seconds, but the GUI stays active, and the user can interrupt
it, at least after the first 2 seconds (simulated "initialization phase").
After a 5-second work phase (interruptible), one more second show the
deactivated button "Finishing ..." (un-interruptible).
*/
void button_cb (Fl_Widget *w, void *) {
Fl_Button *b = (Fl_Button *)w; // the button
if (!state) { // start the calculation
state = 1; // running ...
// you can't stop it during the initializing phase ...
// update the GUI to reflect that
b->label("Initializing ...");
b->deactivate(); // deactivate the button
b->redraw(); // tell FLTK to draw it
Fl::flush(); // let FLTK draw everything
// do some initialization ... NON-interruptible !
wait_here(2000); // initialization (2 seconds)
// now do a long calculation (about 5 seconds) - interruptible !
b->label("S T O P"); // now you can stop it ...
b->activate(); // activate the button again
b->redraw(); // update the display
Fl::flush(); // let FLTK draw everything
// Simulate the long calculation in steps of 10 ms each.
// This keeps the GUI responsive
for (int i=0; i<500; i++) { // simulate a long "calculation"
wait_here(10); // this is our "algorithm" ;-)
Fl::check(); // >>> keep the GUI active <<<
if (!state) // user pressed STOP button
break; // stop prematurely
}
b->label("Finishing ...");
b->deactivate(); // deactivate the button
b->redraw(); // tell FLTK to draw it
Fl::flush(); // let FLTK draw everything
wait_here(1000); // 1 more second
}
state = 0; // work is done
b->activate(); // activate the button
b->label ("S T A R T");
b->redraw();
}
/*
This callback function is called when the user clicks to close
the window. We set the state to 0 to stop all the work as soon as
possible. Note that this doesn't work during the initialization
phase - the stop will be delayed until the "real work" begins.
*/
void win_cb (Fl_Widget *w, void *) {
state = 0; // stop worker (if active)
((Fl_Window *)w)->hide(); // close window
}
int main(int argc, char **argv) {
Fl_Window *window = new Fl_Window(300,180);
Fl_Button *button = new Fl_Button(20,40,260,100,"S T A R T");
button->labelfont(FL_BOLD+FL_ITALIC);
button->labelsize(36);
button->labeltype(FL_SHADOW_LABEL);
//button->color(FL_YELLOW);
window->end();
// attach callbacks to the window and the button
window->callback(win_cb,&button); // window close button or menu
button->callback(button_cb); // button callback !
window->show(argc, argv);
return Fl::run();
}
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk