Thema: Delphi NonVCL: SplashScreen

Einzelnen Beitrag anzeigen

Benutzerbild von wicht
wicht

Registriert seit: 15. Jan 2006
Ort: Das schöne Enger nahe Bielefeld
809 Beiträge
 
Delphi XE Professional
 
#1

NonVCL: SplashScreen

  Alt 12. Jun 2012, 08:50
Guten Morgen!

Am Wochenende war mir langweilig und ich dachte, ich baue mal einen Splash-Screen. Weil er "animiert" sein soll, während im Hintergrund das Main-Formular lädt, habe ich mich entschieden, einen TThread-Nachfahren zu bauen, der das Fenster erstellt und verwaltet. Ja, ich weiß, dass der Hauptthread im optimalen Falle den Splash erstellt und zum Laden der Daten ein Thread benutzt werden sollte, aber ein bisschen mit der API spielen macht ja auch mal Spass. Ich erstelle also das Fenster und habe meine WindowProc, die poste ich mal:

Delphi-Quellcode:
function WindowProc(hwn, msg, wpr, lpr: Longint): Longint; stdcall;
var
  H: HWND;
  Val: Cardinal;
  TC: Cardinal;
  Msg2: TMsg;
  P: TPoint;
begin
  case msg of
    WM_TIMER:
      begin
        TC := GetTickCount;
        if AnimationStart = 0 then
          AnimationStart := GetTickCount;

        H := GetMainWindowWindow;
        case State of
          stFadeIn:
            begin
              Val := Trunc(((TC - AnimationStart) / FADE_TIME) * 254);

              if TC - AnimationStart < FADE_TIME then
              begin
                BlendFunction.SourceConstantAlpha := Val;
                UpdateLayeredWindow(SplashWndHandle, 0, nil, @BitmapSize, SplashBitmap.Canvas.Handle, @SplashBitmapPos, 0, @BlendFunction, ULW_ALPHA);
              end else
              begin
                WaitingStarted := TC;
                State := stWaiting;
              end;
            end;
          stWaiting:
            begin
              if ((H > 0) and IsWindowVisible(H)) or ((TC - AnimationStart) > 2000) then
              begin
                State := stFadeOut;
                AnimationStart := 0;
              end;
            end;
          stFadeOut:
            begin
              Val := 254 - Trunc(((TC - AnimationStart) / FADE_TIME) * 254);

              if TC - AnimationStart < FADE_TIME then
              begin
                BlendFunction.SourceConstantAlpha := Val;
                // Das hier gibt manchmal Fehler 317 bei GetLastError() zurück?
                UpdateLayeredWindow(SplashWndHandle, 0, nil, @BitmapSize, SplashBitmap.Canvas.Handle, @SplashBitmapPos, 0, @BlendFunction, ULW_ALPHA);
              end else
              begin
                SplashBitmap.Free;
                KillTimer(SplashWndHandle, 0);
                Killed := True;
                if H > 0 then
                  SetForegroundWindow(H);
              end;
            end;
        end;
        SetWindowPos(SplashWndHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
      end;
  end;
  Result := DefWindowProc(hwn, msg, wpr, lpr);
end;
Wie man sieht läuft das Fadein/Fadeout mit einem Timer. Das Problem habe ich mit einem Kommentar markiert. Der Fadein funktioniert gut, aber beim Fadeout gibt es manchmal den Fehler 317, was immer der hier bedeuten mag... Kann dazu vielleicht jemand etwas mehr sagen? Es sieht eben blöd aus, wenn der Screen schön einfadet aber beim Ausblenden bei 50% Transparenz "stehen bleibt" und dann direkt verschwindet, wenn das Hauptfenster da ist.
Eine andere Sache ist, ob man so etwas überhaupt mit einer WindowProc machen sollte. Ich habe in einem Beispiel gesehen, dass CreateWindowEx() aufgerufen wurde und dann direkt mit UpdateLayeredWindow() gearbeitet wurde. Ist das sinniger, wenn man nicht mehr als Fadein/Fadeout machen möchte? Und ist das ungefährlich?


Liebe Grüße und danke im Vorraus für eventuelle Antworten
http://streamwriter.org

"I make hits. Not the public. I tell the DJ’s what to play. Understand?"
  Mit Zitat antworten Zitat