wxPython:暂停主脚本并等待按钮按下
我正在使用wxPython开发GUI。这个GUI应该动态地向用户请求同一窗口中的多组输入,在按下按钮“ok”后用新的一组输入更新窗口 为此,我有一个for循环,它调用一个函数来提示窗口上的输入控件。我尝试使用wxPython:暂停主脚本并等待按钮按下,python,user-interface,dynamic,wxpython,Python,User Interface,Dynamic,Wxpython,我正在使用wxPython开发GUI。这个GUI应该动态地向用户请求同一窗口中的多组输入,在按下按钮“ok”后用新的一组输入更新窗口 为此,我有一个for循环,它调用一个函数来提示窗口上的输入控件。我尝试使用threading.Event类,让脚本等待按钮按下,但是python崩溃了 下面是代码中感兴趣的部分 # Iterate through parameters self.cv = threading.Event() for key in pa
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()
现在还不清楚你打算在这里做什么。您的脚本没有崩溃,它只是在第40行的事件上不确定地等待。您没有启动任何可以设置事件的附加线程,因此其他脚本将继续 还要注意wxPython不是线程安全的——因此,如果您从另一个线程中开始添加小部件,您将(实际上)在那里崩溃 实际帧的设置在_uu_u_; init _u函数完成之前不会启动。在该通话中,您等待按钮按下,但该按钮无法按下,因为窗口尚未创建。因此,您的脚本将等待 我本来会为你的问题发布一个实际的解决方案,但如上所述,我不知道你打算在这里做什么 编辑: 如评论中所述,我将使用对话框向用户询问项目 创建对话框子类:
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()
迈克尔现在还不清楚你打算在这里做什么。您的脚本没有崩溃,它只是在第40行的事件上不确定地等待。您没有启动任何可以设置事件的附加线程,因此其他脚本将继续 还要注意wxPython不是线程安全的——因此,如果您从另一个线程中开始添加小部件,您将(实际上)在那里崩溃 实际帧的设置在_uu_u_; init _u函数完成之前不会启动。在该通话中,您等待按钮按下,但该按钮无法按下,因为窗口尚未创建。因此,您的脚本将等待 我本来会为你的问题发布一个实际的解决方案,但如上所述,我不知道你打算在这里做什么 编辑: 如评论中所述,我将使用对话框向用户询问项目 创建对话框子类:
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()
迈克尔谢谢你的回答,并为我拙劣的语言道歉。事实上,脚本会无限期地等待,在某一点上不会应答,但不会崩溃。我想要的是不同的窗口一个接一个地弹出,一旦按下“ok”按钮(当前窗口也应该关闭)。我不知道在我的
\uuuu init\uuuu
功能完成之前,框架的设置不会启动。我现在所做的是移动main_name
函数中的for循环,以便为每组输入生成一个新帧。把wait
放在那里,脚本仍然会无限期地等待。就我个人而言,我会使用一个模式对话框询问用户信息,而不是一个框架。脚本的其余部分将自动等待,直到对话框完成,您可以从那里获得所需的信息。谢谢您的建议。关键是,我想使用wxPython,因为请求给用户的输入集是多种多样的。首先,我应该有一些窗口要求一些文本,然后其他窗口有一个滚动列表和其他文本。我没有找到一个解决方案来递归地弹出框架并关闭它们。问题似乎在于这是在for
周期内完成的。因此,主脚本正在运行,它同时生成所有帧。否则,如果我在任何时候使用wait
,我总是会无限期地等待。也许这会有帮助。对话框关闭后,您将以dlg.data的形式获得对话框的结果。谢谢@Lokla,您上面的示例为我提供了我所寻找的解决方案。谢谢您的回答,并为我拙劣的语言道歉。事实上,脚本会无限期地等待,在某一点上不会应答,但不会崩溃。我想要的是不同的窗口一个接一个地弹出,一旦按下“ok”按钮(当前窗口也应该关闭)。我不知道在我的\uuuu init\uuuu
功能完成之前,框架的设置不会启动。我现在所做的是移动main_name
函数中的for循环,以便为每组输入生成一个新帧。把wait
放在那里,脚本仍然会无限期地等待。就我个人而言,我会使用一个模式对话框询问用户信息,而不是一个框架。脚本的其余部分将自动等待,直到对话框完成,您可以从那里获得所需的信息。谢谢您的建议。关键是,我想使用wxPython,因为请求给用户的输入集是多种多样的。首先,我应该有一些窗口要求一些文本,然后其他窗口有一个滚动列表和其他文本。我没有找到一个解决方案来递归地弹出框架并关闭它们。问题似乎在于这是在for
周期内完成的。因此,主脚本正在运行,它同时生成所有帧。否则,如果我在任何时候使用wait
,我总是会无限期地等待。也许这会有帮助。对话框关闭后,您将以dlg.data的形式获得对话框的结果。感谢@Lokla,您上面的示例为我提供了所需的解决方案。