不能在模式表单中Release自己
Form1的一个方法中如下:
var
x:tform2;
begin
x:=tform2.CreateParented(Self.Handle);
x.ShowModal;
如果在Form2中的某个事件方法中使用Self.Release释放自己,则Form2消失了,Form1却再也不响应键盘和鼠标。如果改成以下这样也不行:
x:=tform2.CreateParented(Self.Handle); (或 x:=tform2.Create(nil) )
x.ShowModal;
x.release; (或x.Free)
将第2句改成 x.Show 以后一切正常。
结论:不能在模式表单中Release自己,
原理:经代码追溯,发现表单是这样实现的:在 ShowModal 方法中重复检查消息和ModalResult属性值,直到符合条件后,再进行关闭自己的一系列动作。所以,如果在模式表单中调用Release或类似方法将引发混乱。要在模式表单中关闭自己,可以调用Close方法,或者将ModalResult属性设置为非零值。
显示模式表单后,该模式表单无法回到屏幕最前面
还是上个问题的第一段代码,
var
x:tform2;
begin
x:=tform2.CreateParented(Self.Handle);
x.ShowModal;
Form2显示后(其FormStyle属性=fsNormal时), 切换到操作系统中其它任务画面后
只有以下方法才能回到该程序画面(也就是让Form2回到屏幕最前面):
1.选择"显示桌面"再点击任务栏上的该程序任务;
2.点击Form1, 虽然Form1不能接收焦点, 但却导致Form2来到屏幕最前面;
3.点击Form2的标题栏。
而以下方法无法让Form2回到屏幕最前面
1.点击Form2的标题栏之外的区域, 这时虽然Form2被激活,却无法回到最前面;
2.点击操作系统任务栏上的该程序任务
3.通过任务管理器来切换到该程序
原因:几乎可以肯定是Delphi中的BUG。
解决办法
覆盖Form2 的WndProc方法,捕捉Wm_Activate消息,获取该消息后 SetWindowPos(Self.Handle,HWND_TOP,
0,0,0,0,SWP_NOSIZE+SWP_NOMOVE); 该语句使得Form2回到前面来。
非模式表单要尽量避免使用 BsDialog 边框
2003.7.28
还发现在Excel中, 用Delphi建立的非模式边框为 BsDialog 的表单也有同样情况,当切换到操作系统中其它任务后,再切换回来时,Excel很难显示出来,
不过,当显示出来时,其中的表单状态是正常的.
所以, 非模式表单要尽量避免使用 BsDialog 边框,
消息响应的问题
我覆盖了WndProc方法试图捕捉用户按下任意组合键中的Shift键,代码如下:
procedure TForm1.wndproc(var message: TMessage);
begin
if message.Msg =WM_KEYUP then
if GetKeyState(VK_SHIFT)=1 then
ShowMessage('shift');
inherited;
end;
结果发现,每按两次组合键(例如Shift+1),GetKeyState才捕捉到一次,更要命的是,当上一次捕捉到Shift时,现在开始只按 1 不按Shift键,可GetKeyState却又每次都捕捉到Shift键。
结论:
无论是WndProc还是MainWndProc方法,其Message参数都是经过加工的,也就是说,有另外一个过程(这个过程是在运行时生成的,具体参考大富翁中的1267299号文章)响应了Windows消息,将该消息加工成TMessage结构后再传递给MainWndProc方法,这些加工后的消息已经和Windows的原始消息有所不同了。