欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
VC知識庫文章 - MFC程序員的WTL指南: Part VIII - 屬性頁(yè)與向導



原作 :Michael Dunn [英文原文]
翻譯 :Orbit(桔皮干了) [http://www.winmsg.com/cn/orbit.htm]

下載演示程序代碼

本章內容 介紹

甚至在成為Windows 95的通用控件之前,使用屬性表來(lái)表示一些選項就已經(jīng)成為一種很流行的方式。向導模式的屬性表通常用來(lái)引導用戶(hù)安裝軟件或完成其他復雜的工作。WTL對這兩種方式的屬性表都提供了很好的支持,可以使用前面介紹的與對話(huà)框相關(guān)的特性,如DDX和DDV。在本章我將演示如何創(chuàng )建一個(gè)基本的屬性表和向導,如何處理屬性頁(yè)發(fā)送的通知消息和事件。

WTL 的屬性表類(lèi)

實(shí)現一個(gè)屬性表需要CPropertySheetWindow和CPropertySheetImpl兩個(gè)類(lèi)聯(lián)合使用,它們都定義在atldlgs.h頭文件中。CPropertySheetWindow類(lèi)是一個(gè)窗口接口類(lèi)(也就是說(shuō)是一個(gè)CWindow派生類(lèi)),CPropertySheetImpl有消息映射鏈和窗口的完整實(shí)現,這和ATL的基本窗口類(lèi)相似,它需要CWindow和CWindowImpl兩個(gè)類(lèi)聯(lián)合使用。

CPropertySheetWindow類(lèi)封裝了對各種PSM_* 消息的處理,例如,SetActivePageByID()封裝了PSM_SETCURSELID消息。CPropertySheetImpl類(lèi)管理一個(gè)PROPSHEETHEADER結構和一個(gè)HPROPSHEETPAGE類(lèi)型的數組,CPropertySheetImpl類(lèi)還提供了
一些方法用來(lái)填充PROPSHEETHEADER結構,添加或刪除屬性頁(yè),你也可以使用m_psh成員變量直接操作PROPSHEETHEADER結構。

最后,CPropertySheet類(lèi)是CPropertySheetImpl類(lèi)的一個(gè)特例,你可以直接使用它而不需要定制整個(gè)屬性表。

CPropertySheetImpl 的方法


下面是CPropertySheetImpl類(lèi)的一些重要方法。由于許多方法僅僅是對窗口消息的封裝,所以就不在這里列出,你可以查看atldlgs.h中完整的函數清單。

CPropertySheetImpl(_U_STRINGorID title = (LPCTSTR) NULL,                   UINT uStartPage = 0, HWND hWndParent = NULL)

CPropertySheetImpl類(lèi)的構造函數允許你使用一些常用的屬性(默認值),所以就不需要在調用其他的方法設置它們。title指定顯示在屬性表的標題欄的文字,_U_STRINGorID是一個(gè)WTL的工具類(lèi),它可以自動(dòng)轉換LPCTSTR和資源ID,例如,下面的兩行代碼都是正確的:

  CPropertySheetImpl mySheet ( IDS_SHEET_TITLE );  CPropertySheetImpl mySheet ( _T("My prop sheet") );

IDS_SHEET_TITLE 是字符串的ID。 uStartPage 是屬性表啟動(dòng)時(shí)激活的屬性頁(yè),是一個(gè)從0開(kāi)始的索引。hWndParent 是屬性表的父窗口的句柄。

BOOL AddPage(HPROPSHEETPAGE hPage)
BOOL AddPage(LPCPROPSHEETPAGE pPage)

添加一個(gè)屬性頁(yè)。如果這個(gè)屬性頁(yè)已經(jīng)創(chuàng )建了,你可以使用第一個(gè)重載函數,使用屬性頁(yè)的句柄(HPROPSHEETPAGE)作為參數。通常是使用第二個(gè)重載函數,使用這個(gè)重載函數只需設置一個(gè)PROPSHEETPAGE數據結構(后面會(huì )講到,它和CPropertyPageImpl一起協(xié)同工作),CPropertySheetImpl會(huì )為你創(chuàng )建并管理這個(gè)屬性頁(yè)。

BOOL RemovePage(HPROPSHEETPAGE hPage)
BOOL RemovePage(int nPageIndex)

移除一個(gè)屬性頁(yè),可以使用屬性頁(yè)的句柄或索引。

BOOL SetActivePage(HPROPSHEETPAGE hPage)
BOOL SetActivePage(int nPageIndex)

設置屬性表的活動(dòng)頁(yè)面??梢允褂脤傩皂?yè)的句柄或索引。你可以在屬性表創(chuàng )建(顯示)之前使用這個(gè)方法動(dòng)態(tài)的設置處于激活的屬性頁(yè)。

