- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个简单的 tkinter 应用程序,现在可以正常工作,但代码写得不好。我的主要问题是,似乎每个 OptionMenu 都需要有自己的 tkvar 和自己的 testFunc 才能让应用程序按照我想要的方式运行。我似乎无法在命令部分调用其他变量,这就是为什么我很难合并这段代码。
该应用程序的目的是允许用户选择动物的顺序并立即显示该顺序。希望有人能为我点亮一盏明灯,让这段代码变得更DRY、更智能。
import tkinter as tk
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("Choose Multiple Animals")
self._frame = None
class AnimalPage(ttk.Frame):
def __init__(self, master, controller):
tk.Frame.__init__(self, master)
self.master = master
self.config(relief='sunken', borderwidth=2)
self.pack(fill = "both", expand = False)
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
self.animalList = ['Cat', 'Dog', 'Bear']
self.choices = ['None', 'Animal1', 'Animal2', 'Animal3']
self.tkvar1 = tk.StringVar(master)
self.tkvar1.set('None')
self.tkvar2 = tk.StringVar(master)
self.tkvar2.set('None')
self.tkvar3 = tk.StringVar(master)
self.tkvar3.set('None')
self.tkvar4 = tk.StringVar()
self.textLabel1 = ttk.Label(self, text=self.animalList[0])
self.textLabel1.grid(column=0, row = 5, sticky = (tk.W), padx=5, pady=5)
self.popupMenu1 = ttk.OptionMenu(self, self.tkvar1, *self.choices, command=self.testFunc1)
self.popupMenu1.grid(column=1, row = 5, sticky = (tk.W, tk.E), padx=5, pady=5)
self.textLabel2 = ttk.Label(self, text=self.animalList[1])
self.textLabel2.grid(column=0, row = 6, sticky = (tk.W), padx=5, pady=5)
self.popupMenu2 = ttk.OptionMenu(self, self.tkvar2, *self.choices, command=self.testFunc2)
self.popupMenu2.grid(column=1, row = 6, sticky = (tk.W, tk.E), padx=5, pady=5)
self.textLabel3 = ttk.Label(self, text=self.animalList[2])
self.textLabel3.grid(column=0, row = 7, sticky = (tk.W), padx=5, pady=5)
self.popupMenu3 = ttk.OptionMenu(self, self.tkvar3, *self.choices, command=self.testFunc3)
self.popupMenu3.grid(column=1, row = 7, sticky = (tk.W, tk.E), padx=5, pady=5)
self.chosenAnimals = {}
self.textLabel4 = ttk.Label(self, text=self.tkvar4.get())
self.textLabel4.grid(column=0, row = 8, sticky = (tk.W, tk.E), padx=5, pady=5)
def testFunc1(self, value):
self.chosenAnimals.update({value: self.animalList[0]})
self.configure()
def testFunc2(self, value):
self.chosenAnimals.update({value: self.animalList[1]})
self.configure()
def testFunc3(self, value):
self.chosenAnimals.update({value: self.animalList[2]})
self.configure()
def configure(self):
self.printout = ["{} is the {}".format(k, v) for (k,v) in self.chosenAnimals.items()]
self.tkvar4.set(self.printout)
self.textLabel4.config(text = self.tkvar4.get())
if __name__ == "__main__":
app = SampleApp()
newFrame = AnimalPage(app, app)
app.geometry("500x200")
app.mainloop()
最佳答案
使用数组或字典:
import tkinter as tk
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.wm_title("Choose Multiple Animals")
self._frame = None
class AnimalPage(ttk.Frame):
def __init__(self, master, controller):
tk.Frame.__init__(self, master)
self.master = master
self.config(relief='sunken', borderwidth=2)
self.pack(fill = "both", expand = False)
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
self.animalList = ['Cat', 'Dog', 'Bear']
self.choices = ['None', 'Animal1', 'Animal2', 'Animal3']
self.animal_vars = dict()
self.text_labels = dict()
self.popup_menus = dict()
self.chosenAnimals = {}
self.tkvar4 = tk.StringVar()
for i, animal in enumerate(self.animalList):
self.animal_vars[animal] = tk.StringVar(master)
self.animal_vars[animal].set('None')
self.text_labels[animal] = ttk.Label(self, text=animal)
self.text_labels[animal].grid(column=0, row = 5 + i, sticky = (tk.W), padx=5, pady=5)
self.popup_menus[animal] = ttk.OptionMenu(self, self.animal_vars[animal], *self.choices, command=lambda selected, my_animal=animal: self.testFunc(my_animal, selected))
self.popup_menus[animal].grid(column=1, row = 5 + i, sticky = (tk.W, tk.E), padx=5, pady=5)
self.textLabel4 = ttk.Label(self, text=self.tkvar4.get())
self.textLabel4.grid(column=0, row = 8, sticky = (tk.W, tk.E), padx=5, pady=5)
def testFunc(self, animal, selection):
self.chosenAnimals.update({animal: selection})
self.configure()
def configure(self):
self.printout = ["{} is the {}".format(k, v) for (k,v) in self.chosenAnimals.items()]
self.tkvar4.set(self.printout)
self.textLabel4.config(text = self.tkvar4.get())
由于您基本上是通过 animalList
进行迭代来动态创建 Label
和 OptionMenu
,因此您不妨使用 dict
或 list
来帮助您管理和迭代对象。
设置好 dict
或 list
后,您现在可以将您创建的 tk 小部件分配/附加到其中并轻松引用。在您的示例中,我个人更喜欢 dict
因为每种动物都有一个有意义的名称,并且更容易调试(查找 self.text_labels['Cat']
会比self.text_labels[0]
)
此外,您还可以利用 lambda 来绕过 tk 小部件中 command=...
的限制。这样您就可以将动物名称直接传递回函数,这样您就不需要为每个动物定义它。
顺便说一句,理想情况下我建议您为对象指定更有意义的名称。远离诸如 textLabel4
或 tkvar4
之类的术语,这样更容易理解代码。
为了让 lambda
在循环中工作,您需要将迭代的 animal
作为默认参数,而不是直接在 lambda
内部,一个快速演示:
def func(v):
print(v)
x = list(range(3))
for i in range(len(x)):
x[i] = lambda: func(i)
x[0]
# 2
您可能期望 x[0]
将导致打印 0
,但实际上它将是 2
,并且它将是x[0:2]
的结果相同。原因是,当 lambda 被赋值时,它在每次迭代中引用 i
对象,而不是它的 [0, 1, 2]
值。因此,自从循环结束后,i = 2
,并且您的x
函数将始终打印2
。
但是,如果您将 i
作为 lambda 中的默认参数传递,则将传递 值:
x[i] = lambda y=i: func(y)
x[0]()
# 0
结合这个事实,我之所以使用lambda selected, my_animal=animal:...
是由于command=...
中的OptionMenu
始终将其变量
(在本例中为选定的 Animal1、Animal2...)作为函数的第一个参数传递。
希望这能让事情变得更清楚。
关于python - 如何智能地将 DRY 原则应用到 tkinter OptionMenu 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52725403/
我目前正在尝试制作两个 OptionMenu,其中第二个将根据第一个 OptionMenu 中选择的内容动态更新。 例如,我想用列表制作OptionMenu_A [North America, Eur
我正在学习 Android 开发。到目前为止,我已经创建了一个基本应用程序,我想显示一个 OptionMenu。我遵循了一个教程。菜单没有出现在我的手机上。也许我忘记了什么? 我看过这篇文章: Opt
这是一个关于 tkinter 中的选项菜单小部件的非常普遍的问题。 当定义一个 OptionMenu 小部件并将一个函数分配为其命令时,为什么它需要一个参数? 我的代码: from tkinter i
我的 GUI 中有一个由列表填充的 OptionMenu。每次用户运行某个进程时,列表都会更新以反射(reflect)这一点。有没有办法根据列表更新 OptionMenu?我已经根据 this que
我有一个大约有 60 个项目的选项菜单,不用说,我无法一次在屏幕上看到所有内容。有没有办法让 tkinter 中的 OptionMenu 小部件可滚动? 最佳答案 简短的回答是否定的,但您可以尝试使用
我在 Windows 下使用 python 2.7 创建 Tkinter 应用程序时遇到问题。基本上,当我创建 OptionMenu 时,它的右角(向下按钮指示单击此处时会发生某些情况)在中间被截断。
在此示例中,如果用户在任何下拉列表中选择任何选项,然后单击另一个下拉列表,则先前选择的项目旁边会显示一个复选标记。即使这个选择是在不同的菜单中选择的。 from Tkinter import * fr
我正在尝试将多个文件夹名称添加到选项菜单中。下面的代码仅将一个文件夹名称添加到列表中,但我想添加目录中的所有文件夹名称。 var = StringVar() os.chdir('C:\\Users\\
当我的 android 应用程序以纵向屏幕启动时,操作栏中有选项菜单;但是当切换到 landspace 时,我发现资源未找到异常。 inflater.inflate(R.menu.main, menu
我正在尝试在实例化后设置或更新 OptionMenu 的命令。 widget.configure(command=foo) 语句适用于 Button 和 CheckButton,但不适用于 Optio
我是 php 的新手,我知道这很简单,但我不知道我做错了什么。无论我尝试什么,我都无法将“事件”变量传递到电子邮件中。 -HTML-
我喜欢明确指定参数。例如: def func(a, b): return a+b 每当我调用它时,我都会写: func(a=6, b=7) 代替: func(6, 7) 我无法使用 Tkint
是否有写保护 tkinter OptionMenu 同时保留检查可用选项的可能性的解决方案? 背景:我有一个 tkinter OptionMenu,其中包含用户可以“快速加载”到应用程序中的一系列文件
如果用户从 OptionMenu 列表中选择了一个选项,那么该选项应该被禁用。 示例:如果用户选择“a”,那么选项“a”应该被禁用,然后用户只能选择 b 或 c。我尝试了下面的代码,但它返回了如图所示
我正在为我的类(class)编写一个程序,即使在关闭程序后,您也可以制作食谱、保存和编辑它。您显然需要一个文本文件来执行此操作。 我正在使用 OptionMenu(Tkinter,Python 3.3
我已经在 python 上进行了一段时间的黑客攻击,并不是真正的程序员,所以作为最后的手段,我在这里寻求帮助。我一整天都在用谷歌搜索这个问题,但我似乎无法破解它。 在从 SE 的示例中提取的这段代码中
我正在尝试创建一个包含项目列表的轻量级跨平台消息框。理想情况下,它有一个 API,允许您传递要显示的消息、标题和选择元组。当按“确定”时,它将返回当前选择的选项。所需的模块最好是标准 python 发
我正在做一个包含选项菜单的GUI,我已经定义了以下菜单来从列表中获取选项,但是我想让每个选项调用不同的函数,但我不知道该怎么做。 options = ["Modem ID: 20",
如何调整此设置,以便在从菜单中选择 xyz17 时运行函数 xyz17()? 我知道 command = xyz17 但我不确定如何使其动态化,以便它取决于菜单选择。 from tkinter imp
我想从 tkinter 中的 OptionMenu 小部件中获取所有选项的列表,如下所示: import tkinter root = tkinter.Tk() var = tkinter.Strin
我是一名优秀的程序员,十分优秀!