使用回调中的值更新 std::vector 的 GUI 滑块的动态数量

Dynamic number of GUI sliders which update an std::vector with values in callbacks

我正在尝试向 GUI 添加动态数量的滑块 window,并根据每个滑块的变化方式更新 std::vector<float> 的值。 GUI 库使用回调,我可以成功地为一个滑块执行此操作(或者复制和粘贴滑块代码 20 次,但这不是解决方案),但是我在将滑块创建分解为函数时遇到问题:变量生命周期存在问题如何告诉每个滑块它应该更新向量中的哪个元素。

我正在使用 nanogui(或者特别是 libigl,它使用 nanogui),但我认为这个问题实际上很普遍,应该也适用于其他 GUI 框架或情况。

这是一个简短的代码版本,说明如何添加一个滑块并更新 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],即每个滑块将更新向量中的哪个元素。 我尝试了类似这样的方法,但它不起作用,因为在实际调用 function/callback 时,变量 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 成为一个 (const) 引用,甚至是 std::shared_ptr<int>(我知道,太可怕了),但仍然 value_id 始终未初始化my_values[value_id] = value;.

我怎样才能做到这一点?我的猜测是它一定是GUI/callback编程中的一个众所周知的pattern/solution,我只是还没有弄明白。

不要将滑块值存储在 std::vector<float> 中,而是使用 map<string, float>map<Slider*, float>。因此,无论何时调用回调,您都会知道要更新哪个变量(通过滑块的地址或名称)。

map<Slider*, float> my_values;
slider->setCallback([&](float value) {
      my_values[slider] = value; 
      });