void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)

使之屬性表窗口的標題文字。nStyle可以是0或PSH_PROPTITLE,如果是PSH_PROPTITLE,則屬性表就具有PSH_PROPTITLE樣式,這樣系統會(huì )在你通過(guò)lpszText參數指定的窗口標題前添加字符串“Properties for”。

void SetWizardMode()

設置PSH_WIZARD樣式,將屬性表改稱(chēng)向導模式,這個(gè)函數必須在屬性表顯示之前調用。

void EnableHelp()

設置PSH_HASHELP樣式,將在屬性表中添加幫助按鈕。需要注意的是你還要在每個(gè)屬性頁(yè)中使幫助按鈕可用并提供幫助才能使之生效。

INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())

創(chuàng )建并顯示一個(gè)模式的屬性表,返回正值表示操作成功,有關(guān)PropertySheet() API的幫助文檔有有關(guān)返回值的詳細解釋?zhuān)绻l(fā)生錯誤,屬性表無(wú)法創(chuàng )建,DoModal()返回-1。

HWND Create(HWND hWndParent = NULL)

創(chuàng )建并顯示一個(gè)無(wú)模式的屬性表,返回值是窗口的句柄,如果發(fā)生錯誤,屬性表無(wú)法創(chuàng )建,Create()返回NULL。

WTL 的屬性頁(yè)類(lèi)

WTL對屬性頁(yè)的封裝類(lèi)與屬性表的封裝類(lèi)相似,有一個(gè)窗口接口類(lèi) CPropertyPageWindow 和一個(gè)實(shí)現類(lèi) CPropertyPageImpl 。CPropertyPageWindow 很小,包含最常用的需要在作為父窗口的屬性表中調用的方法。

CPropertyPageImpl 是從 CDialogImplBaseT派生,由于屬性頁(yè)是從對話(huà)框資源中創(chuàng )建的,這就意味著(zhù)所有可以在對話(huà)框中使用的WTL的特性都可以在屬性頁(yè)中使用,如DDX和DDV。CPropertyPageImpl 有兩個(gè)主要作用:管理一個(gè)PROPSHEETPAGE數據結構(保存在成員變量m_psp中),處理所有PSN_開(kāi)頭的通知消息。對于很簡(jiǎn)單的屬性頁(yè)可以直接使用CPropertyPage類(lèi),這個(gè)類(lèi)只適合與用戶(hù)沒(méi)有任何交互的屬性頁(yè),例如“關(guān)于”頁(yè)面或者向導中的介紹頁(yè)面

也可以創(chuàng )建含有ActiveX控件的屬性頁(yè)。首先,這需要在stdafx.h文件中添加對atlhost.h的包含,還要使用CAxPropertyPageImpl代替CPropertyPageImpl。對于簡(jiǎn)單的頁(yè)面可以使用CAxPropertyPage代替CPropertyPage。

CPropertyPageImpl 的方法

CPropertyPageImpl 管理著(zhù)一個(gè) PROPSHEETPAGE 結構,也就是公有成員 m_psp。CPropertyPageImpl還重載了PROPSHEETPAGE*操作符,所以你可以將CPropertyPageImpl傳遞給需要LPPROPSHEETPAGE 或 LPCPROPSHEETPAGE 類(lèi)型的參數的方法,例如CPropertySheetImpl::AddPage()。

