"Gadget(s)" für Zeiteingabe gesucht

Für allgemeine Fragen zur Programmierung mit PureBasic.
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Omi »

Hello mestnyi,
I didn't fully understand the questions (neither of us are native English speakers) but I'll try to summarize it briefly: (and since I am still lazy today, I try DeepL as translator :wink: )

I recently noticed that there is no gadget for pure time entry in PureBasic.
The DateGadget can be configured on Windows at least for time input (but without seconds). Linux doesn't offer any possibility at all (anymore) and for Mac I don't know.
For Windows and Linux (and maybe Mac) I posted above an evident possibility with 3 SpinGadgets which wastes a lot of space. Also a monitored StringGadget (with error messages on invalid inputs) would be possible.

Most elegant would be to find a counterpart to the PureBasic DateGadget for a formatted time entry (e.g. for daily, periodic actions), at least for Linux and Windows, ideally for all OS.
See the Windows API Control (TimePicker?): http://www.chabba.de/temp/Windows_TimeControl.jpg
For Linux I'm currently trying to achieve a controlled input in a StringGadget - still without up/down arrows.
Under Window there is probably a way to achieve similar a control with DATETIMEPICK_CLASS (but I'm afraid I'm too 'out of window-practice' for that) and on Mac I absolutely don't know how to do.

It's not something that's badly needed, but it would be a nice to have.

Regards, Charly
PureBasic Linux-API-Library: http://www.chabba.de
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Shardik »

Ich bin einen anderen Weg zu einem Zeiteingabe-Gadget gegangen. Ich habe verstanden, dass Charly ein Windows-ähnliches Zeiteingabe-Gadget ("TimePicker") gesucht hat, und er hat ja auch bereits sein eindrucksvolles '3½-Tonner-SUV zum-Brötchen-holen'-Modell für Linux vorgestellt. Allerdings finde ich den Windows TimePicker für Linux- und Mac-Anwender, die nicht von Windows kommen, nicht besonders intuitiv. Und für Multiplattform-Programmierung bin ich eher für das KISS-Prinzip (Keep It Simple Stupid) und habe mich daher bewusst für die von Charly eigentliche verworfene Verwendung von SpinButtons entschieden, nachdem ich diesen Zeit- und Datums-Einstellungsdialog von Gnome gesehen habe:

Bild

Dies ist mit dem von PureBasic angebotenen und auf einem speziell modifizierten GTKBox-Gadget (mit jeweils einer GTKEventBox und GTKArrow für die Schaltflächen nach oben und nach unten) beruhenden SpinGadget nicht möglich. Daher war mein erster Versuch die Verwendung des GTK-Gadgets GtkSpinButton:

Code: Alles auswählen

EnableExplicit

ImportC ""
  gtk_entry_set_text(*Entry.GtkEntry, Text.P-UTF8)
  gtk_orientable_set_orientation(*Orientable, Orientation.I)
  gtk_spin_button_new_with_range(Minimum.D, Maximum.D, StepIncrement.D)
EndImport

Define Layout.I
Define SpinButtonHour.I
Define SpinButtonMinute.I
Define TimeInfo.S

