我定义了一个tkinter checkbutton小部件,用于根据用户定义的列表创建复选框,并返回包含所选元素的新列表。当我直接在IPython控制台上运行它时,它按预期工作(我大部分时间都使用Spyder3)。如果我将函数保存为Python脚本并在Python控制台中将其称为模块函数,它也可以工作。但是,如果我运行包含此函数的脚本,那些检查按钮的所有更改根本不会反映到实际值的行为很奇怪;无论我选择哪些项目,所有值都 False 。以下是代码和示例:
CheckBox.py :
import tkinter as tk
from tkinter.messagebox import askyesno
import sys
def CheckBox(picks, *Args):
class checkboxfromlist(tk.Frame):
def __init__(self, parent, picks):
tk.Frame.__init__(self, parent)
self.vars = []
for pick in picks:
var = tk.BooleanVar()
chk = tk.Checkbutton(self, text=pick, variable=var, onvalue=True, offvalue=False)
chk.pack()
self.vars.append(var)
def state(self):
return list(map((lambda var: var.get()), self.vars))
class MainWindow(tk.Tk):
def __init__(self, picks, text):
tk.Tk.__init__(self)
self.resizable(width=False, height=False)
self.title('Select desired download')
self.protocol('WM_DELETE_WINDOW', self.on_exit)
self.l = tk.Label(self, text='Please select desired download {}'.format(text))
self.l.pack()
self.ChkBox = checkboxfromlist(self, picks)
self.ChkBox.pack()
self.Button = tk.Button(self, text='Ok', width=40, height=2, command=self.quit)
self.Button.pack()
# Make popup window at the centre
self.update_idletasks()
w = self.winfo_screenwidth()
h = self.winfo_screenheight()
size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
x = w/2 - size[0]/2
y = h/2 - size[1]/2
self.geometry('%dx%d+%d+%d' % (size + (x, y)))
def on_exit(self):
# When you click x to exit, this function is called
if askyesno("Exit", "Do you want to quit the application?"):
self.destroy()
sys.exit(0)
text = ' for '.join(Args)
App = MainWindow(picks, text)
App.mainloop()
mask = App.ChkBox.state()
App.destroy()
selected = [item for index, item in enumerate(picks) if mask[index]]
return selected
以下是小部件的快照: widget screenshot
这些工作:
这些不能工作:
以spyder,终端或双击
作为脚本运行if __name__ == '__main__':
CheckBox(MyList, 'item')
在spyder,terminal或者脚本中作为外部模块运行 双击
import CheckBox
if __name__ == '__main__':
CheckBox.CheckBox(MyList, 'item')
我尝试在Ubuntu上使用Python 3.5.2,在Windows 10上使用3.6.4,它们都给了我同样的问题。我花了一整天时间搞清楚发生了什么,但没有运气。任何评论都会非常感激。
修改 :
我发现小部件有效,直到我在main函数的开头添加以下代码:
root = tk.Tk()
root.withdraw()
我这样做的原因是因为在此过程中稍后会有一些用户提示窗口小部件。如果没有 root.withdraw(),屏幕上将始终显示一个空白窗口。以上代码的效果持续到我重新启动Spyder3;这意味着我只需删除上面的代码就可以让我的代码再次运行。这是该计划的快照:
这有效:
Screenshot of Spyder
正如您所看到的,打印输出列表正是我选择的项目(我运行一次然后再次运行它以获取小部件的快照)。
这不是:
Screenshot of Spyder
无论我如何选择项目,打印列表都是空的。
PS : fuck_tk 与我在上面发布的 CheckBox.py 完全相同。
EDIT2 :
我发现为了使所有小部件工作而不显示空白主tkinter窗口,我需要将所有tkinter消息框作为单独的函数,如下所示:
def User_Confirm():
root = tk.Tk()
root.withdraw()
answer = askquestion('test', 'tkinter sucks')
root.destroy()
return answer
然而,这种解决方法对我来说听起来非常愚蠢。是否有任何优雅的方法来隐藏主tkinter窗口,而不影响我的CheckBox小部件的功能?