Jump to content

Need help achieving transparent overlay


qwert
 Share

Recommended Posts

I'm trying to place a transparent rectangle over an external window by having a transparent GUI on top. Everything is working except the background of the rectangle itself. What am I missing? Is there a better approach?

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

GUICtrlCreateGraphic(20, 50, 200, 200)
GUICtrlSetGraphic(-1, $GUI_GR_RECT, 50, 50, 80, 80)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUISetState()

While 1
    If GUIGetMsg() = $exit Then Exit
WEnd

Thanks for any help.

Edited by qwert
Link to comment
Share on other sites

After two full days and countless searches, I now believe it's not possible to make the background color of a graphic control transparent. Here's a link to another post with basically the same question:

link

I'm at the point I need to move on to develop another approach. The best alternative I have now is to use GUICtrlCreatePic to put up a transparent GIF and then draw individual lines on it with DLL calls. It just seems odd that so many controls can set background transparency but graphic controls can't.

Anyone able confirm this restriction? (for me and for others)

Thanks.

Link to comment
Share on other sites

Looking for this ? :)

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, $WS_POPUP, $WS_EX_LAYERED)
GUISetBkColor(0x000000)

GUICtrlCreateLabel("", 50, 0, 200, 50, -1, $GUI_WS_EX_PARENTDRAG)
GUICtrlSetFont(-1,14,900)

$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

GUICtrlCreateGraphic(120, 200, 120, 120)
GUICtrlSetGraphic(-1, $GUI_GR_RECT, 0, 0, 120, 120)
GUICtrlSetBkColor(-1, 0xABCDEF)

DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $Main_Gui, "long", 0xEFCDAB , "byte", 255, "long", 0x1 + 0x2)
GUISetState()

While 1
    If GUIGetMsg() = $exit Then Exit
WEnd
Link to comment
Share on other sites

one with a Ellipse

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, -1, $WS_EX_LAYERED)

GUICtrlCreateLabel("", 50, 0, 200, 50, -1, $GUI_WS_EX_PARENTDRAG)
GUICtrlSetFont(-1,14,900)

$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $Main_Gui, "long", 0xEFCDAB , "byte", 255, "long", 0x1 + 0x2)
GUISetState()

$hdc = GetHDC()

DrawEllipse($hdc, 100, 160, 300, 360, 1, 0xEFCDAB , 0xEFCDAB)

While 1
    $msg = GUIGetMsg()
    If $msg = $exit Then Exit
    If $msg = -3 Then Exit
WEnd

Func GetHDC()
    Local $S_WIN_TILLE     = WinGetTitle("", "")
    Local $S_ClientSize    = WinGetClientSize($S_WIN_TILLE, "")
    Local $S_WIN_GETHANDLE = WinGetHandle($S_WIN_TILLE, "")
    Local $S_RAW_HDC = DllCall("user32.dll", "ptr", "GetDC", "hwnd", $S_WIN_GETHANDLE)
    $hDC = "0x" & Hex($S_RAW_HDC[0])
    Return $hDC
EndFunc

Func DrawEllipse($S_Destination, $S_left, $S_top, $S_right, $S_bottom, $S_linewidth, $S_linecolor, $S_fillcolor)
    $S_pen = DllCall("gdi32.dll", "int", "CreatePen", _
                                  "int", 0, _
                                  "int", $S_linewidth, _
                                  "int", $S_linecolor)
    $S_obj = DllCall("gdi32.dll", "int", "SelectObject", _
                                  "int", $S_Destination, _
                                  "int", $S_pen[0])
    DllCall("gdi32.dll", "int", "DeleteObject", _
                         "int", $S_obj[0])
    $S_brush = DllCall("gdi32.dll", "int", "CreateSolidBrush", _
                                    "int", $S_fillcolor)
    $S_obj   = DllCall("gdi32.dll", "int", "SelectObject", _
                                    "int", $S_Destination, _
                                    "int", $S_brush[0])
    DllCall("gdi32.dll", "int", "DeleteObject", _
                         "int", $S_obj[0])
    DllCall("gdi32.dll", "int", "Ellipse", _
                         "int", $S_Destination, _
                         "int", $S_left, _
                         "int", $S_top, _
                         "int", $S_right, _
                         "int", $S_bottom)
