【问题标题】:How to pass custom data in event wxWidgets如何在事件 wxWidgets 中传递自定义数据
【发布时间】:2020-05-17 18:20:59
【问题描述】:

情况

我目前正在使用 wxPython (wxWidgets for Python) 编写一个应用程序。

在这个应用程序中显示了一个对话列表,每行末尾都有一个“打开对话”按钮。我们将此窗口称为“所有对话”。

点击任一按钮调用函数“open_conversation(self, event)”,显示完整对话。

我要做的是,在窗口“所有对话”的生成时,在每个“绑定”事件或每个“wxButton”对象中传递一些自定义数据,例如字符串(联系人的姓名)实例) ;之后,当单击按钮时,它将在“事件”参数中传递所述数据,从而可以在函数中使用 contact = event.CustomData["recipient"] 之类的内容访问。

问题

参考documentation,我找到了“Bind”方法的“userData”关键字,但是在Python中好像不行。

self.openConversation_button.Bind(wx.EVT_BUTTON, self.open_conversation, userData="test")
TypeError: _EvtHandler_Bind() got an unexpected keyword argument 'userData'

更新

我已将 Rolf of Saxony 的解决方案标记为正确,因为它最适合我的需要,但我一般建议使用 VZ 建议的自定义事件系统。

【问题讨论】:

  • 您可以创建自定义事件。见wxPython docs
  • 好吧,我会深入研究;我可以假设没有内置的方法吗?

标签: python wxpython wxwidgets


【解决方案1】:

一般来说,定义自定义事件的建议绝对是正确的做法,但如果您只需要一个字符串和/或数字,您还可以重新利用现有的 wxCommandEvent 类并使用它的 @ 987654322@ 或 SetInt() 方法。

【讨论】:

  • 好的,很高兴知道!对于大型应用程序,我可以理解编写自定义事件,但是在我的情况下,只传递一个字符串/int 就足够了,所以我将研究你提到的函数。谢谢
【解决方案2】:

将自定义数据传递到callback 事件的一种简单方法是使用lambda 函数。
例如

import wx

class ButtonFrame(wx.Frame):
    def __init__(self, value):
        wx.Frame.__init__(self,None)
        self.btn1 = wx.Button(self, -1, ("a"))
        self.btn2 = wx.Button(self, -1, ("b"))
        self.btn3 = wx.Button(self, -1, ("No flag"))
        self.btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.btnSizer.Add(self.btn1 , 0, wx.RIGHT, 10)
        self.btnSizer.Add(self.btn2 , 0, wx.RIGHT, 10)
        self.btnSizer.Add(self.btn3 , 0, wx.RIGHT, 10)
        self.btn1.Bind(wx.EVT_BUTTON,  lambda event: self.OnButton(event, flag="A"))
        self.btn2.Bind(wx.EVT_BUTTON,  lambda event: self.OnButton(event, flag="B"))
        self.btn3.Bind(wx.EVT_BUTTON,  self.OnButton)
        self.SetSizer(self.btnSizer)
        self.Show()

    def OnButton(self,event, flag=None):
        if flag:
            print ("Button pressed was "+flag)
        else:
            print ("A button got pressed")

if __name__ == "__main__":
    app = wx.App()
    ButtonFrame(None)
    app.MainLoop()

【讨论】:

  • 哇,不错!今天下午我会调查一下,如果可行的话,今晚就关闭线程!
【解决方案3】:

对于任何对完整的 C++ 示例感兴趣的人,这里是:

#include <wx/wx.h>

struct CustomData final : public wxClientData {
    std::string myString;
};

struct MyApp final : public wxApp {
    bool OnInit() final;
};

struct MyWindow final : public wxFrame {
    static constexpr int ID_MY_BUTTON{ 42 };

                MyWindow();
                MyWindow( MyWindow const & ) = delete;
    MyWindow &  operator=( MyWindow const & ) = delete;
    void        OnButton( wxCommandEvent & event );

    wxDECLARE_EVENT_TABLE();
};

bool MyApp::OnInit() {
    MyWindow * const window{ new MyWindow() };
    window->Show( true );
    return true;
}

MyWindow::MyWindow() {
    wxButton * const myButton{ new wxButton( this, ID_MY_BUTTON ) };
    CustomData * const myData{ new CustomData() };
    myData->myString = "Hello World!";
    myButton->SetClientObject( myData );
}

void MyWindow::OnButton( wxCommandEvent & event ) {
    wxEvtHandler const * const eventObject{ static_cast< wxEvtHandler * >( event.GetEventObject() ) };
    if ( eventObject == nullptr ) {
        return;
    }

    CustomData const * const myData{ static_cast< CustomData const * >( eventObject->GetClientObject() ) };
    if ( myData == nullptr ) {
        return;
    }

    std::cout << myData << "\n";
}

wxIMPLEMENT_APP( MyApp );

wxBEGIN_EVENT_TABLE( MyWindow, wxFrame )
EVT_BUTTON( MyWindow::ID_MY_BUTTON, MyWindow::OnButton )
wxEND_EVENT_TABLE()

不需要删除CustomData 实例,wxWidgets 会处理它。 这里的关键步骤是:

  • 继承wxClientDataclass 以附加您的数据
  • 使用您的堆分配自定义数据对象调用 wxEvtHandler::SetClientObject()
  • 在回调中,使用wxCommandEvent::GetEventObject() 检索按钮
  • 使用wxEvtHandler::GetClientObject() 检索您的自定义数据

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-30
    • 2014-02-12
    相关资源
    最近更新 更多