在我的应用程序中,我有一个主窗体,能够在数据库中加载一些图像。在加载图像时,我想显示一个带有进度指示器(带有 bsNone 边框样式)的表单。
但是,如果我用 ShowModal 显示表单,主表单的执行就会停止,所以我不能这样做。
如果我调用 Show,用户可以访问所有其他表单组件,这可能很危险,而照片没有完全加载。
我需要设法禁用主窗体上的所有内容,而加载尚未完成。
请告诉我,这怎么可能。
将 设置MainForm
为PopupParent
进度表单,以便MainForm
永远不会出现在进度表单的顶部。然后只需MainForm.Enabled := False
在进度表打开时设置MainForm.Enabled := True
,在进度表关闭时设置。
procedure TMainForm.ShowProgressForm;
begin
with TProgressForm.Create(nil) do
begin
PopupParent := Self;
OnClose := ProgressFormClose;
Show;
end;
Enabled := False;
end;
procedure TMainForm.ProgressFormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
Enabled := True;
end;
这模拟了ShowModal()
用户的行为方式(MainForm
进度表单打开时不是用户交互的),但不会阻塞代码。
首先,直接回答你的问题。
我需要设法禁用主窗体上的所有内容。
设置MainForm.Enabled
为False
禁用与主窗体关联的窗口。并重新启用将其设置为True
。
但是,您的基本问题是您正在 GUI 线程中执行长时间运行的任务。这总是一个坏主意,出路是在单独的线程中执行那些长时间运行的任务。
将长时间运行的任务移至单独的线程后,您会发现这ShowModal
正是您显示进度表所需要的。
正如我在另一个答案中解释的那样,将长时间运行的任务放入 GUI 线程以外的线程是理想的解决方案。GUI 线程应该处理短时间运行的任务,以便它始终能够及时地为消息队列提供服务。
但是,如果您已经有假设长时间运行的任务在 GUI 线程上运行的代码,您可能更愿意采用更方便的方法并将重构推迟到线程代码。在这种情况下,在我看来,最好还是用它ShowModal
来显示你的进度表。
但是为了使这项工作正常进行,您需要在ShowModal
调用中找到一个让长时间运行的任务执行。你可以这样做:
ShowModal
,将任务传递给表单。例如,将 a 传递TProc
给进度表单的构造函数。Activate
方法。ShowModal
这将在函数开始其模式消息循环之前执行。在执行中Activate
,向表单发布消息。显然,您需要调用ProcessMessages
长时间运行的任务,以保持主 GUI 线程消息队列得到服务。显然,您必须已经这样做了。
您可能想要使用 DisableTaskWindows
和EnableTaskWindows
功能。
如果您ParentForm.Enabled := False
对父表单使用 simple,您仍然可以访问所有其他表单,例如主表单(如果它不同于ParentForm
. 显然还是很危险的。
这是简短的示例:
interface
uses
Vcl.Forms, Winapi.Windows, ...;
type
TPleaseWait = class(TObject)
private
fWindowList: TTaskWindowList;
fActiveWindow: HWND;
fDialog: TPleaseWaitForm;
public
constructor Create;
destructor Destroy; override;
end;
implementation
constructor TPleaseWait.Create;
begin
// Disable all displayed windows
fWindowList := DisableTaskWindows(0);
// Save the last active window
fActiveWindow := GetActiveWindow;
fDialog := TPleaseWaitForm.Create(nil);
fDialog.Show;
end;
destructor TPleaseWait.Destroy;
const
INVALID_HANDLE = 0;
begin
fDialog.Close;
fDialog.Free;
// All windows are enabled now
EnableTaskWindows(fWindowList);
// That helps by enabling the last one form
if (fActiveWindow <> INVALID_HANDLE) and IsWindow(fActiveWindow) then
SetActiveWindow(fActiveWindow);
inherited;
end;
end.
设置子窗体的PopupParent = ParentForm
procedure TParentForm.Button1Click(Sender: TObject);
begin
ParentForm.Enabled:=False;
with Tform1.create(nil) do show;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ParentForm.Enabled := true;
form1.free;
end;