TKinter buttons and function syntax [duplicate] - python

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 3 years ago.
I'm playing around with TKinter trying to make a number generator.
I can't figure out why a new number doesn't get generated when I use this code:
roll = Button(window, text = 'Roll!', command = num())
But it works if I remove the brackets:
roll = Button(window, text = 'Roll!', command = num)
Thanks guys!
Rest of the code:
from tkinter import *
import random
def num():
number = random.randint(1, 6)
num1.configure(text = number)
return
window = Tk()
window.geometry('300x200')
window.title('Dice')
num1 = Label(window, text = 0)
num1.grid(column = 0, row = 0)
roll = Button(window, text = 'Roll!', command = num)
roll.grid(column = 0, row = 1)
window.mainloop()

When you write num() with the parentheses, you're calling the function immediately, and passing its return value as the argument to Button. When you just name the function, you're passing the function object itself as the argument to Button, and it will call the function later (when the button is clicked).

Related

how do i add stuff to listbox (tkinter python) [duplicate]

This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed last year.
I'm making a log/chat system in my program (just Tkinter default looks) and i came across a problem where I can't add or change a listbox. Here is what I'm trying to do:
import tkinter
from tkinter import *
from tkinter import messagebox
import random
window = tkinter.Tk()
window.geometry("250x195")
window.title(" ")
window.iconbitmap("icon.ico")
global loglength, log
log = []
loglength = len(log)
inventorylist = []
def sendmessage(event):
chatstring = chatentry.get()
log.append(chatstring)
print(log, loglength)
checknew() #dont worry abt this it works
serverlog = tkinter.Listbox(
width=20,
height=11,
bg="darkgray",
listvariable=log
).place(x=128,y=-2)
I want to add items to the listbox. Here is an image of my program:
When I press enter (the key bound to the function to add the string to the listbox) this happens:
is Listbox like a program u want?
if u want a program that will make u program list in tkinder this is the code :
from tkinter import *
a= Tk()
a.geometry("400x400")
a.title("test")
Lb1 = Listbox(a,bg = "pink", bd = 10, fg = "black",\
font = "Castellar", cursor = "target")
Lb1.insert(1, "lion")
Lb1.insert(2, "tiger")
Lb1.insert(3, "zebra")
Lb1.insert(4, "elephant")
Lb1.insert(5, "deer")
Lb1.insert(6, "fox")
Lb1.insert(7, "Wolf")
Lb1.insert(8, "Gorilla")
Lb1.insert(9, "Jackal")
Lb1.insert(10, "Otter")
Lb1.pack()
a.mainloop()
hope that i helped u.

tkinter: checkbox doesn't update in for-loop [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 1 year ago.
I'm stuck on the following problem. With a for-loop, I want to make a few checkboxes that automatically update a label stating whether the checkbox is ticked or not. However, it gives the wrong results (it always says that the checkboxes are ticked, whether this is the case or not; noteworthy is the fact that the checkboxes are unticked by default), see here how the GUI looks like (including error). The IntVars corresponding with the checkboxes are working correctly, as can be seen when ticking at least one of the checkboxes and pressing a button whose function is to read the checkboxes. See also the following code:
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(i): # update label saying if checkboxes are ticked
if checkbox_var[i].get == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes(i))
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()
Could somebody help me with updating the labels? If there is another way to fix this issue, e.g. with buttons to be pressed instead of checkbuttons to be ticked, that would also work for mee.
i is always 2 because you're actually not running any loop after mainloop is started.
The following kind of works but you need to change something about the labels, because right now all labels are just added on top of each other. You should create them once and then just update the text but I'll leave that part for you.
import tkinter as tk
top = tk.Tk()
n_passes = 3
checkbox_var = [0] * n_passes
checkbox = [0] * n_passes
def tick_passes(): # update label saying if checkboxes are ticked
for i in range(n_passes):
if checkbox_var[i].get() == 0:
label = tk.Label(top, text = f"pass #{i} not ticked")
else:
label = tk.Label(top, text = f"pass #{i} ticked")
label.grid(row = 1, column = i)
def check_checkbox_var(): # check whether checkbox_var[i] is updated
for i in range(n_passes):
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
for i in range(n_passes):
print(i)
checkbox_var[i] = tk.IntVar() # turn on/off certain passes
print(f"checkbox_var[i].get() = {checkbox_var[i].get()}")
checkbox[i] = tk.Checkbutton(top, text = f"Tick pass {i}", variable =
checkbox_var[i], command = tick_passes)
checkbox[i].grid(row = 0, column = i, sticky=tk.W)
var_button = tk.Button(top, text = "Check checkbox_var", command =
check_checkbox_var).grid(row = 2, column = 0) # check whether checkbox_var[i] is updated
top.mainloop()

