CCoeControl是所有控制項的基類,它封裝了一個控制項的基本屬性和功能。編寫簡單控制項涉及到的函數主要有以下三類:初始化、繪圖及使用者輸入處理。下面是一個簡單控制項的聲明。 class CSimpleControl : public CCoeControl { public: void ConstuctL(const TRect& aRect); ~CSimpleControl(); private: void Draw(const TRect& aRect) const; TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType); }; 初始化:控制項的初始化包括三個主要內容:建立控制項視窗,設定控制項大小及啟用控制項。控制項的預設大小為0 x 0,因此必須設定大小,否則將不可見。因此這三個步驟必不可少。初始化一般在第二階段建構函式ConstructL()完成。 void CSimpleControl::ContructL(const TRect& aRect) { CreateWindowL(); SetRect(aRect); ActivateL(); } 繪圖:直接決定控制面板的函數是Draw()函數。 void CSimpleControl::Draw(const TRect& aRect) const { CWindowGc& gc = SystemGc(); gc.SetPenStyle(CGraphicsContext::ENullPen); gc.SetPenColor(KRgbRed); gc.SetBrushColor(KRgbDarkBlue); gc.SetBrushStyle(CGraphicsContext::ESolidBrush); gc.DrawRect(aRect); } 在這段代碼中,首先調用SystemGc()擷取圖形上下文,SystemGc()是CCoeControl的一個成員函數;然後設定相應的圖形上下文項;最後調用繪圖函數DrawRect()畫一個矩形。 所有的繪圖都是通過圖形上下文(graphics context,GC)來完成的。在Symbian OS中,定義了一個抽象類別CGraphicsContext來統一圖形內容相關的介面,為裝置無關的繪圖提供了豐富的API。衍生類別CWindowGc和CFbsBitGc則具體實現了這些API。我們可以直接使用CFbsBitGc來繪圖,但不推薦使用這種方式。在實際編程時,應用程式應該使用CWindowGc通過視窗伺服器來進行繪圖。CWindowGc的繪圖請求在視窗伺服器的用戶端緩衝區上進行緩衝,這樣可以一次性向視窗伺服器提交多個繪圖請求以提高繪圖效率。CONE為每個GUI應用程式提供一個CWindowGc執行個體作為控制項的預設圖形上下文,它由CConEnv建立,並且可以 使用CCoeControl::SystemGc()來進行訪問。 圖形上下文儲存有下列對繪圖函數有著重要影響的上下文項。1. 畫筆: pen定義繪圖模式(顏色、樣式和大小),它用來繪製線、輪廓以及文本。2. 刷子:brush定義了填充模式、背景色或樣式。3. 字型:font定義了用來繪製文本的字型。圖形上下文沒有預設的字型,因此在使用相關文本函數前,必須調用UseFont()設定字型。另外,在使用完字型後必須調用DiscardFont()來刪除字型,以免記憶體流失。4. 當前位置:當前位置由MoveTo()和各種DrawXxxTo()成員函數來設定(絕對位置),並由MoveBy()和DrawXxxBy()移動(相對位置)。5. 原點:origin定義了相對與裝置原點的位移,繪圖時使用該位移,可以使用SetOrigin()來設定原點。預設的原點為(0,0)。6. 剪輯地區:clipping region定義圖形操作中想要剪輯的地區。可以指定一個簡單的矩形或任意複雜的地區。設定剪輯地區之後,只有落在剪輯地區內的繪圖操作才被顯示出來。可以使用SetClippingRect()函數來設定矩形剪輯地區,使用CancelClippingRect()來取消它;使用SetClippingRegion()函數來設定任意複雜的剪輯地區,使用CancelClippingRegion()來取消它;使用Reset()可以將所有的上下文項設定為預設值。系統調用Draw()函數之前會自動調用Reset()函數,因此通常不需要在控制項中顯式調用該函數。在設定好圖形上下文後,可以調用各種繪圖函數在控制項上進行繪圖。幾乎所有的繪圖函數都被設計為能夠成功執行,因而一般不返回任何值。這使得多個繪圖函數能夠被打包為一條訊息發送到伺服器執行。如果繪圖函數有傳回值的話,這將是不可能的。(1) 點和線.這些函數使用當前畫筆。virtual void Plot(const TPoint& aPoint);virtual void DrawLine(const TPoint& aPnt1, const TPoint& aPnt2);virtual void DrawLineTo(const TPoint& aPoint);virtual void DrawLineBy(const TPoint& aVector);virtual void DrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd);virtual void DrawPolyLine(const CArrayFix<TPoint>* aPointList);virtual void DrawPolyLine(const TPoint* aPointList, TInt aNumPoints);(2) 實心輪廓圖形.這些函數使用畫筆和畫刷,畫筆用來繪製輪廓,刷子用來填充輪廓內部。virtual void DrawPie(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd);virtual void DrawEllipse(const TRect& aRect);virtual void DrawRect(const TRect& aRect);virtual void DrawRoundRect(const TRect& aRect, const TSize& aEllipse);virtual TInt DrawPolygon(const CArrayFix<TPoint>* aPointList, TFillRule aFillRule = EAlternate);virtual TInt DrawPolygon(const TPoint* aPointList, TInt aNumPoints, TFillRule aFillRule = EAlternate);(3) 位元影像.能夠以1:1的比例或者展開到所指定矩形地區的大小來繪製位元影像。virtual void DrawBitmap(const TPoint& aTopLeft, const CFbsBitmap* aSource);virtual void DrawBitmap(const TRect& aDestRect, const CFbsBitmap* aSource);virtual void DrawBitmap(const TRect& aDestRect, const CFbsBitmap* aSource,const TRect& aSourceRect);(4) 文本.使用當前字型。virtual void DrawText(const TDesc& aString, const TPoint& aPosition);virtual void DrawText(const TDesc& aString, const TRect& aBox, TInt aBaselineOffset, TTextAlign aHoriz = ELeft, TInt aLeftMrg = 0);繪圖和重繪:在GUI程式中,所有的繪圖都在控制項上完成,繪圖是由控制項的Draw()函數來完成的,其聲明如下virtual void Draw(const TRect& aRect) const; 基類CCoeControl的Draw()為空白,因此在編寫控制項時必須實現該函數,否則控制項將不可見。Draw()是由應用程式架構來調用,一般不應在應用程式中直接調用Draw()。控制項不只是在初始化繪製它們的外觀,而且在它發生變化時或者系統要求重繪(redraw)時進行重繪。按照重繪的觸發源來劃分,控制項的重繪分為兩種:系統發起的重繪和應用程式發起的重繪。系統發起的重繪處理從視窗伺服器開始,它檢測並判斷何時需要重繪哪部分視窗。實際上,它維護視窗上的一個無效地區,並向擁有視窗的應用程式發送一個重繪事件,要求它重繪無效地區。應用程式發起的重繪處理由應用程式觸發,它可以根據需要採用如下方法來實現(這些函數最終都是通過調用Draw()來實現的):void CCoeControl::DrawNow();立即重繪整個控制項;void CCoeControl::DrawDeferred()const;一旦有機會就重繪整個控制項;void RWindow::Invalidate(const TRect&);一旦有機會就重繪由參數指定的矩形地區。然而通過將重繪活動限制在矩形中,幾乎不會節省很多開銷,因此,編寫大多數控制項時,一般忽略傳遞限制矩形參數。 使用者輸入處理: Symbian OS中處理使用者輸入的兩個基本函數是OfferKeyEventL()和HandlePointerEventL()。由於Series60平台不支援筆寫輸入,所以主要使用OfferKeyEventL()。下面是一個簡單控制項處理按鍵事件的代碼: TKeyResponse CSimpleControl::OfferKeyEventL(const TKenEvent& aKeyEvent, TEventCode aType) { switch(aType) { case: EEventKey: if (aKeyEvent.iScanCode == EStdKeyNkp5 || aKeyEvent.iScanCode == EStdKeyEnter) iMyGameEngine->Fire(); break; case: EEventKeyDown: //.... case: EEventKeyUp: //.... } return EKeyWasNotConsumed; } |