Catching Figure close button

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Catching Figure close button

phofman
Hi,

Please is there a way to assign a hook to the figure close button? I
understand the button is provided by the window manager of my OS but
please can I handle it in octave?

I cannot use uiwait since my main thread cycles reading incoming zeromq
messages and uiwait() rounds timeout to whole seconds.

If I could run a callback when the windows close button is pushed, I
could arrange for quitting the reading loop at next iteration.

Octave 4.4.1, linux

Thanks a lot for any hints.

Best regards,

Pavel.


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
Dne 28. 01. 19 v 20:53 Pavel Hofman napsal(a):

> Hi,
>
> Please is there a way to assign a hook to the figure close button? I
> understand the button is provided by the window manager of my OS but
> please can I handle it in octave?
>
> I cannot use uiwait since my main thread cycles reading incoming zeromq
> messages and uiwait() rounds timeout to whole seconds.
>
> If I could run a callback when the windows close button is pushed, I
> could arrange for quitting the reading loop at next iteration.
>

I think the problem is my main thread does not finish and no GUI
callbacks are run. No pushbutton callbacks are executed. My thread ends
with infinite cycle - reading zeromq messages.

Please what would be a recommended way to solve such problem? Would
running the GUI thread and the reading thread side by side with parallel
package help? The message reading loop thread must have access to the
GUI handles currently stored in a global struct.

Thanks a lot for help with principles of using the octave UI elements.

Best regards,

Pavel.


Reply | Threaded
Open this post in threaded view
|

RE: Catching Figure close button - callbacks not running?

Tony Richardson


> -----Original Message-----
> From: Help-octave <help-octave-
> bounces+richardson=[hidden email]> On Behalf Of Pavel Hofman
> Sent: Tuesday, January 29, 2019 3:50 AM
> To: [hidden email]
> Subject: Re: Catching Figure close button - callbacks not running?
>
> Dne 28. 01. 19 v 20:53 Pavel Hofman napsal(a):
> > Hi,
> >
> > Please is there a way to assign a hook to the figure close button? I
> > understand the button is provided by the window manager of my OS but
> > please can I handle it in octave?
> >
> > I cannot use uiwait since my main thread cycles reading incoming
> > zeromq messages and uiwait() rounds timeout to whole seconds.
> >
> > If I could run a callback when the windows close button is pushed, I
> > could arrange for quitting the reading loop at next iteration.
> >
>
> I think the problem is my main thread does not finish and no GUI callbacks
> are run. No pushbutton callbacks are executed. My thread ends with infinite
> cycle - reading zeromq messages.
>
> Please what would be a recommended way to solve such problem? Would
> running the GUI thread and the reading thread side by side with parallel
> package help? The message reading loop thread must have access to the GUI
> handles currently stored in a global struct.
>
> Thanks a lot for help with principles of using the octave UI elements.
>
> Best regards,
>
> Pavel.
>

Define a callback for the 'DeleteFcn' property of the current figure window (or a handle
returned by the figure() function):

   set(gcf, 'DeleteFcn', @(h, e) mycallback(h, e))

The callback will be run when the window is pressed.  

Here is a simple (specific) example.  Enter at the command prompt:

   set(gct, 'DeleteFcn' @(h, e) disp('bye bye'))

This will display 'bye bye' in the command window when the window is deleted.

Tony Richardson


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

Przemek Klosowski-7
On 1/29/19 1:19 PM, Richardson, Anthony wrote:
> set(gct, 'DeleteFcn' @(h, e) disp('bye bye'))

It works, but the printout seems to be buffered somehow and only appears
after the next command is entered at the CLI.

Specifically, I use commandline Octave 4.2.2 on Fedora Linux, and type

     gcf=figure(1)
     set(gcf, 'DeleteFcn', @(h, e) disp('bye bye'))

nothing happens when I close the window, and I need to hit Enter on the
Octave prompt to see the "bye bye" string.

I thought that it's buffered because it doesn't have a newline, but

     set(gcf, 'DeleteFcn', @(h, e) printf('bye bye\n'))

