FLTK: какая кнопка нажата - передача числа в обратный вызов кнопки (лямбда)

У меня есть кнопки N в окне FLTK. Я хотел бы знать, какая кнопка была нажата пользователем. Как я могу передать номер функции обратного вызова лямбда каждой кнопки? До сих пор я пробовал это:

int main(int argc, char **argv) {
  Fl_Window *w_main = new Fl_Window(640, 480);

  std::vector<int> nums;
  for (int i = 0; i < 5; i++) {
    nums.push_back(i);

    Fl_Button *btn1 = new Fl_Button(50 * i, 0, 50, 50);
    char const *num = std::to_string(i).c_str();
    btn1->label(num);
    btn1->callback(
        [](Fl_Widget *w, void *data) { std::cout << "Clicked on: " << (int)data << std::endl; },
        &nums[i]);
  }
  w_main->show();
  return Fl::run();
}

К сожалению, я получаю на выходе случайные числа (я предполагаю, что какой-то случайный мусор памяти интерпретируется как целые числа).

Не могли бы вы помочь мне найти решение? Спасибо!


person G. C.    schedule 19.02.2020    source источник


Ответы (2)


Когда вы регистрируете свой обратный вызов:

btn1->callback(
        ...,
        &nums[i]);

Вы передаете адрес nums[i] в качестве аргумента обратного вызова (а не само значение). Поэтому вам нужно интерпретировать data как указанный адрес и разыменовать его, чтобы получить доступ к основному номеру.

Это означает:

btn1->callback(
        [](Fl_Widget *w, void *data) { std::cout << "Clicked on: " << *reinterpret_cast<int*>(data) << std::endl; },
        &nums[i]);

«Случайные» числа, которые вы видите, совсем не случайны. Они представляют точное место в памяти, где находится ваш номер. Явное преобразование адреса в числовое значение является вполне допустимым кодом, и это именно то, что вы сделали.

person Frank    schedule 19.02.2020

Вы также можете использовать координаты виджета, чтобы получить номер кнопки, так как вы определили положение кнопок.

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>

#include <iostream>
#include <vector>

void show(Fl_Widget *w){
     std::cout << w->x()/50+1 << std::endl; 
}

int main(int argc, char **argv) {


  Fl_Window *w_main = new Fl_Window(640, 480);

  Fl_Button* bts[5];
  for (int i = 0; i < 5; i++) {
    char *num = new char;
    std::strcpy (num, std::to_string(i+1).c_str());

    bts[i] = new Fl_Button(50 * i, 0, 50, 50,num);
    
    bts[i]->callback(show);
  }
  w_main->show();
  return Fl::run();
}

Таким образом, вам не нужно ничего передавать обратному вызову.

person Eddymage    schedule 19.08.2020