C #: get which button was clicked in a gtk # -buttons array?

I have a set of buttons that will all call the same method, but with the index of the button as an argument.

using System;
using Gtk;

public class Input : Gtk.Window {

    private Gtk.Button[] plus;

    public Input() : base(Gtk.WindowType.Toplevel) {

        plus = new Button[10];

      

[...]

        for (uint i = 0; i < 10; i++) {
            plus[i] = new Button();
            plus[i].Name = i.ToString();
            plus[i].ButtonPressEvent += AddButtonPressed;
        }
    }

      

I tried using this method, but it seems that it is not even called as there is no way out:

    protected virtual void AddButtonPressed(object sender, System.EventArgs e) {
        Console.WriteLine("Button pressed");
        for (uint i = 0; i < plus.Length; i++) {
        if (sender.Equals(plus[i])) {
            uint index = i;
            i = (uint)plus.Length;
            Console.WriteLine(index);
        }
    }

      

Can someone point me in the right direction? Thanks.

+1


a source to share


4 answers


Quick response:

[GLib.ConnectBefore]
protected virtual void AddButtonPressed(object sender, EventArgs e)     {
    Console.WriteLine("Button pressed");
    for (uint i = 0; i < plus.Length; i++) {
        if (sender.Equals(plus[i])) {
        uint index = i;
        i = (uint)plus.Length;
        Console.WriteLine(index);
        }
    }
}

      

Explanation explanation:

This is a really interesting question. It took a bit of searching, but the GTK # FAQ (but not often linked to, I guess) says:

"Since version 0.15, Gtk has been started # using the CONNECT_AFTER flag when attaching event handlers to signals. This means that event handlers do not fire until the signal has default handlers, which means the widget will update when event handlers are executed A side effect of this change is that in the case where the default handlers return true to stop signaling, no Gtk # events will be emitted. This is the case for the example in Gtk.Button where the button-event-button click signal handler overridden to emit an event.

While potentially confusing, this is not really a bug. When you use Gtk.Button, you get a widget that emits pressed events in response to buttons1. If you also want your button to change color or popup context menu on 3 buttons, this is not a Gtk.Button. The correct way to implement such a widget is to subclass Gtk.Button and override the Virtual OnButtonPressEvent method to implement the new desire behavior. "



If it weren't for "public protest" (rarely a sign of a good interface), there would be no way to avoid this other than subclassing, which is sometimes annoying in C # due to the lack of anonymous classes. But luckily, you are not the first person to have this problem. So when the GLib.ConnectBefore attribute appears. Basically he says, call this event handler first so that the event is not consumed by Gtk +.

However, the frustration doesn't end there. Initially, I was going to suggest using a proven solution to pass "extra" parameters to event handlers. In this case, it will allow you to find the index without using equals or string Name

. This mainly involves creating a wrapper delegate that "pretends" to be a ButtonPressEventHandler, but internally passes an int to your backing method:

    Func<uint, ButtonPressEventHandler> indexWrapper = ((index) => ((s, e) => { AddButtonPressed_wrapped(s, e, index); }));   

    ...

    plus[i].ButtonPressEvent += indexWrapper(i);

    ...

    protected virtual void AddButtonPressed_wrapped(object sender, EventArgs e, uint index)
    {
      Console.WriteLine("Button pressed");
      Console.WriteLine("Index = {0}", index);
    }

      

It compiles and runs without error, but has the same problem, the event never fires. I figured out that you cannot put the attribute directly into the delegate / lambda. Therefore, even though the backing method has [GLib.ConnectBefore]

, the delegate does not, so it fails.

As a final note, you can use the Clicked event as in this API example . I have verified that it works as expected. One would think that it would only fire on mouse clicks, but it actually fires on space too.

+2


a source


for (uint i = 0; i < 10; i++) 
{
    plus[i] = new Button();
    plus[i].Data.Add("Index",i);
    plus[i].ButtonPressEvent += AddButtonPressed;
    Add(plus[i]);
}

      

Handler:



protected virtual void AddButtonPressed(object sender, System.EventArgs e) {
   Console.WriteLine("Button pressed");
   Gtk.Button button = sender as Gtk.Button;
   Console.WriteLine("Index: {0}", button.Data["Index"]);
}

      

+1


a source


I'm sure you need to add buttons to your GTK window hierarchy, like this:

    for (uint i = 0; i < 10; i++) {
        plus[i] = new Button();
        plus[i].Name = i.ToString();
        plus[i].ButtonPressEvent += AddButtonPressed;
        Add(plus[i]);
    }

      

It should look like GTK has never been used <. <

0


a source


Use tag property if gtk button has one.

for (uint i = 0; i < 10; i++) {
    plus[i] = new Button();
    plus[i].Name = i.ToString();
    plus[i].ButtonPressEvent += AddButtonPressed;
    plus[i].Tag = i;
    Add(plus[i]);
}

      

Handler:

protected virtual void AddButtonPressed(object sender, System.EventArgs e) {
   Console.WriteLine("Button pressed");
   Gtk.Button button = sender as Gtk.Button;
   Console.WriteLine("Index: {0}", button.Tag);
}

      

0


a source







All Articles