提问人:esdv123 提问时间:6/14/2023 更新时间:6/14/2023 访问量:92
是否可以将多个参数传递给 FLTK 按钮回调函数?
Can I pass more than 1 parameter to a FLTK button callback function?
问:
尝试使用 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";
}
}
答:
FLTK 是旧的,没有针对现代 C++ 进行更新。哎呀,它甚至没有考虑到旧的 C++11 之前的标准来设计或实现。
它使用 C 风格的编码习惯来做很多事情,包括回调,这意味着你将不得不加倍努力地工作并编写额外的代码来解决这些事情。
对于您的特定问题,“最简单”的解决方法是将所有参数收集到某种结构中,并使用指向该结构对象的指针作为回调函数的唯一参数。然后,回调函数将指针转换为正确的类型,并使用结构来获取不同的参数。reinterpret_cast
这种解决方法的好处是,其中一个结构成员可以是指向另一个对象的引用或指针,您可以使用该对象的成员函数作为实际回调。
若要将多个值传递给此回调函数,必须:
- 声明一个,将所需的两个值打包在一起
struct
- 使用要传递的值创建该结构的实例。像这样使用动态内存不被认为是“好的”现代 C++,但我认为它适用于您的示例。
new
- 为回调函数提供指向该实例的指针。
- 完成后,调用以清理分配的内存。
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";
}
}
评论
T
T
nullptr
std::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));