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

时间:2013-01-26 16:52:08

标签: .net mono widget override gtk#

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

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

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

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


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

这是一个小样本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:“在子窗口中覆盖此方法,以便在窗口小部件激活时得到通知,通常是在用户在键导航期间按下Enter或Space时。”

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

我可以使用Gtk#for .NET,Windows 7上的Mono和Ubuntu上的Mono继续重现此行为。

这里发生了什么?

1 个答案:

答案 0 :(得分:1)

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

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