Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 90
Текст из файла (страница 90)
First, Icould call DrawNow() on the control, which may well be good enoughfor this simple example. It causes the whole of the control to be drawnand the window server processes all the drawing for it. However, I cando much better than this.One way to stop the window server processing all the drawing is tocall Invalidate() only on the relevant area (just like the DrawDeferred() function does):TRect symRect(iSymbolPos, TSize(iSymbolSize, iSymbolSize));Win().Invalidate(symRect);This causes the window server to send a redraw event for the rectanglein which this symbol resides. The above function would be called withthe rectangle that contains the left symbol; as it does not take any noticeof the rectangle, everything is still drawn but the window server clips thedrawing to the area that was invalidated, in this case the left symbol.However, if another part of the window also becomes invalid before theredraw event is received then the rectangle passed in the redraw maywell be greater.
Also, if some window-server features are in operationthen the rectangle passed to the redraw function is always the full area ofthe window.DRAWING CONTROLS501How can we draw only one of the symbols? The required drawingfunction is COandXStatusWin::DrawOneTile(). The applicationcode does not directly call the COandXStatusWin::Draw() function;the CoeControl framework does some setup and then calls it. In order tocall the COandXStatusWin::Draw() function, we need to do part ofthe setup that is normally done by the framework. The following functiondraws only one symbol and the window server clips the drawing to thearea of that one symbol:void COandXStatusWin::DrawOneTileNow(TBool aLeft) const{TRect symRect(iSymbolPos, TSize(iSymbolSize, iSymbolSize));TBool isCross = (iLeftSymbol==ETileCross);if (!aLeft){symRect.Move(iSymbolSize, 0);isCross = (iRightSymbol==ETileCross);}Window().Invalidate(symRect);ActivateGc();Window().BeginRedraw(symRect);DrawOneTile(SystemGc(), symRect, isCross);Window().EndRedraw();DeactivateGc();}This code is written assuming that the window being used is an RWindow (a redraw window); if it were a backed-up window (RBackedUpWindow), the code would panic as this type of window does not supportthe functions Invalidate(), BeginRedraw() and EndRedraw().However, if these lines are omitted then the code works fine for a backedup window.
If a control has to work with both types of window, youcould check the window type and, if necessary, skip these lines.There is one CCoeControl function that has to take into accountwhich of the two types of window the control is being displayed in. Thisis DrawDeferred(), whose behavior is shown in the following code:void CCoeControl::DrawDeferred() const{...if(IsBackedUp())DrawNow();elseWindow().Invalidate(Rect());...}For a redraw window it just invalidates the window’s rectangle. Thewindow is drawn when the control eventually receives a redraw eventfrom the window server. On a control using a backed-up window,502GRAPHICS FOR DISPLAYDrawDeferred() simply calls DrawNow(), causing the window to bedrawn immediately.The DrawNow() PatternIt is useful to pause here to note a few rules about application-initiatedredrawing.• An application-initiated redraw is usually done using a function whosename is of the form DrawXxxNow(), where the Xxx represents someapplication-specific graphical element, such as OneTile.• A DrawXxx() function (without the Now) expects to be called fromwithin an activate-graphics-context and begin-redraw bracket, and todraw to an area that was previously marked as invalid.• A simple DrawXxxNow() invalidates, activates the graphics context,begins the redraw, calls DrawXxx(), ends the redraw and deactivatesthe graphics context.• A more complex DrawXxxNow() function may need to call manyDrawXxx() functions.• You should avoid calling multiple consecutive DrawXxxNow() functions if you can because it involves (typically) wasteful invalidation,activate-graphics-context and begin-redraw brackets.• You must in any case avoid calling a DrawXxxNow() functionfrom within an activate-graphics-context/begin-redraw bracket, sinceit causes a panic if you repeat these functions when such a bracket isalready active.You can easily copy the DrawNow() pattern for any selective redrawsin your own applications.We see what the activation and begin-redraw functions actually do alittle later in this chapter.17.5Sharing the ScreenSo far, we have covered the basics of drawing and it has been necessaryto tell you to do something without explaining why – for instance, theneed to call the ActivateGc() and BeginRedraw() functions inDrawOneTileNow().
Now it is time to be precise about how windowsand controls work together to enable your application to share theSHARING THE SCREEN503ScreenFigure 17.7 Overlapping windowsscreen with other applications and to enable the different parts of yourapplication to work together.Symbian OS is a full multitasking system in which multiple applicationsmay run concurrently.
As indicated in Figure 17.7, the screen is a singleresource that must be shared among all these applications. Symbian OSimplements this sharing using the window server. Each application drawsto one or more windows; the window server manages the windows,ensuring that the correct window or windows are displayed, exposingand hiding windows as necessary and managing overlaps.An application must also share the screen effectively between itsown components. These components include the main application view,the button bar and other ornaments: dialogs, menus, and so on. Anapplication uses controls for its components.
Some controls – dialogs, forinstance – use an entire window, but many others simply reside alongsideother controls on an existing window. The buttons on a button bar behavethis way, as do the tiles and the status window in the main applicationview of Noughts and Crosses.CONEEvery GUI client uses CONE, the control environment, to provide thebasic framework for controls and for communication with the windowserver (see Figure 17.8).The window server maintains the windows used by all applications. Itkeeps track of their (x, y) positions and sizes, and also their front-to-backorder, which is referred to as a z coordinate.
As windows are moved andtheir z-order changes, parts of them are exposed and need to be redrawn.For each window, the window server maintains an invalid region. Whenpart of a window is invalid, the window server creates a redraw event,504GRAPHICS FOR DISPLAYScreen windowsWindow serverClientClientWindowserversessionWindowserversession11Controlenvironment1nWindows1nControls11Controlenvironment1nWindows1nControlsFigure 17.8 Windows and the control environmentwhich is sent to the window’s owning application so that the applicationcan redraw it.Every application is a client of the window server (see the descriptionof the client–server framework in Chapter 8). It is not necessary to understand the client–server framework in detail for basic GUI programming,because the client interface is encapsulated by CONE.CONE associates one or more controls with each window and handleswindow-server events.
For instance, it handles a redraw event by callingthe Draw() function for all controls that use the window indicated andfall within the bounding rectangle of the invalid region.Window-owning and Lodger ControlsAs was pointed out in Chapter 15, there are two types of control.• A control that requires a whole window is called a ‘windowowning’ control.• A control that requires only part of a window, on the other hand, is a‘lodger control’ or (more clumsily) a ‘non-window-owning’ control.SHARING THE SCREEN505Figure 17.9 A window displaying many controlsThe screenshot shown in Figure 17.9 has a single window, but severalcontrols:• a caption with a pop-out list box• a captioned text box control• a button array with two buttons.Although a window can have many controls, a control has onlyone window.
Every control, whether it is window-owning or a lodger,occupies a rectangle on just one window, and the control draws tothat rectangle on that window. A control’s window is available via theWindow() function in CCoeControl. There are certain advantages tousing lodger controls.• The client–server traffic between an application and the windowserver is vastly reduced by lodger controls. Only one client–servermessage is needed to create an entire dialog, since it includes onlyone window.
Only one event is needed to redraw the whole dialog,no matter how many of its controls are affected. Dialogs are createdand destroyed frequently in application use, so these optimizationsmake a significant difference.• The overheads associated with complex entities, such as dialogs, arereduced by lodger controls because they are much more compact inmemory than windows.506GRAPHICS FOR DISPLAY• The processing requirements of lodger controls are less demanding.Windows may move, change z-order and overlap arbitrarily.
Lodgercontrols at peer level on the same window never intersect and occupyonly a sub-region of their owning window or control. This makes thelogic for detecting intersections much easier than that required for thearbitrarily complex regions managed by the window server.All these factors improve the system efficiency of Symbian OS, compared to a scenario with no lodger controls. In order to take advantage ofthese features, most controls should be coded as lodgers, but there are afew circumstances in which you need a window:• when there is no window to lodge in – this is the case for theapplication view• when you need a backed-up window• when you need to overlap peer controls in an arbitrary way – notaccording to the stricter nesting rules of lodger controls• when you need the back-up-behind property, which is used by dialogsand menu panes to hold a bitmap of the window behind them.Being window-owning is a fairly fundamental property of a control.There isn’t much point in coding a control to work as both a lodger anda window-owning control.