I used for loop to create buttons in tkinter. And wanna apply an event on all the created button. Event is like, when I click on button its bg color should change and won't back to normal until I click back on it. But in my code color of last button is changing only.
def button_Clicked(e):
bij['bg'] = 'red'
for i in range (0,8):
for j in range (0,8):
bij = tk.Button(compFrame, width = 10, height=4)
bij.grid(row = i, column = j, padx = 5, pady = 5)
bij.bind("<Button-1>", button_Clicked)
Is there any way that I can connect all the buttons with event that if I clicked on any button then only its color should change not of the last one or any others.
Updated Answer:
As #Thingamabobs pointed out, it's possible to get the button via e.widget in button_Clicked function via the event object e. Thus, it's not necessary to pass the button object to the function.
def button_Clicked(e):
button = e.widget
# toggle between 'red' and default color
if button['bg'] != 'red':
button['bg'] = 'red'
else:
button['bg'] = 'SystemButtonFace'
for i in range(0, 8):
for j in range(0, 8):
bij = tk.Button(compFrame, width=10, height=4)
bij.grid(row=i, column=j, padx=5, pady=5)
bij.bind("<Button-1>", button_Clicked)
root.mainloop()
Old Answer:
You need to bind the event inside the loop. Right now, bij is outside the loop, so it's only the last button.
To make sure the event changes color for the correct button, you need to add an argument to button_Clicked
To change toggle the background color on each click, it's necessary to add a condition in button_Clicked
def button_Clicked(e, button):
# toggle between 'red' and default color
if button['bg'] != 'red':
button['bg'] = 'red'
else:
button['bg'] = 'SystemButtonFace'
for i in range (0,8):
for j in range (0,8):
bij = tk.Button(compFrame, width = 10, height=4)
bij.grid(row = i, column = j, padx = 5, pady = 5)
bij.bind("<Button-1>", lambda event, bij=bij: button_Clicked(event, bij))
As #BryanOakley rightly point out, it's necessary to use the trick
lambda event, bij=bij: button_Clicked(event, bij)
to make sure the lambda closure uses the current bij value in the loop.
Alternatively, it's possibly cleaner to use functools.partial for the last line
from functools import partial
...
bij.bind("<Button-1>", partial(button_Clicked, button=bij))
Related
When user write what they want.I want the entry bubble to disappear when you move the mouse over it.When mouse is back at the entry it should be visible can I do that in tkinter?
def change_background(event):
pos = event.widget
if pos['bg'] == 'red':
pos['bg'] = 'white'
else:
pos['bg'] = 'red'
entry = tk.Entry(line_1_tk, font='Times 13 bold')
entry.pack()
entry.place(x=pos.winfo_x() + 10, y=pos.winfo_y() + 30)
def on_focusout(event):
entry.pack_forget()
def on_enter_press(event):
entry.pack_forget()
entry.bind("<FocusOut>", on_focusout)
entry.bind("<Return>", on_enter_press)
it didn't work
then I try bind with mouse it didn't work either
But I need that user data for later
that entry like a notepad
Any idea works for me
Thank you for your interest.
I have a for loop initiating buttons in a grid, and I want the buttons state to togglable, instead of turning off once the mouse button is no longer held. I also need that to know which button called the buttons' function, because I'm initializing a number of them in the same for loop, meaning they all call the same function once activated, anyone know how to help me?
EDIT:
minimal working example:
import tkinter as gui
def createWindow():
window = gui.Tk()
window.title("GoL")
icon = gui.PhotoImage(file='Not showing ya\'ll my files.png')
window.iconphoto(True, icon)
window.config(background="black")
label = gui.Label(window,\
text="Generation:",\
bg="black",\
fg="white",\
font=("Consolas",20))
label.pack()
return window
def newBoard(x = 10,y = 10):
window = createWindow()
for i in range(0, y):
for j in range(1, x+1):
button = gui.Button(window,bg="black",height=1,width=2,command=changeState)
button.place(x=23*(j-1),y=23*(i+2))
window.mainloop()
what I want is the function changeState to change the
You can achieve this by keeping a list of buttons (buttons), then using a lambda function to pass the row/column number to the button command function, which then allows you to change the properties of the selected button. In this case it toggles between black and white background colours.
def changeState(i, j):
global buttons
b = buttons[i][j]
b.config(bg = "white") if b.cget("bg") != "white" else b.config(bg = "black")
def newBoard(x = 10,y = 10):
global buttons
window = createWindow()
buttons = []
for i in range(0, y):
row = []
for j in range(1, x+1):
button = gui.Button(window,bg="black",height=1,width=2,command=lambda i=i, j=j-1: changeState(i,j))
row.append(button)
button.place(x=23*(j-1),y=23*(i+2))
buttons.append(row)
window.mainloop()
I want the color of neighbouring buttons to change when I click a button. I am making a GUI in tkinter for a 19x19 boardgame. Imagine something like mindsweeper, so the entire board consists of Buttons. I am using python 3.7
Here is my code for a simple 1x2 playing field.
import tkinter as tk
def do_something(p):
p.configure(bg = 'blue')
def personal_do_something(p):
p.configure(bg = 'blue')
p1.configure(bg = 'blue')
window = tk.Tk()
frame = tk.Frame(master = window)
frame.pack()
p1 = tk.Button(master = frame, width = 10, height = 5, bg = 'orange', command = lambda:do_something(p1))
p2 = tk.Button(master = frame, width = 10, height = 5, bg = 'khaki', command = lambda:personal_do_something(p2))
p1.pack(side=tk.LEFT)
p2.pack(side=tk.LEFT)
window.mainloop()
starting situation:
click p1:
click p2:
When p1 is clicked, only p1 turns blue, but not its neighbour p2. when p2 is clicked both p1 and p2 turn blue. This however only works because p2 has a personal_do_something() function. In this function I explicitly tell p1 to turn blue. This might be a viable method for a small 1x2 board, but I can't write personal functions for every button when there are 19x19 buttons. Does anyone have any clue how I could write 1 general function that always turns the direct neighbours blue? I assume I would have to add some kind of attribute to a button, for example a coordinate, and then search all the buttons that match neighbouring coordinates or something like that. But I have no clue how.
Thanks in advance :)
You can store the references of those buttons in a 2D list and pass the row and col of the clicked button to do_something() function. Then you can update the background color of those buttons based on passed row and col.
Below is an example based on your code:
import tkinter as tk
def do_something(row, col):
buttons[row][col].config(bg="blue")
# change direct connected buttons (left, right, up, down)
for dir in (-1, +1):
if 0 <= row+dir < len(buttons):
buttons[row+dir][col].config(bg="blue")
if 0 <= col+dir < len(buttons[row]):
buttons[row][col+dir].config(bg="blue")
window = tk.Tk()
frame = tk.Frame(window)
frame.pack()
ROWS = 10
COLS = 10
buttons = [[None]*COLS for _ in range(ROWS)] # for storing references of buttons
for row in range(ROWS):
for col in range(COLS):
buttons[row][col] = tk.Button(frame, width=10, height=5, bg="orange", command=lambda r=row,c=col: do_something(r,c))
buttons[row][col].grid(row=row, column=col, sticky="nsew")
window.mainloop()
I am creating a GUI with a ".grid" of buttons. And I want to make each of those buttons display a different image on press. So when I click button 1, it will bring up "image1", on the bottom of the buttons. When I click button 2, it will bring up "image2" and etc.
Through some research, I was able to make the buttons run a function that takes in a parameter through the method below. However, I can't seem to make the button display the image. rather, it just makes an empty white space underneath the buttons, when I press any buttons.
Disclaimer:
- I do not want there to be loads of images, there will only be 1 image, and it will change depending on what button i press.
Here's the code:
from tkinter import *
def funct(numimg):
image = PhotoImage(file="image"+str(numimg)+".png")
label = Label(image=image)
label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)
def make_funct(number):
return (lambda: funct(number))
root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 6
for x in range(0, numfiles):
if(x % num_of_cols is 0):
row_no+=1
buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13,command = make_funct(x)))
buttons[x].grid(row = row_no, column = x % num_of_cols)
root.mainloop()
So my question is, how do you make each individual button, display a different image when it is pressed? this program right here just leaves an empty white space in replace of the image, and the image is not shown.
There are two major problems with the code you posted.
The first is basically the same as in this question: Why does Tkinter image not show up if created in a function?. You should keep a reference to the PhotoImage object, else it will be garbage collected and it will not show.
The second is that you create a new Label on every button click. You should only make one Label and change the image with the label.config() method.
I would (without wrapping your GUI in a class, which might be a nicer solution) load all images on initialization, save them in a list as attribute of the label and only change the image upon a button click.
I also removed your make_funct function and replaced it with a lambda, which is the most used way to pass variables to a function on callback.
from tkinter import *
def funct(numimg):
label.config(image=label.images[numimg])
root= Tk()
row_no = -1
buttons = []
num_of_cols = 3
root.resizable(0, 0)
numfiles = 3
for x in range(0, numfiles):
if(x % num_of_cols is 0):
row_no+=1
buttons.append(Button(root, text = "Button "+str(x), bg = '#4098D3', width = 30,height = 13, command = lambda n=x: funct(n)))
buttons[x].grid(row = row_no, column = x % num_of_cols)
label = Label(root)
label.grid(row = row_no+1, column = 0, columnspan = num_of_cols)
label.images=[]
for x in range(0, numfiles):
label.images.append(PhotoImage(file="image"+str(x)+".png"))
root.mainloop()
I understand that you can make a button that can do some actions when clicked with Tkinter, but how can I just make a button that turns from one color to another when clicked? Then, from that, how do I replicate that button to make a grid of them? I would also settle for a grid of buttons that just change from one character to another.
import Tkinter
color="red"
default_color="white"
def main(n=10):
window = Tkinter.Tk()
last_clicked = [None]
for x in range(n):
for y in range(n):
b = Tkinter.Button(window, bg=default_color, activebackground=default_color)
b.grid(column=x, row=y)
# creating the callback with "b" as the default parameter bellow "freezes" its value pointing
# to the button created in each run of the loop.
b["command"] = lambda b=b: click(b, last_clicked)
return window
def click(button, last_clicked):
if last_clicked[0]:
last_clicked[0]["bg"] = default_color
last_clicked[0]["activebackground"] = default_color
button["bg"] = color
button["activebackground"] = color
last_clicked[0] = button
w = main()
Tkinter.mainloop()