Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 8 - Displaying, Manipulating, and Printing Data

Basic View Technology

MacApp uses views to represent a Macintosh window and each of its parts, including the window frame (which may include a title bar, size box, zoom box, and close box) and the content area of the window. In addition, many windows feature scroll bars and other control view objects.

The sections that follow describe the major components of MacApp's view technology.

32-Bit Coordinate Space

MacApp supports very large views, using 32-bit coordinate values. Each view has its own coordinate system, with the point (0,0) representing the upper-left corner of the view.

Figure 8-1 shows the values in global and window coordinates that correspond to a line drawn from the point (5,5) to the point (20,30) in a view's local coordinates. These view coordinates correspond to drawing a line from (55,55) to (70,80) in window coordinates or from (75,75) to (90,100) in global coordinates.

All drawing in a view takes place in 16-bit QuickDraw coordinates. Before drawing, MacApp focuses on the view by setting the QuickDraw origin so that (0,0) is at the upper-left corner of the view. A view's drawing method doesn't usually need to worry about global coordinates--it just calls a view method to convert from view coordinates to QuickDraw coordinates before drawing.

Figure 8-1 Local coordinate systems

MacApp supplies the following data types for working with view coordinates. The V in the names of these coordinate data types stands for "View".

A long integer (32 bits) that represents a coordinate value
A pair of VCoordinate values, one for the x component of the point, and one for the y component of the point
A pair of VPoint values, one for the upper-left corner of the rectangle, and one for its lower-right corner
Since QuickDraw coordinates are 16-bit values, the TView class provides conversion methods. These methods may call the view's UpdateCoordinates method to calculate the offset between view and Quickdraw locations. This value is stored in the View's fViewToQDOffset field.

Converts a QuickDraw point into a VPoint value
Converts a QuickDraw rectangle into a VRect value
Converts a VPoint into a QuickDraw point
Converts a VRect into a QuickDraw rectangle
The TView class also provides a number of methods for converting between the coordinates of a view and those of its superview or its window (which may not be the immediate superview), and for converting to global screen coordinates.

These methods include:

Converts a VPoint value from local view coordinates to superview coordinates
Converts a VPoint value from local view coordinates to window coordinates
Converts a VPoint value from superview coordinates to local view coordinates
Converts a VPoint value from window coordinates to local view coordinates
Additional methods are available to perform conversions on VRect and Region data types.

Frame Size/Location

A view's size is specified by its fSize field, a VPoint value, and the view's location within its superview is specified by its fLocation field, also a VPoint value. These values can be changed with the Resize method, which sets the view's size to the passed VPoint value, and the Locate method, which causes the view to be located at the passed VPoint location in the superview, or with SetFrame, which sets both the size and location.

The TView class also has an array field fSizeDeterminer, which contains two entries of type SizeDeterminer, one for the view's vertical dimension and one for the horizontal. The SizeDeterminer data type specifies a view's size in relationship to the size of its superview. The possible values are

The view doesn't change its own size.
The view computes its own size when the AdjustFrame method is called.
The view is the size of one page.
Similar to sizeVariable, but rounded upward to fill an exact number of pages.
The view is the same size as its superview.
The view size is relative to the superview's size.
When an operation such as zooming a window causes a view's size to change, the new size of the view depends on the fSizeDeterminer field. The TView class contains several methods that may be called when the view's size changes, including SetFrame, AdjustFrame, and CalcMinSize. You can read more about these methods in the MacApp Class and Method Reference.

View Hierarchies

The views in a window are linked into a hierarchy, with the window at the top. One view represents the window frame, another represents each scroll bar, another represents the main content area of the window, and so on. Each view can draw the part of the window it represents and can respond to events relating specifically to its part. Each view has a list of the subviews it contains.

Figure 8-2 shows a simple view hierarchy. In this hierarchy, the window is the superview. It contains three immediate subviews, a scroller view and two scroll-bar views. The scroller view contains a subview of its own, the main content view. More complex view hierarchies may contain multiple content views.