behaves in the same way. It looks like it needs an explicit fflush():

     set(gcf, 'DeleteFcn', @(h, e) {printf('bye bye\n'); fflush(stdout)})

'more off' works too.

It surprised me because we're not in octave REPL loop after the callback
runs, but I guess the callbacks are buffering because the interpreter
does not know in advance when they would be done running.



Reply | Threaded
Open this post in threaded view
|

RE: Catching Figure close button - callbacks not running?

Tony Richardson


> -----Original Message-----
> From: Help-octave <help-octave-
> bounces+richardson=[hidden email]> On Behalf Of Przemek
> Klosowski
> Sent: Tuesday, January 29, 2019 1:12 PM
> To: [hidden email]
> Subject: Re: Catching Figure close button - callbacks not running?
>
> On 1/29/19 1:19 PM, Richardson, Anthony wrote:
> > set(gct, 'DeleteFcn' @(h, e) disp('bye bye'))
>
> It works, but the printout seems to be buffered somehow and only appears
> after the next command is entered at the CLI.
>
> Specifically, I use commandline Octave 4.2.2 on Fedora Linux, and type
>
>      gcf=figure(1)
>      set(gcf, 'DeleteFcn', @(h, e) disp('bye bye'))
>
> nothing happens when I close the window, and I need to hit Enter on the
> Octave prompt to see the "bye bye" string.
>
> I thought that it's buffered because it doesn't have a newline, but
>
>      set(gcf, 'DeleteFcn', @(h, e) printf('bye bye\n'))
>
> behaves in the same way. It looks like it needs an explicit fflush():
>
>      set(gcf, 'DeleteFcn', @(h, e) {printf('bye bye\n'); fflush(stdout)})
>
> 'more off' works too.
>
> It surprised me because we're not in octave REPL loop after the callback runs,
> but I guess the callbacks are buffering because the interpreter does not
> know in advance when they would be done running.
>
>

Ahhh.  I am using Windows.  Output in this example appears to be immediately flushed in Windows.
I don't know if this is true for all output to stdout or is specific to disp() or something else.

Tony Richardson


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
In reply to this post by Tony Richardson
Hi Tony,

Dne 29. 01. 19 v 19:19 Richardson, Anthony napsal(a):

>
> Define a callback for the 'DeleteFcn' property of the current figure window (or a handle
> returned by the figure() function):
>
>     set(gcf, 'DeleteFcn', @(h, e) mycallback(h, e))
>
> The callback will be run when the window is pressed.
>
> Here is a simple (specific) example.  Enter at the command prompt:
>
>     set(gct, 'DeleteFcn' @(h, e) disp('bye bye'))
>

Thanks a lot! This is what I was looking for, works great.

There was another problem - I did not call drawnow() in the infinite
reading the messages. Took me a while to learn that the UI code is
single-threaded and drawnow executes the queued callbacks.

Since my callbacks use a lot of pauses and take several secs each, I
must either run them in a different thread (parallel?) or rewrite the
code to run the callbacks code interleaved with reading the messages. I
wonder if people face the same issue and how they tackle it.

Please do you have any idea how to catch the Ctrl+C command from IDE
command window so that the figure can be closed automatically when
forced-stopping the script  in IDE?

I very much appreciate your advice and help.

Best regards,

Pavel.



Reply | Threaded
Open this post in threaded view
|

RE: Catching Figure close button - callbacks not running?

Tony Richardson


