在MFC9(在vc2008和vc2010中,已經有了CTabView的現成類)以前的版本中,有CListView,CTreeView,CEditView,CRichEditView等控件視圖類,但就是沒有類似的CTabView類,因工作需要,最近在做一個簡單的多標簽IE浏覽器,開發環境是vs2005,基本框架是sdi + chtmlview + ctabview,因此自行封裝實現了CTabView,並把它作為一個重要的基礎類來維護使用。先來說下我這個CTabView類的特點及功能:
(1)CTabView本質上就是一種窗口容器,基於CCtrlView實現,能夠容納類型為CWnd的所有窗口,並作為它的子窗口(為描述方便,在這特稱為視圖頁面),每個標簽對應一個視圖頁面。
(2)擴展了標准的標簽項數據結構TC_ITEM,即自定義了一個TC_EXTRA_ITEM擴展數據結構,該結構除包含標准的數據結構(第1個成員)外,還包括視圖頁面對象、內部標志、視圖頁面標題、視圖頁面關聯數據4種類型數據,擴展數據大小需要在創建後插入標簽前調用SetItemExtra設定。
(3)支持容納外部窗口和創建內部窗口,前者是指容納外面已經創建好的窗口;後者是根據窗口類型信息,由CTabView自己來管理創建視圖頁面。
(4)對於內部窗口的管理,為方便區分並有利於消息映射處理,因此窗口ID是唯一的,即在創建時分派一個新的不同的ID,銷毀時回收到ID數組中。而外部窗口ID則由外部管理。
(5)提供激活視圖頁面後的自定義處理,表現為OnViewActivated虛函數。
(6)提供右鍵單擊Tab標簽後的自定義處理,表現為OnTabContextMenu虛函數。
(7)提供Tab標簽提示信息的自定義處理,表現為UpdateTooltipText虛函數。
(8)提供CTabView視圖類的自繪處理(須設定TCS_OWNERDRAWFIXED樣式),表現為DrawItem虛函數。
(9)Tab標簽的文本默認是簡寫的,即當長度超過最大值時,多余部分用省略號...代替,同時也支持自定義處理,表現為ShortenTitle虛函數。
(10)對上述特點7,為了能支持派生類自定義處理,由於提示文本消息的發送者是CToolTipCtrl窗口,而不是CTabView本身,所以不能像TCN_SELCHANGE,NM_RCLICK等通知消息可以使用反射宏來實現,因此使用了窗口子類化來捕獲父窗口的TTN_GETDISPINFO通知消息實現的。這一行為也可以通過UpdateTooltipText來定制,當其返回值是TRUE時,表示允許消息默認被父窗口接收處理,否則,反之。
(11)對上述特點8,本可以重載OnChildNotify來實現WM_DRAWITEM消息的回調,但為了簡潔,如同TTN_GETDISPINFO通知消息,也是使用窗口子類化來捕獲實現的。
(12)對上述10和11的消息捕獲處理,使用了CBasicSubClassWnd類來實現,表現為重寫其SubWindowProc虛函數。
接下來看看CTabView類的接口定義,如下所示
1#ifndef _TABVIEW_H
2#define _TABVIEW_H
3
4#include <afxwin.h>
5#include "basic_subclasswnd.h"
6
7#define WC_TABVIEWA "SysTabControl32"
8#define WC_TABVIEWW L"SysTabControl32"
9
10#if (defined(_UNICODE)||defined(UNICODE))
11#define WC_TABVIEW WC_TABVIEWW
12#else
13#define WC_TABVIEW WC_TABVIEWA
14#endif
15
16class CTabView : public CCtrlView,private CBasicSubClassWnd
17{
18 DECLARE_DYNCREATE(CTabView)
19
20 struct TAB_VIEW
21 {
22 CWnd* pWnd; // 視圖頁面窗口
23 BOOL bInner; // 視圖頁面是否內部創建
24 LPTSTR pszTitle; // 視圖頁面標題
25 LPVOID pData; // 視圖頁面數據
26 };
27
28 //擴展TC_ITEM數據,第一個成員必須為TCITEMHEADER類型
29 struct TC_EXTRA_ITEM
30 {
31 TCITEMHEADER header;
32 TAB_VIEW view;
33 operator LPTCITEM() { return (LPTCITEM)this; }
34 };
35
36public:
37 CTabView();
38 virtual ~CTabView();
39
40 CTabCtrl& GetTabCtrl() const;
41
42 //在最後增加視圖頁面
43 CWnd* AddView(CRuntimeClass* pClass,CCreateContext* pContext=NULL,LPCTSTR pszTitle=NULL,
44 int iImage=-1,LPVOID pData=NULL,BOOL bActivate=TRUE);
45 BOOL AddView(CWnd* pWnd,LPCTSTR pszTitle=NULL,int iImage=-1,LPVOID pData=NULL,BOOL bActivate=TRUE);
46 //在某處插入視圖頁面
47 CWnd* InsertView(int iIndex,CRuntimeClass* pClass,CCreateContext* pContext=NULL,LPCTSTR pszTitle=NULL,
48 int iImage=-1,LPVOID pData=NULL,BOOL bActivate=TRUE);
49 BOOL InsertView(int iIndex,CWnd* pWnd,LPCTSTR pszTitle=NULL,int iImage=-1,
50 LPVOID pData=NULL,BOOL bActivate=TRUE);
51
52 //移除視圖頁面
53 void RemoveView(int iIndex,BOOL bDestroy=TRUE);
54 void RemoveView(CWnd* pWnd,BOOL bDestroy=TRUE);
55 //移除所有視圖頁面
56 void RemoveAllView();
57
58 //獲取活動視圖頁面
59 CWnd* GetActiveView() const;
60 int GetActiveViewIndex() const;
61 //設置活動視圖頁面
62 void SetActiveViewIndex(int iIndex);
63 void SetActiveView(const CWnd* pWnd);
64
65 //按索引獲取某個視圖頁面
66 CWnd* GetView(int iIndex) const;
67 //按窗口獲取視圖頁面的索引
68 int GetIndex(const CWnd* pWnd) const;
69
70 //獲取視圖頁面數量
71 int GetViewCount() const;
72
73 //設置視圖頁面的標題
74 BOOL SetViewTitle(int iIndex,LPCTSTR pszTitle);
75 BOOL SetViewTitle(const CWnd* pWnd,LPCTSTR pszTitle);
76 //獲取視圖頁面的標題
77 BOOL GetViewTitle(const CWnd* pWnd,LPTSTR& pszTitle) const;
78 BOOL GetViewTitle(int iIndex,LPTSTR& pszTitle) const;
79
80 //設置視圖頁面的圖像
81 BOOL SetViewImage(const CWnd* pWnd,int iImage);
82 BOOL SetViewImage(int iIndex,int iImage);
83 //獲取視圖頁面的圖像
84 BOOL GetViewImage(const CWnd* pWnd,int& iImage) const;
85 BOOL GetViewImage(int iIndex,int& iImage) const;
86
87 //設置視圖頁面的數據
88 BOOL SetViewData(int iIndex,LPVOID pData);
89 BOOL SetViewData(const CWnd* pWnd,LPVOID pData);
90 //獲取視圖頁面的數據
91 BOOL GetViewData(int iIndex,LPVOID& pData) const;
92 BOOL GetViewData(const CWnd* pWnd,LPVOID& pData) const;
93
94 //是否為內部創建的視圖頁面
95 BOOL IsInnerView(const CWnd* pWnd,BOOL& bInner) const;
96 BOOL IsInnerView(int iIndex,BOOL& bInner) const;
97
98 //設置tab標簽可顯示的最大文本長度
99 void SetTabMaxTextLen(size_t len);
100 //獲取tab標簽可顯示的最大文本長度
101 size_t GetTabMaxTextLen() const;
102
103 virtual void ShortenTitle(LPCTSTR pszTitle,CString& strShortTitle);
104
105protected:
106 BOOL SetViewInner(const CWnd* pWnd,BOOL bInner);
107 BOOL SetViewInner(int iIndex,BOOL bInner);
108 DWORD GetUniqueId();
109 BOOL IsValidViewIndex(int iIndex) const;
110 void UpdateLayout();
111
112protected:
113 virtual BOOL SubWindowProc(UINT uMsg,WPARAM wParam,LPARAM lParam);
114 virtual int CalcTabHeight();
115 virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItem);
116 virtual void OnViewActivated(int iIndex);
117 virtual void OnTabContextMenu(int iIndex,CPoint point);
118 virtual BOOL UpdateTooltipText(LPNMTTDISPINFO pTTDI);
119
120protected:
121 DECLARE_MESSAGE_MAP()
122 afx_msg int OnCreate(LPCREATESTRUCT lpcs);
123 afx_msg void OnDestroy();
124 afx_msg void OnNMRclick(NMHDR *pNMHDR, LRESULT *pResult);
125 afx_msg void OnTcnSelChange(NMHDR* pNMHDR,LRESULT *pResult);
126 afx_msg void OnSize(UINT nType, int cx, int cy);
127 afx_msg void OnSetFocus(CWnd* pOldWnd);
128 virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
129
130public:
131 virtual void OnInitialUpdate();
132
133private:
134 CArray<UINT,UINT> m_UniqueIDs;
135 int m_iActiveView;
136 int m_cyTabHeight;
137 size_t m_nMaxTabTextLen;
138};
139
140#endif
從上可知,CTabView主要包括2大類操作方法,一是針對視圖頁面窗口,二是針對Tab標簽擴展數據。說明如下:1)增加視圖頁面:AddIView,有2個重載形式,其中帶CRuntimeClass和CCreateConext類型參數的用於創建內部窗口,成功返回對應的窗口,否則為NULL;帶CWnd參數的用於容納外部窗口,成功返回TRUE,否則返回FALSE。2)插入視圖頁面:InsertView,有2個重載形式,其中帶CRuntimeClass和CCreateConext類型參數的用於創建內部窗口,成功返回對應的窗口,否則為NULL;帶CWnd參數的用於容納外部窗口,成功返回TRUE,否則返回FALSE。3)移除某個視圖頁面:RemoveView,有2個重載形式,其中int類型參數的用於按索引移除,CWnd類型的用於按窗口對象移除。4)移除所有視圖頁面:RemoveAllView。5)獲取活動視圖頁面:有2個方法,GetActiveView如果無活動視圖頁面,則返回NULL,否則返回對應的窗口;GetActiveViewIndex如果無活動視圖頁面,則返回-1,否則返回>=0的索引值。5)設置活動視圖頁面:有2個方法:SetActiveView按窗口來設置,SetActiveViewIndex按索引來設置。6)視圖頁面窗口與索引的相互轉換:GetView由窗口得到其索引,操作失敗返回-1,否則返回>=0的索引值。GetIndex由索引得到窗口,失敗返回NULL,否則返回對應的窗口。7)獲取視圖頁面的數量:GetViewCount。8)設置視圖頁面的標題:SetViewTitle,有2個重載形式,int類型參數的按索引設置,CWnd類型參數的按窗口設置,成功返回TRUE,否則返回FALSE。9)獲取視圖頁面的標題:GetViewTitle,有2個重載形式,int類型參數的按索引獲取,CWnd類型參數的按窗口獲取,成功返回TRUE,否則返回FALSE。10)設置視圖頁面的圖像:有2個重載形式,int類型參數的按索引設置,CWnd類型參數的按窗口設置,成功返回TRUE,否則返回FALSE。11)獲取視圖頁面的圖像:有2個重載形式,int類型參數的按索引獲取,CWnd類型參數的按窗口獲取,成功返回TRUE,否則返回FALSE。12)設置視圖頁面的數據:有2個重載形式,int類型參數的按索引設置,CWnd類型參數的按窗口設置,成功返回TRUE,否則返回FALSE。13)獲取視圖頁面的數據:有2個重載形式,int類型參數的按索引獲取,CWnd類型參數的按窗口獲取,成功返回TRUE,否則返回FALSE。14)視圖頁面內部標志查詢:有2個重載形式,int類型參數的按索引查詢,CWnd類型參數的按窗口查詢,成功返回TRUE,否則返回FALSE,當操作成功時,參數bInner為TRUE表示為CTabView內部創建的窗口,否則表示外部窗口。
最後列出主要部分的實現代碼,如下所示
1CTabCtrl& CTabView::GetTabCtrl() const
2{
3 return *(CTabCtrl*)this;
4}
5
6CWnd* CTabView::AddView(CRuntimeClass* pClass,CCreateContext* pContext,LPCTSTR pszTitle,
7 int iImage,LPVOID pData,BOOL bActivate)
8{
9 return InsertView(GetViewCount(),pClass,pContext,pszTitle,iImage,pData,bActivate);
10}
11
12BOOL CTabView::AddView(CWnd* pWnd,LPCTSTR pszText,int iImage,LPVOID pData,BOOL bActivate)
13{
14 return InsertView(GetViewCount(),pWnd,pszText,iImage,pData,bActivate);
15}
16
17CWnd* CTabView::InsertView(int iIndex,CRuntimeClass* pClass,CCreateContext* pContext,
18 LPCTSTR pszTitle,int iImage,LPVOID pData,BOOL bActivate)
19{
20 ASSERT(::IsWindow(CCtrlView::m_hWnd));
21 ASSERT(pClass!=NULL);
22 ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CWnd)));
23 ASSERT(AfxIsValidAddress(pClass,sizeof(CRuntimeClass),FALSE));
24
25 CWnd* pWnd = (CWnd*)pClass->CreateObject();
26 if (NULL==pWnd) return NULL;
27 ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CWnd)));
28
29 CCreateContext context;
30 if(pContext==NULL)
31 {
32 CView* pOldView=(CView*)GetActiveView();
33 if(pOldView!=NULL && pOldView->IsKindOf(RUNTIME_CLASS(CView)))
34 {
35 ASSERT(context.m_pCurrentFrame==NULL);
36 context.m_pLastView=pOldView;
37 context.m_pCurrentDoc=pOldView->GetDocument();
38 if(context.m_pCurrentDoc!=NULL)
39 {
40 context.m_pNewDocTemplate=context.m_pCurrentDoc->GetDocTemplate();
41 }
42 }
43 pContext=&context;
44 }
45 if (!pWnd->Create(NULL,NULL,WS_CHILD,CRect(0,0,0,0),this,GetUniqueId(),pContext))
46 {
47 delete pWnd; return NULL;
48 }
49 if (!InsertView(iIndex,pWnd,pszTitle,iImage,pData,bActivate))
50 {
51 pWnd->DestroyWindow(); return NULL;
52 }
53 SetViewInner(iIndex,TRUE);
54 return pWnd;
55}
56
57BOOL CTabView::InsertView(int iIndex,CWnd* pWnd,LPCTSTR pszTitle,int iImage,LPVOID pData,BOOL bActivate)
58{
59 ASSERT(::IsWindow(CCtrlView::m_hWnd));
60 ASSERT(pWnd&&::IsWindow(pWnd->m_hWnd));
61
62 CString str;
63 ShortenTitle(pszTitle,str);
64
65 TC_EXTRA_ITEM ti;
66 ti.header.mask = TCIF_PARAM|TCIF_TEXT|TCIF_IMAGE;
67 ti.header.pszText = (LPTSTR)(LPCTSTR)str;
68 if (pszTitle)
69 {
70 ti.view.pszTitle = new TCHAR[_tcslen(pszTitle)+1];
71 if (NULL==ti.view.pszTitle)
72 return FALSE;
73 _tcscpy(ti.view.pszTitle,pszTitle);
74 }
75 else
76 {
77 ti.view.pszTitle = NULL;
78 }
79 ti.header.iImage = iImage;
80 ti.view.pWnd = pWnd;
81 ti.view.pData = pData;
82 if (-1==GetTabCtrl().InsertItem(iIndex,ti))
83 {
84 if (pszTitle) delete []ti.view.pszTitle;
85 return FALSE;
86 }
87 pWnd->SetParent(this);
88 if (bActivate)
89 {
90 SetActiveViewIndex(iIndex);
91 OnViewActivated(iIndex);
92 }
93 return TRUE;
94}
95
96void CTabView::RemoveView(CWnd* pWnd,BOOL bDestroy)
97{
98 RemoveView(GetIndex(pWnd),bDestroy);
99}
100
101void CTabView::RemoveView(int iIndex,BOOL bDestroy)
102{
103 ASSERT(::IsWindow(CCtrlView::m_hWnd));
104 ASSERT(IsValidViewIndex(iIndex));
105
106 CWnd* pWnd = GetView(iIndex);
107 ASSERT(pWnd);
108
109 BOOL bInner;
110 if (IsInnerView(iIndex,bInner) && bInner)
111 m_UniqueIDs.Add(pWnd->GetDlgCtrlID());
112 bDestroy ? pWnd->DestroyWindow() : pWnd->ShowWindow(SW_HIDE);
113
114 LPTSTR pszTitle;
115 if (GetViewTitle(iIndex,pszTitle))
116 delete []pszTitle;
117
118 ATLVERIFY(GetTabCtrl().DeleteItem(iIndex));
119 if(m_iActiveView == iIndex)
120 {
121 m_iActiveView = -1;
122 if(iIndex > 0)
123 {
124 SetActiveViewIndex(iIndex-1);
125 }
126 else if(GetViewCount() > 0)
127 {
128 SetActiveViewIndex(iIndex);
129 }
130 else
131 {
132 SetRedraw(TRUE);
133 Invalidate();
134 UpdateWindow();
135 }
136 }
137 else
138 {
139 iIndex = (iIndex < m_iActiveView) ? (m_iActiveView - 1) : m_iActiveView;
140 m_iActiveView = -1;
141 SetActiveViewIndex(iIndex);
142 }
143 if (-1!=m_iActiveView)
144 {
145 OnViewActivated(m_iActiveView);
146 }
147}
148
149void CTabView::RemoveAllView()
150{
151 LPTSTR pszTitle;
152 for (int iIndex=0;iIndex<GetViewCount();++iIndex)
153 {
154 GetView(iIndex)->DestroyWindow();
155 if (GetViewTitle(iIndex,pszTitle))
156 delete []pszTitle;
157 }
158 GetTabCtrl().DeleteAllItems();
159}
160
161int CTabView::GetViewCount() const
162{
163 ASSERT(::IsWindow(CCtrlView::m_hWnd));
164 return GetTabCtrl().GetItemCount();
165}
166
167CWnd* CTabView::GetView(int iIndex) const
168{
169 ASSERT(::IsWindow(CCtrlView::m_hWnd));
170 ASSERT(IsValidViewIndex(iIndex));
171
172 TC_EXTRA_ITEM ti;
173 ti.header.mask = TCIF_PARAM;
174 if (!GetTabCtrl().GetItem(iIndex,ti))
175 return NULL;
176 return ti.view.pWnd;
177}
178
179int CTabView::GetIndex(const CWnd* pWnd) const
180{
181 ASSERT(::IsWindow(CCtrlView::m_hWnd));
182
183 int count = GetTabCtrl().GetItemCount();
184 for (int i=0;i<count;++i)
185 {
186 if (GetView(i)==pWnd)
187 return i;
188 }
189 return -1;
190}
191
192CWnd* CTabView::GetActiveView() const
193{
194 ASSERT(::IsWindow(CCtrlView::m_hWnd));
195 return (-1==m_iActiveView) ? NULL : GetView(m_iActiveView);
196}
197
198int CTabView::GetActiveViewIndex() const
199{
200 return m_iActiveView;
201}
202
203void CTabView::SetActiveView(const CWnd* pWnd)
204{
205 SetActiveViewIndex(GetIndex(pWnd));
206}
207
208void CTabView::SetActiveViewIndex(int iIndex)
209{
210 ASSERT(::IsWindow(CCtrlView::m_hWnd));
211 ASSERT(IsValidViewIndex(iIndex));
212
213 if (iIndex==m_iActiveView)
214 return;
215
216// SetRedraw(FALSE);
217 if (-1!=m_iActiveView)
218 {
219 GetView(m_iActiveView)->ShowWindow(SW_HIDE);
220 }
221 GetTabCtrl().SetCurSel(iIndex);
222 m_iActiveView = iIndex;
223 GetView(m_iActiveView)->ShowWindow(SW_SHOWNORMAL);
224
225 UpdateLayout();
226
227 //SetRedraw(TRUE);
228 //RedrawWindow(NULL, NULL, RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
229
230 if (GetFocus()!=this)
231 {
232 GetView(iIndex)->SetFocus();
233 }
234}
235
236BOOL CTabView::SetViewTitle(const CWnd* pWnd,LPCTSTR pszTitle)
237{
238 return SetViewTitle(GetIndex(pWnd),pszTitle);
239}
240
241BOOL CTabView::SetViewTitle(int iIndex,LPCTSTR pszTitle)
242{
243 ASSERT(::IsWindow(CCtrlView::m_hWnd));
244 ASSERT(IsValidViewIndex(iIndex));
245
246 TC_EXTRA_ITEM ti;
247 ti.header.mask = TCIF_PARAM;
248 if (!GetTabCtrl().GetItem(iIndex,ti))
249 return FALSE;
250 delete []ti.view.pszTitle;
251
252 CString str;
253 ShortenTitle(pszTitle,str);
254
255 ti.header.mask = TCIF_TEXT|TCIF_PARAM;
256 ti.header.pszText = (LPTSTR)(LPCTSTR)str;
257 if (pszTitle)
258 {
259 ti.view.pszTitle = new TCHAR[_tcslen(pszTitle)+1];
260 if (NULL==ti.view.pszTitle)
261 return FALSE;
262 _tcscpy(ti.view.pszTitle,pszTitle);
263 }
264 if (!GetTabCtrl().SetItem(iIndex,ti))
265 {
266 if (pszTitle) delete []ti.view.pszTitle;
267 return FALSE;
268 }
269 return TRUE;
270}
271
272BOOL CTabView::GetViewTitle(const CWnd* pWnd,LPTSTR& pszTitle) const
273{
274 return GetViewTitle(GetIndex(pWnd),pszTitle);
275}
276
277BOOL CTabView::GetViewTitle(int iIndex,LPTSTR& pszTitle) const
278{
279 ASSERT(IsValidViewIndex(iIndex));
280
281 TC_EXTRA_ITEM ti;
282 ti.header.mask = TCIF_PARAM;
283 if (!GetTabCtrl().GetItem(iIndex,ti))
284 return FALSE;
285 pszTitle = ti.view.pszTitle;
286 return TRUE;
287}
288
289BOOL CTabView::SetViewImage(const CWnd* pWnd,int iImage)
290{
291 return SetViewImage(GetIndex(pWnd),iImage);
292}
293
294BOOL CTabView::SetViewImage(int iIndex,int iImage)
295{
296 ASSERT(IsValidViewIndex(iIndex));
297
298 TC_EXTRA_ITEM ti;
299 ti.header.mask = TCIF_IMAGE;
300 ti.header.iImage = iImage;
301 return GetTabCtrl().SetItem(iIndex,ti);
302}
303
304BOOL CTabView::GetViewImage(const CWnd* pWnd,int& iImage) const
305{
306 return GetViewImage(GetIndex(pWnd),iImage);
307}
308
309BOOL CTabView::GetViewImage(int iIndex,int& iImage) const
310{
311 ASSERT(IsValidViewIndex(iIndex));
312
313 TC_EXTRA_ITEM ti;
314 ti.header.mask = TCIF_IMAGE;
315 if (!GetTabCtrl().GetItem(iIndex,ti))
316 return FALSE;
317 iImage = ti.header.iImage;
318 return TRUE;
319}
320
321BOOL CTabView::SetViewData(const CWnd* pWnd,LPVOID pData)
322{
323 return SetViewData(GetIndex(pWnd),pData);
324}
325
326BOOL CTabView::SetViewData(int iIndex,LPVOID pData)
327{
328 ASSERT(IsValidViewIndex(iIndex));
329
330 TC_EXTRA_ITEM ti;
331 ti.header.mask = TCIF_PARAM;
332 if (!GetTabCtrl().GetItem(iIndex,ti))
333 return FALSE;
334 ti.header.mask = TCIF_PARAM;
335 ti.view.pData = pData;
336 return GetTabCtrl().SetItem(iIndex,ti);
337}
338
339BOOL CTabView::GetViewData(const CWnd* pWnd,LPVOID& pData) const
340{
341 return GetViewData(GetIndex(pWnd),pData);
342}
343
344BOOL CTabView::GetViewData(int iIndex,LPVOID& pData) const
345{
346 TC_EXTRA_ITEM ti;
347 ti.header.mask = TCIF_PARAM;
348 if (!GetTabCtrl().GetItem(iIndex,ti))
349 return FALSE;
350 pData = ti.view.pData;
351 return TRUE;
352}
353
354BOOL CTabView::IsInnerView(const CWnd* pWnd,BOOL& bInner) const
355{
356 return IsInnerView(GetIndex(pWnd),bInner);
357}
358
359BOOL CTabView::IsInnerView(int iIndex,BOOL& bInner) const
360{
361 ASSERT(IsValidViewIndex(iIndex));
362
363 TC_EXTRA_ITEM ti;
364 ti.header.mask = TCIF_PARAM;
365 if (!GetTabCtrl().GetItem(iIndex,ti))
366 return FALSE;
367 bInner = ti.view.bInner;
368 return TRUE;
369}
摘自 天道酬勤