我有一个按钮数组,它们都会调用相同的方法,但按钮的索引作为参数。
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);
}
}
也许有人可以指出我正确的方向? 感谢。
答案 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);
}