transparente Fenster (auch semitransparent)
-
hi leute,
ich hab mich mal hingesetzt und weiter im internet gesucht und zusammen mit dem beiden kompos von torry (TGlassy und TStainedGlass) das Ganze mal für den Builder gebastelt, allerdings ist es keine Komponente, sondern lediglich so als Code zum einbauen ins Forumlar:
1. eine Form erzeugen (möglichst klein halten)
2. einige Steuerelemente drauf (muss nicht sein)
3. folgenden Code einsetzen// im header //--------------------------------------------------------------------------- private: Graphics::TBitmap *ScreenBitmap; Graphics::TBitmap *ClientBitmap; Graphics::TBitmap *BackgroundBitmap; bool FormMoving; bool NeedRefresh; Controls::TWndMethod OldWndProc; void __fastcall NewWndProc(TMessage &Msg); void __fastcall PaintTransparentForm(TMessage &Msg); void __fastcall CreateBackground(int bHeight, int bWidth); //---------------------------------------------------------------------------
// im cpp-file //--------------------------------------------------------------------------- void __fastcall TForm1::CreateBackground(int bHeight, int bWidth) { NeedRefresh = false; BackgroundBitmap->Width = bWidth; BackgroundBitmap->Height = bHeight; // hintergrund zeichnen BackgroundBitmap->Canvas->Pen->Style = psClear; BackgroundBitmap->Canvas->Brush->Style = bsSolid; BackgroundBitmap->Canvas->Brush->Color = Color; BackgroundBitmap->Canvas->Rectangle(0, 0, bWidth, bHeight); } //--------------------------------------------------------------------------- void __fastcall TForm1::PaintTransparentForm(TMessage &Msg) { if (ScreenBitmap == NULL) return; // screenshot nur machen, wenn fenster nicht bewegt wird if (!FormMoving) { // fenster verstecken ShowWindow(Handle, SW_HIDE); // desktop als aktives fenster setzen SetActiveWindow(0); DWORD TicksNow = GetTickCount(); DWORD WaitTicks = 250; // kurz warten, bis andere fenster gezeichnet sind while ((GetTickCount() - TicksNow) < WaitTicks) Application->ProcessMessages(); // einen aktuelle screenshot des bildschirms (desktops) machen HDC hDevice = GetDC(0); BitBlt(ScreenBitmap->Canvas->Handle, 0, 0, ScreenBitmap->Width, ScreenBitmap->Height, hDevice, 0, 0, SRCCOPY); ReleaseDC(0, hDevice); } // ein bitmap von der grösse des formulares erzeugen (clientbild) ClientBitmap = new Graphics::TBitmap(); ClientBitmap->Width = ClientWidth + 1; ClientBitmap->Height = ClientHeight + 1; ClientBitmap->PixelFormat = pf24bit; // vom bildschirmbild den ausschnitt unseres formulares // in das clientbild zeichnen ClientBitmap->Canvas->Draw(-ClientOrigin.x, -ClientOrigin.y, ScreenBitmap); if (NeedRefresh) CreateBackground(ClientHeight + 1, ClientWidth + 1); // transparenz setzen int Transparenz = 50; int Hoehe = ClientHeight; // farbwerte des hintergrundes vorberechnen BYTE rb = GetRValue(BackgroundBitmap->Canvas->Pixels[0][0]); BYTE gb = GetGValue(BackgroundBitmap->Canvas->Pixels[0][0]); BYTE bb = GetBValue(BackgroundBitmap->Canvas->Pixels[0][0]); int rt = (100 - Transparenz) * rb; int gt = (100 - Transparenz) * gb; int bt = (100 - Transparenz) * bb; // die gesamte zeichenfläche des bitmaps verarbeiten // -> jede pixelfarbe neu berechnen for (; Hoehe--;) { // eine zeile einlesen RGBTRIPLE *SL = (RGBTRIPLE *) ClientBitmap->ScanLine[Hoehe]; int Breite = ClientWidth; for (; Breite--;) { // einzelne farbwerte berechnen SL[Breite].rgbtRed = ((Transparenz * SL[Breite].rgbtRed) + rt) / 100; SL[Breite].rgbtGreen = ((Transparenz * SL[Breite].rgbtGreen) + gt) / 100; SL[Breite].rgbtBlue = ((Transparenz * SL[Breite].rgbtBlue) + bt) / 100; } } // fenster anzeigen ShowWindow(Handle, SW_SHOW); // geändertes clientbild auf das formular zeichnen PAINTSTRUCT PS; HDC hPS = BeginPaint(Handle, &PS); BitBlt(hPS, 0, 0, ClientBitmap->Width, ClientBitmap->Height, ClientBitmap->Canvas->Handle, 0, 0, SRCCOPY); EndPaint(Handle, &PS); // clientbild löschen delete ClientBitmap; ClientBitmap = NULL; Msg.WParam = (int) hPS; } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { // WindowProzedur austauschen (zum Abfangen und Verarbeiten der Botschaften) OldWndProc = WindowProc; WindowProc = NewWndProc; } //--------------------------------------------------------------------------- void __fastcall TForm1::NewWndProc(TMessage &Msg) { // alles freigeben beim zerstören if (Msg.Msg == WM_DESTROY) { // bild freigeben if (ScreenBitmap != NULL) { delete ScreenBitmap; ScreenBitmap = NULL; } if (BackgroundBitmap != NULL) { delete BackgroundBitmap; BackgroundBitmap = NULL; } } // formular soll neu gezeichnet werden if (Msg.Msg == WM_PAINT) { PaintTransparentForm(Msg); } if (Msg.Msg == WM_ERASEBKGND) { Msg.Result = 1; return; } if (Msg.Msg == WM_ENTERSIZEMOVE) FormMoving = true; if (Msg.Msg == WM_EXITSIZEMOVE) FormMoving = false; // wenn auflösung geändert wird if (Msg.Msg == WM_DISPLAYCHANGE) { if (ScreenBitmap != NULL) { ScreenBitmap->Width = Msg.LParamLo; ScreenBitmap->Height = Msg.LParamHi; NeedRefresh = true; Invalidate(); } } // wenn formular resized oder gemovet wird if (Msg.Msg == WM_WINDOWPOSCHANGED) { if (ScreenBitmap != NULL) Invalidate(); } // original-windowprozedur aufrufen OldWndProc(Msg); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { FormMoving = false; NeedRefresh = true; // Hintergrundbild BackgroundBitmap = new Graphics::TBitmap(); BackgroundBitmap->PixelFormat = pf24bit; // ein bitmap von der grösse der bildschirmauflösung erzeugen ScreenBitmap = new Graphics::TBitmap(); ScreenBitmap->Width = GetSystemMetrics(SM_CXSCREEN); ScreenBitmap->Height = GetSystemMetrics(SM_CYSCREEN); ScreenBitmap->PixelFormat = pf24bit; } //---------------------------------------------------------------------------
wenn ihr das ausprobiert, werden ihr sehen, dass es beim ziehen ganz schön ruckelt und die aktualisierung nicht so richtig hinterher kommt.
vielleicht habt ihr ja noch ein paar idee wie man die berechnungen beschleunigen kann, oder wo man gewisse daten nicht immer erneut abfragen muss. vlei gibts ja auch schnellere zeichenmethoden.
hier mal noch ein paar zeitwerte (per GetTickCount). die werte (in millisekunden) halten sich bei mehreren versuchen in etwa die waage.
ShowWindow : 1 SetActiveWindow : 0 Wait : 250 BitBlt (ScreenShot erstellen): 30 ClientBitmap->Canvas->Draw : 5 CreateBackground : 5 Transparenz berechnen : 780 BitBlt (Client zeichnen) : 5
wie man sieht hagts so ziemlich an der eigentlichen berechnung...
[Edit]
- so hab mal die berechnung und schleifen ein bissel geändert, läuft jetzt um einiges schneller.
[ Dieser Beitrag wurde am 26.02.2003 um 22:16 Uhr von Sunday editiert. ]
-
Hi! Ich habe mal ersucht das Beispiel nachzuvollziehen. Der Compiler scheitert aber an
Controls::TWndMethod OldWndProc;
mit volgender Fehlermeldung:
[C++ Fehler] Unit1.h(23): E2316 'TWndMethod' ist kein Element von 'Controls'
Wenn man die Zeile folgendermaßen abändert gehts:
Classes::TWndMethod OldWndProc;