I've got a glade-constructed TreeView/ListStore that I'm trying to load into an application and manipulate via gtkmm.
Here's the manager's 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);
}
And the implementation:
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);
}
Here's the function I'm trying to call to manipulate the 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;
}
And finally, the relevant 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>
The compilation fails, however, with the following:
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()));
^
I'm obviously misusing TreeModelColumn, but my source tutorial for this method (which as thus far proven reliable) does things in a similar fashion, so I'm at a loss for the correct method here.
Any help is appreciated. =)
You generally can't define the TreeModel (ListStore, TreeStore) in Glade when using gtkmm. The C (as used in Glade) and C++ types are just too different and the statically-typed C++ API can't know about your glade file's TreeModel definition at compile time.
Also, in your code, your treeview_info_column_time in your C++ code is a Gtk::TreeModelColumn<>. Your treeview_info_column_time in your Glade file is a GtkTreeViewColumn. Model columns and View columns are very different things. You can just use get_widget() to turn one into the other.
You are also trying to use get_widget() to get your liststore_info TreeModel (ListStore). But a TreeModel is not a widget. get_object() might work, but I just wouldn't bother trying to define the model in Glade. The tutorial that you link to doesn't do this either.
I've just worked out how to do this. It's slightly dodgy as you have to create a C++ class that matches the types in your .glade file, but providing they do match, you get the same type-safe functions as you do when creating the TreeView manually.
This works by
Cols::Cols()
adding the type-safe columns in the same order as the .glade file, so the index stored in each of thecolX
variables matches the data type in the corresponding index in the model. Just don't forget to update the code if you ever reorder the columns! You can even add some items to the TreeView within Glade, then append more items in code and they will all show up together at runtime!From reading the docs it looks like you could also use the type-unsafe
set_value()
function if you wanted to avoid creating theCols
class entirely, like this: (untested)The docs warn that a crash is likely to result if the data type doesn't match the expected column format, so going to the effort of creating a class like
Cols
is probably worth it.