EndFunc
Link to comment
Share on other sites

or with some text ?

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, -1, $WS_EX_LAYERED)

GUICtrlCreateLabel("", 50, 0, 200, 50, -1, $GUI_WS_EX_PARENTDRAG)
GUICtrlSetFont(-1,14,900)

$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $Main_Gui, "long", 0xEFCDAB , "byte", 255, "long", 0x1 + 0x2)
GUISetState()

$hdc = GetHDC()

SetText($hdc, "Hello", 50, 150, 0xEFCDAB , 0, 120, 1200, "Arial")
SetText($hdc, "World", 50, 250, 0xEFCDAB , 0, 120, 1200, "Arial")

While 1
    $msg = GUIGetMsg()
    If $msg = $exit Then Exit
    If $msg = -3 Then Exit
WEnd

Func GetHDC()
    Local $S_WIN_TILLE     = WinGetTitle("", "")
    Local $S_ClientSize    = WinGetClientSize($S_WIN_TILLE, "")
    Local $S_WIN_GETHANDLE = WinGetHandle($S_WIN_TILLE, "")
    Local $S_RAW_HDC = DllCall("user32.dll", "ptr", "GetDC", "hwnd", $S_WIN_GETHANDLE)
    $hDC = "0x" & Hex($S_RAW_HDC[0])
    Return $hDC
EndFunc

Func SetText($S_Destination, $S_Text, $S_x, $S_y, $S_TextColor, $S_BKColor, $Font_H, $Font_W, $Font_Name)
    $font = DllCall("gdi32.dll", "int", "CreateFontA", _
                                 "int", $Font_H, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", $Font_W, _
                                 "Int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "int", 0, _
                                 "str", $Font_Name)
    $oldfont = DllCall("gdi32.dll", "int", "SelectObject", _
                                    "hwnd", $S_Destination, _
                                    "int",  $font[0])   
    If $S_BKColor = 0 Then
        DllCall("gdi32.dll", "int", "SetBkMode", _
                            "hwnd", $S_Destination, _   
                            "int",  "TRANSPARENT")
    EndIf                       
    DllCall("gdi32.dll", "int",  "SetTextColor", _
                         "hwnd", $S_Destination, _
                         "int",  $S_TextColor)
    DllCall("gdi32.dll", "int",  "SetBkColor", _
                         "hwnd", $S_Destination, _
                         "int",  $S_BKColor)
    DllCall("gdi32.dll", "int",  "TextOutA", _
                         "hwnd", $S_Destination, _
                         "int",  $S_x, _
                         "int",  $S_y, _
                         "str",  $S_Text, _
                         "int",  StringLen($S_Text))    
    DllCall("gdi32.dll", "int",  "selectObject", _
                         "hwnd", $S_Destination, _
                         "int",  $oldfont[0])
    DllCall("gdi32.dll", "int",  "DeleteObject", _
                         "hwnd", $font[0])
EndFunc
Link to comment
Share on other sites

jpam, thanks for the examples. I had found the one with the ellipse during my searches. What I'm looking for is to make the background of the entire area of the graphic transparent-- and then have the ellipse (with no fill) lay over whatever is underneath. The two examples below show the difference.

post-29172-1212185218_thumb.png

post-29172-1212185226_thumb.png

Edited by qwert
Link to comment
Share on other sites

like this ?

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, -1, $WS_EX_LAYERED)

GUICtrlCreateLabel("", 50, 0, 200, 50, -1, $GUI_WS_EX_PARENTDRAG)
GUISetBkColor(0xABCDEF)
GUICtrlSetFont(-1,14,900)

