In the code below, I display a rotated image (ruler) with a blue background. The dialog is given the %WS_Ex_Layered style so that the blue background will be transparent color:
Dialog New Pixels, 0, "Ruler",300,300,400,50, %WS_Popup, %WS_Ex_Layered To hDlg
and then ...
SetLayeredWindowAttributes(hDlg, %Blue, 255, %LWA_ALPHA Or %LWA_ColorKey)
When I use PlgBlt to rotate the image, transparency works fine. But when I rotate the image with GDI+, the transparency effect is lost - the blue background is visible, rather than being transparent.
Is there an interaction between GDI+ and WS_Ex_Layered windows that would explain this?
Here's the compilable code (uses Jose's includes :D). Use the mouse wheel to rotate the image, right mouse click to close the app.
#Compile Exe
#Dim All
#Debug Error On
#Debug Display On
#Include "gdiplus.inc"
Global hDlg, hDC As Dword, rulerH, rulerW, rotateW, rotateH As Long, theta As Single
Function PBMain() As Long
Local StartupInput As GdiplusStartupInput, token As Dword
StartupInput.GdiplusVersion = 1 ' Initialize GDI+
GdiplusStartup(token, StartupInput, ByVal %NULL)
Dialog New Pixels, 0, "Ruler",300,300,400,50, %WS_Popup, %WS_Ex_Layered To hDlg
Dialog Show Modal hDlg Call DlgProc
GDIPlusShutDown token
End Function
CallBack Function DlgProc() As Long
Local PS As PaintStruct
Select Case Cb.Msg
Case %WM_InitDialog
rulerW = 222 : rulerH = 48 'for this example, ruler is fixed at 222x48 pixels
Dialog Set Color hDlg, %Black, %Blue
Dialog Set Size hDlg, rulerW, rulerH
SetLayeredWindowAttributes(hDlg, %Blue, 255, %LWA_ALPHA Or %LWA_ColorKey)
Case %WM_MouseWheel
Select Case Hi(Integer,Cb.WParam) 'note the use of Integer
Case > 0 : theta = theta + 0.05 : RotateRuler
Case < 0 : theta = theta - 0.05 : RotateRuler
End Select
Case %WM_ContextMenu
Dialog End hDlg 'right mouse click to end app
Case %WM_LButtonDown
If Cb.WParam = %MK_LBUTTON Then SendMessage hDlg, %WM_NCLButtonDown, %HTCaption, ByVal %Null ' force drag
Case %WM_Paint
hDC = BeginPaint(hDlg, PS)
RotateRuler
EndPaint hDlg, PS
End Select
End Function
Sub RotateRuler
Local iMax,tempx,tempy,w,h,XCenter,YCenter,dx,dy As Long, hTemp, hTempDC, pGraphics, pImage, hBitmap As Dword
'resize dialog to enclose ruler after rotation
rotateW = RulerW*Abs(Cos(theta)) + RulerH*Abs(Sin(theta)) 'bounding W once ruler is rotated
rotateH = RulerH*Abs(Cos(theta)) + RulerW*Abs(Sin(theta)) 'bounding H once ruler is rotated
Dialog Get Loc hDlg To tempx, tempy : Dialog Get Size hDlg To w,h 'get current dialog size
Dialog Set Size hDlg, RotateW, RotateH 'set dialog size to bounding dimensions
Dialog Set Loc hDlg, tempx - (RotateW-w)/2, tempy -(RotateH-h)/2 'relocate so rotation is about center of dialog
If 1 Then 'GDI+ version of rotation
'load ruler image, which is in larger-than-needed image, surrounded by transparency color)
iMax = 300 'image containg ruler just happens to be 300x300
Graphic Bitmap Load "ruler1.bmp", iMax, iMax To hTemp 'centered ruler + blue surrounding
Graphic Attach hTemp, 0
Graphic Get DC To hTempDC
'create GDI+ object
GdipCreateFromHDC(hTempDC, pGraphics) 'get pGraphics
hBitmap = GetCurrentObject(hTempDC, %OBJ_Bitmap) 'get hBitmap
GDIpCreateBitmapFromHBITMAP(hBitmap, ByVal %Null, pImage) 'get pImage
'rotate the image
GdipTranslateWorldTransform(pGraphics, iMax/2, iMax/2, %MatrixOrderPrepend) ' Move to center
GdipRotateWorldTransform(pGraphics, theta * 57.3, %MatrixOrderPrepend) ' Rotate
GdipTranslateWorldTransform(pGraphics, -iMax/2, -iMax/2, %MatrixOrderPrepend) ' Return
GdipDrawImage(pGraphics, pImage, 0, 0)
Dialog ReDraw hdlg 'clear previous image
BitBlt hDC, 0,0,rotateW,rotateH, hTempDC, iMax/2-rotateW/2,iMax/2-rotateH/2 , %SRCCopy 'copy ruler image to dialog surface
If pImage Then GdipDisposeImage(pImage) 'cleanup
If pGraphics Then GdipDeleteGraphics(pGraphics)'cleanup
Else 'PlgBlt version of rotation
'create memory BMP containing just the ruler (222x48)
Graphic Bitmap Load "ruler2.bmp", rulerW, rulerH To hTemp 'just the ruler, no surrounding blue color
Graphic Attach hTemp, 0
Graphic Get DC To hTempDC
'get the 3 corners of the rotated image (point are located on hDlg)
dx = (rotateW - rulerW)/2 : dy = (rotateH - rulerH)/2
XCenter = rulerW/2 : YCenter = rulerH/2
Dim PlgPts(2) As PointAPI
PlgPts(0).X = XCenter + (0 - XCenter) * Cos(theta) - (0 - YCenter) * Sin(theta) + dx 'upper-left in target
PlgPts(0).Y = YCenter + (0 - XCenter) * Sin(theta) + (0 - YCenter) * Cos(theta) + dy
PlgPts(1).X = XCenter + (RulerW - XCenter) * Cos(theta) - (0 - YCenter) * Sin(theta) + dx 'upper-right in target
PlgPts(1).Y = YCenter + (RulerW - XCenter) * Sin(theta) + (0 - YCenter) * Cos(theta) + dy
PlgPts(2).X = XCenter + (0 - XCenter) * Cos(theta) - (RulerH - YCenter) * Sin(theta) + dx 'lower left in target
PlgPts(2).Y = YCenter + (0 - XCenter) * Sin(theta) + (RulerH - YCenter) * Cos(theta) + dy
Dialog ReDraw hdlg 'clear image, display blue background color
PlgBlt hDC, PlgPts(0),hTempDC, 0,0,RulerW,RulerH,0&,0,0 'copy ruler image to dialog surface
End If
End Sub
Sorry, but left off a link to the two images:
http://www.garybeene.com/images/ruler1.bmp
http://www.garybeene.com/images/ruler2.bmp
More information ... conflicting results.
I'm running on Win7.
When I run under an Aero theme, the transparency works.
But when I run under a basic theme (Windows Classic), the transparency does not work.
More data ... transparency doesn't work on my wife's XP machine either.
In looking around the web, I'm seeing a number of posts who's title suggests a similar problem. But I haven't yet found a clear explanation of why, of how to resolve the problem.
Over in the PowerBASIC forums, Donald gave me some code that will work. But he took a slightly different route so I still don't know why the code I posted fails.
http://www.powerbasic.com/support/pbforums/showthread.php?p=371051#post371051
Different Question:
In these forums, how do I hide the URL above, and use it to make a highlighted link?
Quote
In these forums, how do I hide the URL above, and use it to make a highlighted link?
WS_Ex_Layered + GDI+ Problems? (http://www.powerbasic.com/support/pbforums/showthread.php?p=371051#post371051)
[_url=http://www.powerbasic.com/support/pbforums/showthread.php?p=371051#post371051]WS_Ex_Layered + GDI+ Problems?[_/url]
Without the underscores before url and /url.
Layered windows aren't handled the same on XP and VISTA/SEVEN.
Also in order to work correctly the graphic card must be not too old and running in 32-bit mode.
Did you try the "Boing" demo on your wife's PC,
or the "AeroGL" that is a unique combination of different graphic technologies:
OpenGL + GDI32 + GDIPLUS + composited layered window.
But i can't force you to studdy my SDK code, if you don't want to ;)
Also as a last resort, you can always use a region built on the fly and that will work fine with W2K/XP/VISTA/SEVEN, but the borders of the ruler will look jagged.
Gary,
I am writing a SDK AeroRuler example for you. 8)
...
AeroRuler is here (http://www.jose.it-berater.org/smfforum/index.php?topic=4035.0)
...
Hi Patrice!
QuoteBut i can't force you to study my SDK code, if you don't want to
Yes, that is true. If I wasn't feeling the pressure to work on a couple of other projects I've already started, I'd love to spend the time to catch up on several programming areas which I've neglected, SDK being one of them.
But you know of course, that even when I will be working on SDK, that I'll be trying to do the same thing in DDT so I can understand what works in one vs the other - and how they play together. I plan to be multi-lingual forever! I want to be proficient in SDK, but don't see any reason to neglect DDT solutions as well.
I will say that because I like to post code that is as generally useful as possible, and because (as Jose has pointed out) the PowerBASIC forums are not so SDK intensive as they once were, I do resist moving over to SDK as my mainline programming theme. My upcoming update of my online PowerBASIC tutorials, to incorporate SDK coding, should at least show recognition of the importance of the coding approach, and a commitment to help newbies appreciate/understand their options.
Even this current problem you've been helping me with, GDI+ rotation of the ruler image, doesn't tell me not to use DDT. It only tells me that you SDK folks have already solved the problem. I don't yet know enough to say that there's not an equally straight-forward DDT solution. Years from now, when there are aging PowerBASIC programmers with DDT experience to match your own SDK experience, who knows what the coding landscape will look like!
As always, thank you for your comments, code, and patience!
Gary,
DDT is based on the CreateDialog API, that is itself a limited subset of the CreateWindowEx API.
You won't be able to do what i show you in AeroRuler with DDT, never.
...