【发布时间】:2018-05-29 05:15:44
【问题描述】:
最近我基本上是在自学 Tkinter。我已经在这个项目上工作了大约一个星期,我觉得它进展得相当顺利。今天,当我在处理它时,我得到了这段代码,它在成功运行时设置了 GUI。但是,当我尝试通过Combobox 更改图像时,它会失败并给我以下错误:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
TypeError: <lambda>() takes 0 positional arguments but 1 was given
经过快速搜索,我发现使用lambda x: 可以修复此错误。进行此更改后,GUI 将正常启动,但图像仍然不会更改,事实上,如果从第一个 Combobox 中选择了一个项目,第二个面板会出现故障并删除图像。完全删除“lambda”会导致面板根本无法启动。基本上,我想知道是什么导致了这些故障以及如何更新我的图像。
from tkinter import *
from tkinter.ttk import *
from PIL import Image, ImageTk
import os
class App(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
parent.title('Vainglory DMG Calculator | BETA')
self.dyn_panel = []
self.dyn_combobox = []
self.dyn_image_path = ['', '']
self.dyn_img = ['', '']
self.cwd = os.getcwd()
self.hero_list = ('Adagio', 'Alpha', 'Ardan', 'Baptiste', 'Baron', 'Blackfeather', \
'Catherine', 'Celeste', 'Churnwalker', 'Flicker', 'Fortress', \
'Glaive', 'Grace', 'Grumpjaw', 'Gwen', 'Idris', 'Joule', \
'Kestrel', 'Koshka', 'Krul', 'Lance', 'Lorelai', 'Lyra', 'Ozo', \
'Petal', 'Phinn', 'Reim', 'Reza', 'Ringo', 'Rona', 'Samuel', \
'SAW', 'Skaarf', 'Skye', 'Taka', 'Varya', 'Vox')
for i in range(2):
self.create_hero_combo_box(parent, i)
self.set_image(i)
self.create_hero_panel(parent, self.dyn_img[i], i)
def create_hero_panel(self, window, img, index):
self.dyn_panel.append(Label(window, image=img))
self.dyn_panel[index].grid(row=0, column=index*2)
def create_hero_combo_box(self, window, index):
self.dyn_combobox.append(Combobox(window, values=(*self.hero_list,)))
self.dyn_combobox[index].grid(row=1, column=index*2)
self.dyn_combobox[index].set(self.hero_list[0])
def set_image(self, index):
self.dyn_image_path[index] = (self.cwd + '/img/heroes/' + self.dyn_combobox[index].get().lower() + '.png')
self.dyn_img[index] = ImageTk.PhotoImage(Image.open(self.dyn_image_path[index]))
def update(self, index):
self.dyn_panel[index].configure(image=self.set_image(index))
if __name__ == '__main__':
root = Tk()
app = App(root)
for i in range(2):
app.dyn_combobox[i].bind('<<ComboboxSelected>>', lambda x: app.update(i))
root.mainloop()
【问题讨论】:
-
最好使用
lambda x=i : app.update(x),因为这样它将使用来自i的正确值,而不是引用i,这将保持不同的值。 -
这样做后我得到一个新错误:
File "C:\Users\brigh\Downloads\vg_calc\test.py", line 49, in <lambda> app.dyn_combobox[i].bind('<<ComboboxSelected>>', lambda x=i: app.update_image(x)) File "C:\Users\brigh\Downloads\vg_calc\test.py", line 42, in update_image self.set_image(index) File "C:\Users\brigh\Downloads\vg_calc\test.py", line 38, in set_image self.dyn_image_path[index] = (self.cwd + '/img/heroes/' + self.dyn_combobox[index].get().lower() + '.png') TypeError: list indices must be integers or slices, not Event -
我的错误,
bind()以event作为参数执行函数 - 你需要lambda event, x=i : app.update(x)来获取这个event并跳过它。 -
完美,就像一个魅力,非常感谢你
-
顺便说一句:如果您将从不同的文件夹运行它 - 即作为桌面上的链接/快捷方式 - 然后
os.getcwd()为您提供桌面路径,而不是您的程序文件夹,它找不到你的文件。你必须使用self.cwd = os.path.dirname(os.path.realpath(sys.argv[0]))
标签: python user-interface tkinter ttk