CPropertyPageImpl的構造函數允許你設置頁(yè)面的標題,標題通常顯示在頁(yè)面的Tab標簽上:

CPropertyPageImpl(_U_STRINGorID title = (LPCTSTR) NULL)

如果你不想讓屬性表創(chuàng )建屬性頁(yè)面而是想手工創(chuàng )建頁(yè)面,你可以調用Create():

HPROPSHEETPAGE Create()

Create() 只是調用用m_psp做參數調用了 CreatePropertySheetPage() 。如果你向一個(gè)已經(jīng)創(chuàng )建的屬性表添加屬性頁(yè)或者向另一個(gè)不在控制的屬性表添加屬性頁(yè)(例如,處理系統Shell擴展的屬性表),那就只需要調用Create()函數。

下面的三個(gè)方法用于設置屬性頁(yè)的各種標題文本:

void SetTitle(_U_STRINGorID title)
void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)
void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)

第一個(gè)方法改變頁(yè)面標簽的文字,另外幾個(gè)用來(lái)設置Wizard97樣式的向導中屬性頁(yè)頂部的文字。

void EnableHelp()

設置m_psp中的PSP_HASHELP標志,當本頁(yè)面激活時(shí)使屬性表的幫助按鈕可用。

處理通知消息

CPropertyPageImpl有一個(gè)消息映射處理WM_NOTIFY。如果通知代碼是PSN_*的值,OnNotify()就會(huì )調用相應的通知處理函數。這使用了編譯階段虛函數機制,從而使得派生類(lèi)可以很容易的重載這些處理函數。

由于WTL 3和WTL 7設計的改變,從而存在兩套不同的通知處理機制。在WTL 3中通知處理函數返回的值與PSN_*消息的返回值不同,例如,WTL 3是這樣處理PSN_WIZFINISH的:

case PSN_WIZFINISH:
lResult = !pT->OnWizardFinish();
break;

OnWizardFinish()期望返回TRUE結束向導,FALSE阻止關(guān)閉向導。這個(gè)方法很簡(jiǎn)陋,但是IE5的通用控件對PSN_WIZFINISH處理的返回值添加了新解釋?zhuān)祷匦枰@得焦點(diǎn)的窗口的句柄。WTL 3的程序將不能使用這個(gè)特性,因為它對所有非0的返回值都做相同的處理。

在WTL 7中,OnNotify() 沒(méi)有改變 PSN_* 消息的返回值,處理函數返回任何文檔中規定的合法數值和正確的行為。當然,為了向前兼容,WTL 3 仍然使用當前默認的工作方式,要使用WTL 7的消息處理方式,你必須在中including atldlgs.h一行之前添加一行定義:

#define _WTL_NEW_PAGE_NOTIFY_HANDLERS

編寫(xiě)新的代碼沒(méi)有理由不使用WTL 7的消息處理函數,所以這里就不介紹WTL 3的消息處理方式。

CPropertyPageImpl 為所有消息提供了默認的通知消息處理函數,你可以重載與你的程序有關(guān)的消息處理函數完成特殊的操作。默認的消息處理函數和相應的行為如下:

int OnSetActive() - 允許頁(yè)面成為激活狀態(tài)

BOOL OnKillActive() - 允許頁(yè)面成為非激活狀態(tài)

int OnApply() - 返回 PSNRET_NOERROR 表示應用操作成功完成

void OnReset() - 無(wú)相應的動(dòng)作

BOOL OnQueryCancel() - 允許取消操作

int OnWizardBack() - 返回到前一個(gè)頁(yè)面

int OnWizardNext() - 進(jìn)行到下一個(gè)頁(yè)面

INT_PTR OnWizardFinish() - 允許向導結束

void OnHelp() - 無(wú)相應的動(dòng)作

BOOL OnGetObject(LPNMOBJECTNOTIFY lpObjectNotify) - 無(wú)相應的動(dòng)作

int OnTranslateAccelerator(LPMSG lpMsg) - 返回 PSNRET_NOERROR 表示消息沒(méi)有被處理

