加入事件 (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 程式庫的宣告中
dispInterface_IPolyCtlEvents
methods:
新增下列程式碼:[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
採用兩個座標參數。 當您想要從控制項引發事件時,您可以呼叫這些方法。
藉由建立已選取 [連線ion 點 ] 選項的控制項 ,就會為您產生 _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
其外部按一下時引發。
接下來,您將新增屬性頁。