我应该如何更改我的代码,以便我可以调用 Bind() 函数而不是使用事件表?

How should I change my code so that I can call the Bind() function instead of using the event table?

提问人:joe_dowson 提问时间:7/31/2023 更新时间:8/1/2023 访问量:32

问:

我正在将WxWidgets 3.2用于我的C++ Windows应用程序。

我需要将数据(例如登录)从一个类传递到另一个类。为此,我创建了一个自定义事件,并使用事件表将事件绑定到处理程序。

例如,我有一个 LoginPanel 类,我想将用户输入的登录名传递给另一个类 - MainFrame。

LoginPanel.h

DECLARE_EVENT_TYPE(LOGIN_ENTERED, wxCommandEvent)

enum class Buttons_ID {
    ID_CONNECT_BUTTON = wxID_HIGHEST + 1,
};

class LoginPanel : public wxPanel {
public:
    LoginPanel(wxWindow* parent, wxWindowID id = wxID_ANY);

private:
    void OnConnectButton(wxCommandEvent& event);
    wxTextCtrl* usernameInput;
};

登录面板.cpp

DEFINE_EVENT_TYPE(LOGIN_ENTERED)
LoginPanel::LoginPanel(wxWindow* parent, wxWindowID id)
    : wxPanel(parent, id) {
    wxButton* connectButton = new wxButton(loginTab, wxID_ANY, "Connect");
    connectButton->Bind(wxEVT_BUTTON, &LoginPanel::OnConnectButton, this);
}

void LoginPanel::OnConnectButton(wxCommandEvent& event) {
    wxString username = usernameInput->GetValue();
    wxCommandEvent loginEvent(LOGIN_ENTERED, GetId());
    loginEvent.SetString(username);
    GetParent()->GetEventHandler()->ProcessEvent(loginEvent);
}

MainFrame.h

class MainFrame : public wxFrame {
public:
    MainFrame(const wxString& title);
    ~MainFrame();

private:
    LoginPanel * loginPanel;           

public:
    void ShowLoginPanel();
    void OnLoginEntered(wxCommandEvent& event);
    wxDECLARE_EVENT_TABLE(); 
};

MainFrame.cpp

wxBEGIN_EVENT_TABLE(ChessFrame, wxFrame)                             
    EVT_COMMAND(wxID_ANY, LOGIN_ENTERED, ChessFrame::OnLoginEntered) 
wxEND_EVENT_TABLE()                                                  

MainFrameFrame::MainFrameFrame(const wxString& title)
    : wxFrame(nullptr, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER) {
    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);

    loginPanel = new LoginPanel(this, wxID_ANY);
    mainSizer->Add(loginPanel, 1, wxEXPAND);
    SetSizer(mainSizer);
    ShowLoginPanel();
}

void MainFrameFrame::OnLoginEntered(wxCommandEvent& event) {
    auto login = event.GetString();
}

这就是代码的工作方式,LOGIN_ENTERED事件通常从 LoginPanel 类传递到 MainFrame 类的 OnConnectButton() 处理程序。

由于现在使用事件表不是很现代,因此我想使用 Bind() 函数。我在 MainFrame 类的构造函数中调用 Bind() 函数:

loginPanel->Bind(LOGIN_ENTERED, &ChessFrame::OnLoginEntered, this);

但是,问题是发生错误:

C2664: 'void wxEventFunctorMethod<EventTag,ChessFrame,EventArg,EventHandler>::CheckHandlerArgument(EventArg *)': cannot convert argument 1 from 'wxEvent *' to 'EventArg *'

我应该如何更改我的代码,以便我可以调用 Bind() 函数而不是使用事件表?

C++ 事件 wxwidgets

评论

0赞 Igor 7/31/2023
@joe_dawson,我想你确实看到了这个:docs.wxwidgets.org/latest/......
0赞 Igor 7/31/2023
因此,我敦促您遵循官方文档并相应地更改您的代码。

答:

1赞 New Pagodi 8/1/2023 #1

我认为主要问题是您用来声明/定义新事件的宏。您应该改用 wxDECLARE_EVENTwxDEFINE_EVENT

简而言之,改变

DECLARE_EVENT_TYPE(LOGIN_ENTERED, wxCommandEvent)

wxDECLARE_EVENT(LOGIN_ENTERED, wxCommandEvent);

DEFINE_EVENT_TYPE(LOGIN_ENTERED)

wxDEFINE_EVENT(LOGIN_ENTERED, wxCommandEvent);

另外,我建议改变

GetParent()->GetEventHandler()->ProcessEvent(loginEvent);

简单地说

ProcessWindowEvent(loginEvent);

如果窗口本身未处理命令事件,则命令事件将筛选到父窗口。

评论

0赞 Igor 8/1/2023
谢谢更好的解释。最有可能的是,这些宏以某种方式来自旧版本的 wx......
0赞 joe_dowson 8/1/2023
@new-pagodi,您能否澄清一下如何以相反的方向传递事件:从类 MainFrame 传递到类 LoginPanel ?现在我使用表达式:loginPanel->GetEventHandler()->ProcessEvent(event_fromMainFrame)
0赞 New Pagodi 8/1/2023
如果你想这样做,该代码应该可以工作。但通常你不会将事件从父母传递给孩子。如果需要根据父项中检测到的某些事件以某种方式更新子项,通常只需让父项调用子项的任何方法来执行更新。