#python #tkinter
#python #tkinter
Вопрос:
Я пытаюсь создать функцию, которая автоматически создает кнопки. Это я сделал легко, но как мне создать эти кнопки в цикле, у которых есть специальное имя, чтобы при нажатии кнопки функция знала, какая кнопка нажата, и могла изменить ТЕСТ этих кнопок? До сих пор я ставил
from tkinter import Tk, Label, Button
import random as rdn
x_user = 'X'
o_user = 'O'
window = Tk()
window.resizable(False, False)
def button_pressed():
Button = 'Test'
for rows in range(3):
button_number = 1
for colums in range(3):
Button (window, text='-', width='5', height='5', command=button_pressed) .grid(row=rows, column=colums)
button_number = 1
window.mainloop()
Ответ №1:
Я бы сказал, что это ограничение tkinter в том, что при нажатии кнопки выполняемая функция не даст вам представления о том, что ее вызвало.
Однако в Python вы можете сгенерировать функцию «на лету», чтобы обойти это ограничение. Мой пример заключается в следующем:
def sayit(s):
def f():
print("Button %s is pressed" % s)
return f
for rows in range(3):
button_number = 1
for colums in range(3):
Button (window, text='-', width='5', height='5', command=sayit(button_number)) .grid(row=rows, column=colums)
button_number = 1
sayit()
Функция принимает один параметр и возвращает функцию, которая не принимает аргумент. Когда я создаю кнопку, я назначаю эту сгенерированную на лету функцию в качестве команды.
Если вы хотите превратить это в игру в крестики-нолики, вам также нужно иметь что-то, что удерживало бы весь текст кнопок и связывало бы его с вашим номером кнопки (например, список), чтобы вы могли сбрасывать текст каждой кнопки при нажатии. Как показано ниже:
from tkinter import Tk, Label, Button, StringVar
import random as rdn
x_user = 'X'
o_user = 'O'
who = 'X'
window = Tk()
window.resizable(False, False)
def click(n):
def f():
global who
buttons[n].set(who)
who = 'O' if who == 'X' else 'X'
return f
buttons = []
button_number = 0
for rows in range(3):
for colums in range(3):
s = StringVar()
s.set("-")
buttons.append(s)
Button(window, textvariable=s, width='5', height='5', command=click(button_number)).grid(row=rows, column=colums)
button_number = 1
window.mainloop()
Ответ №2:
Простой способ — переопределить функцию button_pressed()
, чтобы она принимала параметр, который является кнопкой, на которую нажимают. Затем установите для command
опции кнопки значение lambda
функция, в которой button_pressed()
вызывается сама кнопка в качестве параметра функции. Ниже приведен пример кода:
from tkinter import *
window = Tk()
window.resizable(False, False)
marks = ['X', 'O']
colors = ['red', 'green']
player = 0
def button_pressed(btn):
global player
# change the button text and make it not clickable
btn.config(text=marks[player], disabledforeground=colors[player], state='disabled')
player = 1 - player # change player
for row in range(3):
for col in range(3):
btn = Button(window, text='', font=('', 24, 'bold'), width=3)
btn.config(command=lambda b=btn: button_pressed(b))
btn.grid(row=row, column=col)
window.mainloop()