C#:在一个gtk#-buttons数组中按下哪个按钮?

时间:2009-05-25 15:26:02

标签: c# arrays events button gtk#

我有一个按钮数组,它们都会调用相同的方法,但按钮的索引作为参数。

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;
        }
    }

我尝试使用这种方法,但它似乎甚至没有被调用,因为没有输出:

    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);
        }
    }

也许有人可以指出我正确的方向? 感谢。

4 个答案:

答案 0 :(得分:3)

快速回答:

[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);
        }
    }
}

漫无边际的解释:

这实际上是一个有趣的问题。需要一些搜索才能找到,但是GTK#'s FAQ(但我猜不经常链接)说,

  

“截至0.15版本,Gtk#开始了   使用CONNECT_AFTER标志时   将事件处理程序连接到信号。   这意味着事件处理程序是   直到默认信号后才运行   处理程序,这意味着小部件   将在活动时更新   处理程序运行。这样的副作用   改变是在那种情况下   默认处理程序返回true以停止   信号传播,Gtk#事件将   不被发射。情况就是如此   例如Gtk.Button,其中   按钮按下事件默认信号   处理程序被重写以发出Pressed   事件

     

虽然可能令人困惑,但这是   不是一个真正的错误。当你使用   Gtk.Button,你得到一个小部件   发出Pressed事件作为回应   到Button1按下。如果你也想要   您的按钮可以更改颜色或弹出窗口   Button3上的上下文菜单,   那不是Gtk.Button。正确的   实现这样一个小部件的方法是   子类Gtk.Button并覆盖   OnButtonPressEvent虚方法   实施你的新行为   欲望“。

如果不是“公众呐喊”(很少是良好界面的标志),就没有办法避免这种情况,除了由于缺少匿名类而有时在C#中烦人的子类化。但幸运的是,你不是第一个遇到这个问题的人。这就是GLib.ConnectBefore属性的用武之地。它基本上说,先调用这个事件处理程序,这样事件就不会被Gtk +吞噬。

虽然烦恼并没有结束。我本来打算建议应用一个经过验证的解决方案,将“额外”参数传递给事件处理程序。在这种情况下,这将允许您在不使用equals或Name字符串的情况下查找索引。它基本上涉及创建一个“假装”为ButtonPressEventHandler的包装器委托,但在内部将int传递给您的支持方法:

    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);
    }

它编译并运行没有错误,但它有同样的问题,事件永远不会触发。我意识到你不能直接在delegate / lambda上放置一个属性。因此,即使支持方法具有[GLib.ConnectBefore]委托,但它也失败了。

最后一点,您可以使用this API example中的Clicked事件。我确认它按预期工作。人们会认为它只会在鼠标点击时触发,但它实际上也会触发空格键。

答案 1 :(得分:1)

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

处理程序:

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"]);
}

答案 2 :(得分:0)

我很确定你需要将按钮实际添加到GTK窗口层次结构中,例如:

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

应该与此类似,从未实际使用过GTK&lt;。&lt;

答案 3 :(得分:0)

如果Gtk按钮有一个,请使用Tag属性。

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]);
}

处理程序:

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);
}