Re: SpinButton: how to avoid calling signal handler when set_value()



Il 03/11/2016 01:20, infirit ha scritto:
Op 11/03/2016 om 12:19 AM schreef pozzugno:
Il 02/11/2016 18:55, Nicola Fontana ha scritto:
Il Wed, 2 Nov 2016 14:40:58 +0100 Pozz Pozz <pozzugno gmail com>
scrisse:

2016-11-02 11:24 GMT+01:00 Nicola Fontana <ntd entidi it>:
...

you don't necessarily need the handler id. In C (I don't use
python) you could write the following:

void my_set_value(GtkSpinButton *spin_button, gdouble value)
{
      g_signal_handlers_block_matched(spin_button,
                                      G_SIGNAL_MATCH_FUNC,
                                      0, 0, NULL,
                                      callback_to_skip,
                                      NULL);

      /* This will not trigger callback_to_skip */
      gtk_spin_button_set_value(spin_button, value)

      g_signal_handlers_unblock_matched(spin_button,
                                        G_SIGNAL_MATCH_FUNC,
                                        0, 0, NULL,
                                        callback_to_skip,
                                        NULL);
}
I got the idea. I don't know if g_signal_handlers_block_matched() or
similar functionality is available in Python. However, remaining in
C, your
code make the assumption there is a single callback function for all
the
spinbuttons. This is not true: I have a different handler for each
spinbutton, because I have to make different things.
Sorry but I am a developer, not a mind reader.
Yes, of course :-) Thank you for spending some time for me.

I thought using a different callback for each SpinButton was the more
typical solution.

You can match by data or try to lookup the callback by detail with
g_signal_handler_find or refactor your code to use a single
callback.
It seems pyGObject implementation gives only two "handler block"
functions: handler_block(), that needs the handler_id that I don't
have; handler_block_by_func() that needs the callback to block (the
same problem of your solution, because I have different callbacks).

Is it possible to retrieve the list of connected callbacks of an
object and a signal name ("value-changed")?

The fact that you are using different callbacks has a
foul smell indeed.
Yes? I have to generate and send a different request to the device.
Why do you think it's better to have a single callback?
Of course, I could write one single callback as:

   def callback(self, spinbutton):
     if spinbutton is spinSetting1:
       self.callback_setting1(spinbutton)
     elif spinbutton is spinSetting2:
       self.callback_setting2(spinbutton)
     ...

   def callback_setting1(self,spinbutton):
     # This is the callback of the spinbutton associated to setting1
parameter
     set_setting1(spinbutton.get_value())

It seems to me a more complicated way to write different callbacks.

Do you know you can subclass Gtk.SpinButton and override the virtual
methods [1] and emit your own custom signal at the time you want it
based of some attribute? There are some example on the internets but not
much. Ironically the most complete imo is the old pygtk one [2] and gtk3
read the docs is not horrible [3].
Ok, thank you for your suggestion, I'll study this solution. At first, it seems too complicated for a very simple thing... at least, I thought it was a very simple thing.
And I want to reiterate what Nicola said, create a small example with
only 2 or 3 buttons that shows what you are truing to do. It works much
easier that way and we do not have to read minds.
Another situation, similar to mine. You have a dialog window with a SpinButton showing the volume speaker. When the dialog is shown, the SpinButton value should be the current volume level. The user could change the volume speaker by changing the value of the SpinButton, so a callback for the "value-changed" signal is connected. The callback calls the OS API to change the volume speaker. In this scenario (I think it's very common in GUI applications), the value of the SpinButton can be changed by code (when the dialog is shown) and by the user (when he wants to change the volume speaker).

As you can understand, when the value is changed by code, the callback shouldn't be called. The solution is trivial for a single SpinButton. When you have much more SpinButtons, you need a more generic solution.

I think the best approach is the one suggested by Nicola, creating a set_value_by_code() function that blocks the callback, call the original SpinButton.set_value() and unblock the callback again. The only problem is how to retrieve the reference for the callback to block.

In Python I could add an attribute to SpinButton that is the associated callback.

builder.connect_signals(self)
self.spinButton1 = builder.get_object("spinButton1")
self.spinButton1.callback = self.my_callback1 # so it could be retrieved in set_value_by_code()
self.spinButton2 = builder.get_object("spinButton2")
self.spinButton2.callback = self.my_callback2

def set_value_by_code(button, value):
  button.handler_block_by_func(button.callback)
  button.set_value(value)
  button.handler_unblock_by_func(button.callback)

def refresh_widgets_values:
  set_value_by_code(self.spinButton1, get_setting1())
  set_value_by_code(self.spinButton2, get_setting2())
  ...

def my_callback1(self, button):
  set_setting1(button.get_value()

def my_callback2(self, button):
  set_setting2(button.get_value())


However it's strange there isn't a method to retrieve the connected callbacks (the list of callbacks) for a widget and a signal. Gtk should have internally that list, because it must call all the callbacks in sequence.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]