Tkinter Entry/Text widget problem when I use bind function - python

I'm new to Tkinter, I want to print Entry's contents while I'm typing.
Here's my code I've tried:
from tkinter import *
def get_(e):
print(entry.get())
root = Tk()
entry = Entry(root)
entry.pack()
entry.bind("<KeyPress>", get_)
mainloop()
But it seems not "synchronous"(when I type "123" in, output only is "12" and so on)
The following code works properly, but I don't know why:
from tkinter import *
def get_(e):
print(entry.get())
root = Tk()
entry = Entry(root)
entry.pack()
root.bind("<KeyPress>", get_)
## or this: entry.bind("<KeyRelease>", get_)
## or this: entry.bind_all("<KeyPress>", get_)
mainloop()
is there some weird rule I don't know about? Any and all help would be wonderful, thanks in advance!

Question: entry.bind("<KeyPress>" seems not "synchronous" (when I type "123" in output only is "12" and so on ...), while root.bind("<KeyPress>" works.
The event entry.bind("<KeyPress>", ... get fired before the value in tk.Entry is updated. This explains why the output is allways one char behind.
The event root.bind("<KeyPress>", ... get fired after the value in tk.Entry is updated. This explains why this is working.
Alternatives:
Use the "<KeyRelease>" event
tkinter-variable-trace-method
Reference:
Events and Bindings
trace method to attach “observer” callbacks

Related

Python: Reading from a spin box numbers and do following command of one

Good Morning/Evening,
I want to read a number from a spinbox, and if it is 2, it should print something. But my code does not work out. I've tried it with a slider instead of a spinbox and it worked out. But for me, it is really important to use a spinbox, so I hope somebody have an idea.
Code:
from tkinter import *
def a():
if spin.get()==2:
print("Hello World")
root = Tk()
root.geometry('300x100')
spin =Spinbox(root, from_=0, to=10,command=a)
button = Button(root, text='Enter')
button.pack(side=RIGHT)
spin.pack(side=RIGHT)
root.mainloop()
Adding to #coolCloud's answer I would suggest setting a textvariable for spinBox. So if the user changes it using the entry. It would automatically be updated.
Something like this:
from tkinter import *
def a(*event):
if text.get()=='2':
print("Hello World")
root = Tk()
root.geometry('300x100')
text = StringVar()
text.trace('w', a) # or give command=a in the button if you want it to call the event handler only when the button is pressed
spin =Spinbox(root, from_=0, to=10, textvariable=text)
button = Button(root, text='Enter')
button.pack(side=RIGHT)
spin.pack(side=RIGHT)
root.mainloop()

Checkbutton on tkinter retains it's value no matter what

I'm trying to get the value from Checkbutton on tkinter but it retains the original value. I have tried what people say on countless forums including this one but nothing works, it just retains the value i give it with var.set(True) or var.set(False). This chechbutton is on a pop up window btw, but it's not global, it's just defined on said window. this is my code:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
root.geometry('500x500')
var = tk.BooleanVar()
var.set(False)
startup = tk.Checkbutton(root, variable=var, onvalue=True, offvalue=False , text = "test")
when ver i use var.get() i get the initial value. help me plz :( Thanks in advice.
The reason is because Checkbutton requires a callback function to change the state of the button.
def toggle(button):
if button.get() is True:
button.set(True)
else:
button.set(False)
The you would use the callback function in the instantiation of the Checkbutton
startup = tk.Checkbutton(root, variable=var, text = "test",
command=lambda button=var: toggle(button))

OptionMenu widget not updating when StringVar is changed until hovered

I need a menu that can respond to items being clicked by running code then switch the text back to a default text.
Currently, my implementation works but the default text is only displayed when the cursor hovers over the menu after clicking.
I have searched but I could not find anything related to this problem, although maybe that is because I am unsure as to what exactly is causing this.
Here is the code to reproduce this behaviour:
from tkinter import *
root = Tk()
default_text = 'select an item'
def thing_selected(self, *args):
#other stuff happens here
var.set(default_text)
var = StringVar(root)
var.set(default_text)
var.trace('w', thing_selected)
menu = OptionMenu(root, var, *['Pizza','Lasagne','Fries','Fish'])
menu.pack()
root.mainloop()
Here is a gif representing the outcome:
I would expect the text at the top to be updated instantaneously, but it only updates when the cursor has hovered over the widget
I am looking for some way to trigger a hover event on the widget or I am open to suggestions for any other methods of accomplishing this.
You could take a different route and use the command attribute of the OptionMenu:
import tkinter as tk
root = tk.Tk()
default_text = 'select an item'
def thing_selected(selected):
#other stuff happens here
print(var.get())
var.set(default_text)
print(var.get())
var = tk.StringVar()
var.set(default_text)
options = ['Pizza','Lasagne','Fries','Fish']
menu = tk.OptionMenu(root, var, *options, command = thing_selected)
menu.pack()
root.mainloop()

Cannot type in Python Entry Widget

I've got an interesting problem with the tk Entry widget. If I run the following test code,
from Tkinter import *
root =Tk()
def pfunc(self):
print Input.get()
f=Frame(root)
f.pack()
Input=Entry(f)
#Input.bind("<Return>",pfunc)
Input.pack()
root.mainloop()
I can properly enter into the widget and print to console; however the following code, as part of a larger GUI, does not allow me to click in the Entry boxes at all.
self.Tlabel = Label(self.TempFrame, text="Temp")
self.Tlabel.pack( side = LEFT)
self.Tenter = Entry(self.TempFrame,width=10, bd =5)
self.Tenter.bind("<Return>",self.getFlux)
self.Tenter.pack (side=RIGHT)
self.Flabel = Label(self.FluxFrame, text="Flux")
self.Flabel.pack( side = LEFT)
self.Fenter = Entry(self.FluxFrame, width=10, bd =5)
self.Fenter.bind("<Return>",self.getTemp)
self.Fenter.pack(side = RIGHT)
def getFlux(self):
for i in range(len(self.fit_tuples)):
if self.fit_tuples[i][0]==self.currentBFMdate and self.fit_tuples[i][1]==self.cell.get():
fit_data=self.fit_tuples[i][2]
self.Fenter.set(fit_data[0]*np.exp(fit_data[1]*int(self.Tenter.get())))
else:
self.Fenter.set("Invalid")
def getTemp(self):
for i in range(len(self.fit_tuples)):
if self.fit_tuples[i][0]==self.currentBFMdate and self.fit_tuples[i][1]==self.cell.get():
fit_data=self.fit_tuples[i][2]
self.Tenter.set(np.log(float(self.Fenter.get())/fit_data[0])/fit_data[1])
else:
self.Tenter.set("Invalid")
Furthermore, if I run both codes on a separate windows PC I have the same problem. The only difference I can possibly think of is that I am using instance variables within a class; but it seems that other widgets are bound and working properly.
Basically, the bind method is passing "Return" as a parameter to getTemp. As another user suggested, just add another parameter to the function.
If you use bind method, callback is called with an event object. You should add event parameter to the method/function. (See Events and Bindings - An Introduction to Tkinter )
So, rpelcae following lines:
def getFlux(self, event):
...
def getTemp(self, event):
...
The first program work unintentionally. Its parameter name should be event, not self.

Change command Method for Tkinter Button in Python

I create a new Button object but did not specify the command option upon creation. Is there a way in Tkinter to change the command (onclick) function after the object has been created?
Though Eli Courtwright's program will work fine¹, what you really seem to want though is just a way to reconfigure after instantiation any attribute which you could have set when you instantiated². How you do so is by way of the configure() method.
from Tkinter import Tk, Button
def goodbye_world():
print "Goodbye World!\nWait, I changed my mind!"
button.configure(text = "Hello World!", command=hello_world)
def hello_world():
print "Hello World!\nWait, I changed my mind!"
button.configure(text = "Goodbye World!", command=goodbye_world)
root = Tk()
button = Button(root, text="Hello World!", command=hello_world)
button.pack()
root.mainloop()
¹ "fine" if you use only the mouse; if you care about tabbing and using [Space] or [Enter] on buttons, then you will have to implement (duplicating existing code) keypress events too. Setting the command option through .configure is much easier.
² the only attribute that can't change after instantiation is name.
Sure; just use the bind method to specify the callback after the button has been created. I've just written and tested the example below. You can find a nice tutorial on doing this at http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
from Tkinter import Tk, Button
root = Tk()
button = Button(root, text="Click Me!")
button.pack()
def callback(event):
print "Hello World!"
button.bind("<Button-1>", callback)
root.mainloop()

Categories

Resources