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

时间:2016-09-12 17:05:45

标签: python user-interface dynamic wxpython

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

1 个答案:

答案 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()  

迈克尔