是否可以将多个参数传递给 FLTK 按钮回调函数?

Can I pass more than 1 parameter to a FLTK button callback function?

提问人:esdv123 提问时间:6/14/2023 更新时间:6/14/2023 访问量:92

问:

尝试使用 FLTK 制作国际象棋程序,我得到了一个传递参数的回调,特别是一个数字,但我希望回调函数包含“window->hide();”。这意味着我需要将 window 对象传递给回调函数。必须在回调函数中转换为原始数据类型。我收到错误 - 重载函数“Fl_Button::callback”的实例与参数列表不匹配。以及错误 - 'Fl_Widget::callback':没有重载函数需要 3 个参数。两者都指的是我写“wK->callback(....);

int Board::setup(int argc, char** argv, std::vector<Piece*> wow, int turn)
{
    Fl_Window* mainWindow = new Fl_Window(640, 640); //create window

    //draw background squares
    for (int x = 0; x < 8; x++)
    {
        for (int y = 0; y < 8; y++)
        {
            if ((x % 2 == 1 && y % 2 == 0) || (x % 2 == 0 && y % 2 == 1)) {
                Fl_Box* box = new Fl_Box(x * 80, y * 80, 80, 80);
                box->box(FL_FLAT_BOX);
                box->color(FL_BLACK);
            }
        }
    }

    //draw pieces
    if (turn % 2 == 1) {
        whiteButtons(wow, argc, argv, (Fl_Window *)mainWindow);
    }
    if (turn % 2 == 0) {
        blackButtons(wow, argc, argv, (Fl_Window *)mainWindow);
    }


    mainWindow->show();//main loop
    return Fl::run();
}
void Board::whiteButtons(std::vector<Piece*> wow, int argc, char** argv, Fl_Window* w){

    Fl_Button* wK = new Fl_Button(wow[0]->yPos * 80, wow[0]->xPos * 80, 80, 80, u8"\u2654");//unicode chess piece
    wK->box(FL_NO_BOX);
    wK->labelsize(48);
    wK->callback(firstPClicked, (void *)0, (void *)w);//0 being its pos in the piece vector
//the word callback is redlined in visual studio
}
//blackButtons omitted for simplicity's sake. exactly the same as whiteButtons.

void firstPClicked(Fl_Widget* f, void* d, void* w) {//cast or smthg
    if (((int*)d) == 0) {
        firstP = 0;
        ((Fl_Window*)w)->hide();
    }
}

真的不知道我需要在这里改变什么。任何想法或知道自己在做什么的人吗?

代码旨在调用设置函数,直到一个玩家获胜,通过关闭窗口有效地刷新窗口。所有函数都在 .h 文件中正确定义。这是我目前唯一的错误。

很多问题问是否可以对同一个函数进行多个按钮回调,但我想知道是否可以将多个东西传递给回调函数。常规回调语法如下。

void balls(int* argc, char** argv){
    Fl_Window *deez = new Fl_Window(300, 300);
    
    Fl_Button *nuts = new Fl_Button(100, 100, 100, 100, "Funny");
    nuts->callback(imSoFunny, void* 0);

}
void imSoFunny(Fl_Widget *w, (void*) d){
    if (((void*)d) == 0){
        std::cout << "ahhh";
    }
}
C++ FLTK语言

评论

0赞 Some programmer dude 6/14/2023
两件事:第一,每当你在用 C++ 编程时觉得需要做一个 C 风格的转换(类型转换),那么你应该把它看作是你可能做错了什么的标志;第二件事是,如果你有一个类型的变量,那么将其转换为类型是没有意义的。除此之外,在 C++ 中用于空指针。TTnullptr
1赞 john 6/14/2023
在 C++ 中,当您想将多个事物放入一个对象中时,您需要声明一个类或结构。对要传递给回调的内容执行此操作,并将指向该对象的指针传递给函数。然后,回调可以将 void 指针强制转换为对象指针。
0赞 Pepijn Kramer 6/14/2023
还要让自己清楚何时应该创建此结构。如果你可以重用相同的结构(因为你的应用是单线程的),请将其设为板的成员,并将指针传递给该结构。否则,回调必须分配结构,并且处理程序必须将其删除。
0赞 Pepijn Kramer 6/14/2023
在whiteButtons中,你创造了一个新的Fl_Button但你不会在任何地方销毁它。考虑创建一个按钮,以确保在程序结束时至少删除所有按钮。添加成员,然后创建和存储如下所示的按钮 请参阅 std::make_uniquestd::vector<std::unique_ptr<FlButton>>std::vector<FlButton> m_buttons;auto new_button = std::make_unique<FlButton>(wow[0]->yPos * 80, wow[0]->xPos * 80, 80, 80, u8"\u2654"); m_buttons.push_back(std::move(new_button));

答:

2赞 Some programmer dude 6/14/2023 #1

FLTK 是旧的,没有针对现代 C++ 进行更新。哎呀,它甚至没有考虑到旧的 C++11 之前的标准来设计或实现。

它使用 C 风格的编码习惯来做很多事情,包括回调,这意味着你将不得不加倍努力地工作并编写额外的代码来解决这些事情。

对于您的特定问题,“最简单”的解决方法是将所有参数收集到某种结构中,并使用指向该结构对象的指针作为回调函数的唯一参数。然后,回调函数将指针转换为正确的类型,并使用结构来获取不同的参数。reinterpret_cast

这种解决方法的好处是,其中一个结构成员可以是指向另一个对象的引用或指针,您可以使用该对象的成员函数作为实际回调。

1赞 GandhiGandhi 6/14/2023 #2

若要将多个值传递给此回调函数,必须:

  1. 声明一个,将所需的两个值打包在一起struct
  2. 使用要传递的值创建该结构的实例。像这样使用动态内存不被认为是“好的”现代 C++,但我认为它适用于您的示例。new
  3. 为回调函数提供指向该实例的指针。
  4. 完成后,调用以清理分配的内存。delete

其他评论者已经指出了这一点,但这里专门调整了您的示例。如果你想将 a 和 an 传递给你的回调,你可以这样做,你可以这样做:char *int

/* The two data values you want to pass to your callback packaged together */
struct GotEm {
    char * dragon;
    int dees;
}

void balls(int* argc, char** argv){
    Fl_Window *deez = new Fl_Window(300, 300);
    
    Fl_Button *nuts = new Fl_Button(100, 100, 100, 100, "Funny");
    /* Initialize how you want -- note that the callback data has to by dynamically allocated.
     * That means you'll have to call `delete` on it when the data goes out of scope.
     */
    GotEm *callback_data = new GotEm;
    callback_data->dragon = "foo";
    callback_data->dees = 0;

    nuts->callback(imSoFunny, (void*) &callback_data);

}
void imSoFunny(Fl_Widget *w, void* d){
    /* cast your data type back from the void pointer */
    GotEm * callback_data = (GotEm*) d;
    if (callback_data->dees == 0){
        std::cout << "ahhh";
    }
}

评论

0赞 esdv123 6/14/2023
lmao nice one 兄弟