--****************************************************************************** --* * --* File: Clock.lua Revision: 1.0 * --* * --* Contents: a simple analog clock (just a "tkcanvas" experiment) * --* * --* Creation: 04.03.2002 Last Modification: 04.03.2002 * --* * --* Platform: IBM-compatible PC running Windows 98SE * --* * --* Environment: Lua 4.0, TkLua 4.0 * --* * --* Author: Andreas Rozek Phone: ++49 (711) 6770682 * --* Kirschblütenweg 15 Fax: - * --* D-70569 Stuttgart EMail: Andreas.Rozek@T-Online.De * --* Germany * --* * --* URL: http://www.Andreas-Rozek.de/ * --* * --* Copyright: the software is published under the "GNU Lesser General Pub- * --* lic License" (see "http://www.fsf.org/copyleft/lesser.html" * --* for additional information) * --* * --* Comments: since 'tktimer' "fires" after a given interval plus the time * --* required to process the timer function, the display of this * --* clock my sometimes skip a second... * --* * --****************************************************************************** --**** global constants and variables **** ClockView = nil; -- contains the actual clock display HourHand_NodeList = {-2,-1, -2,40, 2,40, 2,-1}; MinuteHand_NodeList = {-1,-3, -1,50, 1,50, 1,-3}; SecondHand_NodeList = {0,-5, 0,58}; --**** local constants and variables **** local Title = "Clock"; local Subtitle = "a simple analog clock"; local LargeTick_NodeList = {-2,0, 2,0, 2,-10, -2,-10}; local SmallTick_NodeList = {-1,0, 1,0, 1,-5, -1,-5}; local TinyTick_NodeList = {0,0, 0,-2}; --****************************************************************************** --* * --* createTick creates a single clock tick * --* * --****************************************************************************** function createTick (NodeList, Angle) local mx,my = 64,64; -- coordinates of clock center local radius = 60; -- clock radius local sinPhi,cosPhi = sin(Angle),cos(Angle); -- required for rotation local ArgList = {ClockView}; -- arguments for Tk canvas command local NodeCount = getn(NodeList); -- actually, it's twice the # nodes if (NodeCount == 4) then tinsert(ArgList, "line"); else tinsert(ArgList, "polygon"); end; for i = 1,NodeCount-1,2 do local x = NodeList[i]; local y = NodeList[i+1] + radius; tinsert(ArgList, mx+(x*cosPhi+y*sinPhi)); tinsert(ArgList, my+(x*sinPhi-y*cosPhi)); end; call(ClockView.create, ArgList); -- a method invoked like a function end; --****************************************************************************** --* * --* newHand creates a single clock hand * --* * --****************************************************************************** function newHand (NodeList, Angle) local mx,my = 64,64; -- coordinates of clock center local sinPhi,cosPhi = sin(Angle),cos(Angle); -- required for rotation local ArgList = {ClockView}; -- arguments for Tk canvas command local NodeCount = getn(NodeList); -- actually, it's twice the # nodes if (NodeCount == 4) then tinsert(ArgList, "line"); else tinsert(ArgList, "polygon"); end; for i = 1,NodeCount-1,2 do local x = NodeList[i]; local y = NodeList[i+1]; tinsert(ArgList, mx+(x*cosPhi+y*sinPhi)); tinsert(ArgList, my+(x*sinPhi-y*cosPhi)); end; return call(ClockView.create, ArgList); -- a method invoked like a function end; --****************************************************************************** --* * --* updateDisplay updates the actual clock display * --* * --****************************************************************************** HourHand, HourHand_Angle = nil; -- canvas ids and angles of clock hands MinuteHand, MinuteHand_Angle = nil; SecondHand, SecondHand_Angle = nil; function updateDisplay () local a,b,hour,minute,second = strfind(date(),"(%d*)%:(%d*)%:(%d*)$"); --**** calculate the angles of each clock hand **** local HourAngle = mod(hour,12)*360/12 + minute*30/60; local MinuteAngle = minute*360/60; local SecondAngle = second*360/60; --**** then (re)create an appropriate canvas object for each hand **** if (HourHand == nil) or (HourHand_Angle ~= HourAngle) then if (HourHand ~= nil) then ClockView:delete(HourHand); end; HourHand = newHand(HourHand_NodeList, HourAngle); HourHand_Angle = HourAngle; -- update global variable end; if (MinuteHand == nil) or (MinuteHand_Angle ~= MinuteAngle) then if (MinuteHand ~= nil) then ClockView:delete(MinuteHand); end; MinuteHand = newHand(MinuteHand_NodeList, MinuteAngle); MinuteHand_Angle = MinuteAngle; -- update global variable end; if (SecondHand == nil) or (SecondHand_Angle ~= SecondAngle) then if (SecondHand ~= nil) then ClockView:delete(SecondHand); end; SecondHand = newHand(SecondHand_NodeList, SecondAngle); SecondHand_Angle = SecondAngle; -- update global variable end; end; --****************************************************************************** --* * --* main program * --* * --****************************************************************************** --**** define display components **** ClockView = tkcanvas{width=128, height=128}; for Angle = 0,359,6 do if (mod(Angle,90) == 0) then createTick(LargeTick_NodeList, Angle); elseif (mod(Angle,30) == 0) then createTick(SmallTick_NodeList, Angle); else createTick(TinyTick_NodeList, Angle); end; end; --updateDisplay(); -- creates the initial clock hands --**** construct application window **** local MainWindow = tkmain{ClockView, {fill="both", expand=1}}; --**** display application window **** MainWindow:title(Title.." - "..Subtitle); MainWindow:show(); -- also triggers a window layout MainWindow:resizable(0,0); -- disables window size changes MainWindow:raise(); -- brings the window into the foreground updateDisplay(); -- the canvas must be visible for this to work properly! --**** start continous display **** tktimer(1000,function() updateDisplay(); end); -- may sometimes skip a second! --**** provide an explicit method to terminate this program! **** MainWindow:protocol("WM_DELETE_WINDOW", "print('done...'); tkexit()");