2013-07-06 27 views
5

在我的應用程序中,我有一個主表單,可以在數據庫中加載一些圖像。 加載圖像時,我想顯示一個窗體,並帶有進度指示器(帶有bsNone邊框樣式)。Delphi在加載時禁用表單

但是,如果我用ShowModal的窗體顯示,主窗體的執行被停止,所以我不能這樣做。

如果我調用Show,用戶可以訪問所有其他表單組件,並且在未完全加載照片的情況下它可能很危險。

我需要找到方法,禁用主窗體上的所有內容,而加載沒有完成。

請告訴我,它是如何可能的。

+1

如果你倒是想保持一個模式的形式,你可以調用從你的語氣中所示的程序形成。例如通過交付方法在模態顯示形式的構造中調用。 – bummi

+0

除了禁用表單之外,您還可以隱藏主窗體。其他可能性包括從模態進度對話框調用Load-procedure。 – GolezTrol

回答

12

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不是用戶交互而進展形式是打開的),但不阻塞的代碼。

3

首先,直接回答你的問題。

我需要找到方法來禁用主窗體上的所有內容。

設置MainForm.EnabledFalse禁用與主窗體關聯的窗口。而要重新啓用,請將其設置爲True


但是,您的根本問題是,您正在GUI線程中執行長時間運行的任務。這總是一個糟糕的主意,出路是在一個單獨的線程中執行那些長時間運行的任務。

將長時間運行的任務移動到單獨的線程後,您會發現ShowModal正是您需要顯示進度表單的內容。

1

正如我在其他答案中所解釋的,將長時間運行的任務放入GUI線程以外的線程是理想的解決方案。 GUI線程應該處理短時間運行的任務,以便它能夠及時地處理消息隊列。但是,如果您已經有了假定長時間運行的任務在GUI線程上運行的代碼,那麼您可能更願意採取更方便的方法並推遲重新分解爲線程代碼。在這種情況下,在我看來,使用ShowModal來顯示你的進度表更好。

但是爲了做到這一點,您需要找到一個讓長期運行的任務在ShowModal調用中執行。你可以這樣做:

  1. 在你致電ShowModal之前,將任務傳遞給表單。例如,將TProc傳遞給進度表的構造函數。
  2. 覆蓋進度表的Activate方法。這將在ShowModal函數啓動其模態消息循環之前執行。在執行Activate時,向表單發送消息。
  3. 當表單處理該消息時,調用傳遞給構造函數的任務。

很明顯,您需要在長時間運行的任務中調用ProcessMessages,以保持主要的GUI線程消息隊列的服務。顯然你一定已經這麼做了。

1

您可能想要使用DisableTaskWindowsEnableTaskWindows函數。

如果您使用簡單的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. 
1

設置子窗體的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;