加入事件 (ATL 教學課程,第 5 部分)
在此步驟中,您會將 和 ClickOut
事件新增ClickIn
至 ATL 控件。 ClickIn
如果使用者在多邊形內按兩下 ,並在用戶按兩下外部時引發ClickOut
事件。 新增事件的工作如下所示:
ClickIn
新增和ClickOut
方法產生類型連結庫
實作連接點介面
新增 ClickIn 和 ClickOut 方法
當您在步驟 2 中建立 ATL 控制項時,選取 [ 連接點 ] 複選框。 這會在 Polygon.idl 檔案中建立 _IPolyCtlEvents
介面。 請注意,介面名稱開頭為底線。 這是表示介面是內部介面的慣例。 因此,可讓您流覽 COM 物件的程式可以選擇不向使用者顯示介面。 另請注意,選取 [連接點 ] 會在 Polygon.idl 檔案中新增下列這一行,以指出 _IPolyCtlEvents
這是預設的來源介面:
[default, source] dispinterface _IPolyCtlEvents;
來源屬性表示控件是通知的來源,因此它會在容器上呼叫這個介面。
現在,將 ClickIn
和 ClickOut
方法新增至 _IPolyCtlEvents
介面。
若要新增 ClickIn 和 ClickOut 方法
在 方案總管 中,開啟 Polygon.idl,並在 PolygonLib 連結庫的宣告中
methods:
dispInterface_IPolyCtlEvents
新增下列程式代碼:[id(1), helpstring("method ClickIn")] void ClickIn([in] LONG x,[in] LONG y); [id(2), helpstring("method ClickOut")] void ClickOut([in] LONG x,[in] LONG y);
ClickIn
和 ClickOut
方法會採用按兩下點的 x 和 y 座標做為參數。
產生類型連結庫
此時產生類型連結庫,因為專案會使用它來取得它建構連接點介面和控件連接點容器介面所需的資訊。
產生類型連結庫
重建您的專案。
-或-
以滑鼠右鍵按兩下 方案總管中的 Polygon.idl 檔案,然後按下快捷方式選單上的 [編譯]。
這會建立Polygon.tlb檔案,也就是您的類型連結庫。 Polygon.tlb 檔案無法從 方案總管 看見,因為它是二進位檔,無法直接檢視或編輯。
實作連接點介面
實作控件的連接點介面和連接點容器介面。 在 COM 中,事件是透過連接點的機制來實作。 若要從 COM 物件接收事件,容器會建立與 COM 物件實作之連接點的諮詢連線。 因為 COM 物件可以有多個連接點,因此 COM 物件也會實作連接點容器介面。 透過這個介面,容器可以判斷支援哪些連接點。
實作連接點的介面稱為 IConnectionPoint
,而實作連接點容器的介面稱為 IConnectionPointContainer
。
為了協助實 IConnectionPoint
作 ,您將使用實作連接點精靈。 此精靈會 IConnectionPoint
讀取您的類型連結庫,並針對可引發的每個事件實作函式,以產生介面。
實作連接點
在 方案總管 中,開啟 _IPolyCtlEvents_CP.h,然後在 類別的
CProxy_IPolyCtlEvents
語句底下public:
新增下列程序代碼:VOID Fire_ClickIn(LONG x, LONG y) { T* pT = static_cast<T*>(this); int nConnectionIndex; CComVariant* pvars = new CComVariant[2]; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p); if (pDispatch != NULL) { pvars[1].vt = VT_I4; pvars[1].lVal = x; pvars[0].vt = VT_I4; pvars[0].lVal = y; DISPPARAMS disp = { pvars, NULL, 2, 0 }; pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); } } delete[] pvars; } VOID Fire_ClickOut(LONG x, LONG y) { T* pT = static_cast<T*>(this); int nConnectionIndex; CComVariant* pvars = new CComVariant[2]; int nConnections = m_vec.GetSize(); for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++) { pT->Lock(); CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex); pT->Unlock(); IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p); if (pDispatch != NULL) { pvars[1].vt = VT_I4; pvars[1].lVal = x; pvars[0].vt = VT_I4; pvars[0].lVal = y; DISPPARAMS disp = { pvars, NULL, 2, 0 }; pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL); } } delete[] pvars; }
您會看到此檔案有名為 的類別 CProxy_IPolyCtlEvents
,其衍生自 IConnectionPointImpl
。 _IPolyCtlEvents_CP.h 現在會定義兩個方法 Fire_ClickIn
,並 Fire_ClickOut
採用兩個座標參數。 當您想要從控件引發事件時,您可以呼叫這些方法。
藉由建立已選取 [連接點] 選項的控件,就會為您產生 _IPolyCtlEvents_CP.h 檔案。 它也會新增 CProxy_PolyEvents
和 IConnectionPointContainerImpl
至控件的多重繼承清單,並藉由將適當的專案新增至 COM 對應,為您公開 IConnectionPointContainer
。
您已完成實作程式代碼以支援事件。 現在,新增一些程序代碼,以在適當的時刻引發事件。 請記住,當使用者按兩下控制件中的滑鼠左鍵時,您將會引發 ClickIn
或 ClickOut
事件。 若要瞭解使用者何時按鍵,請新增訊息的 WM_LBUTTONDOWN
處理程式。
若要新增WM_LBUTTONDOWN訊息的處理程式
在 [類別檢視] 中
CPolyCtl
,以滑鼠右鍵單擊類別,然後按下快捷方式功能表上的 [ 屬性 ]。在 [ 屬性] 視窗中,按兩下 [訊息] 圖示,然後按下
WM_LBUTTONDOWN
左側清單。從出現的下拉式清單中,按兩下 <[新增> OnLButtonDown]。 處理程式
OnLButtonDown
宣告會新增至 PolyCtl.h,並將處理程式實作新增至PolyCtl.cpp。
接下來,修改處理程式。
若要修改 OnLButtonDown 方法
變更程式代碼,其中包含
OnLButtonDown
PolyCtl.cpp 中的方法(刪除精靈放置的任何程序代碼),使其看起來像這樣:LRESULT CPolyCtl::OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) { HRGN hRgn; WORD xPos = LOWORD(lParam); // horizontal position of cursor WORD yPos = HIWORD(lParam); // vertical position of cursor CalcPoints(m_rcPos); // Create a region from our list of points hRgn = CreatePolygonRgn(&m_arrPoint[0], m_nSides, WINDING); // If the clicked point is in our polygon then fire the ClickIn // event otherwise we fire the ClickOut event if (PtInRegion(hRgn, xPos, yPos)) Fire_ClickIn(xPos, yPos); else Fire_ClickOut(xPos, yPos); // Delete the region that we created DeleteObject(hRgn); return 0; }
此程式代碼會使用函式中 OnDraw
計算的點來建立區域,以透過呼叫 PtInRegion
來偵測使用者的滑鼠點選。
uMsg 參數是所處理 Windows 訊息的標識碼。 這可讓您有一個函式來處理一系列訊息。 wParam 和 lParam 參數是所處理訊息的標準值。 bHandled 參數可讓您指定函式是否處理訊息。 根據預設,值會設定為TRUE,表示函式已處理訊息,但您可以將它設定為 FALSE。 這會導致 ATL 繼續尋找另一個訊息處理程式函式來傳送訊息。
建置和測試控制項
現在試用您的事件。 建置控件,然後再次啟動 ActiveX 控制件測試容器。 這次,請檢視事件記錄檔視窗。 若要將事件路由至輸出視窗,請單擊 [選項] 功能表中的 [記錄],然後選取 [記錄至輸出] 視窗。 插入 控件,然後嘗試在視窗中按兩下。 請注意, ClickIn
如果您在填滿的多邊形內按兩下,並在 ClickOut
其外部按兩下時引發。
接下來,您將新增屬性頁。