Jump to content

A Time_Picker UDF?


Recommended Posts

Maybe I'm recreating the wheel, but a forum search found no such critter...

My users find modifying the time portion of the DTP control a pain in the rear.

The date portion is cake, what with the calendar pop-up, but one has to alternate between highlighting sections of the time portion of the DTP with the mouse, then switch to the keyboard, repeat, repeat.

So, I thought I'd make a stab at something I could plug easily into some of my scripts to simplify time entry.

I'll post what I've thrown together, and then list off some gripes about it's shortcomings afterwards...

(This does also allow for a user-defined time interval for incrementing/decrementing the minutes of the control, as we only schedule appointments on the quarter-hour).

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

GUICreate("", 340, 160)
$read_button = GUICtrlCreateButton("Read Second TP", 55, 120, 100, 20)
$kill_button = GUICtrlCreateButton("Kill Third TP", 215, 120, 100, 20)
GUISetState()

; TIME_PICKER PARAMETERS
; INIT, instance, hpos, vpos, interval, HH, MM, AM/PM
; UPDT, instance
; READ, instance
; KILL, instance

Global $TP_Count = 3, $TP_Event[$TP_Count], $TP_Input[$TP_Count][3], $TP_Array[$TP_Count][3], $TP_AM_PM[$TP_Count], $TP_Interval[$TP_Count][3]
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
Time_Picker("INIT", 0, 10, 30, 1, 12, 30, 1)
Time_Picker("INIT", 1, 30, 60, 5, 8, 30, 0)
Time_Picker("INIT", 2, 90, 90, 15, 5, 45, 1)

While 1
    Switch GUIGetMsg()
        Case $read_button
            MsgBox(1,"", Time_Picker("READ", 1))
        Case $kill_button
            Time_Picker("KILL", 2)
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
    For $x = 0 to $TP_Count - 1
        If $TP_Event[$x] Then Time_Picker("UPDT", $x)
    Next
WEnd

;-------------------------------------------------------------------------------
Func Time_Picker($command, $instance, $hpos = 0, $vpos = 0, $interval = 1, $hours = 8, $minutes = 0, $am_pm = 0)
    Local $AM_PM_Array[2] = ["AM", "PM"]
    Switch $command
        Case "INIT"
            $TP_Interval[$instance][1] = 1 ; hours
            $TP_Interval[$instance][2] = $interval ; minutes
            $TP_Array[$instance][1] = $hours
            $TP_Array[$instance][2] = $minutes
            $TP_AM_PM[$instance] = $am_pm
            GUICtrlCreateLabel("", $hpos, $vpos, 60, 20)
            GUICtrlSetBkColor( -1, 0x7F9FAF)
            GUICtrlSetState(-1, $GUI_DISABLE)
            GUICtrlCreateLabel("", $hpos + 1, $vpos + 1, 58, 3)
            GUICtrlSetBkColor( -1, 0xFFFFFF)
            GUICtrlSetState(-1, $GUI_DISABLE)
            $TP_Input[$instance][0] = GUICtrlCreateInput($hours, $hpos + 1, $vpos + 4, 16, 15, $ES_READONLY + $ES_RIGHT, 0)
            GUICtrlSetFont(-1, 8.5, 400, 0, "MS Sans Serif")
            GUICtrlSetBkColor( -1, 0xFFFFFF)
            $TP_Input[$instance][1] = GUICtrlCreateInput($minutes, $hpos + 21, $vpos + 4, 19, 15, $ES_READONLY, 0)
            GUICtrlSetFont(-1, 8.5, 400, 0, "MS Sans Serif")
            GUICtrlSetBkColor( -1, 0xFFFFFF)
            $TP_Input[$instance][2] = GUICtrlCreateInput($AM_PM_Array[$am_pm], $hpos + 40, $vpos + 4, 19, 15, $ES_READONLY, 0)
            GUICtrlSetFont(-1, 8.5, 400, 0, "MS Sans Serif")
            GUICtrlSetBkColor( -1, 0xFFFFFF)
            GUICtrlCreateLabel(":", $hpos + 17, $vpos + 4, 4, 15)
            GUICtrlSetFont(-1, 7, 600, 0, "MS Sans Serif")
            GUICtrlSetBkColor( -1, 0xFFFFFF)
            GUICtrlSetState(-1, $GUI_DISABLE)
        Case "UPDT"
            _GUICtrlEdit_SetSel($TP_Input[$instance][$TP_Event[$instance] - 1], 0, -1)
        Case "READ"
            Return GUICtrlRead($TP_Input[$instance][0]) & ":" & GUICtrlRead($TP_Input[$instance][1]) & " " & GUICtrlRead($TP_Input[$instance][2])
        Case "KILL"
            $x = $TP_Input[$instance][0] - 2
            For $y = 0 to 5
                GUICtrlDelete($y + $x)
            Next
    EndSwitch
EndFunc


;-------------------------------------------------------------------------------
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    $nNotifyCode    = BitShift($wParam, 16)       ;HiWord
    $nID            = BitAnd($wParam, 0x0000FFFF) ;LoWord
    For $x = 0 to $TP_Count - 1
        Switch $nID
            Case $TP_Input[$x][0] to $TP_Input[$x][2]
                Switch $nNotifyCode
                    Case 256    ; gain focus
                        GUIRegisterMsg($WM_MOUSEWHEEL, "_TP_WM_MOUSEWHEEL")
                        $TP_Event[$x] = $nID - $TP_Input[$x][0] + 1 ; Active control: 1 = HH, 2 = MM, 3 = AM/PM
                    Case 512    ; lose focus
                        GUIRegisterMsg($WM_MOUSEWHEEL, "")
                        $TP_Event[$x] = 0
                EndSwitch
        EndSwitch
    Next
    Return $GUI_RUNDEFMSG
