我正在使用wxPython开发GUI。该GUI应该动态地向用户询问同一窗口中的几组输入,在按下“ok”按钮后用新的输入集更新窗口。
为此,我有一个for循环,它调用一个提示窗口输入控件的函数。我试图使用threading.Event
类,让脚本等待按下按钮,但python崩溃。
以下是代码中感兴趣的部分。
# Iterate through parameters
self.cv = threading.Event()
for key in parameters:
self.input_sizer = [None]*len(parameters[key])
self.cv.clear()
self.make_widgets(key, parameters[key])
self.cv.wait()
# Panel final settings
self.panel.SetSizer(self.main_sizer)
self.main_sizer.SetSizeHints(self)
def make_widgets(self, request, parameters):
# Function for widget prompting on the panel
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.controls = {"request": wx.StaticText(self.panel, label="Please type the new alias' " + request),
"txt": [None]*len(parameters),
"tc": [None]*len(parameters)}
self.main_sizer.Add(self.controls["request"], 1, wx.ALL, 10)
for i in range(len(parameters)):
self.input_sizer[i] = wx.BoxSizer(wx.HORIZONTAL)
self.main_sizer.Add(self.input_sizer[i], 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
# Text
self.controls['txt'][i] = wx.StaticText(self.panel, label=parameters[i])
self.input_sizer[i].Add(self.controls["txt"][i], 0, wx.ALIGN_CENTER | wx.LEFT, 10)
# Input
self.controls['tc'][i] = wx.TextCtrl(self.panel)
self.input_sizer[i].Add(self.controls["tc"][i], 0, wx.ALIGN_CENTER)
# Ok button
self.button_ok = wx.Button(self.panel, label="Ok")
self.main_sizer.Add(self.button_ok, 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
self.button_ok.Bind(wx.EVT_BUTTON, self.carry_on)
def carry_on(self, event):
self.cv.set()
有没有人有任何想法?
谢谢,下面是完整的代码。
import wx
from collections import OrderedDict
import threading
############################################################################
class AddMainName(wx.Frame):
# Class definition for main Name addition
def __init__(self, parent, title):
# Constructor
super().__init__(parent, title=title)
# Run the name addition
self.set_alias_name()
self.Centre()
self.Show()
def set_alias_name(self):
# Function for definition of alias name
# Panel
self.panel = wx.Panel(self)
# Lists of parameters to be typed
parameters = OrderedDict([("name parts", [
"Prefix", "Measurement", "Direction", "Item", "Location", "Descriptor", "Frame", "RTorigin"
]),
("SI units", [
"A", "cd", "K", "kg", "m", "mol", "Offset", "rad", "s", "ScaleFactor"
]),
("normal display unit", [
"A", "cd", "K", "kg", "m", "mol", "Offset", "rad", "s", "ScaleFactor"
]),
("other parameters", [
"Meaning", "Orientation Convention", "Contact Person", "Note",
])])
# Iterate through parameters
self.cv = threading.Event()
for key in parameters:
self.input_sizer = [None]*len(parameters[key])
self.cv.clear()
self.make_widgets(key, parameters[key])
self.cv.wait()
# Panel final settings
self.panel.SetSizer(self.main_sizer)
self.main_sizer.SetSizeHints(self)
def make_widgets(self, request, parameters):
# Function for widget prompting on the panel
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.controls = {"request": wx.StaticText(self.panel, label="Please type the new alias' " + request),
"txt": [None]*len(parameters),
"tc": [None]*len(parameters)}
self.main_sizer.Add(self.controls["request"], 1, wx.ALL, 10)
for i in range(len(parameters)):
self.input_sizer[i] = wx.BoxSizer(wx.HORIZONTAL)
self.main_sizer.Add(self.input_sizer[i], 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
# Text
self.controls['txt'][i] = wx.StaticText(self.panel, label=parameters[i])
self.input_sizer[i].Add(self.controls["txt"][i], 0, wx.ALIGN_CENTER | wx.LEFT, 10)
# Input
self.controls['tc'][i] = wx.TextCtrl(self.panel)
self.input_sizer[i].Add(self.controls["tc"][i], 0, wx.ALIGN_CENTER)
# Ok button
self.button_ok = wx.Button(self.panel, label="Ok")
self.main_sizer.Add(self.button_ok, 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
self.button_ok.Bind(wx.EVT_BUTTON, self.carry_on)
def carry_on(self, event):
self.cv.set()
############################################################################
class AddCommonName(wx.Frame):
# Class definition for common name addition
def __init__(self, parent, title):
# Constructor
super().__init__(parent, title=title,
size=(400, 150))
# Run the name addition
self.set_alias()
self.Centre()
self.Show()
def set_alias(self):
panel = wx.Panel(self)
sizer = wx.GridBagSizer(5, 5)
text1 = wx.StaticText(panel, label="Please type the new alias name.")
sizer.Add(text1, pos=(0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM,
border=15)
panel.SetSizer(sizer)
############################################################################
class AliasGUI(wx.Frame):
def __init__(self, parent, title):
# Constructor
super().__init__(parent, title=title)
# Run first dialog of the GUI
self.begin()
self.Centre()
self.Show()
def begin(self):
# Panel initial settings
panel_start = wx.Panel(self)
main_sizer = wx.BoxSizer(wx.VERTICAL)
# Alias type selection
text_start = wx.StaticText(panel_start, label="Please select the type of the new alias.")
main_sizer.Add(text_start, 1, wx.ALL, 10)
# Buttons
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.Add(buttons_sizer, 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
# Main name button
button_main_name = wx.Button(panel_start, label="Main Name")
buttons_sizer.Add(button_main_name, 0, wx.ALIGN_CENTER | wx.RIGHT, 10)
button_main_name.Bind(wx.EVT_BUTTON, self.main_name)
# Common name button
button_common_name = wx.Button(panel_start, label="Common Name")
buttons_sizer.Add(button_common_name, 0, wx.ALIGN_CENTER)
button_common_name.Bind(wx.EVT_BUTTON, self.common_name)
# Panel final settings
panel_start.SetSizer(main_sizer)
main_sizer.SetSizeHints(self)
@staticmethod
def main_name(event):
# Function for main name addition
frame = AddMainName(None, title="New Main Name")
frame.Centre()
frame.Show()
@staticmethod
def common_name(event):
# Function for common name addition
frame = AddCommonName(None, title="New Common Name")
frame.Centre()
frame.Show()
# GUI execution
if __name__ == '__main__':
app = wx.App()
AliasGUI(None, title="Aliases Management GUI")
app.MainLoop()
答案 0 :(得分:2)
你打算在这里做什么并不是很清楚。你的脚本没有崩溃,它只是在第40行的事件上无休止地等待。你没有启动任何可以设置事件的额外线程,所以另一个脚本将继续。
另外请注意,wxPython不是线程安全的 - 所以如果你开始从另一个线程中添加小部件,你会(真的)在那里崩溃。
在完成__ init __功能之前,不会启动实际帧的设置。在此调用中,您等待按钮按下,这是不可能发生的,因为窗口尚未创建。所以你的脚本会等待。
我会为你的问题发布一个实际的解决方案,但如上所述,我不知道你打算在这里做什么。
编辑:
如评论中所述,我会使用一个对话框向用户询问这些项目。
创建一个Dialog子类:
class getDataDlg(wx.Dialog):
def __init__(self, *args, **kwargs):
self.parameters = parameters = kwargs.pop('parameters', None)
request = kwargs.pop('request', None)
assert parameters is not None
assert request is not None
wx.Dialog.__init__(self, *args, **kwargs)
self.data = {}
vsizer = wx.BoxSizer(wx.VERTICAL)
reqLbl = wx.StaticText(self, label="Please type new alias {}".format(request))
vsizer.Add(reqLbl, 1, wx.ALL, 10)
self.controls = controls = {}
for item in parameters:
hsizer = wx.BoxSizer(wx.HORIZONTAL)
parLbl = wx.StaticText(self, label=item)
hsizer.Add(parLbl, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
ctrl = controls[item] = wx.TextCtrl(self)
hsizer.Add(ctrl, 0, wx.ALIGN_CENTER)
vsizer.Add(hsizer, 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
okBtn = wx.Button(self, id=wx.ID_OK)
vsizer.Add(okBtn, 1, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
self.SetSizer(vsizer)
self.Fit()
self.Layout()
okBtn.Bind(wx.EVT_BUTTON, self.saveData)
def saveData(self, event):
for item in self.parameters:
self.data[item] = self.controls[item].GetValue()
event.Skip()
将main_name函数更改为以下内容:
def main_name(self, event):
parameters = OrderedDict([("name parts", ["Prefix", "Measurement", "Direction", "Item", "Location", "Descriptor", "Frame", "RTorigin"]),
("SI units", ["A", "cd", "K", "kg", "m", "mol", "Offset", "rad", "s", "ScaleFactor"]),
("normal display unit", ["A", "cd", "K", "kg", "m", "mol", "Offset", "rad", "s", "ScaleFactor"]),
("other parameters", ["Meaning", "Orientation Convention", "Contact Person", "Note",])])
# Iterate through parameters
self.cv = threading.Event()
for itemKey in parameters:
item = parameters[itemKey]
dlg = getDataDlg(self, parameters=item, request=itemKey)
result = dlg.ShowModal()
if result == wx.ID_OK:
print("Got Result from Dialog:")
print(dlg.data)
dlg.Destroy()
迈克尔