1

我正在尝试从中派生一个类Gtk.Button。我遇到了一个可以解决的障碍(根本不使用OnActivate),但我无法解释,因此解决它可能不安全。

似乎覆盖继承自的OnActivate方法会改变按钮的行为。Gtk.ButtonGtk.Widget

为什么会这样,我该如何预防?

实现这种效果的唯一方法是一些丑陋的基于反射的检查。


这正是我所做的,您可以尝试什么来重现该问题:

这是一个包含自定义按钮类和该类的一个实例的小型 Gtk# 应用程序示例。OnActivate在自定义按钮类中没有被覆盖。

using System;

using Gtk;

namespace ButtonOnActivateExample
{
    class Program
    {
        private class MyButton : Button
        {
            public MyButton()
            {
            }

            public MyButton(IntPtr raw)
            {
            }
        }

        [STAThread]
        public static void Main(string[] args)
        {
            Application.Init();
            using (Window win = new Window("OnActivate Test")) {
                win.SetSizeRequest(300, 200);
                win.Hidden += delegate(object sender, EventArgs e) {
                    Application.Quit();
                };

                MyButton btn = new MyButton();
                btn.Clicked += delegate {
                    Console.WriteLine("clicked");
                };
                win.Add(btn);

                win.ShowAll();
                Application.Run();
                win.Destroy();
            }
        }
    }
}

单击按钮时,单击的单词将添加到控制台中的新行中。如果按钮被聚焦(通常是这种情况,因为它是窗口中唯一可聚焦的元素),并且用户按下空格键,同样会发生预期的情况(即触发Clicked事件)。


在这个修改后的版本中,有一个细微的变化:MyButton该类现在覆盖了该OnActivate方法,但被覆盖的版本除了调用该方法的继承版本之外什么都不做:

using System;

using Gtk;

namespace ButtonOnActivateExample
{
    class Program
    {
        private class MyButton : Button
        {
            public MyButton()
            {
            }

            public MyButton(IntPtr raw)
            {
            }

            protected override void OnActivate()
            {
                base.OnActivate();
            }
        }

        [STAThread]
        public static void Main(string[] args)
        {
            Application.Init();
            using (Window win = new Window("OnActivate Test")) {
                win.SetSizeRequest(300, 200);
                win.Hidden += delegate(object sender, EventArgs e) {
                    Application.Quit();
                };

                MyButton btn = new MyButton();
                btn.Clicked += delegate {
                    Console.WriteLine("clicked");
                };
                win.Add(btn);

                win.ShowAll();
                Application.Run();
                win.Destroy();
            }
        }
    }
}

这在语义上应该与第一个版本相同。然而,它并没有 - 莫名其妙地,应用程序的行为发生了变化!

文档只是说: “OnActivate在子类中覆盖此方法以在小部件被激活时得到通知,通常是在用户在键导航期间按 Enter 或 Space 时。”

单击该按钮仍会触发该Clicked事件。但是,按空格键不再起作用;控制台中什么也没有出现。

我可以使用 Gtk# for .NET、Windows 7 上的 Mono 和 Ubuntu 上的 Mono 始终如一地重现这种行为。

这里发生了什么?

4

1 回答 1

1

这是一个有趣的问题。不幸的是,我无法就确切原因给出明确的答案。尽管我查看了 gtk# 源代码,但我很快就迷失在了默认信号处理程序、类和 gtypes 的丛林中。

但是,如果您只是在寻找解决方案,我可以告诉您:您应该覆盖该OnActivated方法(最后带有 a d)。

于 2013-01-26T23:53:49.210 回答