Przezroczysty komponent (zamazujący tło)

Odpowiedz Nowy wątek
2016-12-09 15:51

Rejestracja: 10 lat temu

Ostatnio: 2 lata temu

0

Cześć,
chciałbym zrobić coś takiego:
Zakrywam cały formularz jakimś komponentem (i tu właśnie nie wiem jakim) np TPanel. Chciałbym, żeby ten Panel zamazał całe tło ale w taki sposób, że widać kontury komponentów w tle ale np tekstu już nie. Czasem spotyka się taki efekt na stronach internetowych gdzie otwiera się okno modalne i każą się zalogować, zapłacić itp.
W załączniku podsyłam przykład.

Czy ktoś wie jak można taki efekt uzyskać?

edytowany 2x, ostatnio: lukasz_p92, 2016-12-09 16:57

Pozostało 580 znaków

2016-12-09 17:10

Rejestracja: 16 lat temu

Ostatnio: 1 tydzień temu

0

Możesz dać np jakiś komponent do malowania - w Lazarusie jest TPaintBox. Zamalowujesz to jakimś kolorem i ustawiasz przezroczystość.


Kto nigdy nie zrobił var dupa niech pierwszy rzuci kamień.

Pozostało 580 znaków

2016-12-09 17:55
Moderator Delphi/Pascal

Rejestracja: 8 lat temu

Ostatnio: 3 minuty temu

Lokalizacja: Tuchów

Najłatwiej to na pewno wstawienie komponentu typu PaintBox, rozciągnięcie go na cały formularz i ukrycie;

Po kliknięciu w przycisk w celu otworzenia jakiegoś okienka modalnego, najpierw robisz "zrzut ekranu", tyle że samego aktywnego okna, pakujesz go do pomocniczej bitmapy, obrabiasz swoim filtrem, pokazujesz PaintBox, w nim malujesz gotową bitmapę i pokazujesz okienko modalne; Po jego zamknięciu chowasz PaintBox;

Wskazówki co do robienia screenshota aktywnego okna znajdziesz tutaj; Kod na rozmywanie obrazu możesz znaleźć nawet w artykułach na 4p; Z komponentami sobie poradzisz, więc nie ma co się rozpisywać;

karpov napisał(a)

Zamalowujesz to jakimś kolorem i ustawiasz przezroczystość.

To nie takie proste - PaintBox nie ma właściwości Transparent :]

Jak chcecie wiedzieć w jaki sposób stworzyć komponent obsługujący przezroczystość to przeanalizujcie sobie kod komponentu TImage; Komponent ten umożliwia wyświetlanie obrazów z przezroczystością (np. 32-bitowy PNG), więc imeplementuje mechanizmy pobierania obrazu tła do łączenia go z półprzezroczystą grafiką załadowaną do komponentu.


edytowany 8x, ostatnio: furious programming, 2016-12-09 18:11

Pozostało 580 znaków

Opi
2016-12-15 23:50
Opi

Rejestracja: 15 lat temu

Ostatnio: 8 miesięcy temu

2

Zapożyczone z projektu "Odkurzacz" :)

 private
  procedure PrzyciemnijOkno(Wlacz: Boolean = True);

type
  TTransparentPanel = class(TPanel)
  private
    Bmp: TBitmap;
    procedure WMEraseBkGnd(var msg: TWMEraseBkGnd); message WM_ERASEBKGND;
  protected
    procedure CaptureBackground;
    procedure Paint; override;
  public
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    property Canvas;
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
 {Panel symulujący ściemnienie i rozmycie okna}
 P_Przyciemnij: TTransparentPanel;

procedure GBlur(Bmp: TBitmap; Radius: Single);
type
 TRGB  = packed record b, g, r: Byte; end;
 TRGBs = packed record b, g, r: Single; end;
 TRGBArray = array[0..0] of TRGB;