EndFunc

Func _TP_WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)
    Local $TP_Array_limit[3] = [0, 12, 59], $AM_PM_Array[2] = ["AM", "PM"], $instance
    For $x = 0 to $TP_Count - 1
        If $TP_Event[$x] then $instance = $x
    Next
    If $TP_Event[$instance] = 3 Then
        $TP_AM_PM[$instance] = Not $TP_AM_PM[$instance]
    Else
        $x = $TP_Event[$instance]
        If _WinAPI_HiWord($wParam) > 0 Then
            While 1 ; wheel up - subtract time
                If $x = 1 And $TP_Array[$instance][$x] = $TP_Array_limit[$x] Then $TP_AM_PM[$instance] = Not $TP_AM_PM[$instance]
                $TP_Array[$instance][$x] -= $TP_Interval[$instance][$x]
                If $TP_Array[$instance][$x] < Abs($x - 2) Then
                    $TP_Array[$instance][$x] = $TP_Array_limit[$x] - $TP_Interval[$instance][$x] + 1
                    If $x = 2 then ; force hour change
                        $x = 1
                        ContinueLoop
                    EndIf
                EndIf
                ExitLoop
            WEnd
        Else
            While 1 ; wheel down - add time
                $TP_Array[$instance][$x] += $TP_Interval[$instance][$x]
                If $TP_Array[$instance][$x] > $TP_Array_limit[$x] Then
                    $TP_Array[$instance][$x] = Abs($x - 2)
                    If $x = 2 then ; force hour change
                        $x = 1
                        ContinueLoop
                    EndIf
                EndIf
                ExitLoop
            WEnd
            If $x = 1 And $TP_Array[$instance][$x] = $TP_Array_limit[$x] Then $TP_AM_PM[$instance] = Not $TP_AM_PM[$instance]
        EndIf
    EndIf
    GUICtrlSetData($TP_Input[$instance][0], $TP_Array[$instance][1])
    GUICtrlSetData($TP_Input[$instance][1], StringFormat('%02s', $TP_Array[$instance][2]))
    GUICtrlSetData($TP_Input[$instance][2], $AM_PM_Array[$TP_AM_PM[$instance]])
    Return 0
EndFunc

Like I said, this is rough and unpolished, just my first version, but I see some problems that wouldn't stop me from incorporating it into scripts, but that do make it more cumbersome to do so.

1. If there was an alternate function, or a low-level DLL call, that could force the equivalent of a _GUICtrlEdit_SetSel() and would execute properly inside of the WM_COMMAND function, then I wouldn't need to set a flag and insert code into the main GUIReadMsg() loop to reselect the active control (no, I don't want to switch to OnEvent mode). A work-around for this would let me trash the manual "UPDT" function I've added.

2. I'm not too thrilled about having to add a couple lines of Globals to the top of any script I stick this into, but I'm reluctant to go the IsDeclared() route and put the Globals in the called function itself (it would feel like "bad form").

3. The big pain, is having to massage the WM_COMMAND portion for the TIME_PICKER controls into existing WM_COMMAND functions that are already servicing other controls. It's not hard to do, but it makes this function far from "drop-in".

OK, someone point me to the slick version of this that is already out there :mellow:

Edit: Oops! Guess I ought to have mentioned, this is all driven off the mouse wheel, but then *everyone* has a wheel mouse I would think...

typos

Edited by Spiff59
Link to comment
Share on other sites

A different approach...

Just adding mouse wheel support to the existing DTP.

Has a much smaller "footprint" than the prior attempt, but doesn't allow for an an adjustable time interval:

#include <GuiDateTimePicker.au3>
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
Global $DTP_Flag

$hGUI = GUICreate("DTP with mouse wheel support", 300, 100)
$hDTP = _GUICtrlDTP_Create($hGUI, 50, 40, 190)
_GUICtrlDTP_SetFormat($hDTP, "ddd MMM dd, yyyy hh:mm ttt")
GUISetState()


GUIRegisterMsg($WM_SETCURSOR, "WM_SETCURSOR")

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

;-------------------------------------------------------------------------------
Func WM_SETCURSOR($hWnd, $iMsg, $iWParam, $iLParam) ; set flag if within DTP control
    If $iWParam = $hDTP Then
        If $DTP_Flag = 0 Then
            GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL") ; enable when entering DTP control
        EndIf
        $DTP_Flag = 1
    Else
        If $DTP_Flag = 1 Then
            GUIRegisterMsg($WM_MOUSEWHEEL, "") ; disable when exiting
        EndIf
        $DTP_Flag = 0
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_MOUSEWHEEL($hWnd, $iMsg, $iwParam, $ilParam)
    If $DTP_Flag Then
        If _WinAPI_HiWord($iwParam) > 0 Then ; mouse wheel up
            Send("{DOWN}")
        Else                                ; mouse wheel down
            Send("{UP}")
        EndIf
    EndIf
    Return 0
EndFunc
Edited by Spiff59
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...