绑定 wxWidgets 中的任意函数

huangapple go评论79阅读模式
英文:

Binding arbitrary function in wxwidgets

问题

I want to create a number of composite objects, each containing a scrolled list and some buttons (for my example, I've reduced the code to creating just one of the objects with just one button). All of these objects will be very similar, except for the layout, size, and the functions called by the buttons (i.e. for each object, the callback for the same button can be different).

So, in the constructor for these composite objects, I want to receive the functions to bind to the buttons (again, in my example, it will be one button).

I have an example version that works (without the Bind function being passed), and an example that won't compile when I try to add the code passing in the function to Bind.

Here's the compiler error:

stack2.cpp: In constructor ‘MainPanel::MainPanel(wxFrame*)’:
stack2.cpp:106:94: error: no matching function for call to ‘MyAddRemoveList::MyAddRemoveList(MainPanel*, const char [12], const char [11], int, int, int, bool, void (MyAddRemoveList::*)(wxCommandEvent&))’
  106 | xLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);
                                                                           1,68          Top
tack2.cpp:61:1: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(wxWindow*, const char*, const char*, int, int, long int, bool, func)’
   61 | MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name,
      | ^~~~~~~~~~~~~~~
stack2.cpp:62:79: note:   no known conversion for argument 8 from ‘void (MyAddRemoveList::*)(wxCommandEvent&)’ to ‘func’ {aka ‘void (*)(wxCommandEvent&)’}
   62 |       const char *table_name, int w, int h, long style, bool do_extract, func fpt) :
      |                                                                          ~~~~~^~~
stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(const MyAddRemoveList&)’
   41 | class MyAddRemoveList : public wxBoxSizer {
      |       ^~~~~~~~~~~~~~~
stack2.cpp:41:7: note:   candidate expects 1 argument, 8 provided
stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(MyAddRemoveList&&)’
stack2.cpp:41:7: note:   candidate expects 1 argument, 8 provided
make: *** [stack2.make:94: stack2.o] Error 1

I don't understand why the compiler can't cast void (*)(wxCommandEvent&) to void (MyAddRemoveList::*)(wxCommandEvent&). This is my problem.

Notes:

  • I have pruned the code down to a minimal version (one that "works" without the Bind, and one with Bind that won't compile). But again, they're each about 100 lines and I don't know if that's too long to include in a question here.
  • POP OS 22.04
  • wxWidgets 3.0

How can I do this?

Here's the (hopefully) relevant code.

For clarity, I have this:

using func = void(*)(wxCommandEvent&);

Here's the constructor:

MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract, func fpt) : wxBoxSizer(wxVERTICAL) {

/* stuff here */

Here's my attempt to bind:

/* stuff here */

wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

add->Bind(wxEVT_BUTTON, fpt);

Here's the call to the constructor:

lookup_lists[0] = new MyAddRemoveList(this, "Ingredients", "ingredient", 80, 200, wxLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);

英文:

I want to create a number of composite objects, each containing a scrolled list and some buttons (for my example, I've reduced the code to creating just one of the objects with just one button). All of these objects will be very similar, except for the layout, size, and the functions called by the buttons
(i.e. for each object, the callback for the same button can be different).

So, in the constructor for these composite objects, I want to receive the functions to bind to the buttons (again, in my example, it will be one button).

I have an example version that works (without the Bind function being passed), and an example that won't compile when I try to add the code passing in the function to Bind.

Here's the compiler error:

stack2.cpp: In constructor ‘MainPanel::MainPanel(wxFrame*)’:
stack2.cpp:106:94: error: no matching function for call to ‘MyAddRemoveList::MyAddRemoveList(MainPanel*, const char [12], const char [11], int, int, int, bool, void (MyAddRemoveList::*)(wxCommandEvent&))’
  106 | xLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);
                                                                           1,68          Top
tack2.cpp:61:1: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(wxWindow*, const char*, const char*, int, int, long int, bool, func)’
   61 | MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name,
      | ^~~~~~~~~~~~~~~
stack2.cpp:62:79: note:   no known conversion for argument 8 from ‘void (MyAddRemoveList::*)(wxCommandEvent&)’ to ‘func’ {aka ‘void (*)(wxCommandEvent&)’}
   62 |       const char *table_name, int w, int h, long style, bool do_extract, func fpt) :
      |                                                                          ~~~~~^~~
stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(const MyAddRemoveList&)’
   41 | class MyAddRemoveList : public wxBoxSizer {
      |       ^~~~~~~~~~~~~~~
stack2.cpp:41:7: note:   candidate expects 1 argument, 8 provided
stack2.cpp:41:7: note: candidate: ‘MyAddRemoveList::MyAddRemoveList(MyAddRemoveList&&)’
stack2.cpp:41:7: note:   candidate expects 1 argument, 8 provided
make: *** [stack2.make:94: stack2.o] Error 1

I don't understand why the compiler can't cast void (*)(wxCommandEvent&) to void (MyAddRemoveList::*)(wxCommandEvent&). This is my problem.

Notes:

  • I have pruned the code down to a minimal version (one that "works" without the Bind, and one with Bind that won't compile). But again, they're each about 100 lines and I don't know if that's too long to include in a question here.
  • POP OS 22.04
  • wxwidgets 3.0

How can I do this?

Here's the (hopefully) relevant code.

For clarity I have this:

using func = void(*)(wxCommandEvent& event);

Here's the constructor:

MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract, func fpt) : wxBoxSizer(wxVERTICAL) {

/* stuff here */

Here's my attempt to bind:

/* stuff here */

wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

add->Bind( wxEVT_BUTTON, fpt );

Here's the call to the constructor:

lookup_lists[0] = new MyAddRemoveList(this, "Ingredients", "ingredient", 80, 200, wxLB_MULTIPLE | wxLB_HSCROLL | wxLB_NEEDED_SB, false, &MyAddRemoveList::OnAddToList);

答案1

得分: 1

你正在完全错误和不正确地做这件事。

请查看使用wxWidgets制作GUI的不同示例。

让我来尝试为您修复它。

您的构造函数是不正确的。
不要将函数传递给构造函数。像这样做:

MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract) : wxBoxSizer(wxVERTICAL)
{

// 如果您确实在某处创建了“panel”,那么按钮创建代码似乎是正确的。

wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

// Bind调用将如下所示:

add->Bind( wxeVT_BUTTON, &MyAddRemoveList::OnButtonClick, this );

}

MyAddRemoveList::OnButtonClick(wxCommandEvent &event)
{

// 从这里开始编写通用代码

switch( event.GetEventObject() )
{
    case add:
    // 添加特定代码
    break;
    case remove:
    // 移除特定代码
    break;
}

// 完成处理程序的通用代码

}

当然要摆脱那个func - 你将不再需要它。

最后,最好使用wxPanel而不是wxBoxSizer,因为sizers不是窗口 - 它们只是布局机制。

并且请先学会语言 - C++、Python、Perl、Ruby。所有这些语言都有一种使用wxWidgets的方式。

只有当您熟悉语言时,再使用wxWidgets。

希望这有所帮助。

英文:

You are doing it all wrong and incorrect.

Please look at the different samples on how to make the GUI using wxWidgets.

Let me try and fix that for you.

You constructor is incorrect.
Do not pass the function into the constructor. Do it like this:

MyAddRemoveList::MyAddRemoveList(wxWindow *panel, const char *display_name, const char *table_name, int w, int h, long style, bool do_extract) : wxBoxSizer(wxVERTICAL)
{

    // The button creation code seems to be fine if you actually do have a "panel" created somewhere.

    wxButton *add = new wxButton(panel, wxID_ADD, "+", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);

    // The Bind call will look like this:

    add->Bind( wxeVT_BUTTON, &MyAddRemoveList::OnButtonClick, this );
}

MyAddRemoveList::OnButtonClick(wxCommandEvent &event)
{

    // Put generic code to start here

    switch( event.GetEventObject() )
    {
        case add:
        // Code unique to add
        break;
        case remove:
        // Code unique to remove
        break;
    }

    // Put generic code to finish the handler
}

And of course get rid of that func - you will not be needing it.

Finally you will be better off with using wxPanel instead of wxBoxSizer as sizers are not windows - they are just layout mechanism.

And please learn the language first - C++, Python, Perl, Ruby. All this languages have some way using wxWidgets.

Only when you know the language - go with the wxWidgets.

I hope it helps.

huangapple
  • 本文由 发表于 2023年5月15日 05:12:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定