Geklickte Linie in einem Raster erkennen

  • Hallo Leute,
    ich denke schon seit langem über ein Problem nach, komme aber nicht auf die Lösung.
    Ich habe ein 10x10 Raster und will darin erkennen, welche Linien angeklickt wurden, dabei
    sollte das Programm jedoch nicht allzu penibel sein, d.h. ein bischen Toleranz beim Linienanklicken muss drin sein,
    sonst ist es nicht sonderlich benutzerfreundlich.
    Ich habe mir für das Raster eine Nummerierung ausgedacht:
    Die Kästchen sind von 0 beginnend durchnummeriert:
    0 1 2 3 4 5 6 7 8 9
    10 11 12 13 14 15 16 17 18 19
    etc,

    Damit man unterscheiden kann, welche Linie gedrückt wurde gibt es sogenannte "Orientierungszahlen". Diese sind im Uhrzeigersinn nummeriert dh. 0 = obere Linie im Kästchen 1 = rechte Linie im Kästchen 2 = untere Linie im Kästchen und 3 = linke Linie im Kästchen. Das Problem bei dieser Variante ist jedoch, dass die Felder doppelt belegt sind zb. Kästchen 0 Orientierung 1 ist das selbe wie Kästchen 1 Orientierung 2.
    Das lässt sich jedoch mit ein bischen rechnen ausgleichen.
    Mein Problem ist jetzt jedoch, das ich erkennen will welche Linie geklickt wurde, ich habe schon einmal so angefangen:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GDIPlus.au3>
    #include <Array.au3>
    #include <Misc.au3>
    $iButtonMainMenuFontSize = 20
    $iButtonTransparency = 250
    $hEditGameMainGui = GUICreate("Käsekästchen",420,510,-1,-1,$WS_POPUP)
    ;$hEditGameBackground = GUICtrlCreatePic($oBackgroundImage,0,0,420,510)
    $hEditGameTransparentBackgroundGuiSaveuAbortButtonGUI = GUICreate("",420,99,0,415,$WS_POPUP,$WS_EX_MDICHILD,$hEditGameMainGui)
    WinSetTrans($hEditGameTransparentBackgroundGuiSaveuAbortButtonGUI,"",$iButtonTransparency)
    $hEditGameSaveButton = GUICtrlCreateButton("Speichern",0,0,420,49)
    GUICtrlSetFont(-1,$iButtonMainMenuFontSize,400,2)
    $hEditGameAbortButton = GUICtrlCreateButton("Abbrechen",0,50,420,49)
    GUICtrlSetFont(-1,$iButtonMainMenuFontSize,400,2)
    Global $pi_ziel = @TempDir & '\picasso.ini'
    _GDIPlus_Startup()
    Global $pi_iWidth = 401, $pi_iHeight = 401
    $pi_hGUI = GUICreate("",$pi_iWidth, $pi_iHeight,10,5,$WS_POPUP,$WS_EX_MDICHILD,$hEditGameMainGui)
    $pi_hGraphic = _GDIPlus_GraphicsCreateFromHWND($pi_hGUI)
    Global $pi_hBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000)
    WinSetTrans($pi_hGUI,"",200)
    GUISetState(@SW_SHOW,$hEditGameMainGui)
    GUISetState(@SW_SHOW,$hEditGameTransparentBackgroundGuiSaveuAbortButtonGUI)
    GUISetState(@SW_SHOW,$pi_hGUI)
    pi_Plan($pi_hGraphic)
    While 1
    Switch GUIGetMsg()
    Case $GUI_EVENT_PRIMARYDOWN
    $aEditGameCoursorInfo = GUIGetCursorInfo($pi_hGUI)
    ConsoleWrite($aEditGameCoursorInfo[0] & @CRLF & $aEditGameCoursorInfo[1] & @CRLF)
    Local $iLinieNummer = ''
    Local $iSpalteNummer = ''
    Local $iKaestchenNummer = ''
    Select
    Case $aEditGameCoursorInfo[1] > 1 and $aEditGameCoursorInfo[1] < 10
    $iLinieNummer = '0'
    Case $aEditGameCoursorInfo[1] > 36 and $aEditGameCoursorInfo[1] < 44
    $iLinieNummer = 1
    Case $aEditGameCoursorInfo[1] > 73 and $aEditGameCoursorInfo[1] < 85
    $iLinieNummer = 2
    Case $aEditGameCoursorInfo[1] > 113 and $aEditGameCoursorInfo[1] < 125
    $iLinieNummer = 3
    Case $aEditGameCoursorInfo[1] > 151 and $aEditGameCoursorInfo[1] < 163
    $iLinieNummer = 4
    Case $aEditGameCoursorInfo[1] > 193 and $aEditGameCoursorInfo[1] < 205
    $iLinieNummer = 5
    Case $aEditGameCoursorInfo[1] > 232 and $aEditGameCoursorInfo[1] < 244
    $iLinieNummer = 6
    Case $aEditGameCoursorInfo[1] > 274 and $aEditGameCoursorInfo[1] < 285
    $iLinieNummer = 7
    Case $aEditGameCoursorInfo[1] > 313 and $aEditGameCoursorInfo[1] < 326
    $iLinieNummer = 8
    Case $aEditGameCoursorInfo[1] > 353 and $aEditGameCoursorInfo[1] < 362
    $iLinieNummer = 9
    Case $aEditGameCoursorInfo[1] > 393 and $aEditGameCoursorInfo[1] < 401
    $iLinieNummer = 10
    EndSelect
    ConsoleWrite($iLinieNummer & @CRLF)
    Select
    Case $aEditGameCoursorInfo[0] > 1 and $aEditGameCoursorInfo[0] < 7
    $iSpalteNummer = '0'
    Case $aEditGameCoursorInfo[0] > 37 and $aEditGameCoursorInfo[0] < 44
    $iSpalteNummer = 1
    Case $aEditGameCoursorInfo[0] > 76 and $aEditGameCoursorInfo[0] < 85
    $iSpalteNummer = 2
    Case $aEditGameCoursorInfo[0] > 118 and $aEditGameCoursorInfo[0] < 125
    $iSpalteNummer = 3
    Case $aEditGameCoursorInfo[0] > 158 and $aEditGameCoursorInfo[0] < 165
    $iSpalteNummer = 4
    Case $aEditGameCoursorInfo[0] > 198 and $aEditGameCoursorInfo[0] < 205
    $iSpalteNummer = 5
    Case $aEditGameCoursorInfo[0] > 235 and $aEditGameCoursorInfo[0] < 244
    $iSpalteNummer = 6
    Case $aEditGameCoursorInfo[0] > 277 and $aEditGameCoursorInfo[0] < 284
    $iSpalteNummer = 7
    Case $aEditGameCoursorInfo[0] > 313 and $aEditGameCoursorInfo[0] < 328
    $iSpalteNummer = 8
    Case $aEditGameCoursorInfo[0] > 355 and $aEditGameCoursorInfo[0] < 367
    $iSpalteNummer = 9
    Case $aEditGameCoursorInfo[0] > 391 and $aEditGameCoursorInfo[0] < 401
    $iSpalteNummer = 10
    EndSelect
    ConsoleWrite($iSpalteNummer & @CRLF)

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

    Case $GUI_EVENT_ClOSE
    Close()
    Case $hEditGameAbortButton
    Exit
    EndSwitch
    WEnd
    Func pi_Plan($pi_hWindowHandle)
    For $pi_u = 0 To 390 Step 40
    _GDIPlus_GraphicsdrawRect($pi_hWindowHandle,$pi_u,0,40,400)
    Next
    For $pi_a = 0 To 390 Step 40
    _GDIPlus_GraphicsdrawRect($pi_hWindowHandle,0,$pi_a,400,40)
    Next
    EndFunc

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

    Func pi_DrawLine($pi_iField,$pi_iDirection,$pi_hWindowHandle)
    Local $pi_y2cord = 0
    Local $pi_ycord = 0
    Local $pi_x2cord = 0
    Local $pi_xcord = 0
    Local $pi_xcord = 40 * StringRight($pi_iField,1)
    If StringLen($pi_iField) = 1 Then
    $pi_ycord = 0
    Else
    $pi_ycord = 40 * StringLeft($pi_iField,1)
    EndIf
    If $pi_iDirection = 0 Then
    $pi_x2cord = 40
    $pi_ycord = $pi_ycord - 3
    $pi_y2cord = 6
    ElseIf $pi_iDirection = 1 Then
    $pi_xcord = $pi_xcord + 37
    $pi_x2cord = 6
    $pi_y2cord = 40
    ElseIf $pi_iDirection = 2 Then
    $pi_ycord = $pi_ycord + 37
    $pi_x2cord = 40
    $pi_y2cord = 6
    Else
    $pi_xcord = $pi_xcord - 3
    $pi_x2cord = 6
    $pi_y2cord = 40
    EndIf
    _GDIPlus_GraphicsFillRect($pi_hWindowHandle,$pi_xcord,$pi_ycord,$pi_x2cord,$pi_y2cord,$pi_hBrush)
    EndFunc

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

    FUnc Close()
    Exit
    EndFunc

    [/autoit]


    Ich kann schon einmal erkennen welche Linie und welche Spalte geklickt wurde, jedoch müsste ich jetzt noch das Kästchen ermitteln, wie mache ich dies jedoch,
    ohne 100 Selects schreiben zu müssen?
    Oder gibt es eine andere, simplere Lösung das zu erkennen?
    Fliwatt

  • Hab das ganze mal durchgespielt und es ist nicht so schwer wie du denkst ;)
    Welches Kästchen geklickt wurde geht recht einfach wenn du Floor() verwendest und damit die x bzw. y koordinate durch 40 (deine Spaltenbreite) teilst.
    Zum erkennen welche Linie geklickt wurde kannst du auch ganz einfach eine For Schleife mit Step 40 verwenden.
    Darin eine If Abfrage einbauen die prüft ob in der Nähe einer Linie geklickt wurde.

    Ich hab das ganze auch schon fertig, aber ich wollte dich erst einmal selbst probieren lassen.
    Wenn du meine Lösung sehen willst dann sags einfach ;)

    PS: Bitte beim nächsten mal ein lauffähiges Script posten

    • Offizieller Beitrag

    Hier mal ein Bsp. mit 20x20 Kästchen.

    Spoiler anzeigen
    [autoit]

    $gui = GUICreate('Test', 420, 420)
    ; Linie=1px -- Kästchen = 20px
    ; Zeichnen:
    For $i = 0 To 19
    GUICtrlCreateLabel('', 21*$i, 0, 1, 420)
    GUICtrlSetBkColor(-1, 0x000000)
    For $j = 0 To 19
    GUICtrlCreateLabel('', 21*$i, 21*$j, 420, 1)
    GUICtrlSetBkColor(-1, 0x000000)
    Next
    Next
    GUISetState()

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

    While 1
    $aMsg = GUIGetMsg(1)
    Switch $aMsg[0]
    Case -3
    Exit
    Case $GUI_EVENT_PRIMARYDOWN
    ;~ $horicontal = Ceiling($aMsg[3]/21) ; == für 1-basierte Angabe
    ;~ $vertical = Ceiling($aMsg[4]/21) ; == für 1-basierte Angabe
    $horicontal = Floor($aMsg[3]/21) ; == für 0-basierte Angabe
    $vertical = Floor($aMsg[4]/21) ; == für 0-basierte Angabe
    ConsoleWrite($horicontal & ', ' & $vertical & @LF)
    EndSwitch
    WEnd

    [/autoit]
    • Offizieller Beitrag

    Ich würde das Ganze mit GDI+ zeichnen. Dann kannst Du auch anschließend die einzelnen Linien besser darstellen.
    Hier mal ein Anfang:

    Spoiler anzeigen
    [autoit]


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

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

    Opt('GUIOnEventMode', 1)

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

    _GDIPlus_Startup()
    Global $iEdge = 32, $iCount = 10, $iRect = $iEdge * $iCount + $iEdge * 2

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

    $hGui = GUICreate('Test', $iRect, $iRect)
    GUISetState()
    GUISetOnEvent($GUI_EVENT_CLOSE, '_End')
    GUISetOnEvent($GUI_EVENT_PRIMARYUP, '_Click')

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

    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGui)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($iRect, $iRect, $hGraphic)
    $hGraphicBuff = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF)
    $hPen = _GDIPlus_PenCreate(0xFFAAAAAA)
    For $y = 0 To $iCount - 1
    For $x = 0 To $iCount - 1
    _GDIPlus_GraphicsDrawRect($hGraphicBuff, $iEdge + $x * $iEdge, $iEdge + $y * $iEdge, $iEdge, $iEdge, $hPen)
    Next
    Next
    _GDIPlus_GraphicsDrawImage($hGraphic, $hBitmap, 0, 0)

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

    GUIRegisterMsg($WM_PAINT, 'WM_PAINT')

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

    WinWaitClose($hGui)
    Exit

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

    Func _End()
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_Shutdown()
    GUIDelete($hGui)
    EndFunc ;==>_End

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

    Func _Click()
    Local $aInfo = GUIGetCursorInfo($hGui), $iX, $iY
    $iX = Int($aInfo[0] / $iEdge)
    $iY = Int($aInfo[1] / $iEdge)
    ToolTip(StringFormat('Spalte:\t%i\nZeile:\t%i', $iX, $iY))
    EndFunc ;==>_Click

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

    Func WM_PAINT($hWnd, $Msg, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphic, $hBitmap, 0, 0)
    EndFunc ;==>WM_PAINT

    [/autoit]
    • Offizieller Beitrag

    denn wie will man zum Beispiel mit Floor diese Linie (im Anhang) bestimmen?


    Ist es tatsächlich wichtig, ob diese Linie geklickt wird (erst mal versuchen diesen Pixel genau zu treffen)? Wenn du ein Spiel mit Kästchen 40x40 machst, halte ich die Zuordnung der Linien für irrelevant.

  • Ich hab es gestern so zusammengebaut wie du beschrieben hattest.
    Hier die Guigetmsg für dein Script

    Spoiler anzeigen
    [autoit]

    Switch GUIGetMsg()
    Case $GUI_EVENT_PRIMARYDOWN
    $aEditGameCoursorInfo = GUIGetCursorInfo($pi_hGUI)
    ConsoleWrite($aEditGameCoursorInfo[0] & @CRLF & $aEditGameCoursorInfo[1] & @CRLF)
    Local $iLinieNummer = ''
    Local $iKaestchenNummer = ''
    ; Kästchen ermitteln:
    $x = Floor($aEditGameCoursorInfo[0]/40)
    $y = Floor($aEditGameCoursorInfo[1]/40)
    If $x >= 0 And $x < 10 And $y >= 0 And $y < 10 Then $iKaestchenNummer = 10 * $y + $x + 1
    ConsoleWrite('Kastchen: ' & $iKaestchenNummer & @LF)
    ; Linie ermitteln:
    $iToleranz = 5
    For $i = 0 To 400 Step 40
    ; horizonal prüfen:
    If $aEditGameCoursorInfo[1] > $i - $iToleranz And $aEditGameCoursorInfo[1] < $i + $iToleranz Then
    ; Oben oder unten
    If Mod($aEditGameCoursorInfo[1], 40) < 20 Then
    $iLinieNummer = 0
    Else
    $iLinieNummer = 2
    EndIf
    EndIf
    ; vertikal prüfen:
    If $aEditGameCoursorInfo[0] > $i - $iToleranz And $aEditGameCoursorInfo[0] < $i + $iToleranz Then
    ; links oder rechts
    If Mod($aEditGameCoursorInfo[0], 40) < 20 Then
    $iLinieNummer = 3
    Else
    $iLinieNummer = 1
    EndIf
    EndIf
    Next
    ConsoleWrite('LinienNr: ' & $iLinieNummer & @LF)
    EndSwitch

    [/autoit]

    Allerdings würde ich mir das mit der Nummerierung nochmal überlegen. Das geht schöner...
    Wenn du mein Scriptteil und Oscars script zusammenbaust bekommst du da schon was ganz schönes ;)