[UDF] (Teil)transparente Bilder-GUIs nach einem Rezept von Meister UEZ

  • UEZ hat hier ein schönes Beispiel für den Umgang mit "Layered Windows" eingestellt. Damit kann man u.a. (teil)transparente GUIs aus Bildern erstellen, ohne dass ständig neu gezeichnet werden muss. Damit das nicht im Hilfeforum untergeht, habe ich ihn gebeten, es in Form einer UDF hier einzustellen. Er hat leider im Augenblick nicht die Zeit dafür, deshalb habe ich mich mit seinem Einverständnis darüber hergemacht:

    Demo.au3
    [autoit]

    #include <GUIConstantsEx.au3>
    #include "GUICreateTransparent.au3"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $SC_DRAGMOVE = 0xF012
    Global $sBildURL = "http://www.autoit.de/index.php?page=Attachment&attachmentID=11980&h=3e1f01006e7557e85e5957cfa8c04a385ebf559a"
    Global $sBilddatei = @ScriptDir & "\bg.png"

    [/autoit] [autoit][/autoit] [autoit]

    If Not FileExists($sBilddatei) Then
    $Result = MsgBox(4, "Bild laden", 'Soll das Bild "bg.png" von' & @CRLF & @CRLF & _
    $sBildURL & @CRLF & @CRLF & 'heruntergeladen werden?')
    If $Result <> 6 Then Exit
    InetGet($sBildURL, $sBilddatei)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Transparentes GUI erzeugen
    $hGUI = _GUICreate_Transparent($sBilddatei)

    [/autoit] [autoit][/autoit] [autoit]

    ; Child-GUI mit Controls erzeugen
    $hChild = GUICreate("MDIChild", 400, 400, 150, 150, $WS_POPUP, $WS_EX_MDICHILD + $WS_EX_LAYERED, $hGUI)
    GUISetBkColor(0x123456)
    GUICtrlCreateButton("Button 1", 20, 20)
    GUICtrlCreateButton("Button 2", 20, 50)
    GUICtrlCreateButton("Button 3", 20, 80)
    GUICtrlCreateInput("Input 1", 20, 110, -1, 20)
    ; Hintergrundfarbe des Child-GUI transparent setzen
    _WinAPI_SetLayeredWindowAttributes($hChild, 0x123456, 0xff)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $hGUI)
    GUISetState(@SW_SHOW, $hChild)

    [/autoit] [autoit][/autoit] [autoit]

    ; Wenn man das GUI bewegen will
    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN")

    [/autoit] [autoit][/autoit] [autoit]

    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam)
    _SendMessage($hGUI, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit]
    GUICreateTransparent.au3
    [autoit]

    #include-once

    [/autoit] [autoit][/autoit] [autoit]

    #include <WindowsConstants.au3>
    #include <GDIPlus.au3>
    #include <WinAPI.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ; #INDEX# =======================================================================================================================
    ; Title .........: GUICreateTransparent
    ; AutoIt Version : 3.3.6.1
    ; Description ...: Transparente BildGUIs erstellen.
    ; Author(s) .....: UEZ und ein bisschen Großvater (http://www.autoit.de)
    ; Dll ...........:
    ; ===============================================================================================================================

    [/autoit] [autoit][/autoit] [autoit]

    ; #CURRENT# =====================================================================================================================
    ; _GUICreate_Transparent
    ; ===============================================================================================================================

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _GUICreate_Transparent
    ; Description ...: Transparente Popup-GUIs aus Bildern (z.B. PNG) erstellen
    ; Syntax.........: _GUICreate_Transparent($sImage, $iLeft = -1, $iTop = -1, $iOpacity = 255)
    ; Parameters ....: $sImage - Pfad zur Bilddatei
    ; $iLeft - Bidschirmposition der linken Seite des GUI in Pixeln
    ; |Default - -1 (zentriert)
    ; $iTop - Bidschirmposition der oberen Seite des GUI in Pixeln
    ; |Default - -1 (zentriert)
    ; $iOpacity - Transparenz für das gesamte GUI (siehe WinSetTrans())
    ; |Default - 255 (nicht transparent)
    ; Return values .: Im Erfolgsfall: HWND des GUI aus GUICreate()
    ; Im Fehlerfall: False, @error wird gesetzt:
    ; |1 = GDIPlus konnte nicht gestartet werden
    ; |2 = Die Bilddatei konnte nicht geladen werden
    ; Author ........: UEZ (http://www.autoit.de/index.php?page…9839#post199839)
    ; Modified.......: Großvater (http://www.autoit.de)
    ; Remarks .......: Das GUI wird immer in der Originalgröße des Bildes mit dem Style $WS_POPUP und dem
    ; Exstyle $WS_EX_LAYERED erstellt. Der Exstyle $WS_EX_LAYERED verträgt sich offenbar
    ; nicht mit normalen Child-GUIs. Controls müssen deshalb in (einer) eigenen GUI(s)
    ; mit den Exstyles $WS_EX_MDICHILD und $WS_EX_LAYERED und der HWND des Bild-GUI
    ; als Parent erstellt werden. Dafür liefert UEZ im o.a. Thread ein Beispiel.
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _GUICreate_Transparent($sImage, $iLeft = -1, $iTop = -1, $iOpacity = 255)
    ; GDIPlus starten
    If Not _GDIPlus_Startup() Then Return SetError(1, 0, 0)
    ; Bild laden
    Local $hImage = _GDIPlus_ImageLoadFromFile($sImage)
    If @error Then
    _GDIPlus_Shutdown()
    Return SetError(2, 0, 0)
    EndIf
    Local $iWidth = _GDIPlus_ImageGetWidth($hImage)
    Local $iHeight = _GDIPlus_ImageGetHeight($hImage)
    ; GUI erstellen
    Local $hGUI = GUICreate("", $iWidth, $iHeight, $iLeft, $iTop, $WS_POPUP, $WS_EX_LAYERED)
    Local $hDCDst = _WinAPI_GetDC($hGUI)
    Local $hDCSrc = _WinAPI_CreateCompatibleDC($hDCDst)
    Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_SelectObject($hDCSrc, $hBitmap)
    Local $tSize = DllStructCreate($tagSIZE)
    Local $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $iWidth)
    DllStructSetData($tSize, "Y", $iHeight)
    Local $tSource = DllStructCreate($tagPOINT)
    Local $pSource = DllStructGetPtr($tSource)
    Local $tBlend = DllStructCreate($tagBLENDFUNCTION)
    Local $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)
    _WinAPI_UpdateLayeredWindow($hGUI, $hDCDst, 0, $pSize, $hDCSrc, $pSource, 0, $pBlend, $ULW_ALPHA)
    ; Ressourcen freigeben
    _GDIPlus_ImageDispose($hImage)
    _WinAPI_DeleteObject($hBitmap)
    _WinAPI_DeleteDC($hDCSrc)
    _WinAPI_ReleaseDC($hGUI, $hDCDst)
    _GDIPlus_Shutdown()
    ; HWND des GUI zurückgeben
    Return $hGUI
    EndFunc ;==>_GUICreate_Transparent

    [/autoit]


    Viel Spaß damit!

    Update am 23.12.2010:
    Wegen des von autoBert gemeldeten Fehlers unter WinXP habe ich die Namen der DCs an die in UpdateLayeredWindow() verwendeten Konventionen angepasst und den Funktionsaufruf entsprechend geändert.
    Damit läuft es auch in meinem virtuellen XP.

    Einmal editiert, zuletzt von Großvater (23. Dezember 2010 um 07:06) aus folgendem Grund: Bug unter WinXP

    • Offizieller Beitrag

    Die UDF ist richtig Klasse, funktioniert einwandfrei unter Win/64 AutoIt 3.3.6.1.
    @Großvater und UEZ, habt ihr gut hinbekommen. :thumbup:
    Wandert sofort in meine Sammlung. :D


    Edit: Das beste daran ist, ein klick wird auch nur auf den sichtbaren Teil angenommen.
    Hierletzt hat Autobert eine Lösung gepostet, da wurde auch ein Klick auf den nicht sichtbaren Teil registriert.
    Komischerweise hat das bewegen des Fesnters unter Windows Xp geklappt wie es sollte und bei Win7 wurde
    der komplette Bereich der GUI zum verschieben verwendet, auch wenn er nicht sichtbar war. 8|

  • Ändere mal die Zeile 73 in GUICreateTransparent.au3 zu _WinAPI_UpdateLayeredWindow($hGUI, 0, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA) um (war bereits in meinem Beispiel so :whistling: ).

    Sollte jetzt auch unter WinXP funzen!

    Es gibt leider einige Codes, die nicht mehr oder anders unter WinXP laufen!

    Ich persönlich bin absolut mit Win7 x64 zufrieden und verwende XP i.d.R. nicht mehr! :D

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    2 Mal editiert, zuletzt von UEZ (23. Dezember 2010 um 00:17)

  • UEZ, danke ich habe jetzt so abgeändert:

    [autoit]

    if @OSBuild = 2600 Then
    _WinAPI_UpdateLayeredWindow($hGUI, 0, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA) ; Ressourcen freigeben
    Else
    _WinAPI_UpdateLayeredWindow($hGUI, $hGUI, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    EndIf

    [/autoit]

    funktioniert unter XP tadellos,

    mfg autoBert

  • _WinAPI_UpdateLayeredWindow($hGUI, 0, 0, $pSize, $hMemDC, $pSource, 0, $pBlend, $ULW_ALPHA) funzt auch auf Vista+ ;)

    Ich weiß nicht mehr, warum ich $hGUI, $hGUI genommen hatte...

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Guten Morgen,

    ich habe die notwendigen Änderungen für WinXP nachvollzogen und die Funktion neu eingestellt.

  • Zitat

    Großvater hat in GUICreateTransparent.au3 folgendes geschrieben:

    [autoit]

    ; Remarks .......: Das GUI wird immer in der Originalgröße des Bildes mit dem Style $WS_POPUP und dem
    ; Exstyle $WS_EX_LAYERED erstellt. Der Exstyle $WS_EX_LAYERED verträgt sich offenbar
    ; nicht mit normalen Child-GUIs. Controls müssen deshalb in (einer) eigenen GUI(s)
    ; mit den Exstyles $WS_EX_MDICHILD und $WS_EX_LAYERED und der HWND des Bild-GUI
    ; als Parent erstellt werden. Dafür liefert UEZ im o.a. Thread ein Beispiel.

    [/autoit]


    Da war ich mir nicht sicher und es stimmt so auch nicht. Man kann schon Controls auf das GUI legen, sie sind nur nicht sichtbar. Ich vermute, es liegt daran, dass das Alphabyte der Farben der Controls auf 0X00 steht.

    Die Unsichtbarkeit hindert AutoIt aber nicht daran, Klicks auf den Controls oder in GUIGetCursorInfo() das unter der Maus liegende Control zu erkennen. Wenn man die Controls geschickt positioniert, kann man so Teile des Bildes für mausgesteuerte Aktionen "missbrauchen". Ich habe die "Demo" deshalb mal verändert und dem im Bild enthaltenen Text "Test Form" ein Label übergeholfen:

    Demo mit Label
    [autoit]

    #include <GUIConstantsEx.au3>
    #include "GUICreateTransparent.au3"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $SC_DRAGMOVE = 0xF012
    Global $sBildURL = "http://www.autoit.de/index.php?page=Attachment&attachmentID=11980&h=3e1f01006e7557e85e5957cfa8c04a385ebf559a"
    Global $sBilddatei = @ScriptDir & "\bg.png"

    [/autoit] [autoit][/autoit] [autoit]

    If Not FileExists($sBilddatei) Then
    $Result = MsgBox(4, "Bild laden", 'Soll das Bild "bg.png" von' & @CRLF & @CRLF & _
    $sBildURL & @CRLF & @CRLF & 'heruntergeladen werden?')
    If $Result <> 6 Then Exit
    InetGet($sBildURL, $sBilddatei)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Transparentes GUI erzeugen
    $hGUI = _GUICreate_Transparent($sBilddatei)
    WinSetOnTop($hGUI, "", True)

    [/autoit] [autoit][/autoit] [autoit]

    $idLbl = GUICtrlCreateLabel("Label Test Form", 383, 94, 109, 19)
    GUICtrlSetTip(-1, "Mich kannst Du klicken!", "Label Test Form")

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW)

    [/autoit] [autoit][/autoit] [autoit]

    ; Wenn man das GUI bewegen will
    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN")

    [/autoit] [autoit][/autoit] [autoit]

    While True
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    ExitLoop
    Case $idLbl
    MsgBox(0, "Transparentes GUI", "Klick auf Label Test Form", 0, $hGUI)
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam)
    _SendMessage($hGUI, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit]


    Wenn jemand eine Idee hat, wie man die unsichtbaren Controls sichtbar machen kann, möge er sie bitte hier posten.

  • Hier, was mit ad hoc eingefallen ist:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    #include "GUICreateTransparent.au3"

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $SC_DRAGMOVE = 0xF012
    Global $sBildURL = "http://www.autoit.de/index.php?page=Attachment&attachmentID=11980&h=3e1f01006e7557e85e5957cfa8c04a385ebf559a"
    Global $sBilddatei = @ScriptDir & "\bg.png"

    [/autoit] [autoit][/autoit] [autoit]

    If Not FileExists($sBilddatei) Then
    $Result = MsgBox(4, "Bild laden", 'Soll das Bild "bg.png" von' & @CRLF & @CRLF & _
    $sBildURL & @CRLF & @CRLF & 'heruntergeladen werden?')
    If $Result <> 6 Then Exit
    InetGet($sBildURL, $sBilddatei)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ; Transparentes GUI erzeugen
    $hGUI = _GUICreate_Transparent($sBilddatei)
    $hGUI2 = GUICreate("Test", 79, 14, 400, 100, $WS_POPUP, $WS_EX_MDICHILD + $WS_EX_LAYERED, $hGUI)
    GUISetBkColor(0x00001, $hGUI2)
    _WinAPI_SetLayeredWindowAttributes($hGUI2, 0x00001, 0xFF, 3)
    $idLbl = GUICtrlCreateLabel("Label Test Form", 0, 0, 79, 14)
    GUICtrlSetColor($idLbl, 0xFFFFFF)
    GUICtrlSetBkColor($idLbl, -2)
    GUICtrlSetTip(-1, "Mich kannst Du klicken!", "Label Test Form")
    WinSetOnTop($hGUI2, "", True)
    GUISetState(@SW_SHOW, $hGUI)
    GUISetState(@SW_SHOW, $hGUI2)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ; Wenn man das GUI bewegen will
    GUIRegisterMsg($WM_LBUTTONDOWN, "_WM_LBUTTONDOWN")

    [/autoit] [autoit][/autoit] [autoit]

    While True
    Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
    ExitLoop
    Case $idLbl
    MsgBox(0, "Transparentes GUI", "Klick auf Label Test Form", 0, $hGUI)
    EndSwitch
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam)
    _SendMessage($hGUI, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
    EndFunc ;==>_WM_LBUTTONDOWN

    [/autoit]

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Hallo UEZ,

    so meinte ich das nicht, das mit dem MDIChild-GUI habe ich ja schon aus Deinem Beispiel in die ursprüngliche Demo (s.o.) übernommen. Aber es gibt wohl keine Möglichkeit, den Farbwerten von Childcontrols des "layered" GUI eventuell auch nachträglich ein Alphabyte 0xFF zu verpassen, oder?