Jump to content

[SOLVED] GDI+ graphics and Clicks


Recommended Posts

Hey all.

I'm trying to know when my user clicks on a Rect drawn via GDI+. Everything is almost working except I have a strange behaviour in the "order" clicks are fired.

I created a simplified code to help :

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1) ;0=disabled, 1=OnEvent mode enabled

_GDIPlus_Startup()
Global $hGUI, $hGraphics
Global $iWidth = 1024, $iHeight = 762

createGUI()
draw()

While 1
    Sleep(10)
WEnd



Func createGUI()
    $hGUI = GUICreate("Current CasparCG Output", $iWidth,$iHeight)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")

    GUISetBkColor(0x000000)
    GUISetState(@SW_SHOW)

    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, $GDIP_SMOOTHINGMODE_HIGHQUALITY) ;sets the graphics object rendering quality (antialiasing)
EndFunc   ;==>Example





Func draw()
    ;_WinAPI_draw($hGUI,"","",BitOR($RDW_ERASE,$RDW_INVALIDATE,$RDW_UPDATENOW))
    _GDIPlus_GraphicsClear($hGraphics)


    $hFamily = _GDIPlus_FontFamilyCreate("Arial")
    $hFont = _GDIPlus_FontCreate($hFamily, 15, 1)
    $hPen = _GDIPlus_PenCreate(0xFFFEDCFF, 2) ;color format AARRGGBB (hex)
    $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)
    $hBrushString = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)
    Local $hBrush = _GDIPlus_BrushCreateSolid(0xFFFF00FF) ;color format AARRGGBB (hex)
    For $i = 1 to 2
        Local $x = 0.25
        Local $y = 0.25
        Local $w = 0.5
        Local $h = 0.5
        Local $title = "Layer "&$i

        If $x >= -1 And $x <= 1 Then $x *= $iWidth
        If $y >= -1 And $y <= 1 Then $y *= $iHeight
        If $w >= -1 And $w <= 1 Then $w *= $iWidth
        If $h >= -1 And $h <= 1 Then $h *= $iHeight



        $hItem = GUICtrlCreateLabel("", $x,$y,$w,$h)
        GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
        GUICtrlSetOnEvent($hItem,"_gui_layer_clicked")
        ConsoleWrite("Created label with handle="&$hItem&" $i= " & $i&@CRLF)
        _GDIPlus_GraphicsFillRect($hGraphics, $x, $y, $w, $h,$hBrush)
        _GDIPlus_GraphicsDrawRect($hGraphics, $x, $y, $w, $h,$hPen)

        $tLayout = _GDIPlus_RectFCreate($x, $y, $w, $h)
        $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $title, $hFont, $tLayout, $hFormat)
        _GDIPlus_GraphicsDrawStringEx($hGraphics, $title, $hFont, $aInfo[0], $hFormat, $hBrushString)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_BrushDispose($hBrushString)



    Return 1
EndFunc

Func _gui_layer_clicked()
    ConsoleWrite("Clicked on " & @GUI_CtrlId&@CRLF)
EndFunc

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Clean up resources
            _GDIPlus_GraphicsDispose($hGraphics)
            _GDIPlus_Shutdown()
            Exit

    EndSelect
EndFunc   ;==>SpecialEvents

What happens there :

We have two rectangles, with the one labelled "2" is front and, the one labelled "1" in background. However when we click, the fired label is the one created first (in the background) and not the second one (in the front).

Is it normal ?

If yes, is there any way to change this order ? If I create another label after a first one on the same coords, I would the second one to be fired instead of the first one (This is a simplified code I can't just invert the label order creation easily)

 

Thanks for your help

 

Edited by timmalos
Link to comment
Share on other sites

Both of your layers are the exact same size so if you want to differentiate between them you need to make one smaller. The reason the label is proccing for layer1 is because it's the first one created in the control chain. Might be easier to manually check, yourself, if the user clicks inside the GDI object using a GUIRegisterMsg. Here's how you can do it

#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <Array.au3>

Opt("GUIOnEventMode", 1) ;0=disabled, 1=OnEvent mode enabled

_GDIPlus_Startup()
Global $hGUI, $hGraphics
Global $iWidth = 1024, $iHeight = 762
; Holds the GDI+ object rects
Global $aGdiPosition[2][5]

createGUI()
draw()

While 1
    Sleep(10)
WEnd

Func createGUI()
    $hGUI = GUICreate("Current CasparCG Output", $iWidth, $iHeight)
    GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")

    GUISetBkColor(0x000000)
    GUISetState(@SW_SHOW)
    ; Register the LBUTTONUP message so we know when someone clicks on the GUI
    GUIRegisterMsg($WM_LBUTTONUP, WM_LBUTTONUP)

    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, $GDIP_SMOOTHINGMODE_HIGHQUALITY) ;sets the graphics object rendering quality (antialiasing)
