创建类似于输入法窗口的非激活窗口

前两日,偶见博客“ 创建类似于输入法窗口的非激活窗口”,觉得内容不错,决定试了试,发现有瑕疵,现将自己的 测试过程赋予其后(本文测试用的是VS2005),和各位网友交流。

image

  按照那篇的博文的第一种方法,新建了Form1,改写了Form1的CreateParams属性,将FormBorderStyle设置为 System.Windows.Forms.FormBorderStyle.None。
  1.   Protected Overrides ReadOnly Property CreateParams() As CreateParams
  2.     Get
  3.       Dim tC As CreateParams = MyBase.CreateParams

  4.       tC.ExStyle = tC.ExStyle Or &H8000000

  5.       Return tC

  6.     End Get

  7.   End Property
复制代码
测试了一下,不错,和打开的“记事本”做了比较,当我单击Form1的时候,光标还在“记事本”里。

  于是,又新建Form2,并改为启动窗口,上面添加了Textbox1 控件,在该控件的双击事件,启动Form1
  1.   Private Sub TextBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.DoubleClick

  2.     Form1.Show()
  3.   End Sub
复制代码
按照设想,双击文本框的时候,弹出Form1,光标仍然在文本框内。

  不成想,光标不见了,文本框失去焦点,焦点在Form1上(后来将Form1的FormBorderStyle设置为 System.Windows.Forms.FormBorderStyle.FixedToolWindow后证实了这一点。焦点的确移到Form1 上)

  后来想想,在启动Form1后,强制将焦点切回来后能不能好一点呢,于是,将上面的代码改为
  1.   Private Sub TextBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.DoubleClick

  2.     Form1.Show()

  3.     Me.Activate()
  4.   End Sub
复制代码
启动Form1后,光标的确在文本框,但单击Form1后,光标又没了,焦点在Form1上。“杯具”呀。

  如此努力了若干次,均没有效果,貌似单个程序里有两个Form(或者超过两个),这个效果就出不来。

  后来查了查&H8000000代表的含义是WS_DISABLED,也没整明白是什么意思。

    后来在网上查找到一篇文章,通篇的英文,没有细看,将里面的代码测试了一下,能成功。网址如下: On-screen Keyboards,相关代码如下:
  1. private const int
  2. WS_EX_NOACTIVATE = 0x08000000;



  3. protected override CreateParams CreateParams

  4. {

  5. get

  6. {

  7. CreateParams createParams =
  8. base.CreateParams;

  9. createParams.ExStyle = createParams.ExStyle & WS_EX_NOACTIVATE;

  10. return createParams;

  11. }

  12. }

  13. Finally, you need to prevent the form getting focus or being activated
  14. when it or the keyboard control are clicked on. This is as easy as
  15. adding the following code to the host form;

  16. private const int WM_MOUSEACTIVATE
  17. = 0x0021;

  18. private const int MA_NOACTIVATE
  19. = 0x0003;

  20. protected override void WndProc(ref Message m)

  21. {

  22. //If we're being activated because
  23. the mouse clicked on us...

  24. if (m.Msg == WM_MOUSEACTIVATE)

  25. {

  26. //Then refuse to be activated, but
  27. allow the click event to pass through (don't use MA_NOACTIVATEEAT)

  28. m.Result = (IntPtr)MA_NOACTIVATE;

  29. }

  30. else

  31. base.WndProc(ref m);

  32. }
复制代码
他的代码中,添加了一段修改Form的WndProc代码,拦截WM_MOUSEACTIVATE消息,改为MA_NOACTIVATE。

  代码如下:
  1.   Private Const WM_MOUSEACTIVATE As Integer = &H21

  2.   Private Const MA_NOACTIVATE As Integer = &H3

  3.   Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
  4.     If m.Msg = WM_MOUSEACTIVATE Then
  5.       m.Result = MA_NOACTIVATE
  6.     Else

  7.       MyBase.WndProc(m)

  8.     End If

  9.   End Sub
复制代码
经测试,终于达到了效果,启动Form1,光标在文本框内,无论怎么点击Form1,光标都不曾发生变化。

  上面这段的代是有效的,甚至去掉一开始的改写CreateParams的代码,仍然有效。

  再做了若干测试,发现上面的代码效果,如果要成功,还必不可少的是Form上没有能接受焦点的控件(Button,TextBox等),而且还不能有标题栏。解决的办法,就是去掉Form的标题栏,不使用能接受焦点的控件(或者是改写控件的WndProc过程,拦截接受焦点的消息,使之不能接受焦点)。虽然Form不能接受焦点,但是经过测试,控件还是能接受其他的事件(例如:Click,DoubleClick,MouseHover,MouseLeave 等事件),合理运用的话,还是能产生不错的效果。(文/ 万仓一黍
 

上文中提到假如窗体上有可以获得焦点的Control时,改写控件的WndProc过程,拦截接受焦点的消息,使之不能接受焦点,

补充代码如下:

       [DllImport("user32.dll")]
        private extern static IntPtr SetActiveWindow(IntPtr handle);
        private const int WM_ACTIVATE = 0x006;
        private const int WM_ACTIVATEAPP = 0x01C;
        private const int WM_NCACTIVATE = 0x086;
        private const int WA_INACTIVE = 0;
        private const int WM_MOUSEACTIVATE = 0x21;
        private const int MA_NOACTIVATE = 3;

 protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_MOUSEACTIVATE)
            {
                m.Result = new IntPtr(MA_NOACTIVATE);
                return;
            }
            else if (m.Msg == WM_NCACTIVATE)
            {
                if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
                {
                    if (m.LParam != IntPtr.Zero)
                    {
                        SetActiveWindow(m.LParam);
                    }
                    else
                    {
                        SetActiveWindow(IntPtr.Zero);
                    }
                }
            }
            base.WndProc(ref m);
        }
这样即使窗体上有可获得焦点的Control,键盘也不会抢占焦点了~

 

要下载例程请点这里

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值