You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现半透明子窗口内红色子窗口不透明且正常显示?(Delphi)

解决Delphi中半透明父窗口内子窗口不显示的问题

问题根源分析

  1. 当窗口设置为WS_EX_LAYERED(分层窗口)后,系统会直接将窗口内容合成到屏幕,其子窗口无法参与常规绘制流程,父窗口的透明度会覆盖子窗口的显示效果。
  2. 你最初的代码中,蓝色分层窗口的透明度会传递给红色子窗口,即使移除子窗口的WS_EX_LAYERED属性也无法解决。
  3. ChatGPT提供的方案是直接绘制静态位图到分层窗口,没有创建实际的红色子窗口,因此看不到独立的红色窗口实例。

解决方案1:使用Delphi自带的AlphaBlend属性(推荐)

Delphi封装的AlphaBlend属性会自动处理分层窗口的子窗口绘制逻辑,无需调用底层API即可实现半透明父窗口+不透明子窗口的效果。

修改后的代码:

procedure TNormalForm.CreateSecondWindow;
begin
  // 半透明蓝色窗口
  SecondWindow := TForm.Create(Self);
  SecondWindow.Parent := Self;
  SecondWindow.Color := clBlue;
  SecondWindow.Width := 400;
  SecondWindow.Height := 300;
  SecondWindow.Left := 100;
  SecondWindow.Top := 100;
  
  // 启用Alpha混合并设置透明度(200/255)
  SecondWindow.AlphaBlend := True;
  SecondWindow.AlphaBlendValue := 200;
  
  SecondWindow.Show;
end;

procedure TNormalForm.CreateThirdWindow;
begin
  // 不透明红色子窗口
  ThirdWindow := TForm.Create(SecondWindow);
  ThirdWindow.Parent := SecondWindow;
  ThirdWindow.Color := clRed;
  ThirdWindow.Width := 200;
  ThirdWindow.Height := 150;
  ThirdWindow.Left := 150;
  ThirdWindow.Top := 150;
  
  // 确保子窗口关闭Alpha混合(默认已关闭,可省略)
  ThirdWindow.AlphaBlend := False;
  
  ThirdWindow.Show;
end;

解决方案2:将红色窗口设为蓝色窗口的兄弟窗口

如果必须使用底层WS_EX_LAYEREDAPI,可让红色窗口作为主窗口的子窗口(而非蓝色窗口的子窗口),通过调整位置和层级使其显示在蓝色窗口内部:

procedure TNormalForm.CreateSecondWindow;
var
  Style: LongInt;
begin
  SecondWindow := TForm.Create(Self);
  SecondWindow.Parent := Self;
  SecondWindow.Color := clBlue;
  SecondWindow.Width := 400;
  SecondWindow.Height := 300;
  SecondWindow.Left := 100;
  SecondWindow.Top := 100;

  Style := GetWindowLong(SecondWindow.Handle, GWL_EXSTYLE);
  SetWindowLong(SecondWindow.Handle, GWL_EXSTYLE, Style or WS_EX_LAYERED);
  SetLayeredWindowAttributes(SecondWindow.Handle, 0, 200, LWA_ALPHA);

  SecondWindow.Show;
end;

procedure TNormalForm.CreateThirdWindow;
begin
  // 红色窗口的父窗口设为主窗口,而非蓝色窗口
  ThirdWindow := TForm.Create(Self);
  ThirdWindow.Parent := Self;
  ThirdWindow.Color := clRed;
  ThirdWindow.Width := 200;
  ThirdWindow.Height := 150;
  // 计算相对于主窗口的位置:蓝色窗口偏移 + 红色窗口在蓝色内的偏移
  ThirdWindow.Left := SecondWindow.Left + 150;
  ThirdWindow.Top := SecondWindow.Top + 150;
  
  // 确保红色窗口显示在蓝色窗口上方
  ThirdWindow.BringToFront;
  
  ThirdWindow.Show;
end;

解决方案3:手动绘制红色区域到分层窗口(静态内容场景)

如果红色部分无需作为独立窗口(仅静态显示),可修改ChatGPT的代码,在绘制蓝色半透明位图时直接加入红色不透明区域:

procedure DrawLayeredWindow(AForm: TForm);
var
  ScreenDC, MemDC: HDC;
  Bitmap: HBITMAP;
  OldBitmap: HBITMAP;
  Blend: BLENDFUNCTION;
  BitmapData: array of TRGBQuad;
  BitmapInfo: TBitmapInfo;
  Width, Height: Integer;
  i, j: Integer;
  PtSize, PtSrc: TPoint;
  PtPos: TPoint;
begin
  Width := AForm.Width;
  Height := AForm.Height;

  SetLength(BitmapData, Width * Height);
  for j := 0 to Height - 1 do begin
    for i := 0 to Width - 1 do begin
      // 红色区域:相对于蓝色窗口的位置调整为你需要的范围
      if (i >= 150) and (i < 150+200) and (j >=150) and (j <150+150) then begin
        BitmapData[j * Width + i].rgbRed := 255;
        BitmapData[j * Width + i].rgbGreen := 0;
        BitmapData[j * Width + i].rgbBlue := 0;
        BitmapData[j * Width + i].rgbReserved := 255; // 完全不透明
      end
      else begin
        BitmapData[j * Width + i].rgbRed := 0;
        BitmapData[j * Width + i].rgbGreen := 0;
        BitmapData[j * Width + i].rgbBlue := 255;
        BitmapData[j * Width + i].rgbReserved := 200; // 半透明
      end;
    end;
  end;

  ScreenDC := GetDC(0);
  MemDC := CreateCompatibleDC(ScreenDC);

  Bitmap := CreateCompatibleBitmap(ScreenDC, Width, Height);
  OldBitmap := SelectObject(MemDC, Bitmap);

  FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
  with BitmapInfo.bmiHeader do begin
    biSize := SizeOf(TBitmapInfoHeader);
    biWidth := Width;
    biHeight := -Height;
    biPlanes := 1;
    biBitCount := 32;
    biCompression := BI_RGB;
  end;

  SetDIBits(MemDC, Bitmap, 0, Height, @BitmapData[0], BitmapInfo, DIB_RGB_COLORS);

  Blend.BlendOp := AC_SRC_OVER;
  Blend.BlendFlags := 0;
  Blend.SourceConstantAlpha := 255;
  Blend.AlphaFormat := AC_SRC_ALPHA;

  PtPos := Point(AForm.Left, AForm.Top);
  PtSize := Point(Width, Height);
  PtSrc := Point(0, 0);

  UpdateLayeredWindow(AForm.Handle, ScreenDC, @PtPos, @PtSize, MemDC, @PtSrc, 0, @Blend, ULW_ALPHA);

  SelectObject(MemDC, OldBitmap);
  DeleteObject(Bitmap);
  DeleteDC(MemDC);
  ReleaseDC(0, ScreenDC);
end;

procedure TNormalForm.CreateSecondWindow;
var
  Style: LongInt;
begin
  SecondWindow := TForm.Create(Self);
  SecondWindow.BorderStyle := bsNone;
  SecondWindow.Parent := Self;
  SecondWindow.Width := 400;
  SecondWindow.Height := 300;
  SecondWindow.Left := 100;
  SecondWindow.Top := 100;

  Style := GetWindowLong(SecondWindow.Handle, GWL_EXSTYLE);
  SetWindowLong(SecondWindow.Handle, GWL_EXSTYLE, Style or WS_EX_LAYERED);

  DrawLayeredWindow(SecondWindow);
  SecondWindow.Show;
end;

内容的提问来源于stack exchange,提问作者NevTon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 03:27:08