ProcedureC OutputCallback(*SpinButton.GtkSpinButton, UserData.I)
  Static LastValue.I

  Shared SpinButtonHour.I
  Shared TimeInfo.S

  Protected TimePart.S
  Protected Value.I

  Value = gtk_spin_button_get_value_as_int_(*SpinButton)

  If Value <> LastValue Or LastValue = 0
    TimePart = RSet(Str(Value), 2, "0")
    gtk_entry_set_text(*SpinButton\entry, TimePart)

    If *SpinButton = SpinButtonHour
      TimeInfo = TimePart + ":" + Right(TimeInfo, 2)
    Else
      TimeInfo = Left(TimeInfo, 3) + TimePart
    EndIf

    StatusBarText(0, 0, TimeInfo, #PB_StatusBar_Center)
  EndIf

  LastValue = Value

  ProcedureReturn #True
EndProcedure

TimeInfo = "00:00"
OpenWindow(0, 200, 100, 150, 120, "Time picker")
CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)
StatusBarText(0, 0, TimeInfo, #PB_StatusBar_Center)

Layout = g_list_nth_data_(gtk_container_get_children_(gtk_bin_get_child_(0 +
  WindowID(0))), 0)

SpinButtonHour = gtk_spin_button_new_with_range(0, 23, 1)
gtk_orientable_set_orientation(SpinButtonHour, #GTK_ORIENTATION_VERTICAL)
gtk_spin_button_set_wrap_(SpinButtonHour, #True)
gtk_layout_put_(Layout, SpinButtonHour, 30, 15)
g_signal_connect_(SpinButtonHour, "output", @OutputCallback(), 0)
OutputCallback(SpinButtonHour, 0)

SpinButtonMinute = gtk_spin_button_new_with_range(0, 59, 1)
gtk_orientable_set_orientation(SpinButtonMinute, #GTK_ORIENTATION_VERTICAL)
gtk_spin_button_set_wrap_(SpinButtonMinute, #True)
gtk_layout_put_(Layout, SpinButtonMinute, 81, 15)
g_signal_connect_(SpinButtonMinute, "output", @OutputCallback(), 0)
OutputCallback(SpinButtonMinute, 0)

LoadFont(0, "CourierNew", 14, #PB_Font_Bold)
TextGadget(0, 70, 39, 10, 20, ":")
SetGadgetFont(0, FontID(0))

gtk_widget_show_all_(WindowID(0))

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
  EndSelect
ForEver
Das sieht dann schon so ähnlich aus wie die Zeiteingabe im obigen Gnome-Dialog. Aber durch die verwendeten API-Befehle ist es ungünstig für die Verwendung in Multiplattform-geeigneten Programmen. Dann bin ich auf die Idee gekommen, statt SpinGadgets einfach ButtonGadgets zu verwenden. Und herausgekommen ist ein Ergebnis, das auf Linux, MacOS und Windows ziemlich ähnlich aussieht und sehr einfach aufgebaut ist. Der einzige verwendete API-Befehl zwingt MacOS dazu, die ButtonGadgets nicht standardmäßig mit abgerundeten Ecken anzuzeigen, sondern mit eckigen, sodass ein einheitliches Erscheinungsbild auf allen drei Plattformen gewährleistet ist. Erfolgreich getestet habe ich das letzte Beispiel auf diesen Betriebssystemen:
- Linux Mint 18.3 x64 Cinnamon mit PB 5.62 x64
- MacOS 10.6.8 (Snow Leopard) mit PB 5.62 x86
- Windows XP SP3 mit PB 5.62 x86
- Windows 7 SP1 x64 mit PB 5.62 x86
- Windows 10 x64 mit PB 5.62 x86

Linux Mint 18.3 mit Cinnamon:
Bild

MacOS 10.6.8:
Bild

Windows 7:
Bild

Code: Alles auswählen

EnableExplicit

#xOffset = 80

Structure IDEntries
  IDButtonDown.I
  IDButtonUp.I
  IDText.I
  MaxValue.I
EndStructure

Define Position.I
Define SelectedGadget.I
Define Text.S
Define TimeInfo.S
Define UpDownDetected.I
Define Value.I

NewList TimePicker.IDEntries()

Procedure CreateTimePicker(List TimePicker.IDEntries(), x.I, y.I,
  DisplaySeconds.I = #False)
  Protected FontButton.I
  Protected FontName.S
  Protected FontSizeButton.I
  Protected FontSizeText.I  
  Protected FontText.I
  Protected IDDelimiter.I

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      FontName = "Courier"
      FontSizeButton = 12
      FontSizeText = 30
    CompilerCase #PB_OS_MacOS
      FontName = "Courier"
      FontSizeButton = 22
      FontSizeText = 34
    CompilerCase #PB_OS_Windows
      FontName = "Courier New"
      FontSizeButton = 12
      FontSizeText = 30
  CompilerEndSelect   

  FontButton = LoadFont(#PB_Any, FontName, FontSizeButton, #PB_Font_Bold)
  FontText = LoadFont(#PB_Any, FontName, FontSizeText, #PB_Font_Bold)

  AddElement(TimePicker())
  TimePicker()\MaxValue = 23

  TimePicker()\IDButtonUp = ButtonGadget(#PB_Any, x, y, 66, 28, "+")
  SetGadgetFont(TimePicker()\IDButtonUp, FontID(FontButton))

  TimePicker()\IDText = TextGadget(#PB_Any, x, y + 28, 66, 44, "00",
    #PB_Text_Border | #PB_Text_Center)
  SetGadgetFont(TimePicker()\IDText, FontID(FontText))

  TimePicker()\IDButtonDown = ButtonGadget(#PB_Any, x, y + 70, 66, 28, "-")
  SetGadgetFont(TimePicker()\IDButtonDown, FontID(FontButton))

  AddElement(TimePicker())
  TimePicker()\MaxValue = 59

  TimePicker()\IDButtonUp = ButtonGadget(#PB_Any, x + #xOffset, y, 66, 28, "+")
  SetGadgetFont(TimePicker()\IDButtonUp, FontID(FontButton))

  TimePicker()\IDText = TextGadget(#PB_Any, x + #xOffset, y + 28, 66, 44, "00",
    #PB_Text_Border | #PB_Text_Center)
  SetGadgetFont(TimePicker()\IDText, FontID(FontText))

  TimePicker()\IDButtonDown = ButtonGadget(#PB_Any, x + #xOffset, y + 70, 66,
    28, "-")
  SetGadgetFont(TimePicker()\IDButtonDown, FontID(FontButton))

  IDDelimiter = TextGadget(#PB_Any, x + #xOffset - 19, y + 27, 17, 35, ":")
  SetGadgetFont(IDDelimiter, FontID(FontText))

  If DisplaySeconds
    AddElement(TimePicker())
    TimePicker()\MaxValue = 59

    TimePicker()\IDButtonUp = ButtonGadget(#PB_Any, x + #xOffset * 2, y, 66,
      28, "+")
    SetGadgetFont(TimePicker()\IDButtonUp, FontID(FontButton))
    
    TimePicker()\IDText = TextGadget(#PB_Any, x + #xOffset * 2, y + 28, 66, 44,
      "00", #PB_Text_Border | #PB_Text_Center)
    SetGadgetFont(TimePicker()\IDText, FontID(FontText))
    
    TimePicker()\IDButtonDown = ButtonGadget(#PB_Any, x + #xOffset * 2, y + 70, 66,
      28, "-")
    SetGadgetFont(TimePicker()\IDButtonDown, FontID(FontButton))

    IDDelimiter = TextGadget(#PB_Any, x + #xOffset * 2 - 19, y + 27, 17, 35,
      ":")
    SetGadgetFont(IDDelimiter, FontID(FontText))
  EndIf

  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    ForEach TimePicker()
      CocoaMessage(0, GadgetID(TimePicker()\IDButtonDown),
        "setBezelStyle:", 10)
      CocoaMessage(0, GadgetID(TimePicker()\IDButtonUp),
        "setBezelStyle:", 10)
    Next
  CompilerEndIf
EndProcedure

OpenWindow(0, 270, 100, 270, 150, "Time picker")
CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)
CreateTimePicker(TimePicker(), 20, 20, #True)
TimeInfo = "00:00"

If ListSize(TimePicker()) = 3
  TimeInfo + ":00"
EndIf

StatusBarText(0, 0, TimeInfo, #PB_StatusBar_Center)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      SelectedGadget = EventGadget()

      ForEach TimePicker()
        Select SelectedGadget
          Case TimePicker()\IDButtonDown
            Value = Val(GetGadgetText(TimePicker()\IDText))
            Value - 1
            
            If Value = -1
              Value = TimePicker()\MaxValue
            EndIf

            UpDownDetected = #True
            Break
          Case TimePicker()\IDButtonUp
            Value = Val(GetGadgetText(TimePicker()\IDText))
            Value + 1
            
            If Value > TimePicker()\MaxValue
              Value = 0
            EndIf

            UpDownDetected = #True
            Break
        EndSelect
      Next 

      If UpDownDetected
        Text = RSet(Str(Value), 2, "0")
        SetGadgetText(TimePicker()\IDText, Text)
        Position = (ListIndex(TimePicker()) + 1) * 3 - 2
        TimeInfo = Left(TimeInfo, Position - 1) + Text +
          Mid(TimeInfo, Position + 2)
        StatusBarText(0, 0, TimeInfo, #PB_StatusBar_Center)
        UpDownDetected = #False
      EndIf
  EndSelect
ForEver
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Omi »

Verdammt, verdammt, verdammt! Ich hab doch gewusst, dass mir wieder jemand zuvorkommt!
Und shardik war so ruhig die letzten Tage :D

Sieht schon mal sehr gut als Lösung aus! Vor allem existiert jetzt mal eine übergreifende Umsetzung. Ich muss es später am Tag nochmal testen.
Zumindest jetzt schon mal Vielen Dank an Dich :allright: !

Heute Morgen bin ich am richtigen Bahngleis gestanden und kam mit der Windows-API-Version etwas in Fahrt (auch Dank einiger Postings in den Foren). Ich hab's grad so halbwegs fertiggestellt. Die Verheiratung mit der Linuxversion steht allerdings noch aus, ebenso eine evtl. Einbindung in den Fokuskreis (falls ich's hinkrieg :| ).

DateGadget, reine Windows-API-Version auf DateTimePicker-Basis, unverheiratet mit Linux und bisher erst mit Wine getestet (Test auf echten Systemen ist erbeten) ...

Code: Alles auswählen

; Module/File:     TimeGadget_WinAPI1.pb
; Function:        Gadget/API-control to edit time (no am/pm, Arrow-Buttons) - Windows
; Author:          Omi
; Date:            Dec. 29, 2018
; Version:         0.11
; Target Compiler: PureBasic 5.46/5.62/5.7
; Target OS:       Windows exclusive (not tested on real OS)
;--------------------------------------------------------------

EnableExplicit

; Object constants
#Win_Main   = 0

#StG2       = 1
#TxtG1      = 2
#TxtG2      = 3
#BtGset     = 4



Global.i gEvent, gEventGadget, gQuit
Global.i gTimeGadget
Global   gTime.systemtime
Global   DtControl.INITCOMMONCONTROLSEX\dwSize= SizeOf(INITCOMMONCONTROLSEX)

DtControl\dwICC = $100
InitCommonControlsEx_(@DtControl)

#MCN_SELCHANGE = -749
#MCN_SELECT    = -746

Procedure Callback_Window(hwnd, msg, wparam, lparam)
	Protected result = #PB_ProcessPureBasicEvents
	Protected *pnmh.NMHDR
	
	Select msg
			
		Case #WM_NOTIFY
			
			If hwnd = WindowID(#Win_Main)
				
				*pnmh = lparam
				
				If *pnmh\hwndFrom = gTimeGadget
					
					Select *pnmh\code
							
						Case #DTN_DATETIMECHANGE
							PostEvent(#PB_Event_Gadget, #Win_Main, gTimeGadget, #PB_EventType_Change)
							
					EndSelect
					
				EndIf
				
			EndIf
			
	EndSelect
	ProcedureReturn result
EndProcedure

Procedure Create_WinMain()
	OpenWindow(#Win_Main, 0, 0, 600, 170, "DateTime Pick w. API", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	TextGadget(#PB_Any,       5,  14, 130,  22, "Set time (h:m:s)")
	
	gTimeGadget=CreateWindowEx_(0, "SysDateTimePick32", "DateTime", #WS_CHILD | #WS_VISIBLE | #WS_BORDER | #DTS_UPDOWN, 140, 10, 80, 26, WindowID(#Win_Main), 0, GetModuleHandle_(0), 0)
	SendMessage_(gTimeGadget, #DTM_SETFORMATW, 0, @"HH:mm:ss"); Set the time format
	SetWindowCallback(@Callback_Window())
	
	StringGadget(#StG2,     400,  75, 195,  26, "Only for focus tests!")
	
	TextGadget(#PB_Any,       5, 110, 190,  22, "Time set:")
	TextGadget(#PB_Any,       5, 135, 190,  22, "Time value set (=seconds):")
	TextGadget(#TxtG1,      200, 110,  98,  22, "")
	TextGadget(#TxtG2,      200, 135,  98,  22, "")
	ButtonGadget(#BtGset,   400, 133, 195,  26, "Set time to 8:00:00")
EndProcedure


Create_WinMain()

Repeat
	gEvent= WaitWindowEvent()
	
	Select gEvent
			
		Case #PB_Event_CloseWindow
			gQuit= #True
			
		Case #PB_Event_Gadget
			gEventGadget= EventGadget()
			Select gEventGadget
					
				Case gTimeGadget;                                                      read time
					SendMessage_(gTimeGadget, #MCM_GETCURSEL, 0, @gTime)
					SetGadgetText(#TxtG1, RSet(Str(gtime\wHour), 2, "0") + ":" + RSet(Str(gtime\wMinute), 2, "0") + ":" + RSet(Str(gtime\wSecond), 2, "0"))
					SetGadgetText(#TxtG2, Str(ParseDate("%hh:%ii:%ss", RSet(Str(gtime\wHour), 2, "0") + ":" + RSet(Str(gtime\wMinute), 2, "0") + ":" + RSet(Str(gtime\wSecond), 2, "0"))))
					
				Case #BtGset;                                                          Set TimeGadget to 08:00:00
					SendMessage_(gTimeGadget, #MCM_GETCURSEL, 0, @gTime)
					gtime\wHour  = 8
					gtime\wMinute= 0
					gtime\wSecond= 0
					SendMessage_(gTimeGadget, #MCM_SETCURSEL, 0, @gTime)
					PostEvent(#PB_Event_Gadget, #Win_Main, gTimeGadget, #PB_EventType_Change)
					
			EndSelect
			
	EndSelect
Until gQuit
Gruß Charly

Codeupdate: 2018-12-29 20:40:00
Zuletzt geändert von Omi am 29.12.2018 21:40, insgesamt 1-mal geändert.
PureBasic Linux-API-Library: http://www.chabba.de
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Shardik »

Omi hat geschrieben:Verdammt, verdammt, verdammt! Ich hab doch gewusst, dass mir wieder jemand zuvorkommt!
Und shardik war so ruhig die letzten Tage :D
Ich bin Dir nicht zuvorgekommen, weil ich ja nicht die von Dir favorisierte Lösung à la Windows verfolgt habe... :wink:

Dein Windows-API Beispiel habe ich unter Windows 7 getestet und es funktioniert prima - bis auf einen kleinen Schönheitsfehler: Wenn Du auf "Set time to 8:00:00" klickst (ohne vorher die Zeit abgeändert zu haben), musst Du ein zweites Mal klicken, bis 8:00:00 angezeigt wird. Der Grund liegt darin, dass Du in dem Case-Zweig anscheinend als erstes ein

Code: Alles auswählen

SendMessage_(gTimeGadget, #MCM_GETCURSEL, 0, @gTime)
aufrufen musst, damit die SYSTEMTIME-Struktur korrekt gefüllt ist (sie enthält ja noch viele andere Einträge).

Kennst Du eigentlich auch die folgenden Programmbeispiele, die ebenfalls versuchen, den TimePicker nachzuprogrammieren?
- Netmaestro (http://www.purebasic.fr/english/viewtopic.php?t=23797)
- Foz (für Timer mit 4 Zeiteinheiten einschließlich Millisekunden ohne Windows API-Befehle: http://www.purebasic.fr/english/viewtop ... 84&start=9)
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Omi »

Ich bin Dir nicht zuvorgekommen, weil ich ja nicht die von Dir favorisierte Lösung à la Windows verfolgt habe...
Natürliche nicht - war die erste Schockstarre kurz vor'm Posten :wink: !

Mit dem Schönheitsfehler hast Du recht - ich hab den obigen, ersten Windows-API-Code berichtigt.

Deine OS-übergreifende SUV-Version funktioniert tadellos, unter Linux auch unter Gtk2.
Als Anzeige wäre noch ein StringGadget wünschenswert, um eine schnellere Direkteingabe zu ermöglichen.


Vielen Dank für die Links. Der Erste von Netmaestro hatte es (unbemerkt) in sich - und zwar der letzte Code-Einzeiler.
D.h. für Windows kann der TimePicker auch als DateGadget mit Flag angelegt werden. Der Daten-Zugriff über die PB-Funktionen ist jedoch auf Grund der PB-gekappten Sekunden fehlerhaft und muss über die API erfolgen.

Ich hab auf dieser Basis nochmals eine abgewandelte Version meines 1. Win-API-Codes zusätzlich erstellt - zusammen mit Ersatz-Funktionen für SetGadgetText(), SetGadgetState(), GetGadgetText(), GetGadgetState(). Die Set-/GetGadgetAttribute()-Funktionen sollten unterbleiben da die Min.-/Max.Werte für die Zeit sowieso fix sind.

DateGadget, 2. Version als getweaktes DateGadget mit API-Zugriff, unverheiratet mit Linux und bisher auch nur mit Wine getestet (Test auf echten Systemen ist erneut erbeten) ...

Code: Alles auswählen

; Module/File:     TimeGadget_WinAPI2+.pb
; Function:        TimePicker via DateGadget and API access (no am/pm, w. Arrow-Buttons) - Windows
; Author:          Omi
; Date:            Dec. 29, 2018
; Version:         0.10
; Target Compiler: PureBasic 5.46/5.62/5.7
; Target OS:       Windows exclusive (not tested on real OS)
;                  https://www.purebasic.fr/english/viewtopic.php?f=12&t=23797
;--------------------------------------------------------------

EnableExplicit

; Object constants
#Win_Main   = 0

#TimeGadget = 0
#StG2       = 1
#TxtG1      = 2
#TxtG2      = 3
#BtGset     = 4


Global.i gEvent, gEventGadget, gQuit


CompilerIf #PB_Compiler_OS = #PB_OS_Windows
	;-Windows TimeGadget API ...
	Procedure GetTimeGadgetState(Gadget)
		Protected TimeVal
		Protected tTime.systemtime
		
		SendMessage_(GadgetID(Gadget), #MCM_GETCURSEL, 0, @tTime)
		TimeVal = Val(Str(ParseDate("%hh:%ii:%ss", RSet(Str(tTime\wHour), 2, "0") + ":" + RSet(Str(tTime\wMinute), 2, "0") + ":" + RSet(Str(tTime\wSecond), 2, "0"))))
		ProcedureReturn TimeVal
	EndProcedure
	
	Procedure SetTimeGadgetState(Gadget, TimeVal)
		Protected tTime.systemtime
		
		If TimeVal > -1 And TimeVal < 86400
			SendMessage_(GadgetID(Gadget), #MCM_GETCURSEL, 0, @tTime)
			tTime\wYear  = 1970
			tTime\wMonth = 1
			tTime\wDay   = 1
			tTime\wHour  = Hour(TimeVal)
			tTime\wMinute= Minute(TimeVal)
			tTime\wSecond= Second(TimeVal)
			SendMessage_(GadgetID(Gadget), #MCM_SETCURSEL, 0, @tTime)
		EndIf
	EndProcedure
	
	Procedure.s GetTimeGadgetText(Gadget)
		Protected.s sTimeString
		Protected   tTime.systemtime
		
		SendMessage_(GadgetID(Gadget), #MCM_GETCURSEL, 0, @tTime)
		sTimeString= RSet(Str(tTime\wHour), 2, "0") + ":" + RSet(Str(tTime\wMinute), 2, "0") + ":" + RSet(Str(tTime\wSecond), 2, "0")
		ProcedureReturn sTimeString
	EndProcedure
	
	Procedure SetTimeGadgetText(Gadget, sTimeString.s)
		Protected TimeVal
		Protected tTime.systemtime
		
		TimeVal= ParseDate("%hh:%ii:%ss", sTimeString)
		If TimeVal > -1 And TimeVal < 86400
			SendMessage_(GadgetID(Gadget), #MCM_GETCURSEL, 0, @tTime)
			tTime\wYear  = 1970
			tTime\wMonth = 1
			tTime\wDay   = 1
			tTime\wHour  = Hour(TimeVal)
			tTime\wMinute= Minute(TimeVal)
			tTime\wSecond= Second(TimeVal)
			SendMessage_(GadgetID(Gadget), #MCM_SETCURSEL, 0, @tTime)
		EndIf
	EndProcedure
	
	Procedure Callback_Window(hwnd, msg, wparam, lparam)
		Protected result = #PB_ProcessPureBasicEvents
		Protected *pnmh.NMHDR
		
		Select msg
				
			Case #WM_NOTIFY
				
				If hwnd = WindowID(#Win_Main)
					
					*pnmh = lparam
					
					If *pnmh\hwndFrom = GadgetID(#TimeGadget)
						
						Select *pnmh\code
								
							Case #DTN_DATETIMECHANGE
								PostEvent(#PB_Event_Gadget, #Win_Main, #TimeGadget, #PB_EventType_Change)
								
						EndSelect
						
					EndIf
					
				EndIf
				
		EndSelect
		ProcedureReturn result
	EndProcedure
	
	Procedure TimeGadget(GadgetNo, x, y, w, h, sTime.s, WindowNo, Flags= #Null)
		DateGadget(GadgetNo, x, y, w, h, "", 0, #DTS_TIMEFORMAT | Flags)
		SetWindowCallback(@Callback_Window())
	EndProcedure
	
	;-... Windows TimeGadget API END
CompilerEndIf

Procedure Create_WinMain()
	OpenWindow(#Win_Main, 0, 0, 600, 170, "DateTime-Pick w. tweaked DateGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		TextGadget(#PB_Any,       5,   5, 590,  22, "Set a time as 'hh:mm:ss' with number keys, <up>/<down> | <+>/<-> keys or mouse scrolling.")
		TextGadget(#PB_Any,       5,  28, 590,  22, "Jump to segments max.-value with <home>.")
		TextGadget(#PB_Any,       5,  51, 590,  22, "Choose editable segment with <left>/<right> keys or mouseclick.")
	CompilerEndIf
	
	TextGadget(#PB_Any,       5,  79,  98,  22, "Set time (h:m:s)")
	TimeGadget(#TimeGadget, 200,  75,  80,  26, "", #Win_Main, #DTS_TIMEFORMAT)
	;SetGadgetState(#TimeGadget, 30);                                            Doesn't work! Seconds are clipped by PB.
	SetTimeGadgetText(#TimeGadget, "12:30:30")
	
	StringGadget(#StG2,     400,  75, 195,  26, "Only for focus tests!")
; 	
	TextGadget(#PB_Any,       5, 110, 190,  22, "Time set:")
	TextGadget(#PB_Any,       5, 135, 190,  22, "Time value set (=seconds):")
	TextGadget(#TxtG1,      200, 110,  98,  22, "")
	TextGadget(#TxtG2,      200, 135,  98,  22, "")
	ButtonGadget(#BtGset,   400, 133, 195,  26, "Set time to 8:00:00")
EndProcedure


Create_WinMain()

Repeat
	gEvent= WaitWindowEvent()
	
	Select gEvent
			
		Case #PB_Event_CloseWindow
			gQuit= #True
			
		Case #PB_Event_Gadget
			gEventGadget= EventGadget()
			Select gEventGadget
					
; 				Case #TimeGadget;                                                      no PB event is released on change of seconds
; 					;doesn't work correctly, use API version below ...
; 					Debug "Time string from PB: " + GetGadgetText(#TimeGadget);          always empty
; 					Debug "Time value from PB (w/ seconds!): " + ParseDate("%hh:%ii:%ss", FormatDate("%hh:%ii:%ss", GetGadgetState(#TimeGadget))); Wrong! Without seconds, compare with dialog time value
					
				Case #TimeGadget;                                                      read time via API, called twice on min./hrs.-change at the moment
					CompilerIf #PB_Compiler_OS = #PB_OS_Windows
						SetGadgetText(#TxtG1, GetTimeGadgetText(#TimeGadget))
						SetGadgetText(#TxtG2, Str(GetTimeGadgetState(#TimeGadget)))
					CompilerEndIf
					
				Case #BtGset;                                                          Set TimeGadget to 08:00:00
					CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; 					SetTimeGadgetText(#TimeGadget, "08:00:00")
						SetTimeGadgetState(#TimeGadget, 28800)
						PostEvent(#PB_Event_Gadget, #Win_Main, #TimeGadget, #PB_EventType_Change)
					CompilerEndIf
					
			EndSelect
			
	EndSelect
Until gQuit
Es wurden Vorbereitungen eingearbeitet um in Kürze die Linux-Version einzuflechten.

Charly
PureBasic Linux-API-Library: http://www.chabba.de
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Shardik »

Omi hat geschrieben:Deine OS-übergreifende SUV-Version funktioniert tadellos, unter Linux auch unter Gtk2.
Eigentlich sollte meine OS-übergreifende Version die Smart-Version sein, denn Deine Windows-ähnliche Lösung ist doch eigentlich die SUV-Version... :D

Ich habe auch Deine neue Version unter Windows 7 getestet. Die Grundfunktionalität ist prima. Folgende Dinge funktionieren bei mir nicht wie im Erklärungstext Deines Fensters angegeben:
- Änderung eines Wertes mit dem Scroll-Rad der Maus (auch nicht, wenn der Fokus auf einem Segment liegt)
- Erhöhen eines Wertes mit <+> (ein Fehlerton wird ausgegeben)
- Erniedrigen eines Wertes mit <-> (der Fokus springt zum nächsten Segment)

Da ich auf einem iMac mit BootCamp und Windows 7 teste, ist meine Tastaturbeschriftung auf einer Apple-Tastatur mit numerischem Zeichenblock anders als bei PC-Tastaturen. Bei der Taste "Pfeil nach schräg links oben" wird der Segmentwert auf 0 gesetzt (auf einer PC-Tastatur "Pos 1"), bei der Taste "Pfeil nach schräg rechts unten" (auf einer PC-Tastatur "Ende") wird der Wert auf den Maximalwert gesetzt. Ich nehme daher an, dass Deine Erklärung "Jump to segments max.-value with <home>." falsch ist, da <Home> wahrscheinlich <Pos 1> entspricht und korrekt 0 einstellt und <Ende> korrekt den Maximalwert einstellt.

Wenn Du die Linux- und Windows-Version verheiratet hast, werde ich wohl in den sauren Apfel beissen müssen und auch eine entsprechende MacOS-Version zusammenbasteln... :wink:
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von mk-soft »

Da ich auf einem iMac mit BootCamp und Windows 7 teste
Schon mal Parallels angeschaut? Ich weiss das es etwas Kostet, aber meine Meinung nach lohnt es sich.
Auf meinen Mac Mini Late 2012 (I7,16GB, 1TB SSD) laufen gerade mal wieder 4 VM´s im Hintergrund
und man kann auf einmal ohne neu zu Booten die Codes auf allen OS ausprobieren.

Im moment kämpfe ich mit mir, ob ich mir einen neuen Mac Mini zulege. Natürlich wieder einen mit I7 (6 Kerne mit Threading)
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Omi
Beiträge: 143
Registriert: 25.03.2013 09:59

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Omi »

Also, die Bedienung muss ich wohl so hinnehmen wie es Windows anbietet. Ich wäre auch nicht fähig hier noch groß einzugreifen.

Ich hab als Referenz für die Kontrollmöglichkeiten in der Linuxversion diese Beschreibung verwendet: https://docs.microsoft.com/en-us/window ... r-controls.
Oder funktioniert Wine mittlerweile besser als das Ziel-OS :wink: ? Das einzige das auf Wine auch nicht wie beschrieben tut ist, dass
- Pos1/Home entgegen der Beschreibung zum Segment-Max. springt und 'End(e)' bei aktuellem Wert '0' nix macht, ansonsten ebenfalls zum Segment-Max. springt. (Aussage korrigiert!). Wäre ich auf'm echten Windows würde ich von einem Windows-Bug sprechen!
- Das Scrollrad funktioniert nur über den Pfeilen aber dieses hat unter Windows eh eher ein Stiefmütterchendasein und hab mir nix dabei gedacht.
(Wenn man dem Windowsianer (nach Eingewöhnung unverzichtbare) Bedienmöglichkeit anbietet, die er nicht gewohnt ist, findet er sie nicht, da er noch nie was anderes gesehen hat, oder nutzt sie trotzdem nicht.)
Mit +/- sind lt. Tests auf Wine die Tasten auf dem Nummernpad gemeint und so hatte ich es auch auf Linux umgesetzt.

Mit SUV war mehr noch der Platzbedarf als die Codemenge gemeint. Wirft halt viel Schatten :wink: .
Der Bedarf nach einem TimeGadget kam bei mir auf, da ich mir täglich die Ergebnisse einer laufenden Dauermessung aus der Arbeit nach Hause in den Urlaub mailen lassen (oder wenigsten ein tägliches Backup der Messdatei machen) wollte um sofort zu sehen, ob sich eines der Messgeräte wieder aufhängt und ich 'bei Bedarf' vor Ort eingreifen muss statt zur Sicherheit vorbei zu schauen. Der Settings-Dialog meines COM-Tool-Mess- und Steuer-Programmes ist bereits Schulter an Schulter vollgepfropft und ein 'Smart'es TimeGadget hätte ich noch irgendwo untergebracht.
... werde ich wohl in den sauren Apfel beissen müssen und auch eine entsprechende MacOS-Version zusammenbasteln...
... auf ein Wort. Ich werd's die nächsten Tage mal verheiraten falls zeitnah keine abschreckenden Rückmeldungen mehr auftauchen.

Schönen Sonntag, Charly

@mk-soft: Wäre auch eine schöne Lösung für mich als alter iMacler. Leider reicht der Platz nicht für noch eine Maschine (+ Monitor(e) oder Umstecken) und spätestens in einer Woche sind Zeit und freier Kopf für Programmierspielchen eh wieder passé.
PureBasic Linux-API-Library: http://www.chabba.de
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Shardik »

Ich habe entdeckt, dass es im Cocoa-Framework von MacOS das Gadget NSDatePicker gibt, das ein ähnliches Verhalten wie SysDateTimePick32 in Windows zeigt. Man kann mit den Pfeiltasten nach oben und unten den fokussierten Wert verändern und mit den Pfeiltasten nach links und rechts zwischen den Segmenten wechseln. Auch eine direkte Werteingabe in ein Segment mit den Zifferntasten ist möglich. Eine Veränderung des fokussierten Segmentwertes mit dem Scrollrad der Maus ist nicht möglich. Es gibt auch die Möglichkeit, zusätzlich einen Pfeil nach oben und unten einzublenden (unterer TimePicker):
Bild
Das Programm dazu ist sehr einfach:

Code: Alles auswählen

EnableExplicit

#NSDatePickerStyleTextField = 2
#NSDatePickerStyleTextFieldAndStepper = 0
#NSHourMinuteSecondDatePickerElementFlag = 14

Define StartDate.S
Define *StartDate
Define TimePicker1.I
Define TimePicker2.I

Procedure CreateTimePicker(WindowID.I, x.I, y.I, Width.I, Height.I, Style.I,
  StartDate.S)
  Protected Frame.NSRect
  Protected *StartDate
  Protected TimePicker.I

  Frame\origin\x = x
  Frame\origin\y = y
  Frame\size\width = Width
  Frame\size\height = Height
  TimePicker = CocoaMessage(0, CocoaMessage(0, 0, "NSDatePicker alloc"),
    "initWithFrame:@", @Frame)
  CocoaMessage(0, TimePicker,
    "setDatePickerStyle:", Style)
  CocoaMessage(0, TimePicker,
    "setDatePickerElements:", #NSHourMinuteSecondDatePickerElementFlag)
  CocoaMessage(0, CocoaMessage(0, WindowID(WindowID), "contentView"),
    "addSubview:", TimePicker)
  *StartDate = CocoaMessage(0, 0, "NSDate dateWithString:$", @StartDate)
  CocoaMessage(0, TimePicker, "setDateValue:@", @*StartDate)

  ProcedureReturn TimePicker
EndProcedure

StartDate = FormatDate("%yyyy-%mm-%dd", Date()) + " 00:00:00 +0100"
OpenWindow(0, 270, 100, 160, 100, "TimePicker")
TimePicker1 = CreateTimePicker(0, 40, 20, 60, 25,
  #NSDatePickerStyleTextField, StartDate)
TimePicker2 = CreateTimePicker(0, 40, 50, 80, 25,
  #NSDatePickerStyleTextFieldAndStepper, StartDate)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Anscheinend fehlt nur in GTK+ ein Windows-ähnlicher TimePicker!
Benutzeravatar
Shardik
Beiträge: 738
Registriert: 25.01.2005 12:19

Re: "Gadget(s)" für Zeiteingabe gesucht

Beitrag von Shardik »

mk-soft hat geschrieben:Schon mal Parallels angeschaut? Ich weiss das es etwas Kostet, aber meine Meinung nach lohnt es sich.
Ich habe den Kauf privat schon in Erwägung gezogen, aber bisher immer davon Abstand genommen, da ich im Linux-Bereich schon öfter von PB-Problemen mit Virtualisierern gehört habe. Im englischen Forum hat sich bei angeblichen Bugs schon mehrfach herausgestellt, dass das Problem nicht an PureBasic lag, sondern an der Virtualisierung. Deshalb weigert sich Fred auch grundsätzlich, Bugs zu untersuchen, die in virtuellen Maschinen auftreten. Ich habe es daher bisher immer vorgezogen, für PureBasic-Tests alle meine Betriebssysteme (8 MacOS-Versionen von Snow Leopard bis High Sierra, 22 Linux-Distributionen und alle Windows-Versionen von Windows 95 bis Windows 10) nur nativ auf Hardware zu betreiben.

Das bedeutet nicht, dass ich mich nicht mit Virtualisierung auskenne. Ich arbeite bei meinem Arbeitgeber als Experte für Hyper-V und VMware und bin für mehr als 500 VMs auf 6 großen HP-Clustern zuständig. Und auf der Arbeit habe ich auf meiner HP Xeon Workstation mit Windows 10 x64 auch lokale Hyper-V VMs mit Windows XP, Windows 7 x64 und Windows 8.1 x64 laufen.
Antworten