读书人

关于关闭窗体的有关问题

发布时间: 2012-02-20 21:18:23 作者: rapoo

关于关闭窗体的问题
一个报警窗体(不能手动关闭),当满足关闭条件时候在FormCloseQuery事件里设置canclose:=true;
现在当报警时候,主窗体缩小到任务拦的话,过段时间,报警消除,把主窗体放大,报警窗体不回消失。
模拟代码如下:
//单元1 ,模拟主线程
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls;

type
TForm1 = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
i:integer;
{ Public declarations }
end;

var
Form1: TForm1;
implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
i:=i-1;
if i <0 then
begin
i:=0;
form2.Close;
end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
form2.show;
i:=10;
end;

end.


[解决办法]
先看下,有空研究研究
[解决办法]
procedure TForm1.Timer1Timer(Sender: TObject);
begin
i:=i-1;
if i <0 then
begin
i:=0;
if Assigned(form2) then FreeAndNil(form2); //form2.Close;直接把他给KILL掉
end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
if Not Assigned(form2) then form2 := TForm2.Create(self); //不存在时就创建!
form2.show;
i:=10;
end;
[解决办法]
分析了原代码之后,有这么点思路,可能不正确!
首先你最小化的时候,系统处理了WMSysCommand消息,处理代码如下:
procedure TCustomForm.WMSysCommand(var Message: TWMSysCommand);begin
with Message do
begin
if (CmdType and $FFF0 = SC_MINIMIZE) and (Application.MainForm = Self) then
Application.WndProc(TMessage(Message))
......
end;
这句可以看出,如果你最小化的是主窗体,系统就把消息传给Application.WndProc处理
再来看看Application.WndProc
procedure TApplication.WndProc(var Message: TMessage);
with Message do
case Msg of
WM_SYSCOMMAND:
case WParam and $FFF0 of
SC_MINIMIZE: Minimize;
SC_RESTORE: Restore;
else
end;
他是调用了Minimize;
procedure TApplication.Minimize;里又调用了NormalizeTopMosts;
NormalizeTopMosts再调用DoNormalizeTopMosts(False);

procedure TApplication.DoNormalizeTopMosts(IncludeMain: Boolean);
var
I: Integer;
Info: TTopMostEnumInfo;
begin
if Application.Handle <> 0 then
begin
if FTopMostLevel = 0 then
begin
Info.TopWindow := Handle;
Info.IncludeMain := IncludeMain;
EnumWindows(@GetTopMostWindows, Longint(@Info));
//这里枚举了窗体,
我们再来看看GetTopMostWindows

function GetTopMostWindows(Handle: HWND; Info: Pointer): BOOL; stdcall;
begin
Result := True;
if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and


((Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
else
begin
PTopMostEnumInfo(Info)^.TopWindow := Handle;
Result := False;
end;
end;

if GetWindow(Handle, GW_OWNER) = Application.Handle then
if (GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) and
((Application.MainForm = nil) or PTopMostEnumInfo(Info)^.IncludeMain or
(Handle <> Application.MainForm.Handle)) then
Application.FTopMostList.Add(Pointer(Handle))
这里应该是把应用程序中所有真显示的窗体的Handle保存在FTopMostList里面
做一下记录,好让Restore的时候可以根据这个列表来恢复显示

而从Restore中调用的RestoreTopMosts中可以看出,确实是利用了FTopMostList进行了恢复!
for I := FTopMostList.Count - 1 downto 0 do
SetWindowPos(HWND(FTopMostList[I]), HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);

所以这里,虽然你已经在TIMER里Close了窗体,但是只是把它给Hide了,FTopMostList
还是记录窗提要被恢复的信息,所以当你Restore的时候它又再度把他显示出来~~~


一点看法,应该很多不正确的地方,多多指教~

读书人网 >.NET

热点推荐