> -----Original Message-----
> From: pavel <[hidden email]>
> Sent: Tuesday, January 29, 2019 1:22 PM
> To: Richardson, Anthony <[hidden email]>; [hidden email]
> Subject: Re: Catching Figure close button - callbacks not running?
>
> Hi Tony,
>
> Dne 29. 01. 19 v 19:19 Richardson, Anthony napsal(a):
> >
> > Define a callback for the 'DeleteFcn' property of the current figure
> > window (or a handle returned by the figure() function):
> >
> >     set(gcf, 'DeleteFcn', @(h, e) mycallback(h, e))
> >
> > The callback will be run when the window is pressed.
> >
> > Here is a simple (specific) example.  Enter at the command prompt:
> >
> >     set(gct, 'DeleteFcn' @(h, e) disp('bye bye'))
> >
>
> Thanks a lot! This is what I was looking for, works great.
>
> There was another problem - I did not call drawnow() in the infinite reading
> the messages. Took me a while to learn that the UI code is single-threaded
> and drawnow executes the queued callbacks.
>
> Since my callbacks use a lot of pauses and take several secs each, I must
> either run them in a different thread (parallel?) or rewrite the code to run
> the callbacks code interleaved with reading the messages. I wonder if people
> face the same issue and how they tackle it.
>
> Please do you have any idea how to catch the Ctrl+C command from IDE
> command window so that the figure can be closed automatically when
> forced-stopping the script  in IDE?
>
> I very much appreciate your advice and help.
>
> Best regards,
>
> Pavel.

I *think* the callbacks are run when the event occurs.  That is consistent with my experience anyway. It's just that the figure window is not updated until drawnow() is run.

It looks as if the onCleanup() function ('help onCleanup') may allow you to hook Ctrl+C.  Not sure though, I haven't tried it myself.

Tony



Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
>
> I *think* the callbacks are run when the event occurs.  That is consistent with my experience anyway. It's just that the figure window is not updated until drawnow() is run.

That would be great news since multithreading would be provided.
Unfortunately until I call drawnow(), the callback does not run in my
case (it creates some files so easy to check). I have a bit hard time
understanding the documentation in detail


========
By default callback functions are queued (they are executed one after
the other in the event queue) unless the drawnow, figure, waitfor,
getframe, or pause functions are used. If an executing callback invokes
one of those functions, it causes Octave to flush the event queue, which
results in the executing callback being interrupted.
========

It does not say whether the queue waits for execution or is executed
right away in a separate thread. But what I see it seems to run in the
main thread - my loop waits until drawnow finishes with the callback.


>
> It looks as if the onCleanup() function ('help onCleanup') may allow you to hook Ctrl+C.  Not sure though, I haven't tried it myself.
>

Thanks for the hint. Just Ctrl+C stops the execution right away, no room
to clear some specific variable to invoke the cleanup. Or maybe I just
do not undertstand the use properly.

Thanks a lot!

Pavel.


Reply | Threaded
Open this post in threaded view
|

RE: Catching Figure close button - callbacks not running?

Tony Richardson


> -----Original Message-----
> From: pavel <[hidden email]>
> Sent: Tuesday, January 29, 2019 2:02 PM
> To: Richardson, Anthony <[hidden email]>; [hidden email]
> Subject: Re: Catching Figure close button - callbacks not running?
>
> >
> > I *think* the callbacks are run when the event occurs.  That is consistent
> with my experience anyway. It's just that the figure window is not updated
> until drawnow() is run.
>
> That would be great news since multithreading would be provided.
> Unfortunately until I call drawnow(), the callback does not run in my case (it
> creates some files so easy to check). I have a bit hard time understanding the
> documentation in detail
>
>
> ========
> By default callback functions are queued (they are executed one after the
> other in the event queue) unless the drawnow, figure, waitfor, getframe, or
> pause functions are used. If an executing callback invokes one of those
> functions, it causes Octave to flush the event queue, which results in the
> executing callback being interrupted.
> ========
>
> It does not say whether the queue waits for execution or is executed right
> away in a separate thread. But what I see it seems to run in the main thread -
> my loop waits until drawnow finishes with the callback.
>
>
> >
> > It looks as if the onCleanup() function ('help onCleanup') may allow you to
> hook Ctrl+C.  Not sure though, I haven't tried it myself.
> >
>
> Thanks for the hint. Just Ctrl+C stops the execution right away, no room to
> clear some specific variable to invoke the cleanup. Or maybe I just do not
> undertstand the use properly.
>
> Thanks a lot!
>
> Pavel.

