How to get notified when a treeview (liststore) row is selected?
-
12-01-2021 - |
Question
How can I connect to a signal of a Gtk.TreeView so that I am notified when a row is selected? Currently I am connecting to the row_activated signal but this requires a double click on the row and I want to be notified on a single click.
Example program:
using Gtk;
public class MyListView : ScrolledWindow {
ListStore list_store;
TreeView tree_view;
GLib.List<string> list;
enum Columns {
TEXT,
N_COLUMNS
}
void make_list () {
list = new GLib.List<string> ();
list.append("Hello World");
list.append("row 2");
list.append("<b>bold</b>");
list.append("<i>italic</i>");
list.append("...");
list.append("etc.");
}
public MyListView () {
make_list();
list_store = new ListStore(Columns.N_COLUMNS, typeof(string));
tree_view = new TreeView.with_model(list_store);
var text = new CellRendererText ();
var column = new TreeViewColumn ();
column.pack_start (text, true);
column.add_attribute (text, "markup", Columns.TEXT);
tree_view.append_column (column);
tree_view.set_headers_visible (false);
TreeIter iter;
foreach (string item in list) {
list_store.append(out iter);
list_store.set(
iter,
Columns.TEXT, item
);
}
this.add(tree_view);
tree_view.row_activated.connect(change);
}
public void change (TreePath path, TreeViewColumn col) {
var index = int.parse(path.to_string());
var item = list.nth_data(index);
print(index.to_string() + ". " + item + "\n");
}
}
public static void main (string[] args) {
Gtk.init(ref args);
var win = new Window();
win.add(new MyListView());
win.show_all();
win.destroy.connect(Gtk.main_quit);
Gtk.main();
}
This program works exactly as I want except for the double click requirement of row_activated.
Solution
There's the changed signal of TreeSelection (get it using tree.get_selection()
), which should be the right way compared to cursor_changed.
OTHER TIPS
To get notified on a single click, connect to the cursor_changed signal. This doesn't expose any variables to the callback function so you need to define a separate function that gets the index of the selected item:
This function can use the get_selection() method of the TreeView object to get a TreeSelection object. Set the selection mode to single selection using the set_mode method. You can then get the TreeModel and TreeIter using the out parameters of the get_selected method. You should check the return value of this function - true if something is selected and false if nothing is selected. Then, use the get_path method of the TreeModel to get the TreePath of the selected item.
Full Example:
using Gtk;
public class MyListView : ScrolledWindow {
ListStore list_store;
TreeView tree_view;
GLib.List<string> list;
enum Columns {
TEXT,
N_COLUMNS
}
void make_list () {
list = new GLib.List<string> ();
list.append("Hello World");
list.append("row 2");
list.append("<b>bold</b>");
list.append("<i>italic</i>");
list.append("...");
list.append("etc.");
}
public MyListView () {
make_list();
list_store = new ListStore(Columns.N_COLUMNS, typeof(string));
tree_view = new TreeView.with_model(list_store);
var text = new CellRendererText ();
var column = new TreeViewColumn ();
column.pack_start (text, true);
column.add_attribute (text, "markup", Columns.TEXT);
tree_view.append_column (column);
tree_view.set_headers_visible (false);
TreeIter iter;
foreach (string item in list) {
list_store.append(out iter);
list_store.set(
iter,
Columns.TEXT, item
);
}
this.add(tree_view);
tree_view.cursor_changed.connect(change);
}
public int get_selected () {
var selection = tree_view.get_selection();
selection.set_mode(SelectionMode.SINGLE);
TreeModel model;
TreeIter iter;
if (!selection.get_selected(out model, out iter)) {
return -1;
}
TreePath path = model.get_path(iter);
return int.parse(path.to_string());
}
public void change () {
var index = this.get_selected();
if (index >= 0) {
var item = list.nth_data(index);
print(index.to_string() + ". " + item + "\n");
}
}
}
public static void main (string[] args) {
Gtk.init(ref args);
var win = new Window();
win.add(new MyListView());
win.show_all();
win.destroy.connect(Gtk.main_quit);
Gtk.main();
}