Clock animation in a drawing with VBA

If you want to create an animation in CATIA, most of the time you use a DMU Kinematics workbench. However, simple animations can be performed without any dedicated CATIA module, just with a plain VBA code. Moreover, you can use VBA across workbenches and Drafting workbench is not an exception. I am going to show you, how you can create a simple animation in a CATIA V5 drawing.

Wanna see it in action?

Timer procedure

We start with a definition of "module-level" variables and a "timer" procedure MyTimer which is running in a loop and in preset intervals regularly redraw our watch. An important part of this procedure is Windows API function Sleep. This function suspends the execution of the current thread until the time-out interval elapses. The function takes as a parameter a time interval (in milliseconds) for which execution is to be suspended.

Within the loop of the MyTimer procedure, we check if redrawing interval has already passed and if so, we call DrawWatch subroutine. The redrawing interval is set to half of a second and it is stored in an interval variable. Then we suspend execution for 20 milliseconds and call DoEvents function which keeps CATIA user interface more responsive. Theoretically, we can continue even without a call to a Sleep function, but then CATIA and DoEvents function become resources hungry and slow down the PC considerably because there's no pause in the processing.

And what official documentation V5Automation.chm says about DoEvents function? See below:

The general purpose of the VBA function DoEvent is to allow the System to manage input events so that the UI becomes more responsive.

Besides this function is generally dangerous because it can generate unexpected reentrancy. CATIA infrastructure is not architectured to manage event treatment while the process is blocked into a VBA macro execution. Calling DoEvent while a macro is executed can so lead to unpredictable behavior.

V5Automation.chm

Well, it does not sound very optimistic, but we can live with it :). Without DoEvents, CATIA, as well as VBA Editor, remain completely frozen and nonresponsive.

Remark

If you need a more advanced timer solution, you can use timer functions provided by Windows API. Functions SetTimer and KillTimer give you some advantage over our simple "DoEvents" timer, but if used inappropriately, CATIA will likely crash completely and you can lose your unsaved work.

Drawing procedures

To draw a face of our clock we call a DrawFace sub. This procedure is called only one time before the main timer loop. Elements of the face are not moving (constant in time) and there is no need to redraw them. To create individual elements of the clock face we use a Factory2D object of a drawing view and some basic geometry equations. To generate text we utilize DrawingTexts collection and text format is set by DrawingTextProperties object.

You can even choose between arabic and roman numerals by commenting/uncommenting some line(s). I am sure you know which lines I am talking about ☺. When you launch this procedure, you should get the following result:

Clock face arabic numerals

Clock face roman numerals

The rest of the code consists of a procedure DrawWatch which is launched on every timer tick (called from inside of the main timer loop) and it draws/redraws the hands of our clock. Hands are just lines (Line2D object) with different length and thickness. On a first call of the method, we create all required elements (lines) and we set their thickness with the help of a Selection object. Once created, they are stored in module variables hourHand, minuteHand, secondHand, and their position is updated on every tick.

To get a proper position of clock hands we use VBA time functions. VBA represents date and time as a number (ddddd.tttttt). Integer portion represents the number of days since [January 0, 1900]. Any dates before this one are stored as negative numbers, all dates after are stored as positive values. The fractional portion of the date represents the fractional portion of a 24 hour day. For example, 6:00 AM is stored as 0.25, or 25% of a 24 hour day. To convert a 24 hour day to its analog counterpart (12-hour format) we use helper function GetHourFraction. It takes a date as a parameter, strip its integer (days) part and return its decimal portion converted to an analog format.