3
votes

My program reads from a configuration file. It loads Gtk3 widgets on the window based on the configuration file.

Example configuration file:

[Clock1]
format = %H:%M:%S
color = #FF0000

[Clock2]
format = %H:%M
bgColor = #00FF00

So, I have made a class of my own for e.g. Clock type widget and I've called it Clock.

Example:

#!/usr/bin/env python

from gi.repository import Gtk, Gdk

import output, Defaults.widget
from time import gmtime, strftime

receiver="Clock"

class Widget():
    def __init__(self, parentName, name):
        print "ADDING CLOCK"
        self.gtkwidget=Gtk.Label();
        self.format= Defaults.widget.defaultClockFormat
        self.name=name+parentName
        self.gtkwidget.set_name(self.name)

    def update(self):
        print "Setting clock text to", strftime(self.format, gmtime())
        self.gtkwidget.set_text(strftime(self.format, gmtime()))

    def runCommand(self, command, lineCount, configurationFile):
        #GMTTIME TRUE OR FALSE
        print "I am about to run", command, "from inside the Clock widget!"

        if(command.startswith("format=")):
            parts=command.split("=")
            if(len(parts)!=2):
                output.stderr(configurationFile+", line "+str(lineCount)+": Badly formatted command 'format': Format: format = format.\nSkipping...")
                return
            
            self.format=parts[1]

    def widget(self):
        return self.gtkwidget

Explanation:

  1. Code reads the configuration file and sees that it has to create a Clock widget. So it makes a Clock class that has a GtkLabel inside it as a variable. The runCommand function applies to the widget any more properties read by the configuration file. E.g. the format property for the clock.

  2. The update function is run every 1 second from a WidgetManager class in order to keep the time updated.

  3. The widget() function, once there are no more commands (properties) for the widget to be added, is run in order to return the GtkWidget and add it to the main window.

The above code runs just fine for some time, but then the label stops updating in some short random time (1-2 minutes or less).

enter image description here

The code run successfully till 18:53:31 and then the label stopped updating. I guess that Gtk internally moves the object to another memory and I cannot longer access it with my old object(?).

How should I address this problem? Should I do something differently?

I thought of passing the parent widget (which is a Gtk.Window subclass) to the child (Clock) and searching by name the Gtk.Label that represents the self.gtkwidget (by iterating through the children?). So, get the Gtk.Widget by its name, cast it to Gtk.Label and call the update code to it. How can I implement this?

On the other hand, I think that I am overthinking it and maybe a simpler solution is available.

EDIT

After some tests, I decided to pass the parent as an argument to the constructor of the child (widget) and on the update() function of the child to run a parent's function and check the string from there (directly accessing the children GtkWidgets from the parent window). Please note that at this moment, the only child of the parent is a Label (GtkLabel). There were some interesting results.

The code is as follows:

#UPDATE FUNCTION OF THE CHILD
def update(self):
        print "Setting clock text to", strftime(self.format, gmtime())
        self.parent.runFromChildToParent(self.gtkwidget, strftime(self.format, gmtime()))
        self.gtkwidget.set_text(strftime(self.format, gmtime()))

#PARENT FUNCTION CALLED FROM THE CHILD
def runFromChildToParent(self, child, textToSet):
    for childd in self.get_children():
        print "The current text on the child is", childd.get_text()
        childd.set_text(textToSet)
        print childd, child

Result:

enter image description here

Some things to notice:

  1. The memory addresses of the widget on the child and on the child of the parent window are the same, even after the label's text has stopped updating. Even then both objects are referring to the same memory address.

  2. If you notice, I call the set_text function directly from the child (named childd) of the window, and this doesn't update the value either.

What is the chance that this isn't a bug in my code and I should force a Gtk redraw?

EDIT2

Even with self.gtkwidget.queue_draw() after set_text, the problem seems to persist.

1

1 Answers

2
votes

You will have to use the GObject timeout_add function for updating periodically the ui...

Please don't be so lazy and read the docs next time! You are able to write thousands of perfect lines of code but you are bored to search for "Gtk update UI periodically" in Google? Why?