带有 gtkmm 的 Glade 构建的 TreeView

Posted

技术标签:

【中文标题】带有 gtkmm 的 Glade 构建的 TreeView【英文标题】:Glade-constructed TreeView with gtkmm 【发布时间】:2015-01-28 19:33:09 【问题描述】:

我有一个空地构造的 TreeView/ListStore,我正在尝试将其加载到应用程序中并通过 gtkmm 进行操作。

这是经理的课程:

typedef struct

  Gtk::ListStore *liststore_info;
  Gtk::TreeModelColumn<string> *treeview_info_column_time;
  Gtk::TreeModelColumn<string> *treeview_info_column_message;
UiElements;

class GuiManager

  Glib::RefPtr<Gtk::Builder> builder;
  UiElements elements;

  public:
    GuiManager();
    ~GuiManager();

    void info_handler(string msg);

以及实现:

GuiManager::GuiManager()

  builder = Gtk::Builder::create();
  builder->add_from_file("GUI.glade");

  builder->get_widget("liststore_info", elements.liststore_info);
  builder->get_widget("treeview_info_column_time", elements.treeview_info_column_time);
  builder->get_widget("treeview_info_column_message", elements.treeview_info_column_message);

这是我试图调用来操作 TreeView 的函数:

void GuiManager::info_handler(string msg)

  Gtk::TreeModel::Row row = *(elements.liststore_info->append());
  row[*(elements.treeview_info_column_time)] = "Now";
  row[*(elements.treeview_info_column_message)] = msg;

最后,相关的 Glade XML:

<object class="GtkListStore" id="liststore_info">
  <columns>
    <!-- column-name Time -->
    <column type="string"/>
    <!-- column-name Message -->
    <column type="string"/>
  </columns>
</object>
<object class="GtkTreeView" id="treeview_info">
  <property name="visible">True</property>
  <property name="can_focus">True</property>
  <property name="model">liststore_info</property>
  <property name="enable_search">False</property>
  <property name="enable_grid_lines">both</property>
  <child internal-child="selection">
    <object class="GtkTreeSelection" id="treeview-selection2"/>
  </child>
  <child>
    <object class="GtkTreeViewColumn" id="treeview_info_column_time">
      <property name="resizable">True</property>
      <property name="sizing">autosize</property>
      <property name="min_width">100</property>
      <property name="title" translatable="yes">Time</property>
      <property name="clickable">True</property>
    </object>
  </child>
  <child>
    <object class="GtkTreeViewColumn" id="treeview_info_column_message">
      <property name="resizable">True</property>
      <property name="sizing">autosize</property>
      <property name="min_width">300</property>
      <property name="title" translatable="yes">Message</property>
      <property name="clickable">True</property>
    </object>
  </child>
</object>

但是编译失败,出现以下情况:

In file included from /usr/include/gtkmm-3.0/gtkmm.h:119:0,
                 from GUI3_gui_manager.h:8,
                 from GUI3_gui_manager.cpp:1:
/usr/include/gtkmm-3.0/gtkmm/builder.h: In instantiation of ‘void Gtk::Builder::get_widget(const Glib::ustring&, T_Widget*&) [with T_Widget = Gtk::TreeModelColumn<std::basic_string<char> >]’:
GUI3_gui_manager.cpp:64:86:   required from here
/usr/include/gtkmm-3.0/gtkmm/builder.h:628:93: error: ‘get_base_type’ is     not a member of ‘Gtk::TreeModelColumn<std::basic_string<char> >’
     widget = dynamic_cast<T_Widget*>(this->get_widget_checked(name, T_Widget::get_base_type()));
                                                                                             ^

我显然误用了 TreeModelColumn,但我的 source tutorial 使用这种方法(迄今为止证明是可靠的)以类似的方式做事,所以我不知道这里的正确方法。

感谢任何帮助。 =)

【问题讨论】:

【参考方案1】:

我刚刚想出了如何做到这一点。这有点狡猾,因为您必须创建一个与 .glade 文件中的类型匹配的 C++ 类,但如果它们匹配,您将获得与手动创建 TreeView 时相同的类型安全功能。

