Gtkmm:创建一个 Gtk::ComboBox,其中列出 Gtk::DrawingArea

Gtkmm: create a Gtk::ComboBox which lists Gtk::DrawingArea

我正在尝试创建一个 Gtk::ComboBox 列表 Gtk::DrawingArea 小部件。我关注了this tutorial。到目前为止,这是 Gtkmm3 的最小工作示例(即可用于重现问题):

#include <gtkmm.h>

class NewPlayerRow : public Gtk::ListBoxRow
{

public:

    NewPlayerRow();

private:

    // Model for the combobox row: a disc with the appropriate player color...
    struct NewPlayerDiscColorComboRowModel : public Gtk::TreeModel::ColumnRecord
    {
        NewPlayerDiscColorComboRowModel()
        {
            add(m_discColorIcon);
        }

        Gtk::TreeModelColumn<Gtk::DrawingArea> m_discColorIcon;
    };

    NewPlayerDiscColorComboRowModel m_comboRowModel;
    Glib::RefPtr<Gtk::ListStore>    m_listStore;

    Gtk::ComboBox m_comboBox;
};

NewPlayerRow::NewPlayerRow()
{
    // First, create and register the TreeModel:
    m_listStore = Gtk::ListStore::create(m_comboRowModel);
    m_comboBox.set_model(m_listStore);

    // Then, populate the TreeModel:
    Gtk::TreeModel::Row row = *(m_listStore->append());
    row[m_comboRowModel.m_discColorIcon] = Gtk::DrawingArea();

    row = *(m_listStore->append());
    row[m_comboRowModel.m_discColorIcon] = Gtk::DrawingArea();

    // Add the model columns to the Combo:
    m_comboBox.pack_start(m_comboRowModel.m_discColorIcon);

    add(m_comboBox);
}

int main(int argc, char** argv)
{
    Glib::RefPtr<Gtk::Application> app{Gtk::Application::create(argc, argv, "com.github.bobmorane22.connectx")};

    NewPlayerRow np;
    Gtk::Window w;
    w.add(np);
    w.show_all();

    return app->run(w);
}

当我编译它时,出现以下错误:

In file included from /usr/include/glibmm-2.4/glibmm/value.h:196:0,
                 from /usr/include/glibmm-2.4/glibmm/propertyproxy_base.h:25,
                 from /usr/include/glibmm-2.4/glibmm/propertyproxy.h:25,
                 from /usr/include/glibmm-2.4/glibmm/objectbase.h:24,
                 from /usr/include/glibmm-2.4/glibmm/object.h:29,
                 from /usr/include/pangomm-1.4/pangomm/context.h:32,
                 from /usr/include/gtkmm-3.0/gtkmm/widget.h:32,
                 from /usr/include/gtkmm-3.0/gtkmm/actiongroup.h:29,
                 from /usr/include/gtkmm-3.0/gtkmm/application.h:32,
                 from src/main.cpp:32:
/usr/include/glibmm-2.4/glibmm/value_custom.h: In instantiation of ‘static void Glib::Value<T>::value_copy_func(const GValue*, GValue*) [with T = Gtk::DrawingArea; GValue = _GValue]’:
/usr/include/glibmm-2.4/glibmm/value_custom.h:257:9:   required from ‘static GType Glib::Value<T>::value_type() [with T = Gtk::DrawingArea; GType = long unsigned int]’
/usr/include/gtkmm-3.0/gtkmm/treemodelcolumn.h:134:64:   required from ‘Gtk::TreeModelColumn<T>::TreeModelColumn() [with T = Gtk::DrawingArea]’
src/main.cpp:50:9:   required from here
/usr/include/glibmm-2.4/glibmm/value_custom.h:283:33: error: use of deleted function ‘Gtk::DrawingArea::DrawingArea(const Gtk::DrawingArea&)’
   dest_value->data[0].v_pointer = new(std::nothrow) T(source);
                                 ^
In file included from /home/morane/Programming/cpp/ConnectX/cxgui/include/GeometricShape.h:35:0,
                 from /home/morane/Programming/cpp/ConnectX/cxgui/include/Disc.h:35,
                 from src/../include/../include/CXDisc.h:35,
                 from src/../include/../include/GBDisc.h:37,
                 from src/../include/GameBoard.h:41,
                 from src/../include/GameWindow.h:17,
                 from src/main.cpp:34:
/usr/include/gtkmm-3.0/gtkmm/drawingarea.h:64:3: note: declared here
   DrawingArea(const DrawingArea&) = delete;

这似乎表明组合框行模型中的类型必须是可复制的才能工作。我已经尝试在上面的代码中将类型 Gtk::DrawingArea 替换为 std::string (可复制)并且它构建良好并且运行良好。我可以看到带有文本行的组合框。

有办法解决这个问题吗?我真的很想创建一个列出绘图区域的组合框。


EDIT 深入研究错误,我发现问题出在 Glibmm 中的文件 value_custom.h 中。以下两个函数似乎解决了这个问题,因为它们试图访问模板化类型的复制成员操作(在我的例子中 Gtk::DrawingArea,如上所述,它是不可复制的)。

// static
template <class T>
GType Value<T>::value_type()
{
  if(!custom_type_)
  {
    custom_type_ = Glib::custom_boxed_type_register(
        typeid(CppType).name(),
        &Value<T>::value_init_func,
        &Value<T>::value_free_func,
        &Value<T>::value_copy_func);
  }
  return custom_type_;
}

// static
template <class T>
void Value<T>::value_copy_func(const GValue* src_value, GValue* dest_value)
{
  // Assume the source is not NULL.  See value_init_func().
  const T& source = *static_cast<T*>(src_value->data[0].v_pointer);
  dest_value->data[0].v_pointer = new(std::nothrow) T(source);
}

我开始觉得没有办法解决这个问题...Glib::Value<T>documentation 甚至提到类型 T 必须实现复制 assignment/construction.

如果你有想法,我洗耳恭听。

经过更多的研究,我得出的结论是 Gtk::ComboBoxes 根本不是为了容纳小部件而设计的(因此 Gtk::DrawingAreas),因为它在其 TreeModel,其中 T 需要可复制。

换句话说,构成组合框模型的类型(即当您单击它时它实际列出的类型)必须是可复制的,否则框架将不允许您的代码编译。

起初,无法复制小部件这一事实对我来说毫无意义,但经过一番研究,我发现 this article,这清楚地解释了一些(棘手的)问题,当使用可复制的小部件。

总而言之,我似乎正在努力完成一些事情,但回想起来,这在 UI 方面有点奇怪,我将尝试找到一些更简洁的方式来表达我的意图。