您的位置:首页 > 其它

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

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





  按照那篇的博文的第一种方法,新建了Form1,改写了Form1的CreateParams属性,将FormBorderStyle设置为 System.Windows.Forms.FormBorderStyle.None。

  Protected Overrides ReadOnly Property CreateParams() As CreateParams

    Get

      Dim tC As CreateParams = MyBase.CreateParams

      tC.ExStyle = tC.ExStyle Or &H8000000

      Return tC

    End Get

  End Property

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

  于是,又新建Form2,并改为启动窗口,上面添加了Textbox1控件,在该控件的双击事件,启动Form1

  Private Sub TextBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.DoubleClick

    Form1.Show()

  End Sub

复制代码
按照设想,双击文本框的时候,弹出Form1,光标仍然在文本框内。

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

  后来想想,在启动Form1后,强制将焦点切回来后能不能好一点呢,于是,将上面的代码改为

  Private Sub TextBox1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.DoubleClick

    Form1.Show()

    Me.Activate()

  End Sub

复制代码
启动Form1后,光标的确在文本框,但单击Form1后,光标又没了,焦点在Form1上。“杯具”呀。

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

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

   后来在网上查找到一篇文章,通篇的英文,没有细看,将里面的代码测试了一下,能成功。网址如下:On-screen Keyboards,相关代码如下:

private const int

WS_EX_NOACTIVATE = 0x08000000;

protected override CreateParams CreateParams

{

get

{

CreateParams createParams =

base.CreateParams;

createParams.ExStyle = createParams.ExStyle & WS_EX_NOACTIVATE;

return createParams;

}

}

Finally, you need to prevent the form getting focus or being activated

when it or the keyboard control are clicked on. This is as easy as

adding the following code to the host form;

private const int WM_MOUSEACTIVATE

= 0x0021;

private const int MA_NOACTIVATE

= 0x0003;

protected override void WndProc(ref Message m)

{

//If we're being activated because

the mouse clicked on us...

if (m.Msg == WM_MOUSEACTIVATE)

{

//Then refuse to be activated, but

allow the click event to pass through (don't use MA_NOACTIVATEEAT)

m.Result = (IntPtr)MA_NOACTIVATE;

}

else

base.WndProc(ref m);

}

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

  代码如下:

  Private Const WM_MOUSEACTIVATE As Integer = &H21

  Private Const MA_NOACTIVATE As Integer = &H3

  Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)

    If m.Msg = WM_MOUSEACTIVATE Then

      m.Result = MA_NOACTIVATE

    Else

      MyBase.WndProc(m)

    End If

  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,键盘也不会抢占焦点了~

要下载例程请点这里

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: