一个关于模态窗体显示方面的问题,困扰很久了,大家请进。(100分)

  • 主题发起人 主题发起人 mylem
  • 开始时间 开始时间
M

mylem

Unregistered / Unconfirmed
GUEST, unregistred user!
我写的一个有任务栏图标的程序,任务栏图标的右键弹出菜单:Open/Hide项用来显示和隐藏主窗体。问题是:当在主窗体中用代码动态创建一个模态窗体,如显示一个关于对话框:
AboutBox := TAboutBox.Create(MainForm); //主窗体为MainForm
AboutBox.ShowModal;
此时,由于关于对话框为模态,所以主窗体不能接受各种操作,但可以通过任务栏的右键弹出菜单:Open/Hide项最小化和最大化主窗体,但最小化然后再最大化主窗体后,主窗体却显示在关于对话框的前面,致使主窗体不接受任何操作,但又看不到“关于”窗体,无法将其关闭。这个问题同样出现在打开一些系统对话框中,如显示一个“打开文件”对话框、显示一个“打印对话框”时,因此特向大家请教解决方案。
我想可能有两种方案,但不知如何实现。
1、当最大化主窗体后,它显示在模态窗体的后面。
2、当显示模态窗体后,任务栏的右键弹出菜单不能弹出。
请各位大侠指点迷津呀!

 
第二种方法很容易实现啊。用一个全局变量做标志,在显示模态窗体时和free后分别赋值,然后在显示弹出菜单前根据这个全局标志来决定是不是显示菜单,或禁用某一菜单项
 
可以用 Synchronize 来解决这个问题,使用后对话框绝不会再到后面去了。
如 Synchronize( showMsg ); 具体可看帮助。
 
to mevip:你说的方法是不现实的,且低效的,我这样想过,但放弃了,你想程序中可能有几十个窗体,外加多个系统对话框,每个执行前后均要设置一个全局变量......我希望当显示模态窗体时,通过检测主窗体的一些属性变化来达到这个目的,但只发现它被UnActive了,可仅用此条件是不行的。也就是说,如何检测主窗体才能够知道当前有模态窗体显示呢?
to helloqiner:你说的方法我还未测试,但如我上面所言,几十个窗体的显示均要使用Synchronize方法也不太好吧。
总之,我的思想是从主窗体上解决问题,因为有很多模态窗体呀。
 
你用RX控件看看!!!!
使用起来非常简单!!!!
我想应该可以解决你的问题
 
在任务栏图标的显示+主窗口之前,判断一下Application.Forms(好像是这个属性,反正就是所有窗口的属性,也许是copmonents属性)里面有没有TAboutForm这个类的实例存在,如果有,就不Show或者Hide主窗口。另外,判断一下Application.ActiveControl属性是什么,也可以知道当前是否打开了About窗口,这样就好判断了。
 
其实,你如果在Show主窗口前,得到Application.Components指向的TAboutFrom的实例后,可以保存它,等主窗口被最大化或最小化动作完成后,调用TAboutForm.BringToFront方法也可以让About提到主窗口的前面来。
 
一个最简单的做法,只要有弹出模式窗体,任务栏菜单不可用,
设置一个全局变量就行了。
 
to:fsse4000
不明白你的意思,能否详细说说?
 
只需要一个全局变量就足够了!在打开模态窗体时都设置同一个标志变量,而不是每个窗体单独设置一个,根本没必要。当然这个标志变量不能用boolean类型,而应该是integer类型,每打开一个模态窗体该标志加1,关闭一个减1,所以只要判断这个标志变量是不是零就能知道当前有没有模态窗体打开。所以,我认为是可行的,而且也不会影响程序执行的效率。不知道各位有何高见?
 
procedure TFormCommServer.FormCreate(Sender: TObject);
begin
Application.OnMinimize:= AppMinimize;
Application.Minimize;
// AddTrayIcon;
end;

procedure TFormCommServer.AppMinimize(Sender: TObject);
begin
OldWindowState := WindowState;//mem it
ShowWindow(Application.Handle, SW_HIDE);
Hide;
end;

procedure TFormCommServer.ShowAppMainForm;
begin
ShowWindow(Application.Handle,SW_SHOW);
Application.ShowMainForm := True;
WindowState := OldWindowState;//restore it with old mem one//wsNormal;
Application.Restore;
Show;
end;

procedure TFormCommServer.HideAppMainForm;
begin
Application.ShowMainForm := False;
Application.Minimize;
end;


procedure TFormCommServer.miRestoreClick(Sender: TObject);
begin
if Assigned(FormAbout) then
if not FormAbout.Showing then ShowAppMainForm
else FormAbout.BringToFront;
end;

procedure TFormCommServer.miAboutClick(Sender: TObject);
begin
if Assigned(FormAbout) and not FormAbout.Showing then
FormAbout.ShowModal;
end;


DPR:
Application.Initialize;

ShowWindow(Application.Handle,SW_HIDE);
Application.ShowMainForm := False;

Application.CreateForm(TFormCommServer, FormCommServer);
Application.CreateForm(TFormCommSetting, FormCommSetting);
Application.CreateForm(TFormAbout, FormAbout);//Auto create
Application.Run;
 
