Tkinter选项菜单的可移植消息框
我想创建一个轻量级的跨平台消息框,里面包含一系列选项。理想情况下,它应该有一个接口,可以让你传入要显示的消息、标题和选项的元组。当你按下“确定”时,它会返回当前选择的选项。最好是所需的模块都能在标准的Python发行版中找到。
Easygui有我想要的功能,叫做choicebox,可以在这个链接找到:http://easygui.sourceforge.net/download/version0.95/tutorial/index.html#contents_item_10.1。不过,它弹出的窗口太大了,而且它总是按字母顺序排列你的选项。由于这些“特性”,easygui并不是最理想的选择。
我还研究过bwidgets、pmw和Tix。在尝试这些时,我遇到了一些问题,包括:很难找到有效的示例,以及在不同平台上运行失败。
我现在的工作模型是使用Tkinter的OptionMenu和pickle来返回数据(见下面的代码示例)。虽然这样可以工作,但每次都要把选择保存到文件系统中,以避免使用全局变量,这让我觉得很烦。有没有办法在GUI关闭时返回选择的结果?
任何帮助或建议都将非常感激。请注意,这些示例仅供参考,可能在你的系统上运行不正常。
状态管理模块
import pickle
def store(pkl_path, data_to_store):
try:
fid = open(pkl_path, 'w')
pickle.dump(data_to_store, fid)
except:
print 'Unable to store data in ' + pkl_path
else:
fid.close()
def load(pkl_path):
try:
fid = open(pkl_path, 'r')
loaded_state = pickle.load(fid)
fid.close()
except:
loaded_state = None
else:
fid.close()
return loaded_state
菜单模块
from Tkinter import *
def Prompt_Dropdown_Ok_Cancel(title, options, pickle_file, default_selection=0):
master = Tk()
master.title(title)
var = StringVar(master)
var.set(options[default_selection]) # default value
w = OptionMenu(master, var, *options)
w.pack()
def ok():
state.store(pickle_file, var.get())
master.quit()
def cancel():
state.store(pickle_file, None)
master.quit()
button = Button(master, text="OK", command=ok)
button.pack()
b2 = Button(master, text="Cancel", command=cancel)
b2.pack()
mainloop()
示例用法
from menu_module import *
def display_com_selection():
pkl_path = '.tmp/comm_selection'
title = 'COM Port Selection'
Prompt_Dropdown_Ok_Cancel(title,get_available_com(),pkl_path)
selection = state.load(pkl_path)
return selection
编辑
不考虑我对全局变量的担忧,我尝试了一种使用全局变量的实现,看看是否更简单。这样确实简单了很多,但我仍然希望找到更好的方法。
下面是重新整理的菜单模块
from Tkinter import *
Prompt_Dropdown_Ok_Cancel_Selection = None
def Prompt_Dropdown_Ok_Cancel(title, message, options, default_selection=0):
master = Tk()
master.title(title)
var = StringVar(master)
var.set(options[default_selection]) # default value
l = Label(master, text=message)
l.pack()
w = OptionMenu(master, var, *options)
w.pack(fill=BOTH, expand=1)
def ok():
global Prompt_Dropdown_Ok_Cancel_Selection
Prompt_Dropdown_Ok_Cancel_Selection = str(var.get())
master.destroy()
def cancel():
global Prompt_Dropdown_Ok_Cancel_Selection
Prompt_Dropdown_Ok_Cancel_Selection = str(var.get())
master.destroy()
button = Button(master, text="OK", command=ok)
button.pack(side=LEFT)
b2 = Button(master, text="Cancel", command=cancel)
b2.pack(side=LEFT)
mainloop()
return Prompt_Dropdown_Ok_Cancel_Selection
1 个回答
对话框的正常工作方式大致是这样的:
mydialog = SomeDialogClass(...)
result = mydialog.Show()
if result == "OK":
print "you clicked OK; dialog value is", mydialog.GetValue()
else:
print "you clicked cancel"
mydialog.Destroy()
这里用的是伪代码,意思是它不依赖于特定的图形界面工具包(虽然看起来很像wxPython)。主要的思路是,你创建一个对话框对象,让这个对象显示出来,然后等待用户完成操作(比如点击“确定”或“取消”),接着再从这个对象获取用户输入的数据,最后销毁这个对象(或者保留它以便以后再用)。
第二种方法是编写代码,让对话框在需要的时候调用一个函数来设置值。像这样:
mydialog = SomeDialogClass(..., callback=self.foo)
....
def foo(self, button, result):
if button == "OK":
print "you clicked OK; result is", result
elif button == "Cancel":
print "you clicked Cancel"
这种第二种方法在对话框不是模态的时候效果很好(也就是说,当对话框出现时,程序仍然可以继续运行)。