Well, I've written several examples that only call drawnow() from within a callback.
(Here's one: https://tinyurl.com/ydas6cws  ) So I know that callbacks are being run before
drawnow() is called.

The documentation you quote seems to be saying (to me) that when drawnow() is called
any queued callbacks will be discarded.   Hmmm, maybe I am flirting with disaster by calling
drawnow from within a callback.  Fortunately, it is the last thing that is done.

Tony


Reply | Threaded
Open this post in threaded view
|

RE: Catching Figure close button - callbacks not running?

Pantxo
Tony Richardson wrote

> Well, I've written several examples that only call drawnow() from within a
> callback.
> (Here's one: https://tinyurl.com/ydas6cws  ) So I know that callbacks are
> being run before
> drawnow() is called.
>
> The documentation you quote seems to be saying (to me) that when drawnow()
> is called
> any queued callbacks will be discarded.   Hmmm, maybe I am flirting with
> disaster by calling
> drawnow from within a callback.  Fortunately, it is the last thing that is
> done.
>
> Tony

I wrote this part of the doc and that is not how it was supposed to be
interpreted, maybe "flush" was the wrong term. Let me try to explain here
and maybe we can come up with a better doc string.

When graphics callback events are fired from the GUI (main thread), they
cannot be executed right away because the interpreter (worker thread) may be
busy with some other task, so the events are stored in an event queue. Now
here are the possible ways to execute the events:
* The interpreter is idle: every 100ms, Octave processes the eventual events
that have been stored in the queue
* The interpreter is busy executing a program: if the program calls one of
the aforementioned functions (drawnow, pause ...), Octave processes events
in the queue.

So instead of "flush the event queue" one should read "process events in the
queue", or anything that does not mean "discard" :-).


Pantxo  



--
Sent from: http://octave.1599824.n4.nabble.com/Octave-General-f1599825.html


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
Hi,

Dne 30. 01. 19 v 9:13 Pantxo napsal(a):
>
> When graphics callback events are fired from the GUI (main thread), they
> cannot be executed right away because the interpreter (worker thread) may be
> busy with some other task, so the events are stored in an event queue.

IIUC that does mean the callbacks are executed in the main worker thread
and do not have a separate thread. That is how my code behaves.


> here are the possible ways to execute the events:
> * The interpreter is idle: every 100ms, Octave processes the eventual events
> that have been stored in the queue

Does calling pause() make the interpreter idle, processing the events?
While waiting in
https://octave.sourceforge.io/zeromq/function/zmq_poll.html does not
make the interpreter idle? That would explain the different behavior of
Tony's and my code (pause() - callbacks are processed vs. zmq_poll() -
callbacks are not processed).

>
> So instead of "flush the event queue" one should read "process events in the
> queue", or anything that does not mean "discard" :-).
>

Yes that would be a good explanation. The fact that the callback is
executed by the main work thread is important IMO.

Please what would be the best practice (if any) for executing callbacks
in another thread so that the main worker thread does not have to wait
for the callback to finish?

I very much appreciate your help. You guys are great!

Thanks,

Pavel.


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

Pantxo

Le mer. 30 janv. 2019 à 12:01, Pavel Hofman <[hidden email]> a écrit :
Hi,

Dne 30. 01. 19 v 9:13 Pantxo napsal(a):
>
> When graphics callback events are fired from the GUI (main thread), they
> cannot be executed right away because the interpreter (worker thread) may be
> busy with some other task, so the events are stored in an event queue.

IIUC that does mean the callbacks are executed in the main worker thread
and do not have a separate thread. That is how my code behaves.
Callback functions are written in m-code, as such they must be interpreted and are thus executed in the "interpreter" (or "worker") thread. The "main" (or "GUI")  thread is the one in which GUI objects (as figures) live.


> here are the possible ways to execute the events:
> * The interpreter is idle: every 100ms, Octave processes the eventual events
> that have been stored in the queue

Does calling pause() make the interpreter idle, processing the events?
While waiting in
https://octave.sourceforge.io/zeromq/function/zmq_poll.html does not
make the interpreter idle? That would explain the different behavior of
Tony's and my code (pause() - callbacks are processed vs. zmq_poll() -
callbacks are not processed).
None of those make the interpreter idle: until "pause" or "zmq_poll" have returned, the interpreter is busy. The difference is that the "pause" explicitly calls process_events (only once in Octave 4.4, every 100ms in the soon released Octave 5) while I guess "zmq_poll" doesn't.
If you want to obtain the same kind of behavior you could do something like