$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $Main_Gui, "long", 0xEFCDAB , "byte", 255, "long", 0x1 + 0x2)
GUISetState()

$hdc = GetHDC()

DrawEllipse($hdc, 100, 160, 300, 360, 1, 0x000000 , 0xEFCDAB)

While 1
    $msg = GUIGetMsg()
    If $msg = $exit Then Exit
    If $msg = -3 Then Exit
WEnd

Func GetHDC()
    Local $S_WIN_TILLE     = WinGetTitle("", "")
    Local $S_ClientSize    = WinGetClientSize($S_WIN_TILLE, "")
    Local $S_WIN_GETHANDLE = WinGetHandle($S_WIN_TILLE, "")
    Local $S_RAW_HDC = DllCall("user32.dll", "ptr", "GetDC", "hwnd", $S_WIN_GETHANDLE)
    $hDC = "0x" & Hex($S_RAW_HDC[0])
    Return $hDC
EndFunc

Func DrawEllipse($S_Destination, $S_left, $S_top, $S_right, $S_bottom, $S_linewidth, $S_linecolor, $S_fillcolor)
    $S_pen = DllCall("gdi32.dll", "int", "CreatePen", _
                                  "int", 0, _
                                  "int", $S_linewidth, _
                                  "int", $S_linecolor)
    $S_obj = DllCall("gdi32.dll", "int", "SelectObject", _
                                  "int", $S_Destination, _
                                  "int", $S_pen[0])
    DllCall("gdi32.dll", "int", "DeleteObject", _
                         "int", $S_obj[0])
    $S_brush = DllCall("gdi32.dll", "int", "CreateSolidBrush", _
                                    "int", $S_fillcolor)
    $S_obj   = DllCall("gdi32.dll", "int", "SelectObject", _
                                    "int", $S_Destination, _
                                    "int", $S_brush[0])
    DllCall("gdi32.dll", "int", "DeleteObject", _
                         "int", $S_obj[0])
    DllCall("gdi32.dll", "int", "Ellipse", _
                         "int", $S_Destination, _
                         "int", $S_left, _
                         "int", $S_top, _
                         "int", $S_right, _
                         "int", $S_bottom)
EndFunc
Link to comment
Share on other sites

DllCall("gdi32.dll", "int", "SetBkMode", _

"hwnd", $S_Destination, _

"int", "TRANSPARENT")

I think it should not be a string there

Const $TRANSPARENT = 1, $OPAQUE = 2

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

@ martin

it must be declared as "0x00000020"

@ qwert

glad i could help you :)

Transparent I suppose you mean?

It seems that any value that is not 2 gives transparent.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

@ qwert

glad i could help you :)

Everything is working very well using the method you posted.

But I do have a couple of questions, since I've never worked with the Graphics.GetHdc Method.

Sometimes I need to be able to delete the first rectangle and replace it with a different rectangle. So what I've done is change the function to return the handle of the drawn object as follows:

$S_rect = DllCall("gdi32.dll", "int", "Rectangle", _
                         "int", $S_Destination, _
                         "int", $S_left, _
                         "int", $S_top, _
                         "int", $S_right, _
                         "int", $S_bottom)
Return $_rect
EndFunc

I then use this DllCall to erase the previous rectangle.

$rect = DrawRect($hdc, 100, 160, 800, 560, 1, 0x000000 , 0xEFCDAB)
Sleep(3000)
DllCall("gdi32.dll", "int", "DeleteObject", "int", $rect)

It seems to work, but is it the proper way?

Also, could you comment on the "CreatePen/SelectObject/DeleteObject" sequence used in the function. Doesn't this delete the pen before it's used? And if I call the function more than once, should the delete steps be put off until exiting the scipt?

I certainly appreciate your help on this. It's opening up a new area of capability.

Link to comment
Share on other sites

here a cleanup version with comments

to erase a Rectangle ,simple draw a new one over the old one with the transparent line color.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

$Main_Gui = GUICreate("", 400, 400, -1, -1, -1, $WS_EX_LAYERED)

