Quartz Clock Tutorial: Page 1/12
Quartz Clock Tutorial: Page 1/12
com
Page 1/12
Were going to dene a Custom Control called QuartzClock which will draw a Clock of course using the Core Graphics Library Quartz. Were going to have a couple of instances of the Quartz clock. One thats visible in a window, and another one in the Dock. The two could be identical, however Ive chosen to make them different because its more fun. Ive also introduced the use of an Obj/C category which well discuss later. I found some code on the internet which saved me some work. I recognize and respect the contribution made by their authors: Gradient ll category:
Basic watch face:
http://www.cocoadev.com/index.pl?GradientFill http://iphone-dev-tips.alterplay.com/2010/03/analog-clock-using-quartz-core.html
You can download the code from: http://clanmills.com/les/QuartzClock.zip All errors are mine and I hope you'll let me know if you are not able to follow the recipe. And of course if you don't understand how/why this all works, I'll be happy to explain a little more. You are also welcome to VNC to my computer for a live demo. Subjects dealt with in this tutorial are: 1) The subjects covered in the Clock Tutorial. Please look at the Clock Tutorial. If you dont understand Clock, youll be lost here. 2) Creating and using a Custom View. 3) Quartz Graphics Model. 4) Drawing in the dock. I recommend that you download, build and run QuartzClock.zip. QuartzClock is pure eye-candy. Youll be motivated to learn how this works. Incidentally, I found the code above and had the application implemented in less than 2 hours. Cocoa is your friend.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 2/12
THE RECIPE
1) Start with an empty application. No need for a document:
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 3/12
5) Convert your existing les to C++ (by renaming the .m les as .mm)
Select QuartzClock/Classes/QuartzClockAppDelegate.m, right-click and rename as QuartzClockAppDelegate.mm Select Clock/Other Sources/main.m, right-click and rename as main.mm
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 4/12
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 5/12
INTERFACE BUILDER
1) Double click MainMenu.xib in XCode
This will launch Interface Builder of course. Resize the QuartzClock dialog box. Bring up the Inspector (cmd-shift-I) and the Library (cmd-shift-L).
2) Drop your header les from XCode into Interface Builders MainMenu.xib window
Drop QuartzClockView.h. There is no visual feedback - Interface Builder is speechless (I think hes sulking and upset).
3) Drag a CustomView from the Library and drop him on your QuartzClock window.
Use the inspector to set the class of the CustomView to be QuartzClockView. Interface Builder will respond by changing the label on the control in the QuartzClock dialog box. Later on well want to size this control correct and well want to dene how he is to be resized. However for the moment, dont worry about that.
5) Save in Interface Builder. (cmd-S) Build and run in X-Code (cmd-B, cmd-R)
At this point you should have a clock. And if you look in the dock, youll see the icon is alive - its a little blue clock.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 6/12
3) Save in Interface Builder. (cmd-S) Build and run in X-Code (cmd-B, cmd-R)
I hope everythings working. Its now time to discuss the Imaging Model and then to discuss the code.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 7/12
Ive written some PostScript to draw a clock with a gradient lled background to demonstrate the kind of thing that can be done. Youll notice the hands are rounded at one end and butted at the other. The wider hands are also shorter. The time is display in both analog and digital format. The digital time is painted in yellow with a black outline. The PostScript code for this is more involved than I want to discuss in this tutorial. The code is in the le clock2.ps if you are interested.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 8/12
Here is some PostScript and its output. You can run the PostScript interpreter using the command pstopdf from the Terminal. The PostScript language uses postx notation (reverse polish) so the operator is placed after the data. The PostScript: 4 setlinewidth would eventually become the C code CGSetLineWidth(context,4.0);
%!PS %%File: pages.ps /red { 1 0 0 setrgbcolor /blue { 0 0 1 setrgbcolor /black { 0 0 0 setrgbcolor /linen { 1 1 0.9 setrgbcolor /page { /p exch 3 string cvs def /Helvetica 15 selectfont 0 0 300 400 rectclip linen 0 0 300 400 rectfill black 0 0 300 400 rectstroke gsave red 10 setlinewidth -20 0 moveto 200 0 lineto -50 20 rlineto stroke 100 20 moveto (X axis) show grestore gsave blue 90 rotate 10 setlinewidth -20 0 moveto 200 0 lineto -50 -20 rlineto stroke 100 -20 moveto (Y axis) show grestore 50 50 moveto (Page: ) show p show } def 1.3 dup scale gsave gsave 250 220 translate 45 rotate .5 .5 scale gsave 10 350 translate -30 rotate .2 .4 scale gsave [ 0.3 .1 -.5 .3 280 450 ] concat showpage %%EOF
} } } }
1 2 3 4
The purpose of this code is to paint a page on the paper. The page is very simple. I draw the linen colored background and then draw the X axis in red (and label it) and the Y axis in blue (and label it). The code to paint the page is in the procedure page. The main program executes the page painting code within the context of gsave .... grestore. So no matter what happens during page painting, the graphical state is the same at the beginning of every page. You can see that the default coordinate system is Right-Handed with 0,0 in the lower left. A positive rotate is anti-clockwise (righthand rule). Ive drawn the page in 4 different locations and scales. Page: 1
is normal. Page: 2
rotated 45 degrees and scaled equally in X and Y by 50% Page: 3
rotated -30 degrees and scaled unequally Page: 4
Ive used a matrix to apply the transform
The matrix [ .... ] is a general 3x2 2-dimensional transformation matrix. Youll appreciate that the PostScript language cannot be explained in a couple of pages. However I hope you can appreciate the concepts of gsave and grestore. Additionally, you can see operators such as rectclip setrgbcolor setlinewidth selectfont rectll rectstroke moveto lineto rlineto setlinewidth stroke and show being used. The are about 400 operators in PostScript - so this is a simple example. The Quartz imaging library provides everything offered by PostScript and much more.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 9/12
/hour hour minute 60 div add def /red /green /blue /white /black /linen { { { { { { 1 0 0 1 0 1 0 0 1 0 0 1 1 1 0 0 1 .9 setrgbcolor setrgbcolor setrgbcolor setrgbcolor setrgbcolor setrgbcolor } } } } } } def def def def def def
/mangle { 6 mul } def % number mangle number /hangle { 5 mul mangle } def % number hangle number /hand { % width xc yx angle length hand save /length exch def /angle exch def moveto setlinewidth 1 setlinecap length width sub angle sin mul length width sub angle cos mul rlineto stroke restore } def 20 20 translate % draw the page gsave linen 0 0 xc 2 mul yc 2 mul rectfill grestore gsave black 0 0 xc 2 mul yc 2 mul rectstroke grestore % fill clock background, stroke the perimeter gsave blue xc yc radius 0 360 arc fill grestore gsave black 30 setlinewidth xc yc radius 0 360 arc stroke grestore % draw the hands of the clock red 18 xc yc hour hangle radius hand green 10 xc yc minute mangle radius hand white 4 xc yc second mangle radius hand showpage %%EOF
Notice the use of setlinecap. This causes the line cap (terminator) to be circular. No effort for the clocks hards to have round ends. And the hand code make the wider hands shorter. So the hour hand is wider and shorter than the minute and second hands. The code in the application takes advantage of shadows in Quartz. PostScript does not support shadows or transparency. Shadows are used on the clock perimeter and the clock hands. This gives QuartzClock a pseudo 3-d appearance. The code in the application uses gradient lls to paint the exterior of the clock and to ll the face of the clock. These are available in PostScript, however Ive chosen to only show the solid ll clock face which is displayed in the dock. Ive also shown the clock perimeter here in white. I colored the hands because its more interesting. In the Obj/C code, the perimeter and hands are white.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 10/12
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 11/12
1) windowWillResize:
This is part of the NSWindowDelegate protocol. We are called back by the window when the window wishes to resize. To avoid the problem of drawing an oval clock, Ive taken advantage of the delegate to ensure that our control is always square.
2) applicationDidFinishLaunching:
This is very similar to the code in the Clock Tutorial. I unchecked the box visible at launch in the Window attributes in Interface Builder. And the rst thing I do is toe hide the app. Then set it to the front. See Clock.pdf for additional information.
3) windowShouldClose:
This is called when you click the Close button (the red top-left window control). Say NO and Hide the application.
CHALLENGES
This is a fun application and many things could be added to this.
1) When you modify the system clock the clock isnt modied. 2) Use a non rectangular window to house the clock (use a circular window) 3) Enable the user to drag the clock over the screen by dragging on the clock face 4) Enable the user to resize a circular window 5) When the clock is asked to close, simply hide him. When asked to show, unhide him. 6) Add a preference panel to the application to allow the user to store preferences such as:
Current location and size of clock Color Settings for the clock (color of the face, gradient colors and so on). Store the preferences in ~/Library/Preferences
11) Design and implement a plugin mechanism to allow other people to add themes
That lot will keep you busy for at least an afternoon. When youre nished, youll have a shareware software product.
QuartzClock Tutorial
Revised: 20100426
http://clanmills.com
Page 12/12
LICENSE
// // // // // // // // // // // // // // // // // // // QuartzClock.pdf This file is part of QuartzClock QuartzClock is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. QuartzClock is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. GNU General Public License for more details. See the
You should have received a copy of the GNU General Public License along with QuartzClock. If not, see <http://www.gnu.org/licenses/>.
This file is original work by Robin Mills, San Jose, CA 2010 http://clanmills.com
400 N First St #311 San Jose, CA 95112 T (408) 288 7673 C (408) 394 1534 [email protected] http://clanmills.com
Revision History
20100426
20100425
20100424
20100423
Added clock2.ps Modied the user experience to start the application without showing the main clock. Starts in dock. Add clock.ps. Fixed some typos. Initial version.
QuartzClock Tutorial
Revised: 20100426