The view object for the window draws the title bar, close box, zoom box, size box, and the blank white background of the window. It responds to mouse clicks in the title bar, close box, zoom box, and size box, which may specify dragging, closing, zooming, or resizing the window.

Figure 8-2 A view hierarchy in MacApp

Each view that represents a scroll bar is responsible for drawing the scroll bar, as well as for responding to mouse clicks in the scroll bar, which typically cause the scroll bar to redraw itself and tell the scroller view to scroll its visible area. That has the affect of scrolling the main content view, since it is a subview of the scroller view.

The main content view is responsible for drawing the document's content and may contain a number of subviews to aid in displaying the data. The behavior of content views varies widely from application to application. In the IconEdit sample application, the content view draws an icon at any level of magnification, and responds to mouse clicks by turning individual pixels on or off. In a word-processing program, the content view draws the current text-editing view and the visible part of its text.

A view hierarchy can be as simple as a window object with a single view, or as complex as a dialog box containing numerous nested views, including views that represent buttons, checkboxes, text fields, and other controls. View hierarchies have the following characteristics:

Figure 8-3 How a view is clipped to a window

Many applications require complex view hierarchies. The design and implementation of those view hierarchies can be greatly simplified by the use a view-editing application, a type of graphical user interface builder. A view-editing application allows you to specify view objects and hierarchies in an interactive, graphical environment. You can often edit views, run the application, and examine your changes, without modifying any code. For more information, see "Specifying Views With View Resource Templates," beginning on page 217.

The TDrawingEnvironment Class

MacApp provides the TDrawingEnvironment class for storing characteristics of the graphics environment, including the pen size, pen pattern, pen mode, foreground color, and background color. You can associate an object of type TDrawingEnvironment with each view object. This makes it possible to customize the drawing environment of a view without having to define a view subclass. You can use a view-editing application to specify the drawing environment for a view in its 'View' resource.

Drawing a View's Contents

In a MacApp application, drawing can refer to either of two operations:

This section describes how a MacApp application draws its views. For information on drawing with the mouse, see page 226.

MacApp calls the Draw method whenever a view needs to be redrawn. Redrawing is necessary not only when a change is made in the view but also when the view is first shown or when any part of the view is uncovered by a user action. Since the Draw method of TView does nothing, you must override Draw in your view subclass and provide code to draw your view's contents.

When MacApp calls the view's Draw method, it passes a parameter specifying the minimum rectangle that needs to be redrawn. You can use this information to optimize your Draw method to draw only the specified portion.

Figure 8-4 shows how MacApp calls your drawing routines to update the views in a window. The Draw method is called by the HandleDraw method of your view object (or by gDrawAdorner--see "MacApp's Adorner Classes," beginning on page 213).

Figure 8-4 How MacApp updates the views in a window

MacApp calls HandleDraw, which calls the Draw method of the view and then the HandleDraw method of all subviews. HandleDraw also manages the drawing of adorners, described in "Adorners," beginning on page 213. You rarely, if ever, call Draw yourself; instead, you call one of the view methods InvalidateRect, InvalidateRegion, or InvalidateVRect to invalidate the part of your view that has changed. You can also call ForceRedraw to invalidate the entire view extent.

In response to update events, MacApp calls the Draw method of any view that has an area that is both visible and invalid. If you need to redraw a view immediately, you can call its Update method (after invalidating).

Your Draw method can do any kind of drawing it wants, using the Macintosh QuickDraw routines. When MacApp calls your Draw method, the view has already been focused, so that any QuickDraw calls you make are drawn in your view. (Focusing is described in the next section.) You use your view's local coordinate system, and the drawing takes place in the correct location. Drawing is clipped to the view's superview.

You can read more about Macintosh drawing in Inside Macintosh: Imaging
With QuickDraw


