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 5 years ago.
I tried to create a window with a button that creates another window.
m = Tk()
def new(a,b):
r = Tk()
r.geometry(str(a) + "x" + str(b) + "+0+0")
b = Button(m, text="Click", command=new(100,300)).place(x=0,y=0)
m.mainloop()
Instead of getting a window with a button i get two without clicking the button.
The two windows.png
What did i do wrong?
You're calling new as you construct the Button (technically, before you construct the Button since new must finish running so its return value can be passed as the command argument), not passing it as a callback to invoke on click.
You need to pass a (no argument) callable as the command without calling it, e.g. using a lambda to wrap your new call and thereby defer it until the lambda is called:
b = Button(m, text="Click", command=lambda: new(100,300)).place(x=0,y=0)
Inside of your Button call you're called the new function. That function is creating a new instance of Tk. This is why you have two windows opening.
Assuming you want to run the geometry operation on the first Tk instance, just pass the Tk object into your new function.
You can do it like so:
from tkinter import *
m = Tk()
def new(a, b, r):
r.geometry(str(a) + "x" + str(b) + "+0+0")
b = Button(m, text="Click", command=new(100, 300, m)).place(x=0, y=0)
m.mainloop()
Related
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 9 months ago.
Good day everyone. I've been baffled dealing with my python code. Im using Tkinter for my GUI for our individual school project.
I have this code as a window (for my Create menu in menu bar in main.py) on another file (let's say functions.py):
def createNew(coord):
#create a new window element
createWindow = tk.Tk()
createWindow.title("Create a new tracker")
createWindow.geometry("350x400")
createWindow.focus_force()
createWindow.grab_set()
x = coord[0]
y = coord[1]
createWindow.geometry("+%d+%d" % (x + 250, y + 200))
The above code has that coord argument which receives the input from main.py with this code (the functions.py is imported as funct):
parentPosition = [window.winfo_x(), window.winfo_y()]
...
menubar = tk.Menu(window)
#file menu
file = tk.Menu(menubar, tearoff=0)
file.add_command(label='Create new tracker', command=funct.createNew(parentPosition))
My problem is that whenever I execute the main.py, this window from functions.py automatically shows up even though I didn't select the Create menu from main.py. The intended location is correct anyway.
Actual snapshot of the UI
What is the issue within my code? Any insights would be appreciated.
PS. I intentionally put the function createNew in functions.py rathen than on main.py
You execute the function immediately when you run the line
file.add_command(label='Create new tracker', command=funct.createNew(parentPosition))
This is because, by putting a pair of brackets after the function name, you call it right away, and pass its return value to the add_command function.
In order to get around this, you can use the lambda keyword to delay execution of the function until it is called again:
file.add_command(label='Create new tracker', command=lambda: funct.createNew(parentPosition))
You can find out more about lambda functions here.
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
How to pass arguments to a Button command in Tkinter?
(18 answers)
Closed 2 years ago.
I was creating a sort of button-based paint with tkinter, so I wanted to give every button a command to paint itself.
for i in range(xc*yc):
grid.append(Button(wn,text=" ",bg="white",padx=5,pady=5))
grid[-1].config(command = paint(i)) <--????
grid[-1].place(x= (i%xc) * 30 +60, y = (math.floor(i/xc) * 30)+30)
The problem is that every button recieves the command "paint(i)" with the final value of i, so everytime it paints the last button
Use root.update() method forecefully updates UI.so you can use that to see every iteration of for loop , if you call it inside that
Maybe something like
for i in range(xc*yc):
button = Button(wn,text=" ",bg="white",padx=5,pady=5)
grid.append(button)
button.config(command = paint(i, button)) # note the additional reference to button here!
button.place(x= (i%xc) * 30 +60, y = (math.floor(i/xc) * 30)+30)
would be helpful.
This question already has answers here:
tkinter creating buttons in for loop passing command arguments
(3 answers)
How to pass arguments to a Button command in Tkinter?
(18 answers)
Closed 6 months ago.
how to change values in buttons done in a loop?
I mean a different text, a command for each of the resulting buttons.
the program counts files in a given folder, then this value is passed to the loop that displays the appropriate number of buttons.
here is the sample text:
files = os.listdir(".")
files_len = len(files) - 1
print(files_len)
def add():
return
for i in range(files_len):
b = Button(win, text="", command=add).grid()
You don't really need to change the Button's text, because you can just put the filename in when they're created (since you can determine this while doing so).
To change other aspects of an existing Button widget, like its command callback function, you can use the universal config() method on one after it's created. See Basic Widget Methods.
With code below, doing something like that would require a call similar to this: buttons[i].config(command=new_callback).
To avoid having to change the callback function after a Button is created, you might be able to define its callback function inside the same loop that creates the widget itself.
However it's also possible to define a single generic callback function outside the creation loop that's passed an argument that tells it which Button is causing it to be called — which is what the code below (now) does.
from pathlib import Path
import tkinter as tk
win = tk.Tk()
dirpath = Path("./datafiles") # Change as needed.
buttons = []
def callback(index):
text = buttons[index].cget("text")
print(f"buttons[{index}] with text {text!r} clicked")
for entry in dirpath.iterdir():
if entry.is_file():
button = tk.Button(win, text=entry.stem,
command=lambda index=len(buttons): callback(index))
button.grid()
buttons.append(button)
win.mainloop()
Try this. By making a list.
files = os.listdir(".")
files_len = len(files) - 1
print(files_len)
def add():
return
b=[]
for i in range(files_len):
b[i] = Button(win, text="", command=add).grid(row=i)
This question already has answers here:
How to pass arguments to a Button command in Tkinter?
(18 answers)
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 4 years ago.
Im trying to get this Listbox in tkinter to update from a sqlite3 database when a button is clicked. I actually had it working using root.after(1000, function) method but the cursor kept resetting every time it was updated.
At the moment I can't get the listbox to populate at the button click.
I would love any help. Thanks!
root=Tk()
ListBox1 = Listbox(root)
ListBox1.grid(row=0, column=0 , sticky='nsew')
def ListUpdate():
listlist = []
#populates list from sql database in a for loop
return listlist
def ListPopulate(listlist):
ListBox1.delete(0, END)
for i in range(0,len(listlist[i]):
ListBox1.insert(END, listlist[i])
ButtonUpdate = Button(root, text='Update', command=ListPopulate(listlist))
ButtonUpdate.grid(row=5, column=6, sticky='nsew')
You're using command wrong. Replace:
Button(..., command=ListPopulate(listlist))
with:
Button(..., command=lambda l=ListUpdate(): ListPopulate(l))
Your command= argument for your Button calls ListPopulate(listlist) when the button is created and assigns its result (which is None, since you don't return anything from that function) as the command. You have therefore told the Button object that it has no command.
You're naturally going to run into problems passing the list to all the places it needs to go in an event-driven system. One approach is to make the list ListList a global variable. Define it outside all your functions at the top of the script, with your other variables:
ListBox1 = Listbox(root)
ListBox1.grid(row=0, column=0 , sticky='nsew')
listlist = []
Next, change the first line of ListUpdate() to use a slice assignment to empty out the existing list object, so you don't need to declare the object global in that function.
def ListUpdate():
listlist[:] = []
Then change ListPopulate() to take no arguments, since it's going to use the global listlist.
def ListPopulate():
Finally, write your Button() constructor to pass ListPopulate rather than calling it.
ButtonUpdate = Button(root, text='Update', command=ListPopulate)
Globals are generally bad practice. What you probably should do is subclass Listbox and give it an attribute that holds the list. Then your two functions would be methods of that class. (In fact, you probably want to update the displayed list on screen every time you change its contents... so you should have one method, not two.) I'll leave that as an exercise for when you learn object-oriented programming.
This question already has answers here:
All tkinter functions run when program starts
(2 answers)
Closed 7 years ago.
I'm very new to python's tkinter gui and I am trying to use it to build a basic test.
I created the menu where one of the menu items must call a function although when I run the program I can see the output from the function before the menu item has been clicked and when the menu item is clicked it does not call the function.
My code is as follows
from tkinter import *
class cl_main():
def __init__(self, master):
lo_mainmenu = Menu(master)
lo_mainmenu.option_add('*tearOff', FALSE)
master.config(menu=lo_mainmenu)
lo_menugroup = Menu(lo_mainmenu)
lo_mainmenu.add_cascade(label="MenuGroup")
lo_menugroup.add_command(label="Command", command=f_message())
def f_message():
print ("This Function Has Been Called")
root = Tk()
co_main = cl_main(root)
root.mainloop()
I can't see what is wrong with it but I'm sure there is something horribly wrong here
lo_menugroup.add_command(label="Command", command=f_message())
callbacks shouldn't have parentheses. As it is, f_message is called right away and its return value is assigned to command, rather than the function object itself.
lo_menugroup.add_command(label="Command", command=f_message)