Search code examples
pythonmultithreadinggtkgtk3glib

GTK3 / Glib Repeating A Function


I need to run a Python function by using GLib without freezing/interupting the GTK3 GUI. GLib.timeout_add(millisecond, function_name) is not adequate. More control is needed in my code. But it gives a warning and it does not repeat the function in every seconds when the following code is used:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib

builder = Gtk.Builder()
builder.add_from_file('test1.ui')
window1 = builder.get_object('window1')

class Signals:
    def on_window1_destroy(self, widget):
        Gtk.main_quit()

builder.connect_signals(Signals())

def function1():
    print("1")
    global source1
    source1 = GLib.timeout_source_new(1000)
    source1.set_callback(function1)
    context1 = GLib.MainContext.default()
    source1.attach(context1)

function1()

window1.show_all()
Gtk.main()

Warning:

TypeError: function1() takes 0 positional arguments but 1 was given

But the following code works without warnings and function repeats in every seconds:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib

builder = Gtk.Builder()
builder.add_from_file('test1.ui')
window1 = builder.get_object('window1')

class Signals:
    def on_window1_destroy(self, widget):
        Gtk.main_quit()

builder.connect_signals(Signals())

def function1(var1):
    print("1")
    global source1
    source1 = GLib.timeout_source_new(1000)
    source1.set_callback(function1)
    context1 = GLib.MainContext.default()
    source1.attach(context1)

function1(1)

window1.show_all()
Gtk.main()

Here is the simple GUI file (test1.ui):

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window1">
    <property name="can-focus">False</property>
    <property name="border-width">10</property>
    <property name="default-width">200</property>
    <property name="default-height">200</property>
    <property name="icon-name">system-monitoring-center</property>
    <child>
      <placeholder/>
    </child>
  </object>
</interface>

I do not need var1 for the function. What could be done here? Here is the documentation but I could not solve the problem: GLib.Source

OS: Debian-like Linux, Python 3.9, GTK 3.24

Solution

  • To fix this error, simply add *args to the parameters for function1: def function1(*args)::

    import gi
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk, GLib
    
    builder = Gtk.Builder()
    builder.add_from_file('/home/sam/programs/python/testing/SO/test1.ui')
    window1 = builder.get_object('window1')
    
    class Signals:
        def on_window1_destroy(self, widget):
            Gtk.main_quit()
    
    builder.connect_signals(Signals())
    
    def function1(*args): # Added *args
        print("1")
        global source1
        source1 = GLib.timeout_source_new(1000)
        source1.set_callback(function1)
        context1 = GLib.MainContext.default()
        source1.attach(context1)
    
    function1()
    
    window1.show_all()
    Gtk.main()
    

    The * tells python to put any positional arguments into a tuple, in this case args. If you print(args) inside function1(), you should see something like (None,). The best part is, using *args works whether arguments are passed to function1() or not!