Programming a Timer
Programming a Timer
Hallo together,
I am very new in Purebasic and also Mac OS.
I want to program a simple timer. For example the timer should count from 45 sec to 0 sec in 1 sec steps
After this wait 15 sec and then count again from 45 sec to 0 sec.
And this for 10 replais /times. I think the the 10 replais I can to with a for next operation.
But I do not know how to code a imple timer.
Thank you very much for any solution or tipps.
I am very new in Purebasic and also Mac OS.
I want to program a simple timer. For example the timer should count from 45 sec to 0 sec in 1 sec steps
After this wait 15 sec and then count again from 45 sec to 0 sec.
And this for 10 replais /times. I think the the 10 replais I can to with a for next operation.
But I do not know how to code a imple timer.
Thank you very much for any solution or tipps.
Re: Programming a Timer
I write a small example. Need short time
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Programming a Timer
Thanks a lot
Re: Programming a Timer
Faster
Code: Select all
EnableExplicit
#XCounterDefaultValue = 10
#LongTimerDefaultValue = 45
#ShortTimerDefaultValue = 15
Define.i LongTimerCounter, ShortTimerCounter, Event, XCounter
OpenWindow(0, 0, 0, 200, 100, "Timer", #PB_Window_SystemMenu)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(60)
AddStatusBarField(60)
AddStatusBarField(60)
XCounter = #XCounterDefaultValue
LongTimerCounter = #LongTimerDefaultValue
AddWindowTimer(0, 0, 1000)
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Timer
Select EventTimer()
Case 0
If LongTimerCounter > 0
LongTimerCounter - 1
Debug LongTimerCounter
If LongTimerCounter = 0
ShortTimerCounter = #ShortTimerDefaultValue
EndIf
Else
ShortTimerCounter - 1
Debug ShortTimerCounter
If ShortTimerCounter = 0
XCounter - 1
If XCounter = 0
Debug "End"
RemoveWindowTimer(0, 0)
Else
LongTimerCounter = #LongTimerDefaultValue
EndIf
EndIf
EndIf
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
EndSelect
EndSelect
Until Event = #PB_Event_CloseWindow
Re: Programming a Timer
Wellcome
Infratec code is fine and simple
Here I have to apologise for my complex example.
But should be as Basic to be the right entry into programming under macOS.
- Structured event processing.
- Time-controlled background processing (thread)
- Rules for passing to the GUI (gadget must not be changed from thread)
- Threads must be terminated before the programme is terminated.
Infratec code is fine and simple
Here I have to apologise for my complex example.
But should be as Basic to be the right entry into programming under macOS.
- Structured event processing.
- Time-controlled background processing (thread)
- Rules for passing to the GUI (gadget must not be changed from thread)
- Threads must be terminated before the programme is terminated.
Code: Select all
;-TOP
#ProgramTitle = "Main Window"
#ProgramVersion = "v1.01.2"
Enumeration Windows
#Main
EndEnumeration
Enumeration MenuBar
#MainMenu
EndEnumeration
Enumeration MenuItems
#MainMenuAbout
#MainMenuExit
EndEnumeration
Enumeration Gadgets
#MainProgress
EndEnumeration
Enumeration StatusBar
#MainStatusBar
EndEnumeration
; ----
Enumeration CustomEvent #PB_Event_FirstCustomValue
#MyEvent_Status
#MyEvent_Timer
EndEnumeration
; ----
Structure udtThreadData
ThreadId.i
Exit.i
Window.i
Gadget.i
EndStructure
Global thData.udtThreadData
Procedure thTimer(*data.udtThreadData)
Protected loop, time
With *data
For loop = 1 To 10
PostEvent(#MyEvent_Status, \Window, 0, 0, loop)
If \Exit
Break
EndIf
For time = 1 To 60
If \Exit
Break 2
EndIf
If time <= 45
PostEvent(#MyEvent_Timer, \Window, 0, 0, time)
EndIf
Delay(1000)
Next
Next
EndWith
EndProcedure
; ----
Procedure UpdateWindow()
Protected dx, dy
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
; Resize gadgets
ResizeGadget(#MainProgress, 10, 10, dx - 20, 30)
EndProcedure
Procedure Main()
Protected dx, dy
#MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, 800, 600, #ProgramTitle , #MainStyle)
; Menu
CreateMenu(#MainMenu, WindowID(#Main))
MenuTitle("&File")
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
MenuItem(#PB_Menu_About, "")
CompilerElse
MenuItem(#MainMenuAbout, "About")
CompilerEndIf
; Menu File Items
CompilerIf Not #PB_Compiler_OS = #PB_OS_MacOS
MenuBar()
MenuItem(#MainMenuExit, "E&xit")
CompilerEndIf
; StatusBar
CreateStatusBar(#MainStatusBar, WindowID(#Main))
AddStatusBarField(200)
AddStatusBarField(#PB_Ignore)
; Gadgets
dx = WindowWidth(#Main)
dy = WindowHeight(#Main) - StatusBarHeight(#MainStatusBar) - MenuHeight()
ProgressBarGadget(#MainProgress, 10, 10, dx - 20, 30, 0, 59)
; Bind Events
BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), #Main)
; Init Thread
thData\Window = #Main
thData\ThreadId = CreateThread(@thTimer(), @thData)
; Event Loop
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Select EventWindow()
Case #Main
If IsThread(thData\ThreadId)
thData\Exit = #True
If Not WaitThread(thData\ThreadId, 2000)
KillThread(thData\ThreadId)
EndIf
EndIf
Break
EndSelect
Case #PB_Event_Menu
Select EventMenu()
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Case #PB_Menu_About
PostEvent(#PB_Event_Menu, #Main, #MainMenuAbout)
Case #PB_Menu_Preferences
Case #PB_Menu_Quit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
CompilerEndIf
Case #MainMenuAbout
MessageRequester("About", #ProgramTitle + #LF$ + #ProgramVersion, #PB_MessageRequester_Info)
Case #MainMenuExit
PostEvent(#PB_Event_CloseWindow, #Main, #Null)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
EndSelect
Case #MyEvent_Status
StatusBarText(#MainStatusBar, 0, " Loop " + EventData())
Case #MyEvent_Timer
SetGadgetState(#MainProgress, EventData())
StatusBarText(#MainStatusBar, 1, " Time " + EventData())
EndSelect
ForEver
EndIf
EndProcedure : Main()
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Programming a Timer
infratec fine code with BindEvent()
Code: Select all
;EnableExplicit
#XCounterDefaultValue = 10
#LongTimerDefaultValue = 45
#ShortTimerDefaultValue = 15
Global LongTimerCounter,ShortTimerCounter,XCounter
Procedure timerCB()
If LongTimerCounter > 0
LongTimerCounter - 1
Debug LongTimerCounter
If LongTimerCounter = 0
ShortTimerCounter = #ShortTimerDefaultValue
EndIf
Else
ShortTimerCounter - 1
Debug ShortTimerCounter
If ShortTimerCounter = 0
XCounter - 1
If XCounter = 0
Debug "End"
RemoveWindowTimer(0, 0)
Else
LongTimerCounter = #LongTimerDefaultValue
EndIf
EndIf
EndIf
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
EndProcedure
;Define.i LongTimerCounter, ShortTimerCounter, Event, XCounter
OpenWindow(0, 0, 0, 200, 100, "Timer", #PB_Window_SystemMenu)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(60)
AddStatusBarField(60)
AddStatusBarField(60)
XCounter = #XCounterDefaultValue
LongTimerCounter = #LongTimerDefaultValue
AddWindowTimer(0, 0, 1000)
BindEvent(#PB_Event_Timer,@timerCB())
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
Repeat
Event = WaitWindowEvent()
Select Event
EndSelect
Until Event = #PB_Event_CloseWindow
Egypt my love
Re: Programming a Timer
I think we all have too much time 
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Programming a Timer
Why is BindEvent() better?
My version catches the event in the main program event loop.
This loop executes all events one after an other.
If you move heavily the mose, for example, then there are many events to process.
This can result in a short delay until the timer event is processed.
But the fault is not additional, since the 1 second timer generates the next event independend.
If you use BindEvent() you get a bit more precise timing.
But I don't know if this is relevant.
My version catches the event in the main program event loop.
This loop executes all events one after an other.
If you move heavily the mose, for example, then there are many events to process.
This can result in a short delay until the timer event is processed.
But the fault is not additional, since the 1 second timer generates the next event independend.
If you use BindEvent() you get a bit more precise timing.
But I don't know if this is relevant.
Re: Programming a Timer
Some actions actually locks the event loop (like resizing a window on Windows) but binded events are still dispatched.
Re: Programming a Timer
Interesting, I asked about the order of event execution in another thread.
Is it true the main event loop responds after bind events and custom post events?
Is it true the main event loop responds after bind events and custom post events?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Re: Programming a Timer
Better use of BindEvent()
Exactly it's not perfect because if it stopped and started again the continuation of the timer cycle is messed up
Exactly it's not perfect because if it stopped and started again the continuation of the timer cycle is messed up
Code: Select all
;EnableExplicit
#XCounterDefaultValue = 10
#LongTimerDefaultValue = 45
#ShortTimerDefaultValue = 15
Global LongTimerCounter,ShortTimerCounter,XCounter
Procedure timerCB()
If LongTimerCounter > 0
LongTimerCounter - 1
Debug LongTimerCounter
If LongTimerCounter = 0
ShortTimerCounter = #ShortTimerDefaultValue
EndIf
Else
ShortTimerCounter - 1
Debug ShortTimerCounter
If ShortTimerCounter = 0
XCounter - 1
If XCounter = 0
Debug "End"
RemoveWindowTimer(0, 0)
Else
LongTimerCounter = #LongTimerDefaultValue
EndIf
EndIf
EndIf
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
EndProcedure
OpenWindow(0, 0, 0, 200, 100, "Timer", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(0,10,10,50,20,"Start")
ButtonGadget(1,65,10,50,20,"Stop")
ButtonGadget(2,120,10,50,20,"END")
CreateStatusBar(0, WindowID(0))
AddStatusBarField(60)
AddStatusBarField(60)
AddStatusBarField(60)
XCounter = #XCounterDefaultValue
LongTimerCounter = #LongTimerDefaultValue
AddWindowTimer(0, 0, 1000)
StatusBarText(0, 0, Str(XCounter) + "-" + Str(#XCounterDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 1, Str(LongTimerCounter) + "-" + Str(#LongTimerDefaultValue), #PB_StatusBar_Center)
StatusBarText(0, 2, Str(ShortTimerCounter) + "-" + Str(#ShortTimerDefaultValue), #PB_StatusBar_Center)
Repeat
Select WaitWindowEvent(1)
Case #PB_Event_CloseWindow
If start = 1
UnbindEvent(#PB_Event_Timer,@timerCB())
EndIf
Quit = 1
Case #PB_Event_Gadget
Select EventGadget()
Case 0
start = 1
BindEvent(#PB_Event_Timer,@timerCB())
Case 1
start = 0
UnbindEvent(#PB_Event_Timer,@timerCB())
Case 2
If start = 1
UnbindEvent(#PB_Event_Timer,@timerCB())
EndIf
Quit = 1
EndSelect
EndSelect
Until Quit = 1
Egypt my love
- Michael Vogel
- Addict

- Posts: 2819
- Joined: Thu Feb 09, 2006 11:27 pm
- Contact:
Re: Programming a Timer
Not a solution for you (windows) but maybe an inspiration (also for creating more console apps)...
Code: Select all
; Define 500 lines of code
EnableExplicit
#Q=#DOUBLEQUOTE$
#Shades=4
#ConsoleTitle="Console Clock by Michael Vogel"
Global Dim Pattern(#Shades)
Structure CharType
Width.i
Height.i
Space.i
DotWidth.i
Bytes.i
OffsetX.i[5]
OffsetY.i
Dot.i
TimeDot.i
Time.i[5]
OldTime.i[5]
Transition.i[2]
Phase.i[2]
ColorMode.i
Foreground.i
Background.i
ConsoleColors.i
Delay.i
Running.i
Refresh.i
FontFace.s
FontType.i
FontRatio.i
ClearOnExit.i
Countdown.i
StopAtZero.i
TimerDone.i
FullChar.i
MidChar.i
HalfChar.i
TimeFormat.s
TimeOffset.i
CpuTime.i
EndStructure
Structure ConsoleType
Handle.i
Width.i
Height.i
Cursor.i
Background.i
Window.i
EndStructure
Global Dim Matrix.b(11,10)
Global Char.CharType
Global Con.ConsoleType
Structure Console_COORD
StructureUnion
coord.COORD
long.l
EndStructureUnion
EndStructure
; EndDefine
Procedure Max(a,b)
If a>b
ProcedureReturn a
Else
ProcedureReturn b
EndIf
EndProcedure
Procedure Limit(value,min,max)
If value>max
ProcedureReturn max
ElseIf value<min
ProcedureReturn min
Else
ProcedureReturn value
EndIf
EndProcedure
Procedure Check(check,yes,no)
If check
ProcedureReturn yes
Else
ProcedureReturn no
EndIf
EndProcedure
Procedure ConsoleBufferLocate(x,y)
Protected Coordinates.Console_COORD
Coordinates\coord\x=x
Coordinates\coord\y=y
SetConsoleCursorPosition_(Con\Handle,Coordinates\long)
EndProcedure
Procedure ConsoleClear()
Protected Coordinates.Console_COORD
Protected NumberOfCharsWritten
Coordinates\coord\x=0
Coordinates\coord\y=0
FillConsoleOutputCharacter_(Con\Handle,' ',Con\Height*Con\Width,Coordinates\long,@NumberOfCharsWritten)
FillConsoleOutputAttribute_(Con\Handle,Con\Background+Char\Foreground,Con\Height*Con\Width,Coordinates\long,@NumberOfCharsWritten)
ConsoleBufferLocate(0,0)
EndProcedure
Procedure ConsoleBackground(color)
ProcedureReturn (#BACKGROUND_BLUE*Bool(color&1)) | (#BACKGROUND_GREEN*Bool(color&2)) | (#BACKGROUND_RED*Bool(color&4)) | (#BACKGROUND_INTENSITY*Bool(color&8))
EndProcedure
Procedure CreateFont()
Protected.f cw,ch,fw,fh,mx,my,ox,oy,px,py
Protected.i i,xmin,xmax,ymin,ymax,z
Protected.i n,w,o,ix,iy
Protected.s s
fw=200
fh=200
xmin=9999
ymin=9999
For i=0 To 10
s=Chr('0'+i)
CreateImage(i,fw+50,fh,32,#White)
StartVectorDrawing(ImageVectorOutput(i))
VectorFont(FontID(0),100)
If i=0
fw=VectorTextWidth(s,#PB_VectorText_Default)
fh=VectorTextHeight(s,#PB_VectorText_Default)
EndIf
cw=VectorTextWidth(s,#PB_VectorText_Visible)
ch=VectorTextHeight(s,#PB_VectorText_Visible)
ox=VectorTextWidth(s,#PB_VectorText_Visible|#PB_VectorText_Offset)
oy=VectorTextHeight(s,#PB_VectorText_Visible|#PB_VectorText_Offset)
mx=(fw-cw)/2
my=(fh-ch)/2
z=Round(mx,#PB_Round_Down) : If xmin>z : xmin=z : EndIf :
z=Round(mx+cw,#PB_Round_Up) : If xmax<z : xmax=z : EndIf :
z=Round(my,#PB_Round_Down) : If ymin>z : ymin=z : EndIf :
z=Round(my+ch,#PB_Round_Up) : If ymax<z : ymax=z : EndIf :
MovePathCursor(25+mx-ox,my-oy)
DrawVectorText(s)
StopVectorDrawing()
If i=0
GrabImage(0,0,0,0,fw+50,fh)
EndIf
Next i
For i=0 To 10
GrabImage(i,i,25+xmin,ymin,xmax-xmin,ymax-ymin)
ResizeImage(i,Char\Width,Char\Height,#PB_Image_Smooth)
Next i
Char\DotWidth=cw*Char\Width/(xmax-xmin)
Char\Bytes=Char\Width*Char\Height
ReDim Matrix(11,Char\Bytes)
w=Char\Width
For i=0 To 10
If i=10
w=Char\DotWidth
o=(Char\Width-w)/2
EndIf
StartDrawing(ImageOutput(i))
n=0
iy=0
While iy<Char\Height
ix=0
While ix<w
z=($FF-(Point(o+ix,iy)&$FF))*#Shades/255
Matrix(i,n)=Round(z,#PB_Round_Nearest)
n+1
ix+1
Wend
iy+1
Wend
StopDrawing()
FreeImage(i)
Next i
EndProcedure
Procedure DrawChar(index)
Protected i,j,n,w,c,o,p
Protected x,y,pt,pc,po
x=Char\OffsetX[index]
y=Char\OffsetY
c=Char\Time[index]
o=Char\OldTime[index]
i=Bool(index)
pt=Char\Transition[i]
po=Char\Phase[i]
pc=pt-po
While j<Char\Height
ConsoleBufferLocate(x,y+j)
i=0
If c>=10
w=Char\DotWidth
Else
w=Char\Width
EndIf
While i<w
If pc And pt And c<>o
p=(Matrix(c,n)*pc+Matrix(o,n)*po)/pt
p=Pattern(p)
Else
p=Pattern(Matrix(c,n))
EndIf
If Char\ColorMode
Print(Chr(p))
Else
ConsoleColor(#Null,p)
Print(" ")
EndIf
n+1
i+1
Wend
j+1
Wend
EndProcedure
Procedure Main()
Protected i,j,e
Protected.s s,t
Protected ConsoleBufferInfo.CONSOLE_SCREEN_BUFFER_INFO
With Char
\FontFace= "Bahnschrift"
\FontType= #PB_Font_HighQuality
\FontRatio= 5
\Foreground= 7
\Background= 0
\HalfChar= 'o'
\MidChar= '@'
\FullChar= '@'
\Transition[0]= 0
\Transition[1]= 0
\Delay=95
\TimeFormat="%hh%ii"
j=CountProgramParameters()
While i<j And e=0
s=ProgramParameter(i)
i+1
t=Trim(Mid(s,3+Bool(Mid(s,3,1)=":")),#Q)
If Left(s,1)="/"
Select PeekC(@s+SizeOf(Character))|$20
Case 'f'
\FontFace=t
Case 't'
t=LCase(t)
If FindString(t,"b") : \FontType|#PB_Font_Bold : EndIf
If FindString(t,"i") : \FontType|#PB_Font_Italic : EndIf
Case 'c'
\Foreground=Limit(Val(t),0,15)
\Background=Limit(Val(StringField(t,2,",")),0,15)
Case 'a'
\Transition[1]=Limit(Val(t),0,10)
t=StringField(t,2,",")
If t
\Transition[0]=Limit(Val(t),0,10)
Else
\Transition[0]=\Transition[1]
EndIf
Case 'd'
\Delay=Limit(Val(t),1,10)*10-5
Case 'h'
\FontRatio=Limit(Val(t),0,10)
Case 'z'
\ClearOnExit=#True
Case 'm'
\TimeFormat="%ii%ss"
If t
i=Val(t)
If i<0
i=-i
\StopAtZero=#True
EndIf
\TimeOffset=Date()+i;*60
\Countdown=Bool(i)
EndIf
Case 's'
If t=""
\FullChar='®'
\MidChar='o'
\HalfChar='·'
Else
\FullChar=Asc(t)
\HalfChar=Asc(StringField(t,2,","))
\MidChar=Asc(StringField(t,3,","))
If \HalfChar=0 : \HalfChar=\FullChar : EndIf
If \MidChar=0 : \MidChar=\FullChar : EndIf
EndIf
Case '?'
e=#True
EndSelect
Else
e=#True<<#True
EndIf
Wend
If e
OpenConsole()
PrintN("")
PrintN(#ConsoleTitle)
PrintN("------------------------------")
If e=1
PrintN("/f:font font name")
PrintN("/h:0-10 font height")
PrintN("/t:[b][i] font type")
PrintN("/c:0-15[,0-15] color mode")
PrintN("/a:0-10[,0-10] animation")
PrintN("/d:0-10 delay")
PrintN("/s:char[,...] text symbols")
PrintN("/m[:time] timer mode")
PrintN("/z clear screen")
;Input()
Else
PrintN("Illegal parameter '"+s+"'.")
EndIf
End
EndIf
LoadFont(0,\FontFace,100,\FontType)
Con\Background=ConsoleBackground(\Background)
\ColorMode=Bool(\Foreground<>\Background)
OpenConsole(#ConsoleTitle)
Con\Handle=GetStdHandle_(#STD_OUTPUT_HANDLE)
ConsoleClear()
If \ColorMode
Pattern(0)=' '
Pattern(1)=\HalfChar
Pattern(2)=\MidChar
Pattern(3)=\FullChar
Pattern(4)=\FullChar
Else
Pattern(0)=\Background
i=Bool(\Background<8)
If Bool(\Background%15)
j=\Background+(i<<4)-8
Pattern(1)=j
Pattern(2)=j
Else
Pattern(1)=check(i,8,7)
Pattern(2)=15-Pattern(1)
EndIf
Pattern(3)=check(i,15,0)
Pattern(4)=Pattern(3)
EndIf
ConsoleCursor(0)
ConsoleColor(\Foreground,\Background)
\Refresh=#True
; ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
CompilerIf #PB_Compiler_Debugger
Debug "Compile as console app"
Debug "Try 'clock /m:45 /a:10'..."
\Transition[0]=8
\Transition[1]=10
\TimeOffset=Date()+45;*60
\TimeFormat="%ii%ss%ss"
\StopAtZero=#True
\Countdown=#True
CompilerEndIf
; ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Repeat
\CpuTime=ElapsedMilliseconds()
GetConsoleScreenBufferInfo_(Con\Handle,@ConsoleBufferInfo)
i=Max(ConsoleBufferInfo\srWindow\right-ConsoleBufferInfo\srWindow\left+1,10)
j=Max(ConsoleBufferInfo\srWindow\bottom-ConsoleBufferInfo\srWindow\top+1,4)
If i<>Con\Width Or j<>Con\Height
Con\Width=i
Con\Height=j
\Space=Round(Con\Width*0.02,#PB_Round_Up)
\Width=(Con\Width-\Space*6)*0.23
\Height=Con\Height*(10+\FontRatio)/20
CreateFont()
\OffsetX[1]=Char\Space
\OffsetX[2]=Char\Width+Char\Space*2
\OffsetX[0]=\OffsetX[2]+Char\Width+Char\Space
\OffsetX[3]=\OffsetX[0]+Char\DotWidth+Char\Space
\OffsetX[4]=\OffsetX[3]+Char\Width+Char\Space
\OffsetY=(Con\Height-\Height)/2
j=(Con\Width-\OffsetX[4]-\Width-\Space)/2
If j
For i=0 To 4
\OffsetX[i]+j
Next i
EndIf
\Refresh=#True
ConsoleClear()
EndIf
i=Date()
j=i-\TimeOffset
If \Countdown
If j=0
\TimerDone|#True
ElseIf j<0
j=-j
ElseIf \StopAtZero
j=0
EndIf
EndIf
s=FormatDate(\TimeFormat,j)+FormatDate("%ss",i)
If Char\Running
If Bool(i%10<>\TimeDot)
\TimeDot=i%10
Char\OldTime[0]=Char\Time[0]
Char\Time[0]=i&1+10
Char\Phase[0]=Char\Transition[0]
\Refresh=#True
If \TimerDone=1
\TimerDone|2
ConsoleColor(12,\Background)
EndIf
EndIf
i=Asc(Mid(s,4,1))-'0'
If i<>Char\Time[4] Or Char\Running=1
Char\Running=2
For i=1 To 4
Char\OldTime[i]=Char\Time[i]
Char\Time[i]=Asc(Mid(s,i,1))-'0'
Next
Char\Phase[1]=Char\Transition[1]
EndIf
If Char\Phase[0] Or \Refresh
Char\Phase[0]=Max(Char\Phase[0]-1,0)
DrawChar(0)
EndIf
If Char\Phase[1] Or \Refresh
Char\Phase[1]=Max(Char\Phase[1]-1,0)
For i=1 To 4
DrawChar(i)
Next i
EndIf
\Refresh=#Null
Else
Char\Time[0]=(Asc(Mid(s,6,1))&1)+10
Char\OldTime[0]=Char\Time[0]!1
For i=1 To 4
Char\Time[i]=11
Next
Char\Running=#True
EndIf
Delay(\Delay+Max(\CpuTime-ElapsedMilliseconds(),1-\Delay))
Until Inkey()<>""
ConsoleColor(7,0)
ConsoleCursor(1)
If \ClearOnExit
Con\Background=ConsoleBackground(\Background)
ConsoleClear()
Else
PrintN("")
EndIf
EndWith
EndProcedure
Main()
Re: Programming a Timer
Not that we scare off Hessi1971 
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Re: Programming a Timer
Thanks a lot for all your code and solutions. They are all working well for me.
Great community!!!
Great community!!!



