NevTon
NevTon

Reputation: 289

non-transparent window with semi-transparent child window with non-transparent child window

I have this type of situation:

sample

Main window that is non-transparent, with semi-transparent blue child window, that have red child window.
How can I make red window non-transparent.

Right now i use this simple code, can you help me ?

procedure TNormalForm.CreateSecondWindow;
var
  Style: LongInt;
begin
  // semi-transparent window
  SecondWindow := TForm.Create(Self);
//  SecondWindow.BorderStyle := bsNone;
  SecondWindow.Parent := Self;
  SecondWindow.Color := clBlue;
  SecondWindow.Width := 400;
  SecondWindow.Height := 300;
  SecondWindow.Left := 100;
  SecondWindow.Top := 100;

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

  // set transparency (alfa = 200/255)
  SetLayeredWindowAttributes(SecondWindow.Handle, 0, 200, LWA_ALPHA);

  SecondWindow.Show;
end;

procedure TNormalForm.CreateThirdWindow;
var
  Style: LongInt;
begin
  // non-transparent window
  ThirdWindow := TForm.Create(SecondWindow);
//  ThirdWindow.BorderStyle := bsNone;
  ThirdWindow.Parent := SecondWindow;
  ThirdWindow.Color := clRed;
  ThirdWindow.Width := 200;
  ThirdWindow.Height := 150;
  ThirdWindow.Left := 150;
  ThirdWindow.Top := 150;

  Style := GetWindowLong(ThirdWindow.Handle, GWL_EXSTYLE);
  SetWindowLong(ThirdWindow.Handle, GWL_EXSTYLE, Style and not WS_EX_LAYERED);

  RedrawWindow(ThirdWindow.Handle, Nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or RDW_ALLCHILDREN);

  ThirdWindow.Show;
end;

EDIT: I asked ChatGPT about how to draw non-transparent window on top of semi-transparent child form and i got this answear from 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 > 0) and (i < 200) and (j > 0) and (j < 150) then begin
        BitmapData[j * Width + i].rgbRed := 255;    // red color
        BitmapData[j * Width + i].rgbGreen := 0;
        BitmapData[j * Width + i].rgbBlue := 0;
        BitmapData[j * Width + i].rgbReserved := 255; // Alfa
      end
      else begin
        BitmapData[j * Width + i].rgbRed := 0;      // blue color
        BitmapData[j * Width + i].rgbGreen := 0;
        BitmapData[j * Width + i].rgbBlue := 255;
        BitmapData[j * Width + i].rgbReserved := 128; // Alfa
      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
  // semi-transparent window
  SecondWindow := TForm.Create(Self);
  SecondWindow.BorderStyle := bsNone;
  SecondWindow.Parent := Self;
  SecondWindow.Color := clBlue;
  SecondWindow.Align := alClient;

  DrawLayeredWindow(SecondWindow);

  SecondWindow.Show;
end;

but now third window is not drawn at all, what can be done to fix this problem ?

Upvotes: 2

Views: 47

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598029

SetLayeredWindowAttributes() applies its attributes to an entire window as a whole, which is why the red window is not solid when it is a child of the translucent blue window. You simply can't achieve the effect you want by using this API function. You will have to use UpdateLayeredWindow() instead, so that you have more control over each pixel's alpha and can decide exactly which pixels are opaque and which are translucent.

Also, keep in mind that child windows could not have the WS_EX_LAYERED style until Windows 8, so if you need to support Windows 7 or earlier than you'll need to find a different solution.

Upvotes: 3

Related Questions