var
 MatrixRadius: Byte;
 Matrix: array[-100..100] of Single;
 R, G, B, Divisor: Single;
 BmpSL: ^TRGBArray;
 BmpRGB: ^TRGB;
 BmpCopy: Array of Array of TRGBs;
 BmpCopyRGB: ^TRGBs;
 x, y, mx, BmpWidth, BmpHeight: Integer;
begin
 Bmp.PixelFormat := pf24bit;
 if Radius <= 0 then Radius := 1
 else
 if Radius > 99 then Radius := 99;

 Radius := Radius + 1;
 MatrixRadius := Trunc(Radius);
 if Frac(Radius) = 0 then Dec(MatrixRadius);
 Divisor := 0;
 for x := -MatrixRadius to MatrixRadius do
   begin
    Matrix[x] := Radius - Abs(x);
    Divisor   := Divisor + Matrix[x];
   end;

 for x := -MatrixRadius to MatrixRadius do Matrix[x] := Matrix[x] / Divisor;
 BmpWidth  := Bmp.Width;
 BmpHeight := Bmp.Height;
 SetLength(BmpCopy, BmpHeight, BmpWidth);

 for y :=0 to Pred(BmpHeight) do
   begin
    BmpSL      := Bmp.Scanline[y];
    BmpCopyRGB := @BmpCopy[y,0];
    for x := 0 to Pred(BmpWidth) do
      begin
       R := 0;
       G := 0;
       B := 0;
       for mx := -MatrixRadius to MatrixRadius do
         begin
          if x + mx < 0 then BmpRGB := @BmpSL^[0]
          else
          if x + mx >= BmpWidth then BmpRGB := @BmpSL^[Pred(BmpWidth)]
          else BmpRGB := @BmpSL^[x + mx];

          B := B + BmpRGB^.b * Matrix[mx];
          G := G + BmpRGB^.g * Matrix[mx];
          R := R + BmpRGB^.r  *Matrix[mx];
         end;

       BmpCopyRGB^.b := B;
       BmpCopyRGB^.g := G;
       BmpCopyRGB^.r := R;
       Inc(BmpCopyRGB);
      end;
   end;

 for y := 0 to Pred(BmpHeight) do
   begin
    BmpRGB := Bmp.ScanLine[y];
    for x := 0 to Pred(BmpWidth) do
      begin
       R := 0;
       G := 0;
       B := 0;
       for mx := -MatrixRadius to MatrixRadius do
         begin
          if y + mx <= 0 then BmpCopyRGB := @BmpCopy[0,x]
          else
          if y + mx >= BmpHeight then BmpCopyRGB := @BmpCopy[Pred(BmpHeight),x]
          else BmpCopyRGB := @BmpCopy[y + mx,x];

          B := B + BmpCopyRGB^.b * Matrix[mx];
          G := G + BmpCopyRGB^.g * Matrix[mx];
          R := R + BmpCopyRGB^.r * Matrix[mx];
         end;

       BmpRGB^.b := Round(B);
       BmpRGB^.g := Round(G);
       BmpRGB^.r := Round(R);
       Inc(BmpRGB);
      end;
   end;
end;

procedure TTransparentPanel.CaptureBackground;
var
 Canvas: TCanvas;
 DC: HDC;
 SourceRect: TRect;
begin
 Bmp := TBitmap.Create;
 with Bmp do
   begin
    PixelFormat := pf24bit;
    Width  := ClientWidth;
    Height := ClientHeight;
   end;

 SourceRect.TopLeft     := ClientToScreen(ClientRect.TopLeft);
 SourceRect.BottomRight := ClientToScreen(ClientRect.BottomRight);
 DC := CreateDC('DISPLAY', nil, nil, nil);
 try
  Canvas := TCanvas.Create;
  try
   Canvas.Handle := DC;
   Bmp.Canvas.CopyRect(ClientRect, Canvas, SourceRect);

   {Rozmycie Gaussowskie}
   GBlur(Bmp, 6);
  finally
   Canvas.Handle := 0;
   Canvas.Free;
  end;
 finally
  DeleteDC(DC);
 end;
