Динамическое число ползунков GUI, которые обновляют std::vector со значениями в обратных вызовах

Я пытаюсь добавить динамическое количество ползунков в окно графического интерфейса и обновить std::vector<float> со значениями в зависимости от того, как меняется каждый слайдер. Библиотека GUI использует обратные вызовы, и я могу успешно сделать это для одного слайдера (или когда код 20 слайдера копируется и вставляется, но это не решение), однако у меня возникают проблемы, связанные с созданием слайдера в функцию: существуют проблемы с временем жизни переменной как сказать каждому ползунку, какой элемент в векторе он должен обновлять.

Я использую nanogui (или, в частности, libigl, который использует nanogui), но я думаю, что проблема на самом деле довольно общая и должна применяться и к другим средам или ситуациям с графическим интерфейсом.

Вот краткая версия кода, как добавить один ползунок и его обновления my_values[0] (обратите внимание, я должен был поставить "0" вручную):

int main(int argc, char *argv[])
{
  igl::viewer::Viewer viewer;
  std::vector<float> my_values(50);
  viewer.callback_init = [&](igl::viewer::Viewer& viewer)
    {
    nanogui::Slider* slider = new nanogui::Slider(viewer.ngui->window());

    slider->setCallback([&](float value) {
      my_values[0] = value; // this slider sets the value at element '0'
      });

    viewer.ngui->addWidget("0", slider);

    viewer.screen->performLayout();
    return false;
  };

  viewer.launch();
}

Теперь, как упоминалось ранее, в viewer.callback_initТеперь я хотел бы добавить 50 таких ползунков, но, очевидно, я не хочу копировать и вставлять ползунок и его код обратного вызова 50 раз. Но как-то мне нужно пройти my_values[i]то есть, какой элемент в векторе каждый слайдер будет обновлять. Я попытался что-то вроде этого, что не работает, потому что во время, когда функция / обратный вызов фактически вызывается, переменная value_id не определено:

int main(int argc, char *argv[])
{
  igl::viewer::Viewer viewer;
  std::vector<float> my_values(50);

  auto add_slider = [&](igl::viewer::Viewer& viewer, std::vector<float>& my_values, int value_id, std::string value_name)
    {   
    nanogui::Slider* slider = new nanogui::Slider(viewer.ngui->window());

    slider->setCallback([&](float value) {
      my_values[value_id] = value; // offending line, 'value_id' is not initialized
      // also I'm using 'value_name' to give the slider a name - code omitted
      });
    return slider;
  };

  viewer.callback_init = [&](igl::viewer::Viewer& viewer) {

    // Now add all 50 sliders (in a for-loop in real code obviously):
    viewer.ngui->addWidget("0", add_slider(viewer, 0, "0"));
    viewer.ngui->addWidget("1", add_slider(viewer, 1, "1"));
    // etc.

    viewer.screen->performLayout();
    return false;
  };

  viewer.launch();
}

Я пробовал разные вещи, делая value_id (постоянная) ссылка, даже std::shared_ptr<int> (Я знаю, ужасно), но все же value_id всегда не инициализируется в строке my_values[value_id] = value;,

Как я могу сделать это? Я предполагаю, что это должен быть известный шаблон / решение в программировании GUI/ обратного вызова, я просто еще не понял это.

1 ответ

Решение

Вместо того, чтобы хранить значения ползунка в std::vector<float>использовать map<string, float> или же map<Slider*, float>, Следовательно, всякий раз, когда вызывается ваш обратный вызов, вы будете знать, какую переменную обновлять (по адресу или имени ползунка).

map<Slider*, float> my_values;
slider->setCallback([&](float value) {
      my_values[slider] = value; 
      });
Другие вопросы по тегам