havedata = false;
while (! havedata)
  havedata = zmq_poll (sock, 100);
  drawnow ();
endwhile


>
> So instead of "flush the event queue" one should read "process events in the
> queue", or anything that does not mean "discard" :-).
>

Yes that would be a good explanation. The fact that the callback is
executed by the main work thread is important IMO.

Please what would be the best practice (if any) for executing callbacks
in another thread so that the main worker thread does not have to wait
for the callback to finish?
I don't understand your use case, but anyway, as stated above, callback functions will always end up being executed in the "interpreter" (not "main") thread, where your program is executed.
 

Pantxo


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
>
> Callback functions are written in m-code, as such they must be
> interpreted and are thus executed in the "interpreter" (or "worker")
> thread. The "main" (or "GUI")  thread is the one in which GUI objects
> (as figures) live.

Thanks for the explanation. I am slowly getting to understand octave
details :-)

>
> None of those make the interpreter idle: until "pause" or "zmq_poll"
> have returned, the interpreter is busy. The difference is that the
> "pause" explicitly calls process_events (only once in Octave 4.4, every
> 100ms in the soon released Octave 5) while I guess "zmq_poll" doesn't.

That  explains why Tony's callbacks are processed (pause) while mine are
not (zmq_poll with timeout).

> If you want to obtain the same kind of behavior you could do something like
>
> /havedata = false;/
> /while (! havedata)/
> /havedata/ *=* /zmq_poll (sock, 100);/
> /  drawnow ();/
> /endwhile/

Thanks, I will explicitely call drawnow in the poll loop then.

>
> I don't understand your use case, but anyway, as stated above, callback
> functions will always end up being executed in the "interpreter" (not
> "main") thread, where your program is executed.

IMO the important information (which I was not sure about) is "all code
in one thread". Thanks for enlightenment.

Do you think it would be technically possible to run the callbacks in
another thread using parallel package, allowing the callbacks to call
pause() while the zmq_poll loop could cycle unaffected? It would require
all the threads sharing/having access to global variables. I do not know
if the parallel package allows this kind of computing.

Thanks a lot,

Pavel.


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

Pantxo



>
> I don't understand your use case, but anyway, as stated above, callback
> functions will always end up being executed in the "interpreter" (not
> "main") thread, where your program is executed.

IMO the important information (which I was not sure about) is "all code
in one thread". Thanks for enlightenment.

Do you think it would be technically possible to run the callbacks in
another thread using parallel package, allowing the callbacks to call
pause() while the zmq_poll loop could cycle unaffected? It would require
all the threads sharing/having access to global variables. I do not know
if the parallel package allows this kind of computing.

Thanks a lot,

Pavel.

Can you sketch a little more precisely what your are trying to do (or point me to a relevant thread if you already did)?

IIRC the parallel package works with a bunch of independent Octave sessions (each one having its own interpreter) communicating with each other through files or pipes or some kind of shared memory. Am I right? If so when a figures is instantiated from one of those "sessions" (probably the main one, the one that spawns other processes), the figure callbacks must be executed by the associated interpreter.

Pantxo


Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman
Dne 30. 01. 19 v 14:05 Pantxo Diribarne napsal(a):
>
> Can you sketch a little more precisely what your are trying to do (or
> point me to a relevant thread if you already did)?

* a figure UI with several pushbuttons and text fields

* a thread which loop receiving zeromq messages, every 200ms. Most
messages results in some data shown in the UI. This thread can be paused
for a bit longer, but no more than e.g. 500ms to make sure the displayed
data are up-to-date.

