使用 gtkmm 构建的 Glade TreeView
Glade-constructed TreeView with gtkmm
我有一个林间空地构造的 TreeView/ListStore,我正在尝试将其加载到应用程序中并通过 gtkmm 进行操作。
这是经理的class:
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 这个方法(迄今为止被证明是可靠的)以类似的方式做事,所以我不知道这里的正确方法。
感谢任何帮助。 =)
在使用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 中定义模型。您 link 的教程也不会这样做。
我刚刚弄清楚如何做到这一点。它有点狡猾,因为您必须创建一个 C++ class 来匹配您的 .glade 文件中的类型,但如果它们确实匹配,您将获得与手动创建 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
class,您也可以使用类型不安全的 set_value()
函数,如下所示:(未经测试)
row.set_value(0, "value for first column");
row.set_value(1, "value for second column");
文档警告说,如果数据类型与预期的列格式不匹配,则可能会导致崩溃,因此努力创建 class 类似 Cols
可能是值得的它。
我有一个林间空地构造的 TreeView/ListStore,我正在尝试将其加载到应用程序中并通过 gtkmm 进行操作。
这是经理的class:
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 这个方法(迄今为止被证明是可靠的)以类似的方式做事,所以我不知道这里的正确方法。
感谢任何帮助。 =)
在使用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 中定义模型。您 link 的教程也不会这样做。
我刚刚弄清楚如何做到这一点。它有点狡猾,因为您必须创建一个 C++ class 来匹配您的 .glade 文件中的类型,但如果它们确实匹配,您将获得与手动创建 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
class,您也可以使用类型不安全的 set_value()
函数,如下所示:(未经测试)
row.set_value(0, "value for first column");
row.set_value(1, "value for second column");
文档警告说,如果数据类型与预期的列格式不匹配,则可能会导致崩溃,因此努力创建 class 类似 Cols
可能是值得的它。