EndFunc   ;==>createGUI

Func WM_LBUTTONUP($hWnd, $iMsg, $wParam, $lParam)
    ; X and Y positions are in the $lParam
    Local $iX = _WinAPI_LoWord($lParam)
    Local $iY = _WinAPI_HiWord($lParam)
    Local $bValidClick = False

    ; Go through these layers in reverse order they were created, top to bottom
    For $i = UBound($aGdiPosition) - 1 To 0 Step -1
        ; The click is inside the rect where the GDI+ object is
        If (_WinAPI_PtInRectEx($iX, $iY, $aGdiPosition[$i][0], $aGdiPosition[$i][1], $aGdiPosition[$i][2], $aGdiPosition[$i][3])) Then
            ConsoleWrite("Clicked on " & $aGdiPosition[$i][4] & @LF)
            $bValidClick = True
            ExitLoop
        EndIf
    Next
    If (Not $bValidClick) Then ConsoleWrite("Clicked outside the valid layers" & @LF)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_LBUTTONUP

Func draw()
    ;_WinAPI_draw($hGUI,"","",BitOR($RDW_ERASE,$RDW_INVALIDATE,$RDW_UPDATENOW))
    _GDIPlus_GraphicsClear($hGraphics)


    $hFamily = _GDIPlus_FontFamilyCreate("Arial")
    $hFont = _GDIPlus_FontCreate($hFamily, 15, 1)
    $hPen = _GDIPlus_PenCreate(0xFFFEDCFF, 2) ;color format AARRGGBB (hex)
    $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)
    $hBrushString = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)
    Local $hBrush = _GDIPlus_BrushCreateSolid(0xFFFF00FF) ;color format AARRGGBB (hex)
    For $i = 1 To 2
        Local $x = 0.25
        Local $y = 0.25
        Local $w = 0.5
        Local $h = 0.5
        Local $title = "Layer " & $i

        If $x >= -1 And $x <= 1 Then $x *= $iWidth
        If $y >= -1 And $y <= 1 Then $y *= $iHeight
        If $w >= -1 And $w <= 1 Then $w *= $iWidth / $i ; so the second one is smaller
        If $h >= -1 And $h <= 1 Then $h *= $iHeight / $i ; so the second one is smaller
        $aGdiPosition[$i - 1][0] = $x
        $aGdiPosition[$i - 1][1] = $y
        $aGdiPosition[$i - 1][2] = $x + $w
        $aGdiPosition[$i - 1][3] = $y + $h
        $aGdiPosition[$i - 1][4] = $title

        _GDIPlus_GraphicsFillRect($hGraphics, $x, $y, $w, $h, $hBrush)
        _GDIPlus_GraphicsDrawRect($hGraphics, $x, $y, $w, $h, $hPen)

        $tLayout = _GDIPlus_RectFCreate($x, $y, $w, $h)
        $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, $title, $hFont, $tLayout, $hFormat)
        _GDIPlus_GraphicsDrawStringEx($hGraphics, $title, $hFont, $aInfo[0], $hFormat, $hBrushString)
    Next
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_BrushDispose($hBrushString)

    Return 1
EndFunc   ;==>draw

Func _gui_layer_clicked()
    ConsoleWrite("Clicked on " & @GUI_CtrlId & @CRLF)
EndFunc   ;==>_gui_layer_clicked

Func SpecialEvents()
    Select
        Case @GUI_CtrlId = $GUI_EVENT_CLOSE
            ; Clean up resources
            _GDIPlus_GraphicsDispose($hGraphics)
            _GDIPlus_Shutdown()
            Exit

    EndSelect
EndFunc   ;==>SpecialEvents

 

Link to comment
Share on other sites

Hey all.

Managed to find a solution with the right keyword : "z-order".

 

This makes the trick :

GUICtrlSetState(-1, $GUI_ONTOP)

 

EDIT : Just saw InunoTaishou answer which works well without needing the text controls, I'll use your solution , thanks !

 

 

Edited by timmalos
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

×
×
  • Create New...