10er Countdown mit Abfrage

  • Hallo,

    meine Name ist Chris und ich bin im AutoIT Bereich absoluter Anfänger. Bin im Realen Leben php und mysql Programmierer.

    Ich benötige eure Hilfe. Ich möchte ein ganz kleines Programm schreiben.

    Der Ablauf.

    Nachdem das Programm geöffnet wurde, sind 10 Countdown Zähler zu sehen.
    Wenn man jetzt auf einen klickt, soll ein kleines Fenster geöffnet werden wo eine abfrage drin steht. (15, 20, 30).
    Das ist die Zeitangabe für den Countdown. Der Countdown soll dann gleich starten. ca. 1min vor ende sollte eine Meldung kommen das es nur noch eine Minute Rest zeit ist..
    Ist der Countdown am ende soll die zuvor ausgewählte zeit wieder da stehen.

    Ich hoffe ihr könnt mir Helfen.

    [verschoben nach Hilfe & Unterstützung]

  • Hi,

    nach meinem rumgooglen bis jetz, bin ich nur auf so Sachen gestoßen wie "mehrere Funktionen gleichzeitig nicht möglich" und "AutoIt ist prozedurale Programmierun".

    Glaube sowas auch schonmal probiert zu haben, endete dann damit, dass ich mehrere *.exe kompiliert hatte.

    Kein Plan, obs mittlerweile geht, ich denke eher nicht :)

    Gruß,
    x0r

    Simon nörgelt, Simon nervt - aber Simon verbessert die Welt. Glaubt er.

  • Wüsste nicht warum man hierzu mehrere exen kompilieren muss und was das mit prozeduraler Programmierung zu tun hat.

    Im Prenzip ist das alles ganzeinfach. Man braucht nur ein MessageLoopModus und eine While Schleife, einpaar Variablen und einige If Abfragen :)

    Aus meiner Sicht ist da realisierbar.


    Seh ich auch so. Wird vielleicht nicht so Ressourcensparend wie eine Programmiersprache die für Hyperthreading etc. gedacht ist, aber als alternative würde mir eine Variante mit AdlibRegister noch einfallen. Damit habe ich auch schon einiges realisiert bekommen wo ich zunächst dachte das wird mit AutoIt nichts.

    Grüße Yaerox

    Grüne Hölle

  • Gerne ;) Wenn ich mich nicht irre kannst du mehrere AdlibRegisters nebeneinander laufen lassen, ich würde halt vorher vll. mal testen ob die wirklich "parallel" laufen oder ob sich da was in die Quere kommt.

    Grüße Yaerox

    Grüne Hölle

    • Offizieller Beitrag

    Im Prenzip ist das alles ganzeinfach. Man braucht nur ein MessageLoopModus und eine While Schleife, einpaar Variablen und einige If Abfragen


    Nun, das ist eine seeehr optimistische Aussage. :D
    Kannst du vergessen, wenn du mit mehreren Countdown arbeiten willst, viel zu ungenau.
    Alles was mit Zeitintervallen zu tun hat, sollte man über Timer regeln. Damit bekommt man sauber mehrere Countdowns zum Laufen, die sich auch nicht in die Quere kommen.
    AdlibRegister ist schon parallel, aber wenn du mehrere Adlibs hast, können sich die Intervalle überschneiden und dann werden sie auch in der Reihenfolge ihres "Anklopfens" abgearbeitet.

  • Zitat

    Nun, das ist eine seeehr optimistische Aussage. :D
    Kannst du vergessen, wenn du mit mehreren Countdown arbeiten willst, viel zu ungenau.
    Alles was mit Zeitintervallen zu tun hat, sollte man über Timer regeln. Damit bekommt man sauber mehrere Countdowns zum Laufen, die sich auch nicht in die Quere kommen.
    AdlibRegister ist schon parallel, aber wenn du mehrere Adlibs hast, können sich die Intervalle überschneiden und dann werden sie auch in der Reihenfolge ihres "Anklopfens" abgearbeitet.

    Ok hier hast du recht. Aber wir bewegen uns dan im Millisekundenbereich, wenn ich jetzt keinen konkreten Denkfehler habe.

    • Offizieller Beitrag

    Aber wir bewegen uns dan im Millisekundenbereich


    Grundsätzlich ja. Wenn du in der Schleife aber noch andere Dinge betreibst kann das relevant werden. Soll der Counter nur im Sekundentakt generieren kommt es selbst auf 2..3 Zehntel nicht an. Verwendest du ihn aber z.b. für eine Stoppuhr sind Timer das einzig Brauchbare.
    Aber auch bei 10 Countern, die parallel laufen, kannst du schnell pro Abarbeiten jedes Counters 1 Zehntel verbraten. Dann hast du schnell mal einen Sekundensprung drin, was einfach doof aussieht. ;)

    • Offizieller Beitrag

    Ich wollte doch mal sehen, wie man sowas programmieren kann und habe mal ein Script erstellt:

    Spoiler anzeigen
    [autoit]


    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>

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

    Opt('GUIOnEventMode', 1)

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

    Global Const $UDM_SETACCEL = 1131
    Global Const $UDM_SETRANGE32 = 1135
    Global $UDACCEL = DllStructCreate("UINT nSec; UINT nInc")
    Global $pUDACCEL = DllStructGetPtr($UDACCEL)
    DllStructSetData($UDACCEL, "nSec", 0)
    DllStructSetData($UDACCEL, "nInc", 15) ; Sprungweite 15 Minuten

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

    Global $iAdlibTicks = 20 ; ms für den AdlibRegister-Aufruf
    Global $iTimerCount = 10 ; Anzahl der Timer
    Global $aidTimerDisplay[$iTimerCount], $aidUpDownButton[$iTimerCount]
    Global $aidLED[$iTimerCount], $aidStartButton[$iTimerCount]
    Global $aTimer[$iTimerCount], $aTimerStart[$iTimerCount]

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

    Global $hGui = GUICreate($iTimerCount & ' Timer', 660, Int($iTimerCount / 5) * 140 + 50)
    GUISetOnEvent($GUI_EVENT_CLOSE, '_CloseGui')
    For $i = 0 To $iTimerCount - 1
    $aTimerStart[$i] = 15 ; TimerStart auf 15 Minuten vorbelegen
    GUICtrlCreateLabel(StringFormat('Timer %02i', $i+1), 10 + Mod($i, 5) * 130, 20 + Int($i/5) * 140, 100, 32, $SS_CENTER)
    GUICtrlSetFont(-1, 12, 400, 0, 'Tahoma')
    $aidTimerDisplay[$i] = GUICtrlCreateInput('15:00.000', 10 + Mod($i, 5) * 130, 50 + Int($i/5) * 140, 116, 32, $ES_READONLY)
    GUICtrlSetOnEvent(-1, '_ChangeTime')
    GUICtrlSetFont(-1, 14, 400, 0, 'Tahoma')
    GUICtrlSetBkColor(-1, 0xFFFFFF)
    $aidUpDownButton[$i] = GUICtrlCreateUpdown(-1)
    GUICtrlSendMsg(-1, $UDM_SETRANGE32, 15, 45) ; Wertebereich 15 - 45 Minuten
    GUICtrlSendMsg(-1, $UDM_SETACCEL, 1, $pUDACCEL)
    $aidLED[$i] = GUICtrlCreateLabel('', 10 + Mod($i, 5) * 130, 91 + Int($i/5) * 140, 16, 16, Default, $WS_EX_CLIENTEDGE)
    GUICtrlSetBkColor(-1, 0xFF0000)
    $aidStartButton[$i] = GUICtrlCreateButton('Start', 28 + Mod($i, 5) * 130, 88 + Int($i/5) * 140, 98, 22)
    GUICtrlSetOnEvent(-1, '_StartTimer')
    Next
    GUICtrlCreateButton('Alle starten', 140, Int($iTimerCount / 5) * 140, 116, 30)
    GUICtrlSetOnEvent(-1, '_StartAll')
    GUICtrlCreateButton('Alle stoppen', 400, Int($iTimerCount / 5) * 140, 116, 30)
    GUICtrlSetOnEvent(-1, '_StopAll')
    GUISetState()
    AdlibRegister('_Timer', $iAdlibTicks)
    WinWaitClose($hGui)
    Exit

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

    Func _CloseGui()
    AdlibUnRegister('_Timer')
    GUIDelete($hGui)
    EndFunc

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

    Func _Timer()
    Local $iTicks
    For $i = 0 To $iTimerCount - 1
    If BitAND(GUICtrlGetState($aidUpDownButton[$i]), $GUI_DISABLE) Then
    $iTicks = $aTimerStart[$i] * 60000 - TimerDiff($aTimer[$i])
    GUICtrlSetData($aidTimerDisplay[$i], _MyTicksToTime($iTicks))
    EndIf
    Next
    EndFunc

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

    Func _MyTicksToTime($iTicks)
    Local $sOut = ''
    $sOut = StringRight('0' & Int($iTicks / 60000), 2)
    $iTicks = Mod($iTicks, 60000)
    $sOut &= ':' & StringRight('0' & Int($iTicks / 1000), 2)
    $iTicks = Mod($iTicks, 1000)
    Return $sOut & '.' & StringRight('00' & $iTicks, 3)
    EndFunc

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

    Func _ChangeTime()
    Local $iCount = (@GUI_CtrlId - $aidTimerDisplay[0]) / 5
    $aTimerStart[$iCount] = GUICtrlRead(@GUI_CtrlId)
    GUICtrlSetData(@GUI_CtrlId, $aTimerStart[$iCount] & ':00.000')
    GUICtrlSetState($aidStartButton[$iCount], $GUI_FOCUS)
    EndFunc

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

    Func _StartAll()
    For $i = 0 To $iTimerCount - 1
    GUICtrlSetOnEvent($aidStartButton[$i], '_StopTimer')
    GUICtrlSetData($aidStartButton[$i], 'Stop')
    GUICtrlSetState($aidUpDownButton[$i], $GUI_DISABLE)
    GUICtrlSetBkColor($aidLED[$i], 0x00FF00)
    $aTimer[$i] = TimerInit()
    Next
    EndFunc

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

    Func _StopAll()
    For $i = 0 To $iTimerCount - 1
    GUICtrlSetOnEvent($aidStartButton[$i], '_StartTimer')
    GUICtrlSetData($aidStartButton[$i], 'Start')
    GUICtrlSetState($aidUpDownButton[$i], $GUI_ENABLE)
    GUICtrlSetBkColor($aidLED[$i], 0xFF0000)
    Next
    EndFunc

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

    Func _StartTimer()
    Local $iCount = (@GUI_CtrlId - $aidStartbutton[0]) / 5
    GUICtrlSetOnEvent(@GUI_CtrlId, '_StopTimer')
    GUICtrlSetData(@GUI_CtrlId, 'Stop')
    GUICtrlSetState($aidUpDownButton[$iCount], $GUI_DISABLE)
    GUICtrlSetBkColor($aidLED[$iCount], 0x00FF00)
    $aTimer[$iCount] = TimerInit()
    EndFunc

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

    Func _StopTimer()
    Local $iCount = (@GUI_CtrlId - $aidStartbutton[0]) / 5
    GUICtrlSetOnEvent(@GUI_CtrlId, '_StartTimer')
    GUICtrlSetData(@GUI_CtrlId, 'Start')
    GUICtrlSetState($aidUpDownButton[$iCount], $GUI_ENABLE)
    GUICtrlSetBkColor($aidLED[$iCount], 0xFF0000)
    EndFunc

    [/autoit]

    Beim Start aller Timer laufen diese relativ synchron. Lediglich die Millisekunden weichen voneinander ab (beim Stoppen aller Timer). Wobei die Abweichung nicht linear in der Reihenfolge der Timer ist, was ich etwas merkwürdig finde. Vielleicht hat dazu mal jemand eine Erklärung parat?

    • Offizieller Beitrag

    Wobei die Abweichung nicht linear in der Reihenfolge der Timer ist, was ich etwas merkwürdig finde. Vielleicht hat dazu mal jemand eine Erklärung parat?


    Da muss ich auch raten. Meine Vermutung ist, dass Timer sich überlagern. Scheinbar werden sie dann nicht, wie ich eigentlich annahm, in einen Queue geschoben, sondern verfallen und werden erst beim nächsten Aufruf bearbeitet. Möglicherweise eine Art Lease-Time innerhalb der ein Adlibaufruf nach Ablauf des Intervalls bearbeitet werden muss.
    Aber das ist alles nur Fischen im Trüben. :whistling:

    • Offizieller Beitrag

    Argh! Nein! Mir ist ein Denkfehler unterlaufen. Meine Funktion "_MyTicksToTime" braucht unterschiedlich lange (je nach Anzahl der Ticks). Da ich den TimerDiff innerhalb der Schleife auslese, fällt die Ausführungszeit der Funktion da mit rein.
    Ich habe das ganze Script jetzt mal auf nur einen Timer reduziert und den Einfluß der Funktion ausgeschaltet. Wenn man dann noch den AdlibRegister-Aufruf auf 10 ms verkürzt, laufen alle Timer völlig synchron. Bei mir selbst mit 20 Timern. :)

    Spoiler anzeigen
    [autoit]


    #include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>

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

    Opt('GUIOnEventMode', 1)

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

    Global Const $UDM_SETACCEL = 1131
    Global Const $UDM_SETRANGE32 = 1135
    Global $UDACCEL = DllStructCreate("UINT nSec; UINT nInc")
    Global $pUDACCEL = DllStructGetPtr($UDACCEL)
    DllStructSetData($UDACCEL, "nSec", 0)
    DllStructSetData($UDACCEL, "nInc", 15) ; Sprungweite 15 Minuten

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

    Global $iAdlibTicks = 10 ; ms für den AdlibRegister-Aufruf
    Global $iTimerCount = 20 ; Anzahl der Timer
    Global $aidTimerDisplay[$iTimerCount], $aidUpDownButton[$iTimerCount]
    Global $aidLED[$iTimerCount], $aidStartButton[$iTimerCount]
    Global $aTimer[$iTimerCount], $aTimerStart[$iTimerCount]
    Global $iProgTimer = TimerInit()

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

    Global $hGui = GUICreate($iTimerCount & ' Timer', 660, Int($iTimerCount / 5) * 140 + 50)
    GUISetOnEvent($GUI_EVENT_CLOSE, '_CloseGui')
    For $i = 0 To $iTimerCount - 1
    $aTimerStart[$i] = 15 ; TimerStart auf 15 Minuten vorbelegen
    GUICtrlCreateLabel(StringFormat('Timer %02i', $i+1), 10 + Mod($i, 5) * 130, 20 + Int($i/5) * 140, 100, 32, $SS_CENTER)
    GUICtrlSetFont(-1, 12, 400, 0, 'Tahoma')
    $aidTimerDisplay[$i] = GUICtrlCreateInput('15:00.000', 10 + Mod($i, 5) * 130, 50 + Int($i/5) * 140, 116, 32, $ES_READONLY)
    GUICtrlSetOnEvent(-1, '_ChangeTime')
    GUICtrlSetFont(-1, 14, 400, 0, 'Tahoma')
    GUICtrlSetBkColor(-1, 0xFFFFFF)
    $aidUpDownButton[$i] = GUICtrlCreateUpdown(-1)
    GUICtrlSendMsg(-1, $UDM_SETRANGE32, 15, 45) ; Wertebereich 15 - 45 Minuten
    GUICtrlSendMsg(-1, $UDM_SETACCEL, 1, $pUDACCEL)
    $aidLED[$i] = GUICtrlCreateLabel('', 10 + Mod($i, 5) * 130, 91 + Int($i/5) * 140, 16, 16, Default, $WS_EX_CLIENTEDGE)
    GUICtrlSetBkColor(-1, 0xFF0000)
    $aidStartButton[$i] = GUICtrlCreateButton('Start', 28 + Mod($i, 5) * 130, 88 + Int($i/5) * 140, 98, 22)
    GUICtrlSetOnEvent(-1, '_StartTimer')
    Next
    GUICtrlCreateButton('Alle starten', 140, Int($iTimerCount / 5) * 140, 116, 30)
    GUICtrlSetOnEvent(-1, '_StartAll')
    GUICtrlCreateButton('Alle stoppen', 400, Int($iTimerCount / 5) * 140, 116, 30)
    GUICtrlSetOnEvent(-1, '_StopAll')
    GUISetState()
    AdlibRegister('_Timer', $iAdlibTicks)
    WinWaitClose($hGui)
    Exit

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

    Func _CloseGui()
    AdlibUnRegister('_Timer')
    GUIDelete($hGui)
    EndFunc

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

    Func _Timer()
    Local $aTicks[$iTimerCount], $iTicks = TimerDiff($iProgTimer)
    For $i = 0 To $iTimerCount - 1
    $aTicks[$i] = ($iTicks - $aTimer[$i])
    Next
    For $i = 0 To $iTimerCount - 1
    If BitAND(GUICtrlGetState($aidUpDownButton[$i]), $GUI_DISABLE) Then
    $iTicks = $aTimerStart[$i] * 60000 - $aTicks[$i]
    GUICtrlSetData($aidTimerDisplay[$i], _MyTicksToTime($iTicks))
    EndIf
    Next
    EndFunc

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

    Func _MyTicksToTime($iTicks)
    Local $sOut = ''
    $sOut = StringRight('0' & Int($iTicks / 60000), 2)
    $iTicks = Mod($iTicks, 60000)
    $sOut &= ':' & StringRight('0' & Int($iTicks / 1000), 2)
    $iTicks = Mod($iTicks, 1000)
    Return $sOut & '.' & StringRight('00' & $iTicks, 3)
    EndFunc

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

    Func _ChangeTime()
    Local $iCount = (@GUI_CtrlId - $aidTimerDisplay[0]) / 5
    $aTimerStart[$iCount] = GUICtrlRead(@GUI_CtrlId)
    GUICtrlSetData(@GUI_CtrlId, $aTimerStart[$iCount] & ':00.000')
    GUICtrlSetState($aidStartButton[$iCount], $GUI_FOCUS)
    EndFunc

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

    Func _StartAll()
    Local $iTimerDiff = TimerDiff($iProgTimer)
    For $i = 0 To $iTimerCount - 1
    GUICtrlSetOnEvent($aidStartButton[$i], '_StopTimer')
    GUICtrlSetData($aidStartButton[$i], 'Stop')
    GUICtrlSetState($aidUpDownButton[$i], $GUI_DISABLE)
    GUICtrlSetBkColor($aidLED[$i], 0x00FF00)
    $aTimer[$i] = $iTimerDiff
    Next
    EndFunc

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

    Func _StopAll()
    For $i = 0 To $iTimerCount - 1
    GUICtrlSetOnEvent($aidStartButton[$i], '_StartTimer')
    GUICtrlSetData($aidStartButton[$i], 'Start')
    GUICtrlSetState($aidUpDownButton[$i], $GUI_ENABLE)
    GUICtrlSetBkColor($aidLED[$i], 0xFF0000)
    Next
    EndFunc

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

    Func _StartTimer()
    Local $iCount = (@GUI_CtrlId - $aidStartbutton[0]) / 5
    GUICtrlSetOnEvent(@GUI_CtrlId, '_StopTimer')
    GUICtrlSetData(@GUI_CtrlId, 'Stop')
    GUICtrlSetState($aidUpDownButton[$iCount], $GUI_DISABLE)
    GUICtrlSetBkColor($aidLED[$iCount], 0x00FF00)
    $aTimer[$iCount] = TimerDiff($iProgTimer)
    EndFunc

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

    Func _StopTimer()
    Local $iCount = (@GUI_CtrlId - $aidStartbutton[0]) / 5
    GUICtrlSetOnEvent(@GUI_CtrlId, '_StartTimer')
    GUICtrlSetData(@GUI_CtrlId, 'Start')
    GUICtrlSetState($aidUpDownButton[$iCount], $GUI_ENABLE)
    GUICtrlSetBkColor($aidLED[$iCount], 0xFF0000)
    EndFunc

    [/autoit]
  • Hallo Oscar!
    Dein Script zeigt perfekt, dass es nur eine "Zeit" und somit nur einen "Timer" gibt :thumbup:
    Wer auf das schmale Brett mit Hyperthreading bzw. Multithreading (-tasking) kommt, sollte sich mal fragen, wie diese Technik überhaupt funktioniert....nämlich mit genau EINEM Timer!

    Aber einen winzig kleinen Verbesserungsvorschlag hätte ich noch^^

    [autoit]

    Func _StopAll()
    _Timer() ;synchronisiert die Uhren im 10ms-Bereich
    For $i = 0 To $iTimerCount - 1

    [/autoit]


    Ohne die Synchronisierung kommt es vor, dass der Stop-event mitten in der For/To-Schleife innerhalb der Timer()-Funktion unterbricht und somit die Uhren zwei unterschiedliche Zeiten anzeigen. Bis zur Unterbrechung bereits die "neue" Zeit, und ab der Unterbrechung noch die "alte" Zeit.

  • Hi,

    Zitat

    Es gibt eine UDF bei der man Threads erstellen kann die AutoIt Funktionen ausführen!

    Die aber nicht funktioniert, da keine der Standard-Funktionen und somit auch kaum ein AutoIt-Script threadsicher ist.
    Um threadsichere Funktionen zu gewährleisten und in mehreren Threads in AutoIt zu benutzen würde ich diese Funktionen in einer anderen (threadsicheren) Hochsprache erstellen und bspw. per DLL einbinden.
    Multithreading per Inline Asm oder C ist ziemlich easy, Beispiele habe ich hier im Forum schon gepostet.

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (27. Oktober 2013 um 23:01)