end;

constructor TTransparentPanel.Create(aOwner: TComponent);
begin
 inherited;

 ControlStyle := ControlStyle - [csSetCaption];
end;

destructor TTransparentPanel.Destroy;
begin
 Bmp.Free;

 inherited;
end;

procedure TTransparentPanel.Paint;
begin
 if csDesigning in ComponentState then inherited;
 // would need to draw frame and optional caption here
 // do NOT call inherited, the control fills its client area if you do!
end;

procedure TTransparentPanel.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
 if Visible and HandleAllocated and not (csDesigning in ComponentState) then
   begin
    Bmp.Free;
    Bmp := nil;
    Hide;

    inherited;
    Parent.Update;
    Show;
   end
 else inherited;
end;

procedure TTransparentPanel.WMEraseBkGnd(var Msg: TWMEraseBkGnd);
var
 Canvas: TCanvas;
begin
 if csDesigning in ComponentState then inherited
 else
   begin
    if not Assigned(Bmp) then CaptureBackground;
    Canvas := TCanvas.Create;
    try
     Canvas.Handle := Msg.DC;
     Canvas.Draw(0, 0, Bmp);
    finally
     Canvas.Handle := 0;
     Canvas.Free;
    end;

    Msg.Result := 1;
   end;
end;

procedure TForm1.PrzyciemnijOkno(const FormaRodzic: TForm; Wlacz: Boolean = True);
begin
 if not Wlacz then
   begin
    P_Przyciemnij.Free;

    Exit;
   end;

 if Wlacz then
   begin
    {Tworzenie przeźroczystego panelu}
    P_Przyciemnij := TTransparentPanel.Create(FormaRodzic);
    with P_Przyciemnij do
      begin
       Visible  := False;
       Parent   := FormaRodzic;
       AutoSize := False;
       DoubleBuffered := True;
       Left     := 0;
       Top      := 0;
       Height   := FormaRodzic.ClientHeight;
       Width    := FormaRodzic.ClientWidth;
       Name     := 'P_Przyciemnij';
       BringToFront;
      end;

    Application.ProcessMessages;
    P_Przyciemnij.Visible := True;
   end;
end;
{
Wywołanie np.: poprzez komponent TMS VistaDialog.
Pamiętaj o przywrócenia okna do stanu normalnego: Najpierw (True), potem (False)
}
procedure TFormMR.DialogVistaDialogCreated(Sender: TObject);
begin
 PrzyciemnijOkno;
end;

{Przywrócenie okna i zwolnienie zmiennych}
procedure TFormMR.DialogVistaDialogClose(Sender: TObject;
  var CanClose: Boolean);
begin
 PrzyciemnijOkno(False);
end;
edytowany 1x, ostatnio: furious programming, 2019-02-14 01:09
W swoim projekcie używam czegoś podobnego - dezaktywowane okno przechodzi w stan szarości oraz zostaje nieco przyciemnione; Z tą różnicą, że za stanszarości okna odpowiadaja styl rysowania komponentów, a nie dodatkowy panel zasłaniający całość; Dzięki temu całość działa bardzo szybko (wystarczy Invalidate wszystkich komponentów), całe okno zostaje wyszarzone (łącznie z obramowaniem), a dodatkowo, mogę wyszarzyć w ten sposób tylko niektóre komponenty; Efekt końcowy super, ale 15kLoC trzeba było naklepać... :] - furious programming 2016-12-16 00:28
W tym rozwiązaniu dodatkowo dochodzi rozmycie tła lub dowolna inna graficzna modyfikacja tła, ale sposób z szarością okna jest lepszy Twój. - Opi 2016-12-22 15:23
Dzięki @Opi za gotowca – nareszcie mi się ten kod do czegoś przyda. Dobrze że pamiętałem o tym poście. ;) - furious programming 2019-07-21 01:00
Proszę bardzo :) - Opi 2019-11-18 20:02

Pozostało 580 znaków

Odpowiedz

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