* callbacks hooked to the UI pushbuttons. Each callback runs a sequence
of commands separated by some waiting (using fixed pause() now, but will
be replaced with waiting for acknowledgement msgs through zeromq). Each
callback runs several seconds.

>
> IIRC the parallel package works with a bunch of independent Octave
> sessions (each one having its own interpreter) communicating with each
> other through files or pipes or some kind of shared memory. Am I right?
> If so when a figures is instantiated from one of those "sessions"
> (probably the main one, the one that spawns other processes), the figure
> callbacks must be executed by the associated interpreter.

If that is the case, I cannot use the parallel package since all my
"threads" need to update the shared UI.

However, since my callbacks will have to wait for the feedback received
through the zeromq messages (instead of "dumb" pausing), the solution
will have to implement some finite state machine anyway, running in the
single interpreter thread and run it completely in the same loop the
zeromq messages are being read. Pause is easy to implement with checking
whether enough time has already passed. The way e.g. small single-thread
microprocessors (arduino) are programmed.

Thanks a lot for your invaluable help, to all of you.

Pavel.



Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

Pantxo
Le 31/01/2019 à 16:17, Pavel Hofman a écrit :
Dne 30. 01. 19 v 14:05 Pantxo Diribarne napsal(a):

Can you sketch a little more precisely what your are trying to do (or point me to a relevant thread if you already did)?

* a figure UI with several pushbuttons and text fields

* a thread which loop receiving zeromq messages, every 200ms. Most messages results in some data shown in the UI. This thread can be paused for a bit longer, but no more than e.g. 500ms to make sure the displayed data are up-to-date.

* callbacks hooked to the UI pushbuttons. Each callback runs a sequence of commands separated by some waiting (using fixed pause() now, but will be replaced with waiting for acknowledgement msgs through zeromq). Each callback runs several seconds.


IIRC the parallel package works with a bunch of independent Octave sessions (each one having its own interpreter) communicating with each other through files or pipes or some kind of shared memory. Am I right? If so when a figures is instantiated from one of those "sessions" (probably the main one, the one that spawns other processes), the figure callbacks must be executed by the associated interpreter.

If that is the case, I cannot use the parallel package since all my "threads" need to update the shared UI.

However, since my callbacks will have to wait for the feedback received through the zeromq messages (instead of "dumb" pausing), the solution will have to implement some finite state machine anyway, running in the single interpreter thread and run it completely in the same loop the zeromq messages are being read. Pause is easy to implement with checking whether enough time has already passed. The way e.g. small single-thread microprocessors (arduino) are programmed.

Thanks a lot for your invaluable help, to all of you.

Pavel.

I never used the parallel package but I was under the impression that it was mainly a parallel implementation of (par)arrayfun, (par)cellfun ... And I am pretty sure you cannot affect the state of the figure, which lives in the main process, by calling those functions.

Pantxo



Reply | Threaded
Open this post in threaded view
|

Re: Catching Figure close button - callbacks not running?

phofman

Dne 01. 02. 19 v 15:41 Pantxo Diribarne napsal(a):
>>
> I never used the parallel package but I was under the impression that it
> was mainly a parallel implementation of (par)arrayfun, (par)cellfun ...
> And I am pretty sure you cannot affect the state of the figure, which
> lives in the main process, by calling those functions.
>

Pantxo, thanks a lot for your insight. In the end I wrote a simple
scheduler which stores current position of every callback at each
schedPause call and when the time is up, it returns back to the callback
at requested position. The callback code is still relatively legible and
understandable

Before scheduling, using pause():
https://github.com/pavhofman/nonlinear-compensation/blob/3aec0c676ab3218b78bce52c43409821387842dc/octave/ctrl/clbkCalibrateFreqs.m

After scheduling, using schedPause, with code split into switch blocks:
https://github.com/pavhofman/nonlinear-compensation/blob/master/octave/ctrl/calibrateFreqsSched.m

I know it is ugly but seems to work OK.

Thanks for your patience.

Regards,

Pavel.