按照那篇的博文的第一种方法,新建了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
于是,又新建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的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
如此努力了若干次,均没有效果,貌似单个程序里有两个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);
- }
代码如下:
- 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
上面这段的代是有效的,甚至去掉一开始的改写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,键盘也不会抢占焦点了~
要下载例程请点这里