rrirower
rrirower

Reputation: 4590

Get selected column from GTK# NodeView

I'm writing some C# code on a Raspberry Pi using MonoDevelop. I've got a NodeView widget that contains three columns. I'd like to detect the column that was clicked in the NodeView. I've tried to use NodeSelection.Changed, but, that does not tell me the column. I've also tried coding a ButtonPress event for the NodeView and drilling down to the TreePath. I got nowhere with that.

I've noticed this question asked several times. But, I haven't seen a straight forward wy to get the row/column for a selected item in a NodeView.

Does anyone know how to do this?

Upvotes: 1

Views: 219

Answers (1)

Andy
Andy

Reputation: 13607

Finally figured it out. This was a pain because, like you said, there is zero documentation on this.

So, to outline what I did, here is what my window looks like: program

When I click on different columns, this is the output:

Clicked on column index 3 with title "hello 3"
Node selected: Prop1 29478338;Prop2 55998661;Prop3 1058200043;Prop4 1429485106
Clicked on column index 2 with title "hello 2"
Node selected: Prop1 1781730137;Prop2 618078535;Prop3 1253079243;Prop4 1149116957
Clicked on column index 1 with title "hello 1"
Node selected: Prop1 1577113328;Prop2 1907291485;Prop3 764000225;Prop4 1871218984
Clicked on column index 0 with title "hello 0"
Node selected: Prop1 1267506574;Prop2 692394441;Prop3 1291543143;Prop4 41456018
Clicked on column index 1 with title "hello 1"
Node selected: Prop1 1659363497;Prop2 873230641;Prop3 1799765877;Prop4 83248840
Clicked on column index 2 with title "hello 2"
Node selected: Prop1 1882743696;Prop2 419098689;Prop3 554049937;Prop4 671882960

And the code, as "not pretty" as it is (just quickly throwing stuff up to get it to work):

Random r = new Random();

[Gtk.TreeNode(ListOnly = true)]
public class MyTreeNode : Gtk.TreeNode
{
    public MyTreeNode(Random r)
    {
        AnotherProp1 = $"Prop1 {r.Next()}";
        AnotherProp2 = $"Prop2 {r.Next()}";
        AnotherProp3 = $"Prop3 {r.Next()}";
        AnotherProp4 = $"Prop4 {r.Next()}";
    }

    [Gtk.TreeNodeValue(Column = 0)]
    public string AnotherProp1 { get; private set; }

    [Gtk.TreeNodeValue(Column = 1)]
    public string AnotherProp2 { get; private set; }

    [Gtk.TreeNodeValue(Column = 2)]
    public string AnotherProp3 { get; private set; }

    [Gtk.TreeNodeValue(Column = 3)]
    public string AnotherProp4 { get; private set; }

    public override string ToString() =>
        $"{AnotherProp1};{AnotherProp2};{AnotherProp3};{AnotherProp4}";
}

private readonly NodeStore _store = new NodeStore(typeof(MyTreeNode));

public MainWindow() : base(Gtk.WindowType.Toplevel)
{
    Build();

    for (var i = 0; i < 6; ++i)
    {
        _store.AddNode(new MyTreeNode(r));
    }
    nodeview2.NodeStore = _store;

    nodeview2.AppendColumn("hello 0", new CellRendererText(), "text", 0).Clickable = true;
    nodeview2.AppendColumn("hello 1", new CellRendererText(), "text", 1).Clickable = true;
    nodeview2.AppendColumn("hello 2", new CellRendererText(), "text", 2).Clickable = true;
    nodeview2.AppendColumn("hello 3", new CellRendererText(), "text", 3).Clickable = true;

    // how to detect column header clicks:
    nodeview2.GetColumn(0).Clicked += (s, e) => Console.WriteLine("HERE 0");
    nodeview2.GetColumn(1).Clicked += (s, e) => Console.WriteLine("HERE 1");
    nodeview2.GetColumn(2).Clicked += (s, e) => Console.WriteLine("HERE 2");
    nodeview2.GetColumn(3).Clicked += (s, e) => Console.WriteLine("HERE 3");

    nodeview2.WidgetEvent += (s, e) =>
    {
        if ((e.Event is Gdk.EventButton ev) &&
           (ev.Type == Gdk.EventType.ButtonPress) &&
           (ev.Window == nodeview2.BinWindow))
        {
            if (nodeview2.GetPathAtPos((int)ev.X, (int)ev.Y, out var path, out var column))
            {
                // get the column index. There must be a better way?
                var columnIndex = nodeview2.Columns.Select(
                    (col, index) => new { col, index }).First(x => ReferenceEquals(x.col, column)).index;

                Console.WriteLine($"Clicked on column index {columnIndex} with title \"{column.Title}\"");

                var nodeValue = (MyTreeNode)_store.GetNode(path);
                Console.WriteLine($"Node selected: {nodeValue}");
            }
        }
    };

    nodeview2.ShowAll();
}

So the trick here is to catch the EventButton's ButtonPress then take the coordinates and pass them to GetPathAtPos(). That returns column and path info. You can use that to derive what you need. I wish Gtk# was better documented/more widely used.

Upvotes: 1

Related Questions