Before drawing can take place, a view must be prepared so that drawing will appear in the correct place on the screen. This is called focusing the view. Focusing includes setting the QuickDraw graphics port, setting the port's coordinate system to match the view's coordinates, and clipping the view's drawing to the margins of its superview (clipping is shown in Figure 8-3).

To focus a view in MacApp, you call the TView::Focus method. MacApp automatically calls Focus at many times, including when a view is activated, updated, zoomed, or drawn. The global variable gFocusedView is set to refer to the currently focused view. MacApp uses gFocusedView to avoid performing unnecessary calculations when Focus is called for a view that is already focused.

If necessary, the TView::Focus method sets the current port to the port of the window the view resides in, calls the Toolbox routine SetOrigin to set the port's origin to the origin of the view, and clips the view to the visible area of its superview.

The Focus method recursively calls FocusOnSuperView, which calls Focus for the view's superview if it has one. View hierarchies always have a window as the topmost view, and the TWindow::Focus method sets the clip region to the window's update region, if there is an update pending; otherwise, it sets the clip region to the window's visible region.

Focus returns FALSE if it is unable to focus. For example, Focus fails if no superview is able to supply a port--that is, if the view is not in a window and the application is not printing or drawing into a QuickDraw Picture.

Focus returns TRUE, however, if it is able to focus but none of the view is currently visible due to clipping or scrolling by a superview. This allows you to assemble a view hierarchy and focus its views without necessarily showing them to the user. After focusing, you can call the TView method IsVisible to determine whether the view is in fact visible. MacApp never asks a view to draw unless it is visible.


An adorner is a graphical object that knows how to draw in the view to which it is attached. Each view object contains a list of zero or more adorners. Whenever the view's Draw method is called, the DrawAdorners method is also called (if the view has any adorners). The DrawAdorners method iterates through the view's list of adorners, calling the Draw method for each adorner.

Adorners can be used to

An adorner can be associated with multiple views, so you can create an adorner to perform a special kind of drawing and attach it to all the views that can benefit from that drawing. You can specify an adorner for a view in a 'View' resource with a view-editing application, or you can add an adorner to a view object in your application by calling the view's AddAdorner method.

MacApp's Adorner Classes

MacApp defines a number of adorner subclasses that you can instantiate in your application, each of which implements a specific kind of drawing or highlighting. These include frame adorners, line adorners, oval adorners, and rectangular adorners.

MacApp also provides global access to certain standard adorners it creates:

The Draw method of gDimAdorner calls the Dim method of the view it is attached to.
The Draw method of gDrawAdorner calls the Draw method of the view. It is added to a view's adorner list automatically if the view has any other adorners, so you have control over when the view is drawn relative to the other adorners (as described in "Adorner Priorities," beginning on page 215).
The Draw method of gEraseAdorner erases the area of the view that will be drawn. This adorner is automatically added to window objects.
The Draw method of gHiliteAdorner calls the Hilite method of the view.
The DoHighlightSelection method of gPrintAdorner calls the DoDrawPrintFeedback method of the view. This adorner is added automatically by MacApp when a print handler is attached to the view.
The DoHighlightSelection method of gResizeIconAdorner calls the window's DrawResizeIcon method. This adorner is added automatically to any resizable window object.
The DoHighlightSelection method of gSelectionAdorner calls the DoHighlightSelection method of the view.
The TAdorner class has an instance variable fIdentifier, of type IDType, that specifies the type of adorner object. MacApp defines identifier constants for its predefined adorner classes in the UAdorners unit.

How a View's Adorners Are Drawn

