Question

I've got a tkinter window that have 3 features: background color,foreground color, and a text label. These features is in a text config file (properties.conf) in my home folder. I want to update window features when the config file changed. I watch the changes in config file with pyinotify and I want to update window when it changes. This is the code:

#!/usr/bin/python
import threading
from Tkinter import *
import os
import ConfigParser
import pyinotify

class WatchFile(threading.Thread):
      def run(self):
          def onChange(ev):
              Gui().updateGUI()
              print 2
          wm = pyinotify.WatchManager()
          wm.add_watch('/home/mnrl/window_configs', pyinotify.IN_CLOSE_WRITE, onChange)
          notifier = pyinotify.Notifier(wm)
          notifier.loop()

class ConfigParse():
      def __init__(self):
          self.confDir =  os.path.join(os.getenv('HOME'), 'window_configs/')
          self.confFile = os.path.join(self.confDir + "properties.conf")
          self.config = ConfigParser.ConfigParser()

          if os.path.isfile(self.confFile):
             self.config.read(self.confFile)
          else:
              if not os.path.exists(self.confDir):
                  os.makedirs(self.confDir)
              self.config.add_section('bolum1')
              self.config.set('section1', 'setting1', 'green')
              self.config.set('section1', 'setting2', 'red')
              self.config.set('section1', 'setting3', 'sample text')

              with open(self.confFile, 'wb') as self.confFile:
                    self.config.write(self.confFile)


class Gui(object):
    def __init__(self):
        self.root = Tk()
        self.lbl = Label(self.root, text=ConfigParse().config.get('section1', 'setting3'), fg=ConfigParse().config.get('section1', 'setting1'),  bg=ConfigParse().config.get('section1', 'setting2'))
        self.lbl.pack()

    def updateGUI(self):
        self.lbl["text"] = ConfigParse().config.get('bolum1', 'ayar3')
        self.lbl["fg"] = ConfigParse().config.get('bolum1', 'ayar1')
        self.lbl["bg"] = ConfigParse().config.get('bolum1', 'ayar2')
        self.root.update()



WatchFile().start()
Gui().root.mainloop()

But whenever properties.conf file changes a new window more appears near the old tkinter window. So tkinter window not updates, new windows open. How can I correct it?

Was it helpful?

Solution

The problem is that in WatchFile.run() you're doing this:

      def onChange(ev):
          Gui().updateGUI()

This does something different than what you're expecting. It creates a new GUI instance, and then immediately calls the updateGUI() method on it. Hence the two windows.

What you need to do instead, is something along the lines of:

#!/usr/bin/env python

gui = None

class WatchFile(threading.Thread):
      def run(self):
          def onChange(ev):
              gui.updateGUI()

[...]

WatchFile().start()
gui = Gui()
gui.root.mainloop()

Here, a variable gui is created, and has an instance of your GUI class assigned to it. Later, the updateGUI() method is called on the same instance.

This problem is more or less repeated with your usage of your ConfigParser class, for example:

self.lbl["text"] = ConfigParse().config.get('bolum1', 'ayar3')

In this case, it 'works' because your ConfigParse() class can be executed twice without side-effects (such as opening windows), but it's not very efficient. You're reading the same file multiple times.
What would be better, is to just use a function (a class with only a __init__ defined is effectively the same), run this once, and return a dict.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top