Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the page entitled “GNU Free Documentation License”.
This is a guide to creating custom view classes in GNUstep and drawing your own views.
The guide assumes that you have completed the Introduction to ProjectCenter and gorm, and builds on the project created in that article. You can either work through that article now, or clone the bitbucket project and start where the other guide leaves off.
The digital clock you created in the ProjectCenter and gorm introduction is alright for some, but other people prefer a traditional, analog clock appearance. GNUstep doesn’t contain a ready-made clock view, but it’s easy to make one.
What GNUstep does give you is NSView, a class that represents the abstract essence of something that can be drawn, but has no knowledge of what to draw. Much of what you see on the screen in a GNUstep application is drawn by NSView or its subclasses—a window has a content view which draws its background; textfields, labels, buttons and other controls are all also views.
Subclassing represents an specialisation action: the subclass is a version of its parent class, more specifically suited to a certain task. By creating a new view class as a subclass of NSView, you can create something that works in the same way as all of the other views in GNUstep, but that draws content relevant to your application. Open the Clock project in ProjectCenter, and from the “File” menu choose “New in project”. The “File Type” drop-down lets you choose different kinds of file to add: select “Objective-C Class”. Give the file the name “ClockView.m”, and check the “Add Header File” box as shown in figure 1.
When you have chosen a location for the class, you will see that ProjectCenter has added ClockView.m to the “Classes” group and ClockView.h to the “Headers” group in your project. Before using the class, there’s some housekeeping to do. Open ClockView.h and change it as below, so that the AppKit headers are imported and the class is a subclass of NSView, not of NSObject. You’ll also add some methods and instance variables to set and store the hour, minute and second displayed by the clock.1
Now switch to the implementation file (ClockView.m) and fill in the definitions of the three methods in the @implementation section.
When any of your methods change the time represented by the ClockView, they send the view a -setNeedsDisplay: message. That message indicates to the view that it needs to update its content, so next time the application refreshes its views the clock view will be included as one that needs to be redrawn.
Open gorm, and from the Classes browser’s Operations drop-down select “Load Class”. Navigate to and open your ClockView.h file. Now resize the clock window, and from the controls palette drop a Custom View into the window. In the custom view’s inspector, change its custom class to ClockView (figure 2). Your interface in gorm will look like figure 3.
But if you build and launch the clock now, you’ll discover that the custom view remains resolutely empty. You’ll need to tell the clock how to draw itself.
The GNUstep appkit framework isn’t always drawing views. As you saw when creating ClockView, a -setNeedsDisplay: call tells the view that it needs redrawing, and GNUstep will only draw views when this is the case. In fact, it can be a bit more efficient than that, telling a view to only redraw part of its content if necessary.
The framework will send the view a -drawRect: message, with the parameter being an NSRect representing the part of the view’s bounds that needs updating. To get the clock built, draw the whole view when -drawRect: is called: this fits the “do it right, do it well, do it fast” approach to working.
The -[ClockView drawRect:] method will draw the clock face (a circle, and the ‘ticks’ at each hour mark), and the three hands. Each of these is drawn by creating an NSBezierPath representing the component of the clock face, then telling it to either stroke (draw its line) or fill (paint within itself up to its line).
Now you have a clock that draws the time…as long as the time is twelve o’clock. It usually isn’t midnight, so you need the clock controller to tell the view what the time is.
In Project Center, switch to ClockController.h and add an instance variable for the clock view.
gorm will automatically tell you that it has re-parsed the file and that this might have broken some connections (it won’t have broken any connections, in this case). Switch to gorm, and connect the clockView outlet on the ClockController to the custom view in the Clock window. This connection will appear in the inspector as figure 4.
Now the controller has a reference to the clock view, it should tell it the time. This can be done in the same timer method that currently updates the digital clock.
Now, when you build and run the application, the clock will be updated in real time, and will look like figure 5.
You have created a custom view in a GNUstep application as a subclass of NSView, and used gorm to connect it to your controller. You made the view draw its content using bezier paths when the framework told it that it’s time to draw.
The source code for the Clock application created here is available in its entirety from gs-analog-clock on Bitbucket, under the terms of the GNU General Public License, Version 3.