在我的應用程序中,我有一個主表單,可以在數據庫中加載一些圖像。 加載圖像時,我想顯示一個窗體,並帶有進度指示器(帶有bsNone邊框樣式)。Delphi在加載時禁用表單
但是,如果我用ShowModal的窗體顯示,主窗體的執行被停止,所以我不能這樣做。
如果我調用Show,用戶可以訪問所有其他表單組件,並且在未完全加載照片的情況下它可能很危險。
我需要找到方法,禁用主窗體上的所有內容,而加載沒有完成。
請告訴我,它是如何可能的。
在我的應用程序中,我有一個主表單,可以在數據庫中加載一些圖像。 加載圖像時,我想顯示一個窗體,並帶有進度指示器(帶有bsNone邊框樣式)。Delphi在加載時禁用表單
但是,如果我用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
之前,將任務傳遞給表單。例如,將TProc
傳遞給進度表的構造函數。Activate
方法。這將在ShowModal
函數啓動其模態消息循環之前執行。在執行Activate
時,向表單發送消息。很明顯,您需要在長時間運行的任務中調用ProcessMessages
,以保持主要的GUI線程消息隊列的服務。顯然你一定已經這麼做了。
您可能想要使用DisableTaskWindows
和EnableTaskWindows
函數。
如果您使用簡單的ParentForm.Enabled := False
作爲父表單,則仍然可以訪問所有其他表單,如主表單與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;
如果你倒是想保持一個模式的形式,你可以調用從你的語氣中所示的程序形成。例如通過交付方法在模態顯示形式的構造中調用。 – bummi
除了禁用表單之外,您還可以隱藏主窗體。其他可能性包括從模態進度對話框調用Load-procedure。 – GolezTrol