Compare Tkinter entry values as integers only when the entry has text inside of it [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 2 years ago.
I need to do some basic conditional logic on entries, but I am running into an issue.
There are 2 entries, "dosage" and "week". In both will be entered only numbers (25, 3, etc.). I have a "Get Info" button that activates a function what will preform conditional logic on the entries, although since when the program runs there isn't any text inside of the entries, I run into an error.
ValueError: invalid literal for int() with base 10: ''
Here is my code:
from tkinter import *
import tkinter.font as font
# Window setup
root = Tk()
root.title("Dosage GUI")
root.geometry("330x450")
# Entries
weekEntry = Entry(root)
dosageEntry = Entry(root)
# Labels to describe entries
weekLabel = Label(root, text="Week #")
dosageLabel = Label(root, text="Dosage in mg (enter only a number)")
# Information text
# State = disabled, but when changing text, change to normal, then back to disabled
def setInfoText(textBox, text):
textBox.config(state="normal")
textBox.insert(1.0, text)
textBox.config(state="disabled")
infoTextFont = font.Font(size=8)
infoText = Text(root, height=17, width=30, padx=10,pady=10, state="disabled", font=infoTextFont, bd=5,bg="#e8ebea")
# Get Info button
def getInfo(week, dosage):
# Check what is possible based on the dosage rules
if week > 3:
setInfoText(infoText, "PI may change dosage if needed.")
if week < 3:
setInfoText(infoText, "PI cannot change dosage until week 3.")
getInfoFont = font.Font(size=13,weight="bold")
getInfoBut = Button(root, text="Get Info", padx=20,pady=20,bd=10,bg="#7299ed",activebackground="#729ffc", fg="#40e677", command=getInfo(int(weekEntry.get()), int(dosageEntry.get())))
getInfoBut['font'] = getInfoFont
# Grid
weekEntry.grid(row=0,column=5)
dosageEntry.grid(row=0, column=10)
weekLabel.grid(row=5,column=5)
dosageLabel.grid(row=5,column=10)
getInfoBut.place(x=100,y=70)
infoText.place(x=50,y=170)
# mainloop
root.mainloop()
The command keyword argument needs a function as parameter.
Right now you're passing getInfo(int(weekEntry.get()), int(dosageEntry.get())) - which is the return value of getInfo - which is None (because there are no return statements in that function).
Instead, you may want to pass this a statement inside a lambda - this way you create a function that gets called whenever that button is pressed:
getInfoBut = Button(root, text="Get Info", padx=20,pady=20,bd=10,bg="#7299ed",activebackground="#729ffc", fg="#40e677", command=lambda: getInfo(int(weekEntry.get()), int(dosageEntry.get())))
The reason the error occurs is because Python attempts to evaluate the call to getInfo even before the UI shows - the fields weekEntry anddosageEntry are empty at this point - attempting to convert an empty string to an int results in the error.

Tkinter keyboard buttons add letters to Entry [duplicate]

This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
Closed 5 years ago.
I'm trying to write a code for my GUI. I want a keyboard that adds a letter to the Entry widget. I'm close to it but the problem is that its adding to the entry only the letter 'a' when clicking on the buttons .
As you see in my code i added 'a' to the command. command=lambda: set_text('a')
Ofcourse is this the reason why its printing 'a' only. But if i take letter from the forloop and make set_text(letter) its showing only H in the Entry widget.
I try'd also to remove the second loop change it to set_text(lst[count])
All buttons are adding now 'A' to the Entry.
Any idea what i'm doing wrong?
my code:
from tkinter import *
from ttk import *
def maakbuttons():
count = 0
lst = []
if count <= 7:
for letter in 'ABCDEFGH':
lst.append(letter)
for letter in lst:
Buttons = Button(master=root, text=letter, command=lambda: set_text('a'))
Buttons.place(x=20, y=30 +50 * count)
count+=1
def set_text(text):
a = e.get() + text
e.delete(0, len(e.get()))
e.insert(0, a)
def remove_letter():
last = len(e.get())-1
if last >= 0:
e.delete(last)
root= Tk()
a = root.wm_attributes('-fullscreen', 1)
e = Entry(root,width=10)
e.place(x=500, y=500)
maakbuttons()
root.mainloop()
Repalce your line with:
Buttons = Button(master=root, text=letter, command=lambda x=letter: set_text(x))
Also:
for letter in 'ABCDEFGH':
lst.append(letter)
for letter in lst:
...
Seems to be redundant.

Why is the function called before pressing a button? [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 7 years ago.
My program draws the fractal using pointSize_max and pointSize variables, which are entered by the user in Tkinter. The problem is that the fractal is drawn before pressing a button (as soon as the program is run), and the program does not draw the fractal when the button is pressed.
pointLabel = tk.Label(frame,text="minimaalne pikkus")
pointLabel.pack()
pointSize = tk.StringVar()
pointEntry = tk.Entry(frame,textvariable=pointSize)
pointEntry.pack()
pointSize.set(str(10))
pointLabel_max = tk.Label(frame,text="maksimaalne pikkus")
pointLabel_max.pack()
pointSize_max = tk.StringVar()
pointEntry_max = tk.Entry(frame,textvariable=pointSize_max)
pointEntry_max.pack()
pointSize_max.set(str(30))
drawButton = tk.Button(frame, text = "Draw a fractal", command=koch(int(pointSize_max.get()), int(pointSize.get())))
# koch function draws the fractal
drawButton.pack()
tk.mainloop()
The koch function is called when the button is created, as part of the parameter evaluation before the tk.Button call. You can create a function object to call instead.
def koch_invoke():
koch(int(pointSize_max.get()), int(pointSize.get()))
drawButton = tk.Button(frame, text = "Draw a fractal", command=koch_invoke)
When your script is compiled it comes to this line and runs the function since you are calling it:
command=koch(int(pointSize_max.get()), int(pointSize.get()))
Try using a lambda to prevent this from happening:
command= lambda x = int(pointSize_max.get()), y = int(pointSize.get()): koch(x, y))

Categories

Resources