wxPython:暂停主脚本并等待按钮按下

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

我正在使用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()

现在还不清楚你打算在这里做什么。您的脚本没有崩溃,它只是在第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,您上面的示例为我提供了所需的解决方案。