When programming with tkinter I have found a very strange behaviour of the Checkbutton widget. I have re-created the bug with the code below:
import tkinter
from tkinter import *
def displayWelcomeScreen(root):
root2 = Toplevel(root)
root2.geometry('600x380')
root2.focus_set()
Checked = IntVar()
CheckButton1 = Checkbutton(root2, variable=Checked)
CheckButton1.place(relx=0.5, rely=0.5, anchor=CENTER)
CheckButton1.select()
# Create a dummy button that makes the Checkbutton appear checked to the user
#Button(root2, command= lambda event: Checked.get())
root = Tk()
root.geometry('700x400')
displayWelcomeScreen(root)
root.mainloop()
When a new window is created with Toplevel(root) and I put a Checkbutton inside it, it does not appear checked to the user even though I use the .select() method.
However, when I create a dummy button whose command mentions the IntVar associated with my Checkbutton, somehow it is initialised as checked properly. It's almost as if the compiler checks whether the Checkbutton will be useful and decides based on that whether it will display it as selected or not.
EDIT: The Checkbutton is definitely checked under the hood because if I run print(Checked.get()) before and after the CheckButton1.select() command, the value is changed, it just doesn't appear to the user.
Does anyone know why this happens?
EDIT 2: Thanks to jasonharper's explanation, I have added the line CheckButton1.intvar = Checked and it worked without needing the dummy button. When the function went out of scope, the Checked variable got lost so the Checkbutton had nowhere to store its state, therefore we needed to keep a reference to it so it didn't disappear.
Related
I bring up here a problem, that's been there for ages, but is obviously still not solved and older workarounds don't work on my Python 3.7.2 (64-bit on Win10).
I have this code:
import tkinter as tk
import tkinter.simpledialog
# message box to enter a value where to set the scale to
class EnterValueBox(tk.simpledialog.Dialog):
def body(self, master):
self.e = tk.Entry(self, width=10)
self.e.pack(pady=5)
return self.e # initial focus
def apply(self):
print(self.e.get())
# callback to open message box
def enterValue(event):
EnterValueBox(root, title="Enter Value 0..100")
# create window with scale widget
root = tk.Tk()
scale = tk.Scale(root, orient=tk.HORIZONTAL, from_=0, to=100)
scale.pack()
# unbind any button-3 events
scale.unbind("<ButtonPress-3>")
scale.unbind("<ButtonRelease-3>")
scale.unbind("<Button-3>")
# bind button-3 press event to open message box
scale.bind("<ButtonPress-3>", enterValue)
tk.mainloop()
It creates a window with a single scale widget. I want to bind ButtonPress-3 to open a little dialog to directly enter a new value. The code only prints that value to the shell, but the example shows, that the unbind is not working, because after printing the value, the dialog box is closed (when the user clicks OK) and then the default binding is executed, which sets the slider, where the user clicked in the trough of the slider widget.
I tried the workaround from Deleting and changing a tkinter event binding with a PatchedScale widget (instead of the PatchedCanvas shown there), but that didn't make any difference.
Any help would be greatly appreciated!
The default bindings are not on the widget, they are on the widget class. Calling unbind on a widget for which there is no widget-specific binding won't have any effect.
If you don't want the default binding to run after your widget-specific binding, the normal technique is to have your bound function return the string break.
def enterValue(event):
EnterValueBox(root, title="Enter Value 0..100")
return "break"
Please kick here to see the current output and expected output
I have a simple python program where i want to deselect the checkbutton by default. I want to see it the same way as when a user unchecks a tick box. Please let me know how to achieve it.
from tkinter import *
from tkinter import ttk
def urgentReq():
global box
state = box.state()
if(box.instate(['selected'])):
print ("--> Urgent: ",state)
else:
print ("--> Not Urgent:",state)
gui = Tk()
gui.title("GUI")
gui.geometry('200x150')
box = ttk.Checkbutton(gui, text ='Urgent Request', command=lambda: urgentReq())
box.grid(column=1, row=4, pady=40, sticky="N")
#write something here to unselect the box by default
box.state(['!alternate']) #box appear unchecked
box.state(['selected']) #box appear checked
Use the .invoke() method, but from what I read elsewhere is will also call the command, if one is associated. The instance I was trying to use this, my check button didn't have a command as a parameter, so this worked perfectly for me.
Hope this helps and good luck!
Somehow the initial state of the CheckButton = ('alternate',).
There is a workaround I found here: tkk checkbutton appears when loaded up with black box in it. If you apply it to your code like this, it seems to work:
checkVar = IntVar()
box = ttk.Checkbutton(gui, text ='Urgent Request', command=lambda: urgentReq(), variable=checkVar)
I think you can write box.deselect() to deselect it.
Edit: Oops, I just tested it, it's not working with ttk... Sorry. :)
goal
To understand how the check button works in a Tkinter menu. Especially how the value of the variable associated is changed and when the function mentioned in the command is called.
code
I have the following checkbutton that I have added to a Tkinter menu:
window = Tk()
shown = BooleanVar()
shown.set(True)
menubar = Menu(window)
optionsmenu = Menu(menubar,tearoff=0)
optionsmenu.add_checkbutton(label='Show timing after the run is completed',command=PopUp,variable=shown,onvalue = True,offvalue = False)
For simplicity the on value of the check button is true and the off value is false.
what I want to know:
Is the value of the variable changed when the check button is pressed or is the function called and the value of the variable needs to be changed explicitly?
Is the command executed before the variable is toggled or after it has been toggled??
specs
Windows XP SP3
Python 2.7
Please help me with this doubt.
The answers to your questions are as so:
Yes the variable is changed when the check button is pressed. That is the normal behavior of the check button widget.
The command is called after the value of the variable has been toggled from on to off or vice versa whatsoever be the case.
Specs:
Python2.7.1
Tkinter (Tk version 8.5)
Windows7
IDLE 2.7.1
I'm coding a program that 'spawns' two windows, withdraws both, destroys one and then deiconifies the other (which then enters a mainloop).
This arrangement is interfering with a Checkbutton on the remaining window.
eg:
temp = Tk()
temp.withdraw()
root = Tk()
root.withdraw()
temp.destroy()
root.mainloop()
(It seems unusual, but it is set up this way so that the 'temp' window will display the problems that arose, during building of the root window).
However,
it seems that as soon as a single program deals with two Tkinter windows,
functionality of a Checkbutton (in root) goes out the window.
def ClickAButton():
print Toggle.get()
Toggle = IntVar()
Checkbutton(root, text = "Me is broke", variable = Toggle).pack()
ClickAButton
Toggle.get() should return a 1 if the Checkbutton is ticked, otherwise a 0.
However, since adding the new window, Toggle.get always returns a 0.
(I've tried reformatting code {this brings up strange erros of it's own},
renaming variables, etc.
The Checkbutton works just fine without the 'temp' window.
The 'temp' window is destroyed before the Checkbutton is even assigned, packed,
or 'root' even enters a mainloop!)
Entire eg:
temp = Tk()
temp.withdraw()
root = Tk()
root.withdraw()
if 'certain condition':
root.destroy()
temp.deiconify()
temp.mainloop()
else:
temp.destroy()
Toggle = IntVar()
Checkbutton(root, text = "Why I only return 0?", variable = Toggle).pack()
root.deiconify()
root.mainloop()
For some reason,
the Checkbutton is always returns 0, even when checked.
I suspect it's a multi-threading issue with Tkinter.
Is there anything at all I can do here?
(The actual coding is HUGE. I'm not eager to switch it all to another GUI module)
:|
Greatly appreciated!
(I only started programming the start of this year.
Please forgive me if I've made some horribly noobish mistake!)
Tkinter isn't designed to have two root windows. I'm amazed your code works at all. This has nothing to do with multi-threading -- Tkinter is single threaded and you don't appear to be creating any new threads (though if you are, that might contribute to the problem)/
You need to create a single root window with a single mainloop. If you need another window, create a Toplevel window -- that's precisely what that widget is for.
I'm trying to associate a variable with a Tkinter entry widget, in a way that:
Whenever I change the value (the "content") of the entry, mainly by typing something into it, the variable automatically gets assigned the value of what I've typed. Without me having to push a button "Update value " or something like that first.
Whenever the variable gets changed (by some other part of the programm), I want the entry value displayed to be adjusted automatically. I believe that this could work via the textvariable.
I read the example on http://effbot.org/tkinterbook/entry.htm, but it is not exactly helping me for what I have in mind. I have a feeling that there is a way of ensuring the first condition with using entry's "validate". Any ideas?
I think you want something like this. In the example below, I created a variable myvar and assigned it to be textvariable of both a Label and Entry widgets. This way both are coupled and changes in the Entry widget will reflect automatically in Label.
You can also set trace on variables, e.g. to write to stdout.
from tkinter import *
root = Tk()
root.title("MyApp")
myvar = StringVar()
def mywarWritten(*args):
print "mywarWritten",myvar.get()
myvar.trace("w", mywarWritten)
label = Label(root, textvariable=myvar)
label.pack()
text_entry = Entry(root, textvariable=myvar)
text_entry.pack()
root.mainloop()