Forma z progressbarem

0

Cześć, jestem ciekawy, jak rozwiązujecie ten aspekt. Forma z progress barem. Krótko mówiąc takie ProgressForm. Jakie wymagania? Forma ma być zawsze na wierzchu(aplikacji). Jak się aplikacje minimalizuje, to forma ma być niewidoczna. Jak się aplikacje przywraca, to forma ma być znowu widoczna(nie ma to związku z aktywnością aplikacji, bo aplikacja może być nieaktywna, ale widoczna).

Ja próbuję na różne sposoby i mam problemy z osiągnięciem tych założeń. Albo forma nie pokazuje się po maksymalizacji, albo nie chowa po minimalizacji, albo po maksymalizacji pokazuje się po jakimś czasie, ale też nie zawsze, albo pokazuje się pod aplikacją.

Ja mam to rozwiązane tak, że jak mam jakąś operację w pętli, to wywołuję procedurę w stylu ShowProgress, do której przekazuje procent wykonania operacji itp. Ale czasami operacja nie jest w pętli(np. procedura składowana SQL) i wtedy pokazuje mi się okienko bez progressBara, sama informacja: "Czekaj, operacja trwa".

Na pewno jakoś kosntruujecie takie okna i moje pytanie: jak? Czytałem o tym w necie, ale za wiele informacji nie znalazłem.

Mój kod, który nie jest dobry wygląda tak:

procedure ShowProgress(Status: string; PercentDone: byte = 0; HideGauge: boolean = false);
begin
  if Application.Active then
  begin
    progressForm.Show;
    SetWindowPos(ProgressForm.Handle, HWND_TOP, ProgressForm.Left, ProgressForm.Top,
      0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOOWNERZORDER);
  end else
  begin
    ProgressForm.Hide;
    ProgressForm.sLabel.Caption:=Status;
    exit;
  end;
  
  if HideGauge then
  begin
    ProgressForm.GroupBox1.Visible:=false;
    ProgressForm.Panel1.Height:=20;
    ProgressForm.Height:=30; //21
  end else
  begin
    ProgressForm.GroupBox1.Visible:=true;
    ProgressForm.Panel1.Height:=61;
    ProgressForm.Height:=72;
  end;
  
  ProgressForm.sLabel.Caption:=Status;
  if percentDone>100 then percentDone:=100;
  ProgressForm.Gauge.Progress:=PercentDone;
  application.ProcessMessages;
end;



procedure HideProgress;
begin
  if ProgressForm<>nil then
  begin
    ProgressForm.Hide;
    ProgressForm.sLabel.Caption:='';
    progressForm.Gauge.Progress:=0;
  end;
end;


{ TProgressForm }

procedure TProgressForm.FormShow(Sender: TObject);
begin
  timer.Enabled:=true;
end;

procedure TProgressForm.TimerTimer(Sender: TObject);
begin
  timer.Enabled:=false;
  SetWindowPos(Handle, HWND_TOP, Left, Top,
      0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOOWNERZORDER);
end;

initialization
  ProgressForm:=TProgressForm.Create(nil);

finalization
  ProgressForm.Free;
0

Formatka jak najbardziej NIE powinna być zawsze na wierzchu, bo po co utrudniać użytkownikowi życie i pracę. Co do minimalizowania całej aplikacji oraz naszego okna z postępem, w sposób prawidlowy, to ja to rozwiązałem tak, jak pokazałem poniżej. Chyba o taki problem może też Tobie chodzić. Oczywiśćie postęp pokazuje przed rozpoczęciem długo trwającej operacji w wątku.

//...
  private
    procedure WMSysCommand(var Msg : TMessage); message WM_SYSCOMMAND;
//...
procedure TLogonProgressForm.WMSysCommand(var Msg : TMessage);
begin
  case Msg.WParam of
    SC_MINIMIZE :
      begin
        Application.Minimize;
      end;
  else
    begin
      inherited
    end;
  end;
end;
//...

Natomiast pokazywanie i zamykanie formatki robię tak. I może nie do końca dobrze, ale działa ok i nie powoduje błędów, a w inny sposób działalo nie tak, jak tego chcialem.

//...
  if LogonProgressForm = nil then
  begin
    LogonProgressForm := TLogonProgressForm.Create(Self);
  end;
  LogonProgressForm.ShowModal;
  // Po zakończeniu długo trwałej operacji...
      if LogonProgressForm <> nil then
      begin
        Synchronize(LogonProgressForm.CloseTheForm);
      end;
//...

Metoda CloseTheForm jest zadeklarowana oczywiście w sekcji public i wygląda nastepująco. Zmienna CanBeClosed jest używana po to aby nie można było zamknąć formatki X'em (który jest też "wyszarzony"). Do zamykania formatki służy osobny przycisk do anulowania operacji na dole formatki z postepem.

procedure TLogonProgressForm.CloseTheForm;
begin
  with MainForm do
  begin
    if SynHttp <> nil then
    begin
      SynHttp.Sock.OnStatus := nil;
    end;
    ActiveThr := nil;
  end;
  Screen.Cursor := crDefault;
  Self.CanBeClosed := True;
  Self.Close;
end;

procedure TLogonProgressForm.FormDestroy(Sender : TObject);
begin
  LogonProgressForm := nil;
end;

procedure TLogonProgressForm.AbortBtnClick(Sender : TObject);
begin
  with MainForm do
  begin
    if ActiveThr <> nil then
    begin
      ActiveThr.Suspend;
    end;
    if SynHttp <> nil then
    begin
      SynHttp.Free;
      SynHttp := nil;
    end;
    SetLVControlsAvailable(True, True);
    AlreadyLogged := False;
    CanBeClosed := True;
  end;
  CloseTheForm;
end;
//...

Metoda SetLVControlsAvailable' uaktywnia dwa TListView na formatce głownej oraz je odpowiednio czyści i robi Repaint`. A i pewnie ktoś tutaj doradzi Tobie coś bardziej sprawdzonego, lepszego i w może stworzonego w osobnej oraz gotowej klasie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1