GUICtrlCreateLabel("", 50, 0, 200, 50, -1, $GUI_WS_EX_PARENTDRAG)
GUISetBkColor(0xABCDEF)
GUICtrlSetFont(-1,14,900)

$exit = GUICtrlCreateButton("Exit", 200, 100, 80, 21)

DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $Main_Gui, "long", 0xEFCDAB , "byte", 255, "long", 0x1 + 0x2)
GUISetState()

$hdc = GetHDC()

DrawEllipse($hdc, 100, 160, 300, 360, 1, 0x000000 , 0xEFCDAB)
Sleep(2000)
DrawEllipse($hdc, 100, 160, 300, 360, 1, 0xEFCDAB , 0xEFCDAB) ; draw a new shape over the old one 
                                                              ; with transparent line color to erase old shape from screen

While 1
    $msg = GUIGetMsg()
    If $msg = $exit Then Exit
    If $msg = -3 Then Exit
WEnd

Func GetHDC()
    Local $S_WIN_TILLE     = WinGetTitle("", "")
    Local $S_ClientSize    = WinGetClientSize($S_WIN_TILLE, "")
    Local $S_WIN_GETHANDLE = WinGetHandle($S_WIN_TILLE, "")
    Local $S_RAW_HDC = DllCall("user32.dll", "ptr", "GetDC", "hwnd", $S_WIN_GETHANDLE)
    $hDC = "0x" & Hex($S_RAW_HDC[0])
    Return $hDC
EndFunc

Func DrawEllipse($S_Destination, $S_left, $S_top, $S_right, $S_bottom, $S_linewidth, $S_linecolor, $S_fillcolor)
    $S_hNewPen   = DllCall("gdi32.dll", "int", "CreatePen", _       ; Create new pen to draw with  
                                        "int", 0, _
                                        "int", $S_linewidth, _
                                        "int", $S_linecolor)
                                    
    $S_hOldPen  = DllCall("gdi32.dll", "int", "SelectObject", _     ; Select new pen into DC 
                                       "int", $S_Destination, _     ; and save handle to old one 
                                       "int", $S_hNewPen[0])
                                    
    $S_NewBrush = DllCall("gdi32.dll", "int", "CreateSolidBrush", _ ; Create new brush to fill shapes
                                       "int", $S_fillcolor)
                                       
    $S_OldBrush = DllCall("gdi32.dll", "int", "SelectObject", _     ; Select new brush into DC 
                                       "int", $S_Destination, _     ; and save handle to old one 
                                       "int", $S_NewBrush[0])
                                       
    DllCall("gdi32.dll", "int", "Rectangle", _                      ; draw Rectangle
                         "int", $S_Destination, _
                         "int", $S_left, _
                         "int", $S_top, _
                         "int", $S_right, _
                         "int", $S_bottom)
                         
    DllCall("gdi32.dll", "int", "SelectObject", _      ; Displace New Pen from DC 
                         "int", $S_Destination, _
                         "int", $S_hOldPen[0])
                         
    DllCall("gdi32.dll", "int", "DeleteObject", _      ; delete pen to free up system resources
                         "int", $S_hNewPen[0])         ; when a pen is still selected in the dc ,you can not delete it

    DllCall("gdi32.dll", "int", "SelectObject", _      ; Displace New brush from DC 
                         "int", $S_Destination, _      ; when a Brush is still selected in the dc ,you can not delete it
                         "int", $S_OldBrush[0])
                         
    DllCall("gdi32.dll", "int", "DeleteObject", _      ; delete brush to free up system resources
                         "int", $S_NewBrush[0])        ; when a brush is still selected in the dc ,you can not delete it
EndFunc
Link to comment
Share on other sites

here's a cleanup version with comments

Excellent work.

Given the new order of the steps, it does look like the pen create and delete steps could be pulled outside of the draw function for the case where repeated calls will be made using the same settings. I'll give it a try just to know, although it works great, as is.

Thanks again for your help.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...