)
设计丢来一个系统升级界面UI图是个异形窗口即有窗体圆角又有个火箭头凸出来挺带感的。旧貌换新颜这事值一做。一. 预处理首先想到的实现方式是填个底色然后设置窗体的TransparentColor为该底色即可毕竟软件启动时的splash屏就是这么实现的。在PhotoShop里填充上黄色底色导出为WEB格式时选择PNG8格式并仔细裁剪掉边缘杂色。最后存储为png图像文件。二. 通过TransparentColor属性实现异形窗体设置窗体TransparentColortrue、TransparentColorValue黄色底色补上点击和窗体移动代码运行测试效果。显示效果倒是实现了但有一个问题点击窗体上半部分会穿透到下层窗口下半部分却能正常响应。反复测试发现该现象与图片的宽高比例关系不大。三. 通过RGN实现异形窗体既然点击不正常而delphi窗体自带的的实现方法不便修改那就换种实现方式直接读取像素信息把底色对应的区域从窗体 RGN 中剔除。快速撸了一段实现代码procedure TfrmUpdate.FormCreate(Sender: TObject); var bmp: TBitmap; FullRgn, LineRgn: HRGN; x, y, StartX: Integer; Row: PRGBTriple; //从ScanLine读取像素 IsTransparent: Boolean; TargetB, TargetG, TargetR: Byte; begin ClientWidth : Image1.Width; ClientHeight : Image1.Height; //底色的RGB分量 TargetB : $00; TargetG : $D8; TargetR : $FF; bmp : TBitmap.Create; try bmp.Assign(Image1.Picture.Graphic); //24位色深度让PRGBTriple准确对位 bmp.PixelFormat : pf24bit; //初始化一个空RGN FullRgn : CreateRectRgn(0, 0, 0, 0); //水平扫描线像素 for y : 0 to bmp.Height - 1 do begin //依当前图片特性优化计算跳过没有透明色的区域。其他图片注释掉这两行 if (y 55) and (y bmp.Height - 8) then Continue; Row : bmp.ScanLine[y]; //获取当前行的内存指针 x : 0; while x bmp.Width do begin //判断是否为底色透明色 IsTransparent : (Row.rgbtBlue TargetB) and (Row.rgbtGreen TargetG) and (Row.rgbtRed TargetR); //如果是透明色一直往右找直到找到不透明的像素 while (x bmp.Width) and IsTransparent do begin Inc(x); Inc(Row); if x bmp.Width then IsTransparent : (Row.rgbtBlue TargetB) and (Row.rgbtGreen TargetG) and (Row.rgbtRed TargetR); end; //记录这段不透明区域的起点X坐标 StartX : x; //从不透明像素起往右找直到再次遇到透明色或到达边界 while (x bmp.Width) and (not IsTransparent) do begin Inc(x); Inc(Row); if x bmp.Width then IsTransparent : (Row.rgbtBlue TargetB) and (Row.rgbtGreen TargetG) and (Row.rgbtRed TargetR); end; //将这段不透明的水平线段(StartX 到 x)加到RGN if StartX x then begin //创建一个1像素高的矩形区域 (左闭右开y到y1) LineRgn : CreateRectRgn(StartX, y, x, y 1); //将这个细长条合并到总区域中 (RGN_OR并集) CombineRgn(FullRgn, FullRgn, LineRgn, RGN_OR); DeleteObject(LineRgn); end; end; end; //依当前图片特性优化计算将没有透明色的区域加入RGN LineRgn : CreateRectRgn(0, 55, bmp.Width, bmp.Height - 8); CombineRgn(FullRgn, FullRgn, LineRgn, RGN_OR); DeleteObject(LineRgn); //计算完毕将RGN应用到窗体 SetWindowRgn(Handle, FullRgn, True); DeleteObject(FullRgn); finally bmp.Free; end; end;运行后功能正常达到要求的效果。四. 针对PNG8位色优化既然用的PNG图片没必须再转一次24位色的bmp来计算直接基于8位索引色的PNG图片来运算性能更佳。首先要处理下图片将底色转为透明。