为什么重写Gtk.Widget.OnActivate()更改窗口小部件的行为?

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

似乎覆盖了 Gtk.ButtonGtk.Widget 继承的OnActivate method改变了按钮的行为 .

Why is that, and how can I prevent it?

实现这种效果的唯一方法是进行一些难看的基于反射的检查 .


这正是我所做的,以及你可以尝试重现的问题:

这是一个小样本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 event被触发) .


在这个修改版本中,有一个小的改动: 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();
            }
        }
    }
}

这应该在语义上与第一个版本相同 . 然而,它并非 - 莫名其妙地,应用程序的行为已经改变了!

docs只是说 OnActivate :"Override this method in a subclass to be notified when the widget is activated, commonly when the user presses Enter or Space during key navigation."

单击该按钮仍会触发 Clicked 事件 . 但是,按空格键不再有效;控制台中没有任何内容 .

我可以用Gtk#for .NET,Windows 7上的Mono和Ubuntu上的Mono来持续重现这种行为 .

What is going on here?

回答(1)

2 years ago

这是一个有趣的问题 . 不幸的是,我无法就确切的原因给出明确的答案 . 即使我已经查看了gtk#source,我很快就在默认信号处理程序,类和gtypes的丛林中迷失了 .

但是,如果您只是在寻找解决方案,我可以告诉您:您应该重写 OnActivated 方法(最后使用 d ) .