• [Delphi] 分享一个模态弹窗背景模糊的实现


    这是一个很久以前写的demo,今天又看到了,就发出来记录一下。

    先来看一下效果图:

    代码很简单

    Unit1.pas

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Edit1: TEdit;
        CheckBox1: TCheckBox;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    uses
      Unit2;
    
    type
      TMCustomControl = class(TCustomControl);
      
    const
      HSLRange: Integer = 240;
    
    type
      TPixelLine = Array[Word] of TRGBQuad;
      pPixelLine = ^TPixelLine;
    
    type
      PDIBInfo = ^TDIBInfo;
      TDIBInfo = object
        BufferDC: HDC;          // 兼容内存DC
        BufferBits: Pointer;    // 位图数据
        BytesPerRow: Integer;   // 每行数据的大小
        OldBitmap, BufferBitmap: HBitmap; // 位图句柄
        bmInfo: TBitmapInfo;    // 位图信息
        function InitDIB(dc: HDC; aw, ah: Integer): Boolean;
        function GetScanline(Row: Integer): PRGBQuad;
        procedure FreeRes();
      end;
    
    procedure InitBmpInfo(var bInfo: TBitmapInfo; w, h: Integer; bitCount: Word = 32); inline;
    begin
      FillChar(bInfo, SizeOf(bInfo), 0);
      with bInfo.bmiHeader do begin
        biSize := SizeOf(TBitmapInfoHeader);
        biWidth := w;
        biHeight := h;
        biPlanes := 1;
        biBitCount := bitCount;
        biCompression := BI_RGB;
        biSizeImage := w * h * (biBitCount div 8);
      end;
    end;
    
    { TDIBInfo }
    
    procedure TDIBInfo.FreeRes;
    begin
      if BufferDC <> 0 then begin
        SelectObject(BufferDC, OldBitmap);
        DeleteObject(BufferBitmap);
        DeleteDC(BufferDC);
      end;
    end;
    
    function TDIBInfo.GetScanline(Row: Integer): PRGBQuad;
    begin
      Integer(Result) := Integer(BufferBits) + Row * BytesPerRow;
    end;
    
    function TDIBInfo.InitDIB(dc: HDC; aw, ah: Integer): Boolean;
    begin
      Result := False;
      BufferDC := 0;
      if (aw < 1) or (ah < 1) then Exit;
      // 创建内存兼容DC
      BufferDC := CreateCompatibleDC(dc);
      if (BufferDC = 0) then Exit;
    
      // 初始化临时DIB位图信息
      InitBmpInfo(bmInfo, aw, ah, 32);
    
      // 创建临时DIB位图
      BufferBitmap := CreateDIBSection(BufferDC, bmInfo, DIB_RGB_COLORS,
        BufferBits, 0, 0);
      if (BufferBitmap = 0) or (BufferBits = Nil) then begin
        if BufferBitmap <> 0 then DeleteObject(BufferBitmap);
        DeleteDC(BufferDC);
        BufferDC := 0;
        Exit;
      end;
      OldBitmap := SelectObject(BufferDC, BufferBitmap);
    
      // DIB数据行大小
      BytesPerRow := (((bmInfo.bmiHeader.biBitCount * aw) + 31)
        and not 31) div 8;
        
      Result := True;
    end;
    
    
    {-------------------------------------------------------------------------------
      函数名:    FillTransRect
      作者:      YangYxd
      日期:      2013.08.28
        - dc: HDC;                     目标设备场景句柄
        - r: TRect;                    目标矩形区域
        - color: LongInt;              阴影颜色
        - alpha: Byte;                 透明度(0..255)
        - blur: Byte;                  模糊半径 (半径越大,速度越慢)
      返回值:    无
    -------------------------------------------------------------------------------}
    function FillTransRect(dc: HDC; r: TRect; color: LongInt; alpha: Byte; blur: Byte): LongInt;
    var
      DIBInfo      : TDIBInfo;
      BufferDC     : HDC;
      Bursh        : HBRUSH;
    
      ImageData,
      UpRowData,
      NextRowData  : pPixelLine;
    
      p1, p3, p5, p6, p8: PRGBQuad;
      cr, cg, cb   : Integer;
      nalpha       : Byte;
      
      i, j, x, y : Integer;
      W, H : Integer;
    begin
      Bursh := CreateSolidBrush(color);
      if alpha < 1 then begin
        FillRect(dc, r, Bursh);
      end else begin
        w := r.Right - r.Left;
        h := r.Bottom - r.Top;
        if not DIBInfo.InitDIB(dc, w, h) then begin
          DIBInfo.FreeRes;
          Exit;
        end;
        BufferDC := DIBInfo.BufferDC;
    
        cr := color and MaxByte;;
        cg := (color shr 8) and MaxByte;;
        cb := (color shr 16) and MaxByte;
        nalpha := not alpha;
        BitBlt(BufferDC, 0, 0, w, h, DC, r.Left, r.Top, SRCCOPY);
    
        ImageData := DIBInfo.BufferBits;
        for y := 1 to H do begin
          for x := 0 to W - 1 do begin
            p1 := @ImageData^[x];
            p1.rgbBlue := ($7F + p1.rgbBlue * alpha +
              cb * (nalpha)) div $FF;
            p1.rgbGreen := ($7F + p1.rgbGreen * alpha +
              cg * (nalpha)) div $FF;
            p1.rgbRed := ($7F + p1.rgbRed * alpha +
              cr * (nalpha)) div $FF;
          end;
          inc(Longint(ImageData), DIBInfo.BytesPerRow);
        end;
        
        for i := 1 to blur - 1 do begin
          UpRowData := DIBInfo.BufferBits;
          ImageData := UpRowData;
          Inc(Longint(ImageData), DIBInfo.BytesPerRow);
          NextRowData := ImageData;
          Inc(Longint(NextRowData), DIBInfo.BytesPerRow);
          for y := 2 to H - 1 do begin
            for x := 1 to W - 3 do begin
              p1 := @ImageData^[x];
              p3 := @UpRowData^[x];
              p5 := @ImageData^[x-1];
              p6 := @ImageData^[x+1];
              p8 := @NextRowData^[x];
    
              p1.rgbBlue := (p1.rgbBlue + p3.rgbBlue + p5.rgbBlue + p6.rgbBlue + p8.rgbBlue) div 5;
              p1.rgbGreen := (p1.rgbGreen + p3.rgbGreen + p5.rgbGreen + p6.rgbGreen + p8.rgbGreen) div 5;
              p1.rgbRed := (p1.rgbRed + p3.rgbRed + p5.rgbRed + p6.rgbRed + p8.rgbRed) div 5;
            end;
            UpRowData := ImageData;
            ImageData := NextRowData;
            inc(Longint(NextRowData), DIBInfo.BytesPerRow);
          end;
        end;
    
        BitBlt(dc, r.Left, r.Top, w, h, BufferDC, 0, 0, SRCCOPY);  
        DIBInfo.FreeRes;
      end;
      DeleteObject(Bursh);
    end;
    
    function ShowModel(AOwner: TCustomForm; const FromCls: TFormClass): Integer;
    
      function CaptureScreen(const R: TRect): TBitmap;
      const
        CAPTUREBLT = $40000000;
      var
        hdcScreen: HDC;
        hdcCompatible: HDC;
        hbmScreen: HBITMAP;
      begin
        hdcScreen := GetDC(0);
        hdcCompatible := CreateCompatibleDC(hdcScreen);
        hbmScreen := CreateCompatibleBitmap(hdcScreen, GetDeviceCaps(hdcScreen, HORZRES), GetDeviceCaps(hdcScreen, VERTRES));
        if hbmScreen <> 0 then begin
          Result := TBitmap.Create;
          Result.Handle := hbmScreen;
          SelectObject(hdcCompatible, hbmScreen);
          BitBlt(hdcCompatible, 0, 0, Result.Width, Result.Height, hdcScreen, R.Left, R.Top, SRCCOPY or CAPTUREBLT);
        end;
        DeleteDC(hdcScreen);
        DeleteDC(hdcCompatible);
        // 画上半透明区域
        FillTransRect(Result.Canvas.Handle, Result.Canvas.ClipRect, clBlack, 110, 5);
      end;
    
      function CaptureWindow(const Wnd: THandle): TBitmap;
      var
        R: TRect;
        PT: TPoint;
      begin
        GetWindowRect(Wnd, R);
        SetRect(R, 0, 0, R.Right - R.Left, R.Bottom - R.Top);
        PT := R.TopLeft;
        ClientToScreen(AOwner.Handle, PT);
        R.TopLeft := PT;
        PT := R.BottomRight;
        ClientToScreen(AOwner.Handle, PT);
        R.BottomRight := PT;
        Result := CaptureScreen(R);
      end;
    
    var
      P: TMCustomControl;
      V: Integer;
      Bmp: TBitmap;
      F: TCustomForm;
    begin
      Bmp := CaptureWindow(AOwner.Handle);
      P := TMCustomControl.Create(AOwner);
      try
        P.Parent := AOwner;
        P.Left := 0;
        P.Top := 0;
        P.Width := AOwner.Width;
        P.Height := AOwner.Height;
        P.Enabled := False;
        P.Canvas.Draw(0, 0, Bmp);
        P.Visible := True;
        P.SetZOrder(True);
        FreeAndNil(Bmp);
    
        F := FromCls.Create(AOwner);
        Result := F.ShowModal;
      finally
        FreeAndNil(Bmp);
        AOwner.RemoveControl(P);
        P.Free; 
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ShowModel(Self, TForm2);
    end;
    
    end.

    Unit2.pas

    unit Unit2;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TForm2 = class(TForm)
        procedure FormDblClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form2: TForm2;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm2.FormDblClick(Sender: TObject);
    begin
      Close;
    end;
    
    end.

    实现原理就是将背景窗口截个图,再模糊一下,显示在一个置顶的控件上,再显示模态窗口。

    这个实现性能不怎么好,正式使用的不是这个实现。

  • 相关阅读:
    平均值滤波之经典形式改进
    Matlab编程实例(4) 相位角与相关系数曲线
    Matlab编程实例(3) 函数向左或向右平移N点 左移右移
    Matlab编程实例(2) 同期平均
    Matlab编程实例(1) 移动平均
    使用js在网页上记录鼠标划圈的小程序
    《你不知道的JavaScript》整理(五)——值与原生函数
    Vuex 学习总结
    HTML移动端开发常见的兼容性总结
    一步一步实现字母索引导航栏
  • 原文地址:https://www.cnblogs.com/yangyxd/p/12970800.html
Copyright © 2020-2023  润新知