吵吵   2013-07-01  阅读:3,354

在做吵吵检验科试剂管理系统的时候,我突然发现一个问题。由于我是用菜单来控制功能窗口打开的,如果用户点击两次,就打开了两个窗口,如何解决这个问题?当更换了用户,用户权限变化了的时候,如何关闭原来的窗口?

这还不简单,声明一个窗口的全局变量不就OK了么,要关闭就直接form.close就卡可以了嘛!

但是如果窗口是动态创建的呢?如果我不想弄成全局变量,消耗大量内存呢?

首先想到程序只执行一个实例的方法,用互斥体?这将产生一个问题,你所有的窗口在加载之前都需要建立一个互斥变量,每个窗口你都去重载一次构造函数,你想累死我么?

既然不想保存类的变量,那么不如尝试一下windows窗口的特有属性,HWND,即窗口的句柄。

那么如何解决句柄存在的问题,即通过句柄可以判断这个窗口是否打开呢?吵吵找了半天,找到一个API函数IsWindow。

于是整个流程可以如下运作:

通过保存的句柄判断窗口是否存在->存在即不打开新窗口,不存在就打开新窗口并保存句柄。

关闭所有的窗口只需要向所有的句柄PostMessage WM_QUIT就行了。

我建立了一个类,代码和简单,如下:


unit FMForm;

interface

uses Winapi.Windows,  Winapi.Messages,Data.Win.ADODB, System.Classes,System.Variants,System.SysUtils,Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus,Vcl.Grids,Comobj, StdCtrls;
type
  FormInfo=record
    Caption:string[20];
    Handle:HWND;
  end;
type
  TFMForm= class(TObject)
  public
    function FormExist(ACaption:string):Boolean;
    function CaptionExist(ACaption:string):Boolean;
    procedure AddForm(ACaption:string;AHandle:HWND);
    procedure SetCaptionHandle(ACaption:string;AHandle:HWND);
    procedure AddCaptionHandle(ACaption:string;AHandle:HWND);
    procedure CloseAllForms();

  private
    FForms:array of FormInfo;
end;

implementation

function TFMForm.CaptionExist(ACaption:string):Boolean;
var
  i:Integer;
begin
  result:=False;
  for i := 0 to Length(FForms)-1 do
  begin
    if FForms[i].Caption=ACaption then
    begin
      Result:=True;
      Exit;
    end;
  end;
    
end;

function TFMForm.FormExist(ACaption:string):Boolean;
var
  i:Integer;
begin
  result:=False;
  for i := 0 to Length(FForms)-1 do
  begin
    if FForms[i].Caption=ACaption then
    begin
      if isWindow(FForms[i].Handle)=true then
      begin
        Result:=True;
        Exit;
      end
      else
      begin
        result:=False;
        Exit;
      end;
      
    end;
  end;
  result:=False;

end;
procedure TFMForm.AddForm(ACaption:string;AHandle:HWND);
begin
  if CaptionExist(ACaption)=True then
  begin
    SetCaptionHandle(ACaption,AHandle);
  end
  else
  begin
    AddCaptionHandle(ACaption,AHandle);
  end;
  
end;

procedure TFMForm.SetCaptionHandle(ACaption:string;AHandle:HWND);
var
  i:Integer;
begin
  for i := 0 to Length(FForms)-1 do
  begin
    if FForms[i].caption=ACaption then
    begin
      FForms[i].Handle:=AHandle;
      Exit;
    end;
  end;
    
end;
procedure TFMForm.AddCaptionHandle(ACaption:string;AHandle:HWND);
begin
  setlength(FForms,Length(FForms)+1);
  FForms[Length(FForms)-1].Caption:=ACaption;
  FForms[Length(FForms)-1].Handle:=AHandle;
end;

procedure TFMForm.CloseAllForms();
var
  i:Integer;
begin
  for i := 0 to Length(FForms)-1 do
  begin
    PostMessage(FForms[i].Handle,WM_CLOSE,0,0);
  end;
end;
end.

使用方法也很简单:

if FFMForm.FormExist('使用记录')=false then  //判断窗口是否存在
  begin
    frmUseRecord:= TfrmUseRecord.Create(self);
    frmUseRecord.Show;
    FFMForm.AddForm('使用记录',frmUseRecord.Handle);
  end;

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

发表评论

电子邮件地址不会被公开。 必填项已用*标注