http://www.delphibbs.com/keylife/iblog_show.asp?xid=1073
http://www.delphibbs.com/keylife/iblog_show.asp?xid=294
 
谢谢上面两位,看来这是一个Delphi中VCL的封装问题,要想完美的解决这个问题真是很难,但我还是希望有高手能提供一个较好的解决方案。
目前我的理解是这样:TApplication是从Tcomponent类继承下来的,而TForm是从TCumtomForm(Tcomponent类的派生类)继承下来的,所以可以这样说:TApplication是一个不健全的窗体,很多TForm类功能和消息机制都没有,而程序中所有的窗体又将TApplication做为默认的父窗体,从而使程序产生了一些不正常的现象,如L:我所问的这个问题。
CathyEagle的解决方案是通过改变窗体创建时的参数强制使其父窗体变成程序中的主窗体,而不再是TApplication。虽在一定程度上解决了一些问题,但并不完善,就我所问的这个问题而言:当程序打开一个系统对话框,比如:OpenDialog.Execute;由于我们无法改变系统对话框的创建参数,所以问题仍然出现了。
我感觉这个问题一定有解,希望大家能进一步的深入讨论,分数可以再加的。
 
mylem:你的理解有错误,首先TApplication类和TCustomForm类之间不存在任何继承关系,TApplication.Run方法只是实现了一个操作主窗口的消息循环而已,也就是TApplication.Run过程前面第一个CreateForm方法传递给TApplication的TCustomForm被TApplication对象保存,并以它为基础建立一个消息循环。Delphi的封装机制中,TCustomForm.ShowModal的方法实际上是通过对全局变量Application(这个变量就是TApplication的实例,是在Forms.pas单元的initliaztion块中初始化的,并且每个exe文件中只会有一个TApplication对象的实例)中所有Forms进行循环,找到并设置其为Enabled := False来实现的,所以,这里的情况非常特殊。

我昨天特地试了一下我说的方法,尝试在TrayIcon.ShowForm的方法里面判断主窗口是否为Enabled = False,但是这样的操作还是不对。如果留心一下的话,可以看到,如果你显示了一个Modal窗口,在点击任务栏图标,显示主窗口,这时主窗口在前面,但已经被锁定,被显示的Modal窗口在后面,无法呼出,出现假死情况,这时如果你按Alt+Tab键,切换一下窗口,你看到什么效果了?ShowModal的窗口又出来了!可见,一定又办法做到,比如用SendMessage什么的,但现在就是不知道怎么做!我认为应该不是很难的事情,可能是我们想错了方向。希望有高手来指点一下:)
 
.Create(Application);
或.Create(nil);
试试!
 
应该抛弃Delphi的TApplication,直接创建任务栏窗体

1.主窗体覆盖CreateParams方法,实现任务栏图标及隐藏Application对象在任务栏上的按钮
2.子窗体覆盖CreateParams,把父设置为主窗体
3.修改Dialogs单元源码,把所有
hWndOwner := Application.Handle;
替换成
if Owner is TWinControl then
hWndOwner := TWinControl(Owner).Handle
else
hWndOwner := Application.Handle;

1,2解决窗体的顺序问题,3解决对话框的问题

参考:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1929737

贴一个基类吧,主窗体及子窗体都从这个类继承,子窗体Create要用类似这样的方法
FormChild := TFormChild.Create(FormMain);//主窗体为父,而不是Application对象
//==============================================================================
// Unit Name: BaseFrm
// Author : ysai
// Date : 2003-11-28
// Purpose :
// History :
//==============================================================================

unit BaseFrm;

interface

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

type
TFrmBase = class(TForm)
private
procedure WMSysCommand(var Message:TWMSysCommand);message WM_SYSCOMMAND;
protected
procedure CreateParams(var Params:TCreateParams); override;
public
constructor Create(AOwner: TComponent);reintroduce;override;
end;

implementation

{$R *.dfm}

constructor TFrmBase.Create(AOwner: TComponent);
begin
//让Application对象不出现在任务栏
with Application do
SetWindowLong(Handle, GWL_EXSTYLE,
GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
inherited;
end;

procedure TFrmBase.CreateParams(var Params: TCreateParams);
begin
inherited;
if Owner is TForm then
Params.WndParent := TForm(Owner).Handle //子窗体
else
Params.ExStyle := Params.ExStyle + WS_EX_APPWINDOW; //主窗体
end;

procedure TFrmBase.WMSysCommand(var Message: TWMSysCommand);
begin
case Message.CmdType of
SC_MINIMIZE :
DefWindowProc(Handle,WM_SYSCOMMAND,SC_MINIMIZE,0);
SC_RESTORE:
DefWindowProc(Handle,WM_SYSCOMMAND,SC_RESTORE,0);
else
inherited;
end;
end;

end.
 
我现在想换一个角度考虑这个问题,为什么显示模态窗体后,通过任务栏图标菜单最小化然后最大化主窗体,它会跑到模态窗体的前面来呢?如何让它显示在模态窗体后的后面?
 
看来真的没有好办法了,算了,结帖
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
553
import
I
后退
顶部