3

This is my first Question here at StackOverflow, so please be patient with me if some info isn't present or I missed something important, but anyways i'll do my best :)

Recently I started to code in Python2.7, so I'm not very good at it. While playing with PyGtk, PyGObject, Glade, etc I found something particular about switches (Haven't tried with any other widget, so I don't know if it happens somewhere else. Most likely it doesn't, I hope...)

I made a very basic GUI with a single "window" plus a "switch" using Glade

My objective was to deactivate switch after user tried to activate it if some exeption raised up before, something like:

  • Activate it --> * Found error --> * Deactivate it

I made some code, and after a while, I noted that THIS piece of code created a loop-like block, blocking GUI's window afterwards:

builder = Gtk.Builder()
window1 = builder.get_object('window')
switchie = builder.get_object('switchie')

switchie.set_active(False)

def Hi(switch, active):
    print switchie.get_active()
    switchie.set_active(not switchie.get_active())


switchie.connect("""notify::active""", Hi)

window1.set_position(Gtk.WindowPosition.CENTER)
window1.connect("delete-event", Gtk.main_quit)
window1.show_all()

If i'm right, "switchie.connect" links "switchie" object with "Hi" func whenever "switchie" gets clicked.

But if I execute this and try to turn switch on, GUI hangs up. I did try to execute this via script & command-line and adding the "print switch state", resulting in an endless loop (True & False)

I tried with many other funcs I made, but neither of them could solve this issue. In fact, this is the "essence" of all the other funcs I made.

Why does this happen?

Where's the loop?

Am I wrong in some line?

Help is appreciated!

(If you need to see the rest of my faulty funcs, just ask for 'em, but I don't think they'll help...)

PythonNoob
  • 235
  • 1
  • 2
  • 12
  • Your `Hi` event handler is called every time the switch is toggled. Since you're toggling the switch _inside_ the event handler, you obviously end up with an infinite loop. – Aran-Fey Aug 14 '16 at 09:33
  • Is there a safely way to achieve my principal objective? Activate it --> * Found error --> * Deactivate it EDIT: Are you saying that "switchie.connect()" also links "switchie.set_active()" calls? – PythonNoob Aug 14 '16 at 09:37
  • 1
    Yes, the signal handler is called regardless of _why_ the switch's state changes. If you must toggle the switch inside the event handler, you'll have to temporarily [disconnect](https://developer.gnome.org/gobject/unstable/gobject-Signals.html#g-signal-handler-disconnect) or [block](https://developer.gnome.org/gobject/unstable/gobject-Signals.html#g-signal-handler-block) it. – Aran-Fey Aug 14 '16 at 09:53
  • Well, after a while of experimenting, i couldn't success in this task. Could you help me? PD: I tried using both methods you told me to use (Disconnect & Block) – PythonNoob Aug 15 '16 at 06:07
  • I'm not sure what's going on, but for some reason you can't seem to disconnect or block the `notify::active` event. It works if you connect to the `state-set` event instead. – Aran-Fey Aug 15 '16 at 06:24
  • In fact, it does work when you try to block `notify::active`, but something weird it's happening here, because when I try to block it, then do whatever I try to do, and then unblocking it, it seems like `switchy.set_active(bool)` "keeps" its signal hidden, and when python executes `switchy.handler_unblock(handler_id)` it reads the saved signal and it acts like if I haven't blocked & unblocked the signal. Do you know how does exactly this work? Meanwhile I'll try to change my signal for `state-set` to see what happens... – PythonNoob Aug 15 '16 at 06:59
  • PD: How do I connect to `set-state` event? `switchie.connect("""state_set""", Hi)` won't work... – PythonNoob Aug 15 '16 at 07:27
  • `switchie.connect('state-set', Hi)` – Aran-Fey Aug 15 '16 at 07:43
  • Nope: `TypeError: : unknown signal name: state-set` – PythonNoob Aug 15 '16 at 07:49
  • It works for me in Gtk 3.20.6. You aren't actually using pygtk, right? That's outdated. Gtk should be imported as `from gi.repository import Gtk`. – Aran-Fey Aug 15 '16 at 08:21
  • Yup, I'm using PyGobject, not PyGtk. Maybe here's the reason: `import gi; gi.require_version('Gtk', '3.0'); from gi.repository import Gtk, GdkPixbuf;` In fact, my GUI was designed using Gtk 3.4 & Glade I'm not using a "very" recent version of Gtk because I want to make sure that my app is retro-compatible with older releases of Linux that don't support newer release of Gtk OR that final user doesn't want to install – PythonNoob Aug 15 '16 at 08:28
  • At this point, I think I've tried everything I know till here. Since I'm not getting any good results, I'll try to open a new question, but this time pointing directly to my objective without providing any code. Maybe some guy will come with a totally new way to do this, I hope. In any case, thanks @Rawing, you were the only one that helped me. – PythonNoob Aug 16 '16 at 01:04

1 Answers1

1

You want to hook up the switch like this:

switchie.connect("""activate""", Hi)

This will only get called once for every time it is clicked. What you were doing is hooking up to the signal after it changed, so it was constantly changing, and never catching up. You will also want to change

def Hi(switch, active):

to

def Hi(switch, active = None):

for keyboard support.

theGtknerd
  • 3,647
  • 1
  • 13
  • 34
  • Wow. I'm slightly impressed about two things: *It's been a long time since I asked this *I've alredy dumped this little proyect of mine xDDD Anyways, thanks. I'll try to recreate my situation, and try this answer. By the way: In my most recent proyect, in fact, I've been using the "activate" signal with some other widgets (As I alredy forgot about my old proyect, I didn't note that it could be solve my problem...) BUT I have a question: *Is there any other difference between "notify::active" and "activate" aside from the "infinite" loop the first one creates? – PythonNoob Sep 26 '16 at 05:23
  • And almost forgot to mention: *What do you mean with the "keyboard support" part? Support for "what"? Keyboard bindings? Shortcuts? Focus the switch? Accelerators? – PythonNoob Sep 26 '16 at 05:31
  • Yes, the "notify::active" gets called **after** the switch is activate/inactive which creates a loop. The "activate" is called when the user responds to the switch, therefore it is only called one time for each user/switch interaction, and the signal is called **before** the switch gets active/inactive. Keyboard support means if the switch has focus, you can press enter on your keyboard to activate/deactivate it. – theGtknerd Sep 26 '16 at 19:25
  • I'm glad you found this Q. You solved some useful questions that were kinda of complicated to me. It seems like if you were my counterpart (PythonNoob != theGtknerd).Thank you very much, really. I'll try these answers so I can accept this one as the "Correct answer", Ok? – PythonNoob Sep 28 '16 at 05:44
  • Sure, glad to be of help. I am using Gtk for about a year now. I use Anjuta for my IDE. Anjuta is a big help as all the different signals are listed and it has a very fast development cycle. It takes some setup, though. I would like to create a tutorial sometime, but do not have any 'extra' time right now. – theGtknerd Sep 28 '16 at 19:19