A view is drawn through a call to its HandleDraw method, which behaves as follows:

  1. If the view has any adorners, the view's DrawAdorners method is called to iterate over the list of adorners. If the view has no adorners, the view's Draw method is called instead.

    When a view does have adorners, MacApp automatically installs gDrawAdorner so that the view's own Draw method is always called, and so that you have control over when it gets drawn relative to the other adorners (as described in the next section).

  2. Each behavior attached to the view is given an opportunity to draw.
  3. The HandleDraw method is called for each subview of the view.
  4. The HighlightAdorners method of the view is called to iterate through the list of highlighting adorners attached to the view and call the DoHighlightSelection method of each adorner that needs to perform highlighting.

Adorner Priorities

You use the TView method AddAdorner to add an adorner to a view's list of adorners. AddAdorner is defined as follows:

virtual void AddAdorner ( TAdorner *anAdorner;
                     AdornPriority itsPriority,
                     Boolean invalidate );
The itsPriority parameter specifies the drawing priority for the adorner in the list: the lower the priority value, the earlier the adorner is called to draw. MacApp defines several adornment priority constants:

const short kAdornLast  = 127;
const short kAdornAfter  = kAdornLast - 32;
const short kDrawView  = 64;
const short kAdornBefore = kDrawView - 32;
const short kAdornFirst  = 0;
The priority assigned to calling the view's own Draw method is kDrawView. If you add an adorner with a priority lower than kDrawView, it will be drawn before the view's Draw method; with a higher priority, it will be drawn after the view's Draw method. You never specify a priority value of kDrawView for an adorner that you add. Always use a value that is lower or higher than kDrawView.

Highlighting in a View

Highlighting is performed whenever a view is drawn and whenever the view's highlight state changes (becoming active or inactive). Highlighting is not performed for printing or imaging for the Clipboard.

MacApp's highlighting mechanism works through the combined effort of view and adorner objects. A view uses highlighting

MacApp's designators provide a standard way to keep track of what is selected in a view. Designators are described in Chapter 7, "Document Handling." Visual feedback for drag and drop is described in Chapter 9, "Drag and Drop."

When MacApp draws a view, it first focuses the view (page 212), then calls the view's Draw method (page 210), then calls the HighlightAdorners method. The HighlightAdorners method iterates over the view's adorners, giving each adorner a chance to draw its adornment in the view.

Highlighting and Selection Adorners

MacApp supplies every application with a number of global adorner objects, including two that are useful for highlighting and selecting, gHiliteAdorner and gSelectionAdorner.

Highlighting States

MacApp defines the HLState type for storing a highlight state, along with constants for specifying the different states of highlighting in a view. These states apply to the view itself or to selected items in the view:

The view is unhighlighted.
The view is dimly highlighted (inactive).
The view is fully highlighted (active).
You pass these constants to view highlighting methods to indicate the previous state and the desired state of highlighting.

For example, the DoHighlightSelection method is defined as follows:

void DoHighlightSelection(HLState fromHL, HLState toHL);
A view must be focused before calling DoHighlightSelection; you can ensure this, as MacApp does, by calling the Focus method of the view object before calling DoHighlightSelection.

Specifying Views With View Resource Templates

MacApp provides a useful tool for defining views and view hierarchies: view resource templates. A view resource template defines the resource format for a MacApp view class. View resource templates are defined as 'View' resource definitions in the file ViewTypes.r.

You can use a resource-editing application that knows about 'View' resource templates, such as Ad Lib (available from Apple Computer), to create view resources that specify the user interface for your application. A view resource can define an entire window or view hierarchy, containing many MacApp view objects, such as views that represent checkboxes, radio buttons, and other controls. You can specify the initial settings for any window or view in the view hierarchy. And you can reuse a view resource whenever you need a view of the same type. For example, all documents of a given type can create their views using the same view resource.

By editing your view resources and rebuilding the application, you can change the appearance and initial settings of your windows without recompiling your application's code. This allows great flexibility in changing the appearance and behavior of your views, with fast turnaround. For more information, see "Working With View Resource Templates," beginning on page 425.

Your application uses MacApp's global view server object, gViewServer (described in the next section) to create windows and views based on the view resources you have defined.