HWND OnQueryInitialFocus(HWND hWndFocus) - 返回 NULL 表示將按Tab Order順序的第一個(gè)控件設為焦點(diǎn)狀態(tài)

創(chuàng )建一個(gè)屬性表

關(guān)于這些類(lèi)的解釋就全部講完了,現在需要一個(gè)例子程序演示如何使用它們。本章的例子工程是一個(gè)簡(jiǎn)單的SDI程序,它在客戶(hù)區顯示一幅圖片并使用一總顏色填充背景,使用的圖片和顏色可以通過(guò)一個(gè)選項對話(huà)框(一個(gè)屬性表)來(lái)設置,還有一個(gè)向導(稍后會(huì )介紹)。

最簡(jiǎn)單的屬性表

首先用WTL的向導創(chuàng )建一個(gè)SDI工程,然后為關(guān)于對話(huà)框添加一個(gè)屬性表。首先改變向導創(chuàng )建的關(guān)于對話(huà)框樣式,使它用起來(lái)像個(gè)屬性頁(yè)。

第一步就是去除OK按鈕,因為屬性表不希望屬性頁(yè)自己關(guān)閉。在Style Tab中,將對話(huà)框樣式改為Child,Thin Border,選擇Title Bar,在More Styles tab,選擇Disabled。

第二步(也是最后一步)是在OnAppAbout()的處理函數中創(chuàng )建一個(gè)屬性表,我們使用非定制的CPropertySheet 和 CPropertyPage類(lèi):

LRESULT CMainFrame::OnAppAbout(...){CPropertySheet sheet ( _T("About PSheets") );CPropertyPage<IDD_ABOUTBOX> pgAbout;     sheet.AddPage ( pgAbout );    sheet.DoModal();    return 0;}

結果看起來(lái)向下面這樣:

創(chuàng )建一個(gè)有用的屬性頁(yè)

并不是每一個(gè)屬性表中的每一個(gè)屬性頁(yè)都像關(guān)于對話(huà)框這么簡(jiǎn)單,大多數屬性頁(yè)需要使用CPropertyPageImpl的派生類(lèi),所以我們現在就看一個(gè)這樣的類(lèi)。我們創(chuàng )建了一個(gè)新的屬性頁(yè)用來(lái)設置客戶(hù)區背景顯示的圖片,它是這個(gè)樣子的:

這個(gè)對話(huà)框的樣式和關(guān)于頁(yè)面相同,我們需要一個(gè)新類(lèi)來(lái)和這個(gè)屬性頁(yè)協(xié)同工作,我們將其命名為CBackgroundOptsPage。這個(gè)類(lèi)是從CPropertyPageImpl類(lèi)派生的,它有一個(gè)CWinDataExchange來(lái)支持DDX。

class CBackgroundOptsPage :    public CPropertyPageImpl<CBackgroundOptsPage>,    public CWinDataExchange<CBackgroundOptsPage>{public:    enum { IDD = IDD_BACKGROUND_OPTS };     // Construction    CBackgroundOptsPage();    ~CBackgroundOptsPage();     // Maps    BEGIN_MSG_MAP(CBackgroundOptsPage)        MSG_WM_INITDIALOG(OnInitDialog)        CHAIN_MSG_MAP(CPropertyPageImpl<CBackgroundOptsPage>)    END_MSG_MAP()     BEGIN_DDX_MAP(CBackgroundOptsPage)        DDX_RADIO(IDC_BLUE, m_nColor)        DDX_RADIO(IDC_ALYSON, m_nPicture)    END_DDX_MAP()     // Message handlers    BOOL OnInitDialog ( HWND hwndFocus, LPARAM lParam );     // Property page notification handlers    int OnApply();     // DDX variables    int m_nColor, m_nPicture;};

關(guān)于這個(gè)類(lèi)需要注意幾點(diǎn):

