Running a Python program that I wanted to add a GTK Settings menu to. The below functions as needed, but there's a couple problems with it. Here's the relevant code:
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
def gtk_on_activate(app):
win = Gtk.ApplicationWindow(application=app)
win.set_title('Settings')
win.set_default_size(320,240)
box = Gtk.ListBox()
for k,v in config['Settings'].items():
btn = Gtk.CheckButton(label=k,active=bool(int(v)))
btn.connect('toggled', gtk_toggled)
box.append(btn)
win.set_child(box)
win.present()
def gtk_toggled(btn):
global config
print('hi')
btn.set_active(not btn.get_active())
config.set('Subscriptions', btn.get_label(), str(int(btn.get_active())))
with open(os.path.join(os.path.dirname(__file__), 'Config/SavedVariables.cfg'), 'w') as cfg:
config.write(cfg)
app = Gtk.Application(application_id='org.gdi.Settings')
app.connect('activate', gtk_on_activate)
app.run()
And here's the output:
[...]
hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
Traceback (most recent call last):
RecursionError: maximum recursion depth exceeded while calling a Python object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/xyz/.local/bin/scripts/Settings/Settings.py", line 95, in gtk_toggled
with open(os.path.join(os.path.dirname(__file__), 'Config/SavedVariables.cfg'), 'w') as cfg:
RecursionError: maximum recursion depth exceeded while calling a Python object
What I imagine the RecursionError
is about is that file likely being opened dozens of times. But I don't understand:
print('hi')
is required for the code to even work(other strings work)?Thank you for any and all help!
EDIT: I've since moved the open
out of that function, and that solved the RecursionError
. I also have now tried with Gtk3, and noticed the same pattern of the signal being spammed. So I guess it's just normal? Gtk3 seems to have solved the print('hi')
being an odd requirement. I noticed with Gtk4, that weird trick only worked if the program was run from the terminal. Don't really understand what's going on there... Perhaps I should file a bug report?
I've changed the code so that it works with Gtk 3 (and without error messages relating to config
), and it seems to be that the problem comes down to the btn.set_active(not btn.get_active())
line. Here is the code I used:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
def gtk_on_activate(app):
win = Gtk.ApplicationWindow(application=app)
win.set_title('Settings')
win.set_default_size(320,240)
box = Gtk.ListBox()
for k,v in {"Button1": "1", "Button2": "0", "Button3": "1"}.items():
btn = Gtk.CheckButton(label=k,active=bool(int(v)))
btn.connect('toggled', gtk_toggled)
box.insert(btn, 0)
win.add(box)
win.show_all()
win.present()
def gtk_toggled(btn):
print('hi')
btn.set_active(not btn.get_active()) # This line is causing the error message
app = Gtk.Application(application_id='org.gdi.Settings')
app.connect('activate', gtk_on_activate)
app.run()
To fix this, just remove the btn.set_active(not btn.get_active())
. It's completely useless, since the checkbutton will automatically change its state by itself. And if you don't want the user to be able to change the state of the checkbutton, just use btn.set_sensitive(False)
for any checkbuttons you want to be disabled.
So, in answer to your questions:
print('hi')
isn't required for the code to work; the code fails whether you print('hi')
or not (at least in Gtk 3).btn.set_active()
function in the btn.set_active(not btn.get_active())
line sends toggled
signal, which then calls gtk_toggled()
, which calls btn.set_active()
, which sends the toggled
signal, which calls gtk_toggled()
, which then calls btn.set_active()
, on and on and on until the maximum recursion depth is reached.And no, thankfully it's not normal, and no, you don't need to file a bug report.