The TViewServer Class

The TViewServer class provides methods to manage the creation of views for your application. During initialization of the application, MacApp automatically creates a TViewServer object and stores a reference to it in the global variable gViewServer. You create views by calling on the methods of gViewServer listed here:

Creates a window that has a main view which may or may not scroll, plus a nonscrolling palette along the left edge or a nonscrolling status area at the top of the window.
Creates a simple window that contains one view, which may or may not scroll.
Creates a window from a 'View' resource. The window may have a view hierarchy of arbitrary complexity.
Creates a view hierarchy of arbitrary complexity from a 'View' resource, then calls the DoPostCreate method. The view hierarchy is not assumed to have a window at its root.
Figure 8-5 shows the process of creating a view hierarchy from a view resource. In this example, a document's DoMakeViews method calls the NewTemplateWindow method of the gViewServer object. NewTemplateWindow calls the DoCreateViews method, which uses MacApp's streaming mechanism to create the view objects specified by the view resource. After the whole view hierarchy has been created, the DoCreateViews method calls the DoPostCreate method for each view it creates, giving each view a chance to perform additional initialization that may depend on the existence of other views in the hierarchy.

Figure 8-5 Creating a window from a resource template

Registering View Classes

If your application uses resources to define view hierarchies, it must register its view classes so that the view server can create views based on class names stored in the view resource. To register your view classes, MacApp provides the MA_REGISTER_CLASS macro, which is invoked with a line like one of the following:


For more information on the MA_REGISTER_CLASS macro, see "Registering Class Information," beginning on page 30.


Most windows that display data on the Macintosh feature scroll bars that allow the user to scroll through the data when it cannot all be displayed at once in its enclosing view. MacApp provides the TScroller subclass of TView to manage scrolling of the data displayed in views and the TScrollerScrollBar class to display a scroll bar that knows how to work with a TScroller object. Figure 8-2 on page 208 shows a view hierarchy with a scroller view and scroll bars.

Scrolling is implemented by adding a scroller view to the view hierarchy, beneath the view or views to be scrolled. The scroller view is invisible--it exists merely to impose a translation on the contents of the window. The scroller view shifts the coordinates of any view drawn on top of it by a translation amount. The translation amount may be specified by user manipulation of a scroll bar but is not limited to that source.

When a scroller scrolls, it offsets the visible region of the view or views to be scrolled by the translation amount. It then calls the Toolbox routine ScrollRect, which moves the specified data (up, down, left, or right) and returns a region showing the area that needs to be redrawn (the area that is scrolled into view). The scroller then invalidates that region, causing it to be redrawn. Using this mechanism, only the new area that was scrolled into view needs to be redrawn.

As with any view, drawing in a scroller is clipped to the superview.


Autoscrolling is the process of scrolling automatically when a user moves the cursor to the boundaries of a view. MacApp supports autoscrolling in its tracker commands, which are described in more detail in "Drawing With the Mouse," beginning on page 226. One of the parameters of the ITracker initialization method of the TTracker command is

TScroller* itsScroller
If your drawing view contains a scroller subview, and if you supply a reference to that scroller when initializing a drawing command that descends from TTracker, the drawing command will automatically support autoscrolling in the view. You can use the GetScroller method of TView to obtain a reference to a view's enclosing scroller, if any. For more details, see "Recipe--Implementing Autoscrolling" on page 396.

MacApp also supports autoscrolling automatically for drag operations in its views that support drag and drop.

Synchronized Scrolling

Synchronized scrolling refers to the simultaneous scrolling of more than one view. MacApp provides the TPrimaryScroller and TSecondaryScroller classes to implement synchronized scrolling. A TPrimaryScroller object has a list of secondary scrollers. If that list is not NULL, when the primary scroller scrolls, it makes the scrollers in the list scroll too.

Synchronized scrolling is demonstrated in the Calc sample application.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996