  • 有一個(gè)名為IDD的公有成員將對話(huà)框于資源聯(lián)系起來(lái)。
  • 消息映射鏈和CDialogImpl相似。
  • 消息映射鏈將消息鏈入CPropertyPageImpl,從而使我們能夠處理與屬性表相關(guān)的通知消息。
  • 有一個(gè)OnApply()處理函數在單擊屬性表中的OK按鈕時(shí)保存用戶(hù)的選擇。

OnApply() 非常簡(jiǎn)單,它調用 DoDataExchange() 更新 DDX 變量,然后返回一個(gè)代碼標識是否可以關(guān)閉這個(gè)屬性表:

int CBackgroundOptsPage::OnApply(){    return DoDataExchange(true) ? PSNRET_NOERROR : PSNRET_INVALID;}

我們還要在主窗口添加一個(gè)Tools|Options菜單來(lái)打開(kāi)屬性表,這個(gè)菜單的處理函數創(chuàng )建一個(gè)屬性表,但是添加了一個(gè)新屬性頁(yè)CBackgroundOptsPage。

void CMainFrame::OnOptions ( UINT uCode, int nID, HWND hwndCtrl ){CPropertySheet sheet ( _T("PSheets Options"), 0 );CBackgroundOptsPage pgBackground;CPropertyPage<IDD_ABOUTBOX> pgAbout;     pgBackground.m_nColor = m_view.m_nColor;    pgBackground.m_nPicture = m_view.m_nPicture;     sheet.m_psh.dwFlags |= PSH_NOAPPLYNOW;     sheet.AddPage ( pgBackground );    sheet.AddPage ( pgAbout );     if ( IDOK == sheet.DoModal() )        m_view.SetBackgroundOptions ( pgBackground.m_nColor,                                      pgBackground.m_nPicture );}

屬性表的構造函數的第二個(gè)參數是0,表示將索引是0的頁(yè)面初始是可見(jiàn)的,你可以將其設為1,使得屬性表第一次顯示時(shí)顯示關(guān)于頁(yè)面。既然是演示代碼,我就偷個(gè)懶,使用一個(gè)公有變量與CBackgroundOptsPage屬性頁(yè)的radio button建立關(guān)聯(lián),在主窗口中直接為其賦初始值,當用戶(hù)單擊屬性表的OK按鈕時(shí)在將其讀出來(lái)。

如果用戶(hù)點(diǎn)擊OK按鈕,DoModal()發(fā)揮IDOK,我們通知視圖窗口使用新的圖片和背景顏色。下面是幾個(gè)屏幕截圖顯示幾個(gè)不同的樣式的視圖:

創(chuàng )建一個(gè)更好的屬性表類(lèi)

在OnOptions()中創(chuàng )建屬性表是個(gè)好主意,但是在這里使用很多初始化代碼卻非常糟糕,這不是CMainFrame應該做得事情。更好的方法是從CPropertySheetImpl派生一個(gè)新類(lèi),在這個(gè)類(lèi)中完成這些任務(wù)。

#include "BackgroundOptsPage.h" class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>{public:    // Construction    CAppPropertySheet ( _U_STRINGorID title = (LPCTSTR) NULL,                         UINT uStartPage = 0, HWND hWndParent = NULL );    // Maps    BEGIN_MSG_MAP(CAppPropertySheet)        CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>)    END_MSG_MAP()    // Property pages    CBackgroundOptsPage         m_pgBackground;    CPropertyPage<IDD_ABOUTBOX> m_pgAbout;};

我們使用這個(gè)類(lèi)封裝屬性表中各個(gè)屬性頁(yè)的細節,將初始化代碼移到屬性表內部完成,構造函數完成添加頁(yè)面,并設置其他必需的標志:

CAppPropertySheet::CAppPropertySheet ( _U_STRINGorID title, UINT uStartPage,                                        HWND hWndParent ) :    CPropertySheetImpl<CAppPropertySheet> ( title, uStartPage, hWndParent ){    m_psh.dwFlags |= PSH_NOAPPLYNOW;    AddPage ( m_pgBackground );    AddPage ( m_pgAbout );}

這樣一來(lái),OnOptions()處理函數就變得簡(jiǎn)單了一些:

void CMainFrame::OnOptions ( UINT uCode, int nID, HWND hwndCtrl ){CAppPropertySheet sheet ( _T("PSheets Options"), 0 );    sheet.m_pgBackground.m_nColor = m_view.m_nColor;    sheet.m_pgBackground.m_nPicture = m_view.m_nPicture;    if ( IDOK == sheet.DoModal() )        m_view.SetBackgroundOptions ( sheet.m_pgBackground.m_nColor,                                      sheet.m_pgBackground.m_nPicture );}
創(chuàng )建一個(gè)向導樣式的屬性表

創(chuàng )建一個(gè)向導和創(chuàng )建一個(gè)屬性表很相似,這并不奇怪,只需稍做修改添加“上一步”和“下一步”按鈕就行了。和MFC一樣,你需要重載OnSetActive()函數并調用SetWizardButtons()使相應的按鈕可用。我們先從一個(gè)簡(jiǎn)單的介紹頁(yè)面開(kāi)始,它的ID是IDD_WIZARD_INTRO:

注意這個(gè)頁(yè)面沒(méi)有標題欄文字,因為向導中的所有的頁(yè)面通常都有相同的標題,我更愿意在CPropertySheetImpl的構造函數中設置這些文字,然后每個(gè)頁(yè)面使用這個(gè)字符串資源。這就是為什么我只需要改變一個(gè)字符串就能改變所有頁(yè)面標題文字的原因。

關(guān)于這個(gè)頁(yè)面的實(shí)現代碼在CWizIntroPage類(lèi)中:

class CWizIntroPage : public CPropertyPageImpl<CWizIntroPage>{public:    enum { IDD = IDD_WIZARD_INTRO };    // Construction    CWizIntroPage();    // Maps    BEGIN_MSG_MAP(COptionsWizard)        CHAIN_MSG_MAP(CPropertyPageImpl<CWizIntroPage>)    END_MSG_MAP()    // Notification handlers    int OnSetActive();};

構造函數使用(引用)一個(gè)字符串資源ID來(lái)設置頁(yè)面的文字:

CWizIntroPage::CWizIntroPage() :    CPropertyPageImpl<CWizIntroPage>( IDS_WIZARD_TITLE ){}

當這個(gè)頁(yè)面激活時(shí),字符串IDS_WIZARD_TITLE ("PSheets Options Wizard")將出現在向導的標題欄。OnSetActive()僅僅使“下一步”按鈕可用:

int CWizIntroPage::OnSetActive(){    SetWizardButtons ( PSWIZB_NEXT );    return 0;}

為了實(shí)現一個(gè)向導,我們需要創(chuàng )建一個(gè)類(lèi)COptionsWizard,還要在主窗口添加菜單Tools|Wizard。COptionsWizard類(lèi)的構造函數和CAppPropertySheet類(lèi)的構造函數一樣,只是設置必要的樣式標志和添加頁(yè)面。

class COptionsWizard : public CPropertySheetImpl<COptionsWizard>{public:    // Construction    COptionsWizard ( HWND hWndParent = NULL );    // Maps    BEGIN_MSG_MAP(COptionsWizard)        CHAIN_MSG_MAP(CPropertySheetImpl<COptionsWizard>)    END_MSG_MAP()    // Property pages    CWizIntroPage m_pgIntro;};COptionsWizard::COptionsWizard ( HWND hWndParent ) :    CPropertySheetImpl<COptionsWizard> ( 0U, 0, hWndParent ){    SetWizardMode();    AddPage ( m_pgIntro );}

CMainFrame類(lèi)的Tools|Wizard菜單處理函數是這個(gè)樣子:

void CMainFrame::OnOptionsWizard ( UINT uCode, int nID, HWND hwndCtrl ){COptionsWizard wizard;    wizard.DoModal();}

這就是向導的效果:

添加更多的屬性頁(yè),使用DDV

為了使這個(gè)向導能夠有點(diǎn)用處,我們要為其添加一個(gè)設置視圖背景顏色的頁(yè)面。這個(gè)頁(yè)面還將有一個(gè)checkbox演示如何處理DDV驗證失敗并阻止向導進(jìn)行到下一頁(yè)。下面就是新的頁(yè)面,ID是IDD_WIZARD_BKCOLOR:

這個(gè)類(lèi)的實(shí)現代碼在CWizBkColorPage類(lèi)中,下面是相關(guān)的部分代碼

class CWizBkColorPage :    public CPropertyPageImpl<CWizBkColorPage>,    public CWinDataExchange<CWizBkColorPage>{public:    // some stuff removed for brevity...    BEGIN_DDX_MAP(CWizBkColorPage)        DDX_RADIO(IDC_BLUE, m_nColor)        DDX_CHECK(IDC_FAIL_DDV, m_bFailDDV)    END_DDX_MAP()    // Notification handlers    int OnSetActive();    BOOL OnKillActive();    // DDX vars    int m_nColor;protected:    int m_bFailDDV;};

OnSetActive()的工作和前面的介紹頁(yè)面相同,它使“上一步”和“下一步”按鈕可用。OnKillActive()是個(gè)新的處理函數,它觸發(fā)DDV,然后檢查m_bFailDDV的值,如果是TRUE就表示checkbox處于選中狀態(tài),OnKillActive()將阻止向導進(jìn)行到下一頁(yè)。

int CWizBkColorPage::OnSetActive(){    SetWizardButtons ( PSWIZB_BACK | PSWIZB_NEXT );    return 0;}int CWizBkColorPage::OnKillActive(){    if ( !DoDataExchange(true) )        return TRUE;    // prevent deactivation    if ( m_bFailDDV )        {        MessageBox (          _T("Error box checked, wizard will stay on this page."),          _T("PSheets"), MB_ICONERROR );        return TRUE;    // prevent deactivation        }    return FALSE;       // allow deactivation}

需要注意的是OnKillActive()中做的事情也可以在OnWizardNext()中完成,因為這兩個(gè)處理函數都可以使向導維持在當前頁(yè)面。它們的不同之處在于OnKillActive()在用戶(hù)單擊“上一步”和“下一步”按鈕時(shí)被調用,而OnWizardNext()只是在用戶(hù)單擊“下一步”按鈕時(shí)被調用。OnWizardNext()還被用來(lái)完成其它目的,比如,它可以直接將向導引導到指定的頁(yè)面而不是按順序的下一頁(yè)。

例子工程的向導還有另外兩個(gè)頁(yè)面,CWizBkPicturePage 和 CWizFinishPage,由于它們和前面的兩個(gè)頁(yè)面相似,我就不再詳細介紹它們,想了解它們的細節可以查看源代碼。

其他的界面考慮 置中一個(gè)屬性表

屬性頁(yè)和向導的默認位置是出現在父窗口的左上角:

這看起來(lái)有點(diǎn)不爽,還好有方法可以補救。第一種方法是重載CPropertySheetImpl::PropSheetCallback()函數,在這個(gè)函數中將屬性表置中。PropSheetCallback()是MSDN中介紹的PropSheetProc()的回調函數,操作系統在屬性表創(chuàng )建時(shí)調用這個(gè)函數,WTL也是利用這個(gè)時(shí)間子類(lèi)化屬性表窗口的。所以我們的第一種嘗試是:

class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>{//...    static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)    {    int nRet = CPropertySheetImpl<CAppPropertySheet>::PropSheetCallback (                                                        hWnd, uMsg, lParam );         if ( PSCB_INITIALIZED == uMsg )            {            // center sheet... somehow?            }         return nRet;    }};

正如你看到的,我們遇到了棘手的問(wèn)題。PropSheetCallback()是一個(gè)靜態(tài)方法,不能使用this指針訪(fǎng)問(wèn)屬性表窗口。那將這些代碼從CPropertySheetImpl::PropSheetCallback()中拷貝出來(lái),然后添加我們自己的方法行不行呢?撇開(kāi)剛才將代碼和特定版本的WTL聯(lián)系在一起的方法(這已經(jīng)被證明不是各好方法),現在代碼應該是這樣的:

class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>{//...    static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM)    {        if(uMsg == PSCB_INITIALIZED)        {            // Code copied from WTL and tweaked to use CAppPropertySheet            // instead of T:            ATLASSERT(hWnd != NULL);            CAppPropertySheet* pT = (CAppPropertySheet*)                                        _Module.ExtractCreateWndData();            // subclass the sheet window            pT->SubclassWindow(hWnd);            // remove page handles array            pT->_CleanUpPages();             // Our own code follows:            pT->CenterWindow ( pT->m_psh.hwndParent );        }         return 0;    }};

這從理論上講很完美,但是我試過(guò),屬性表的位置并未改變。顯然,通用控件的代碼在我們調用CenterWindow()之后又改變了屬性表窗口的位置。

必須放棄這個(gè)將代碼封裝到屬性表類(lèi)的方法,盡管它是個(gè)好的解決方案。我又回到原來(lái)的方案,即使用屬性頁(yè)窗口和屬性表窗口相互協(xié)作是屬性表窗口置中。我添加了一個(gè)用戶(hù)定義消息UWM_CENTER_SHEET:

  #define UWM_CENTER_SHEET WM_APP

CAppPropertySheet 在它的消息映射鏈中處理這個(gè)消息:

class CAppPropertySheet : public CPropertySheetImpl<CAppPropertySheet>{//...    BEGIN_MSG_MAP(CAppPropertySheet)        MESSAGE_HANDLER_EX(UWM_CENTER_SHEET, OnPageInit)        CHAIN_MSG_MAP(CPropertySheetImpl<CAppPropertySheet>)    END_MSG_MAP()     // Message handlers    LRESULT OnPageInit ( UINT, WPARAM, LPARAM ); protected:    bool m_bCentered;  // set to false in the ctor}; LRESULT CAppPropertySheet::OnPageInit ( UINT, WPARAM, LPARAM ){    if ( !m_bCentered )        {        m_bCentered = true;        CenterWindow ( m_psh.hwndParent );        }     return 0;}

然后,每個(gè)屬性頁(yè)的OnInitDialog() 方法發(fā)送這個(gè)消息到屬性表窗口:

BOOL CBackgroundOptsPage::OnInitDialog ( HWND hwndFocus, LPARAM lParam ){    GetPropertySheet().SendMessage ( UWM_CENTER_SHEET );     DoDataExchange(false);    return TRUE;}

添加m_bCentered標志確保屬性表窗口只響應收到的第一個(gè)UWM_CENTER_SHEET消息。

在屬性頁(yè)中添加圖標

如果要使用屬性表和屬性頁(yè)的未被成員函數封裝的特性,就需要直接訪(fǎng)問(wèn)相關(guān)的數據結構:CPropertySheetImpl類(lèi)中的PROPSHEETHEADER類(lèi)型(結構)成員m_psh和CPropertyPageImpl類(lèi)中的PROPSHEETPAGE類(lèi)型(結構)成員m_psp。

例如:為例子中Option屬性表中的Background頁(yè)面添加一個(gè)圖標,就需要添加一個(gè)標志并設置屬性頁(yè)的PROPSHEETPAGE結構中的幾個(gè)成員:

CBackgroundOptsPage::CBackgroundOptsPage(){    m_psp.dwFlags |= PSP_USEICONID;    m_psp.pszIcon = MAKEINTRESOURCE(IDI_TABICON);    m_psp.hInstance = _Module.GetResourceInstance();}

 

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
用VS2008 制作對話(huà)框向導
關(guān)閉系統不用的端口
VB ListView的使用 - 筆記 - 梅梅 - CSDN學(xué)生大本營(yíng) - Powere...
木馬編程DIY之星號密碼查看工具
實(shí)用的TextBox控件的Undo屬性
談?wù)劯复翱诤退姓叽翱?- 兔子的技術(shù)博客 - C++博客
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久