0

我正在尝试将动态数量的滑块添加到 GUI 窗口,并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],即每个滑块将更新向量中的哪个元素。我尝试了类似这样的方法,但它不起作用,因为在实际调用函数/回调时,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/回调编程中众所周知的模式/解决方案,我只是还没有弄清楚。

4

1 回答 1

1

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

map<Slider*, float> my_values;
slider->setCallback([&](float value) {
      my_values[slider] = value; 
      });
于 2017-05-04T14:45:19.243 回答