class Cols: public Gtk::TreeModel::ColumnRecord 
    public:
        Cols() 
            // This order must match the column order in the .glade file
            this->add(this->colA);
            this->add(this->colB);
            this->add(this->colC);
        

        // These types must match those for the model in the .glade file
        Gtk::TreeModelColumn<Glib::ustring> colA;
        Gtk::TreeModelColumn<Glib::ustring> colB;
        Gtk::TreeModelColumn<Glib::ustring> colC;
;

...

// Get hold of the TreeView from the .glade file
Gtk::TreeView* tv = nullptr;
refBuilder->get_widget("treeview1", tv); // refBuilder is Gtk::Builder instance
assert(tv);

// Get hold of the ListStore model from the .glade file
auto items = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(
    refBuilder->get_object("listmodel1")
);
assert(items);

Cols mycols;

// Populate tree view with items
auto row = *(items->append());
row[mycols.colA] = "Row 1 Col 1";
row[mycols.colB] = "Row 1 Col 2";

row = *(items->append());
row[mycols.colA] = "Row 2 Col 1";

这通过Cols::Cols() 以与 .glade 文件相同的顺序添加类型安全列来工作,因此存储在每个colX 变量中的索引与模型中相应索引中的数据类型匹配。如果您对列重新排序,请不要忘记更新代码!您甚至可以在 Glade 中向 TreeView 添加一些项目,然后在代码中附加更多项目,它们将在运行时一起显示!

从阅读文档看来,如果您想完全避免创建 Cols 类,您也可以使用类型不安全的 set_value() 函数,如下所示:(未经测试)

row.set_value(0, "value for first column");
row.set_value(1, "value for second column");

文档警告说,如果数据类型与预期的列格式不匹配,可能会导致崩溃,因此努力创建像 Cols 这样的类可能是值得的。

【讨论】:

今晚我终于回到了这个问题。当我完全实施您的解决方案时,我会在控制台中得到以下信息:(gui3:2812): Gtk-WARNING **: gtkliststore.c:836: Unable to convert from glibmm__CustomPointer_Pc to gchararray 如果您愿意,我可以用新的源代码修改原始帖子。 =) 注意:这是因为我对列类和 Glade 文件使用了 gchararray 类型。我尝试切换到 Glib::ustring 并得到:Unknown type Glib::ustring specified in treemodel liststore_infogtkliststore.c:516: Invalid type (null) Glib::ustring 是用于gchararray 类型的 Glade GtkListStore 列的正确 C++ 类型。你能确认你没有将Glib::ustring 放入 Glade 文件中吗? 我可以做得更好,并用一个新线程确认我目前的状况:***.com/questions/32530367/glade-gtkmm-treeview =) 之所以被选为答案,是因为这个,加上新线程,有效。【参考方案2】:

在使用 gtkmm 时,一般不能在 Glade 中定义 TreeModel(ListStore、TreeStore)。 C(在 Glade 中使用)和 C++ 类型太不同了,静态类型的 C++ API 在编译时无法知道您的 glade 文件的 TreeModel 定义。

此外,在您的代码中,您的 C++ 代码中的 treeview_info_column_time 是 Gtk::TreeModelColumn。 Glade 文件中的 treeview_info_column_time 是 GtkTreeViewColumn。模型列和视图列是非常不同的东西。您可以使用 get_widget() 将一个变成另一个。

您还尝试使用 get_widget() 来获取您的 liststore_info TreeModel (ListStore)。但是 TreeModel 不是小部件。 get_object() 可能有效,但我只是不会费心尝试在 Glade 中定义模型。您链接到的教程也不这样做。

【讨论】:

以上是关于带有 gtkmm 的 Glade 构建的 TreeView的主要内容,如果未能解决你的问题,请参考以下文章

gtkmm & glade - 多个窗口不工作

进度条 gtkmm Glade

使用 Glade 和 gtkmm 对 GTK+ 对象进行内存管理

关于 glade3 和 gtkmm 的 Linux / C++ 帮助

gtkmm 对某些 gtk::builder 函数 add_from_file 的未定义引用

调整对象不是小部件类型 GtkBuilder