我是 python 的新手,正在學習在 Windows 中制作一些基本的 tkinter 應用程式。我定義了一個選單欄并向其添加了一個選單。然后在這個選單中添加了多個標簽,但是當我點擊選單中的任何一個按鈕時,所有的命令都運行了,我想知道如何只運行被點擊的選單?
MWE
(問題:無論我點擊哪個選單,它都會運行所有選單標簽)
import tkinter as tk
from tkinter import ttk,messagebox
def show_child_win(win,text=''):
win_child = tk.Toplevel(win)
var_l1 = tk.StringVar()
l1 = tk.Label(win_child,textvariable=var_l1)
l1.grid(row=0, column=0)
var_l1.set(text)
win_child.after(3*1000,lambda: win_child.destroy())
win = tk.Tk()
menubar = tk.Menu(win)
menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Scripts", menu=menu)
dict_label_func = {
'function_01': lambda win: show_child_win(win,text='function_01'),
'function_02': lambda win: show_child_win(win,text='function_02'),
'last_function': lambda win: show_child_win(win,text='last_function')
}
for label, func in dict_label_func.items():
menu.add_command(label=label,command = lambda x=win: func(x))
win.config(menu=menubar)
win.mainloop()
如何讓代碼只運行它應該做的功能?
uj5u.com熱心網友回復:
問題出在您的lambda功能上,我認為您無法理解 和 之間的func區別func()。
abcd基本上代表一個可以呼叫的函式。
abcd()實際上是在呼叫該abcd函式。
lambda舉止像abcd,所以不需要做abcd: abcd()。
這是代碼的更正部分:
dict_label_func = {
'function_01': lambda: show_child_win(win, text='function_01'),
'function_02': lambda: show_child_win(win, text='function_02'),
'last_function': lambda: show_child_win(win, text='last_function')
}
for label, func in dict_label_func.items():
menu.add_command(label=label,command = func)
請參閱本教程中有關函式和lambda的內容。
uj5u.com熱心網友回復:
根據@Henry 的評論,
以下代碼對我有用:
command = lambda f=func: f(win)
uj5u.com熱心網友回復:
所有三個選單項只運行最后一個函式版本的問題的原因是 Python 中可變值賦值背后的機制,在該機制中,變數不是在可變物件后面分配實際當前值,而是保存物件本身,該物件本身的值可能會改變是什么導致了意想不到的副作用。
這是一個常見的混淆來源,不僅對于初學者來說,當回圈結束后,在每次迭代中分配不同值的不同物件在回圈退出后,所有相同的值都分配給最后一次回圈迭代中的最后一個值(在你的情況下所有這三個“不同”的功能都只是最后一次回圈迭代中分配的第三個功能)。
編程成功的最佳途徑是通過干凈簡單的代碼結構設計來解決此類問題。在沒有必要的地方使用回圈進行三次迭代和 lambda 只會使代碼更加復雜和難以維護。
遵循此指導規則以獲得更好的代碼設計會導致顯式創建不同的函式來處理不同的選單條目。這樣就沒有回圈,沒有 lambda,并且以正確的方式獲得它也沒有麻煩。這里好的副作用是代碼變得更好可讀和可維護,因為您可以從代碼中輕松地看到哪個函式處理哪個事件,而無需查看回圈做什么或哪些專案實際存盤在字典中或關于什么是 lambda 函式的原因實際上會做。
下面的代碼消除了回圈和 lambda,因此不需要字典。我建議在這種代碼設計的基礎上進一步編程,而不是尋找修復不必要的復雜代碼的方法:
import tkinter as tk
from tkinter import ttk,messagebox
def show_child_win(win,text=''):
win_child = tk.Toplevel(win)
var_l1 = tk.StringVar()
l1 = tk.Label(win_child,textvariable=var_l1)
l1.grid(row=0, column=0)
var_l1.set(text)
win_child.after(3*1000,lambda: win_child.destroy())
win = tk.Tk()
# ^ -- create window and use it as default
# parameter value --v
def show_child_win_1(win=win,text='function_01'):
show_child_win(win,text)
def show_child_win_2(win=win,text='function_02'):
show_child_win(win,text)
def show_child_win_l(win=win,text='last_function'):
show_child_win(win,text)
# ^-- create different functions handling different menu entries
menubar = tk.Menu(win)
menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Scripts", menu=menu)
menu.add_command(label='function_01' ,command = show_child_win_1)
menu.add_command(label='function_02' ,command = show_child_win_2)
menu.add_command(label='last_function',command = show_child_win_l)
win.config(menu=menubar)
win.mainloop()
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/536899.html
上一篇:當按下其中任何一個時,在for回圈中創建的Tkinter單選按鈕更改為相同的值
下一篇:每次我運行這個函式時它越來越慢
