2

It appears that I cannot set the text of a ttk.Entry with a root of ttk.Label during an event:

import tkinter
from tkinter import ttk

def modify_label_text(event):
    entry = event.widget
    newvalue = entry.get()
    label = entry.master
    label.configure(text=newvalue)
    entry.unbind("<Return>")
    entry.pack_forget()
    label.focus()

def create_entry(event):
    label = event.widget
    oldvalue = label.cget("text")
    newvalue = tkinter.StringVar()
    entry = ttk.Entry(label, textvariable=newvalue)
    '''
    entry = tkinter.Entry(label, textvariable=newvalue)
    '''
    entry.pack()
    entry.delete(0, "end")
    entry.insert(0, oldvalue)
    entry.bind("<Return>", modify_label_text)
    entry.focus()

root = tkinter.Tk()

clickme = ttk.Label(root, width=16)
clickme.pack()

clickme.bind("<Button-1>", create_entry)
clickme.focus()

root.mainloop()

When I click the empty label and enter a new value, the value is reflected in the label. However, if I click the label again to "edit" the value, the entry field is empty again.

Furthermore, if I use tkinter.Entry rather than ttk.Entry, it appears to work.

Why is the text of the entry only set when using tkinter.Entry? How can I fix this to work with ttk.Entry?

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
  • 2
    You should not use the `newvalue` StringVar in `entry` because it will be garbage collected after `create_entry()` function which causes the `entry` becomes empty again. – acw1668 May 23 '21 at 07:16

2 Answers2

1

I suggest you create an instance of Entry outside the function and simply pack() and pack_forget() in the function. pack_forget() will not delete your widget it will only hide it from the layout. To delete the widget you might have to use widget.destroy().

import tkinter
from tkinter import ttk

def modify_label_text(event):
    newvalue = entry.get()
    clickme.configure(text=newvalue)
    entry.pack_forget()
    clickme.focus()

def create_entry(event):
    label = event.widget
    entry.pack()
    entry.focus()


root = tkinter.Tk()

newvalue = tkinter.StringVar()

clickme = ttk.Label(root, width=16)
clickme.pack()

clickme.bind("<Button-1>", create_entry)
clickme.focus()

entry = ttk.Entry(clickme, textvariable=newvalue)
entry.bind("<Return>", modify_label_text)

root.mainloop()

Edit(writing my comment as answer)

I suspect that it has to do something with the textvariable being set. Simply removing it or changing the newvalue to global scope seems to work. Also, since you don't seem to be using .set or .get methods you can simply remove it if you want.

Art
  • 2,836
  • 4
  • 17
  • 34
  • I appreciate the answer but I asked the question I did for a reason; this is meant to be a simple example that demonstrates the problem. Having a singular global entry won't scale well when I have more than one label. – S.S. Anne May 23 '21 at 03:53
  • 1
    @S.S.Anne I was trying to answer your second part of your question. I suspect that it has to do something with the `textvariable` being set. Simply removing it or changing the newvalue to global scope seems to work.. Also, since you don't seem to be using `.set` or `get` methods you can simply remove it if you want. – Art May 23 '21 at 04:26
  • You should put that in your answer. That seemed to be the issue. – S.S. Anne May 23 '21 at 16:17
  • @S.S.Anne what should I put in my answer? @ acw1668 seems to have found the cause. – Art May 23 '21 at 16:29
  • "I suspect that it has to do something with the textvariable being set. Simply removing it or changing the newvalue to global scope seems to work.. Also, since you don't seem to be using .set or get methods you can simply remove it if you want." The last one seems to be the best option in my case – S.S. Anne May 23 '21 at 18:30
  • @S.S.Anne I was like you on the wrong track to debug it, but by that I found some solutions. I did delete my answer after acw has given the right answer, but if you intrested I will undelete it and you can see if something of intrest is in that answer. – Thingamabobs May 23 '21 at 19:42
1

This may not an answer, but a bit too large for a comment. Also could someone elaborate this behavior in a different enviorment. I ran that code with:

Mashine:

Windows 10 Home; x64-base,Intel(R) Core(TM) i3-2120 @ 3.30GHz, 3300 MHz, 2Cores

with

Python 3.7.2 and tkinter 8.6

After some research I couldnt find a reason for this behavior. Neither in the docs, nor in the sometimes tricky style_map or in the default bindings.

Can I assume that you create the labels with the entries in a function/loop? You may want to reuse the entry, because for some reason the exact same code works if you adress the entry by winfo_children(). And even if I call .update_idletasks() or just for experience the evil .update() it dosent work for no reason.

import tkinter
from tkinter import ttk

def modify_label_text(event):
    entry = event.widget
    newvalue = entry.get()
    label = entry.master
    label.configure(text=newvalue)
    entry.unbind("<Return>")
    entry.pack_forget()
    label.focus()

def create_entry(event):
    label = event.widget
    oldvalue = label.cget("text")
    newvalue = tkinter.StringVar()
    if len(label.winfo_children()) == 0:
        print('new')
        entry = ttk.Entry(label, textvariable=newvalue)
    '''
    entry = tkinter.Entry(label, textvariable=newvalue)
    '''
    e = label.winfo_children()[0]
    e.pack()
    e.delete(0, "end")
    e.insert(0, oldvalue+' works')
    e.bind("<Return>", modify_label_text)
    e.focus()

root = tkinter.Tk()

clickme = ttk.Label(root, width=16)
clickme.pack()

clickme.bind("<Button-1>", create_entry)
clickme.focus()

root.mainloop()

Another solution could be:

def create_entry(event):
    label = event.widget
    oldvalue = label.cget("text")
    newvalue = tkinter.StringVar()
    entry = ttk.Entry(label, textvariable=newvalue)
    '''
    entry = tkinter.Entry(label, textvariable=newvalue)
    '''
    root.after(100,after_time,entry,oldvalue)

def after_time(entry,oldvalue):    
    entry.pack()
    entry.delete(0, "end")
    entry.insert(0, oldvalue)
    entry.bind("<Return>", modify_label_text)
    entry.focus()
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54