0

I have an Entry that updates once via a textvariable set to a StringVar, but then only via manual keypress from user after that.

I'm writing a GUI using model-view-controller pattern.

I have a controller class, that owns the main tk object. It also owns a StringVar(). I've set up a callback to fire when the StringVar is written to.

from Tkinter import *
from tkFileDialog import askopenfilename

class Controller:
    def __init__(self):
        self.root = Tk()
        self.fname = StringVar()
        self.fname.trace('w', self.file_name_updated)
        self.view = View(self.root, self.fname)

    def file_name_updated(self, name, index, mode):
        varValue = self.root.globalgetvar(name)
        print ('filename updated!!! %s' % varValue)
        self.root.globalsetvar(name, 'changing it again!')

    def run(self):
        self.root.mainloop()

class View:
    def __init__(self, tk, fname_var):
        self.form = tk
        self.fileNameVar = fname_var

        self.inFileTxt = Entry(self.form, textvariable=fname_var)
        self.inFileTxt.grid(row=1)

        self.inFileBtn = Button(self.form, text="Browse ...", command=self.open_file)
        self.inFileBtn.grid(row=1, column=8)

    def open_file(self):
        fname = askopenfilename()
        self.fileNameVar.set(fname) # update the updateable text 

if __name__ == '__main__':
    c = Controller()
    c.run()

The controller creates a View instance. The View object, draws an Entry box which assigns the StringVar to its textvariable attribute. The View object also has a Button. When clicked, this sets the value of the StringVar(), and fires the callback.

So far so good. The StringVar has been set to the chosen filename, the callback fires, I see my debug. But then, in my callback, I update the value of the StringVar again. It's just a test, ultimately I want to clear the value of the StringVar if the filename chosen has errors (but that wasn't working, so I'm trying to narrow it down).

Anyway, I'm expecting the text in the entry box to say 'changing it again!'. But I don't see that. It stays the same.

Debug shows that the value of the variable is 'changing it again!', but the Entry box has not updated.

However, when I place the cursor inside the Entry box and press SPACE, then my text gets updated.

How can I update the text without user having to enter anything?

possibly related - event processing, StringVar is always 1 event behind. Tkinter: set StringVar after <Key> event, including the key pressed

Community
  • 1
  • 1
patchwork
  • 1,161
  • 3
  • 8
  • 23
  • When I select a file, the `StringVar()` becomes the file name, when I try and change the filename the `StringVar()` changes to "changing it again!", I don't see an error? – Tom Fuller Mar 05 '17 at 20:25
  • Really? Hmm. Must be something else in my code then. The entire thing is too big to paste here unfortunately. – patchwork Mar 05 '17 at 20:27
  • You can always try using `.update()` or `.update_idletasks()`, this isn't the best solution but it sometimes works – Tom Fuller Mar 05 '17 at 20:28
  • I tried `update_idletasks()` with no joy, but I will try `update()`. – patchwork Mar 05 '17 at 20:29
  • If that doesn't work all I can suggest is having a debug at every place you change the `StringVar()` – Tom Fuller Mar 05 '17 at 20:31
  • Ok - I'll try that. Even the cut down version doesn't work for me. – patchwork Mar 05 '17 at 20:32
  • This "cut down" version is not nrunnable as-is, so the problem is likely in the code you aren't showing us. Please read and follow the advice here: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Bryan Oakley Mar 05 '17 at 22:42
  • @BryanOakley - updated. – patchwork Mar 05 '17 at 23:24
  • @TomFuller: neither `update` nor `update_idletasks` should have any effect here. – Bryan Oakley Mar 05 '17 at 23:57

1 Answers1

0

When the insert method of the Entry is used instead of the set method of the StringVar in the open_file function, it works as expected (the text is replaced by "changing it again!"):

def open_file(self):
    fname = askopenfilename()
    self.inFileTxt.delete(0, 'end')
    self.inFileTxt.insert(0, fname)

instead of

def open_file(self):
    fname = askopenfilename()
    self.fileNameVar.set(fname) # update the updateable text

But I don't understand why because in both cases file_name_updated is executed. So if someone can explain this, please edit this answer.

j_4321
  • 15,431
  • 3
  • 34
  • 61