⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtl for mfc programmers, part viii.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
    <SPAN class=3Dcpp-comment>// Maps</SPAN>
    BEGIN_MSG_MAP(COptionsWizard)
        CHAIN_MSG_MAP(CPropertySheetImpl&lt;COptionsWizard&gt;)
    END_MSG_MAP()

    <SPAN class=3Dcpp-comment>// Property pages</SPAN>
    CWizIntroPage m_pgIntro;
};

COptionsWizard::COptionsWizard ( HWND hWndParent ) :
    CPropertySheetImpl&lt;COptionsWizard&gt; ( 0U, <SPAN =
class=3Dcpp-literal>0</SPAN>, hWndParent )
{
    SetWizardMode();

    AddPage ( m_pgIntro );
}</PRE>
      <P>Then the <CODE>CMainFrame</CODE> handler for the=20
      <I>Tools</I>|<I>Wizard</I> menu looks like this:</P><PRE><SPAN =
class=3Dcpp-keyword>void</SPAN> CMainFrame::OnOptionsWizard ( UINT =
uCode, <SPAN class=3Dcpp-keyword>int</SPAN> nID, HWND hwndCtrl )
{
COptionsWizard wizard;

    wizard.DoModal();
}</PRE>
      <P>And here's the wizard in action:</P>
      <P><IMG height=3D348 alt=3D" [Wizard on intro page - 6K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC8/wizintro.png" =
width=3D441=20
      align=3Dbottom border=3D0></P>
      <H3><A name=3Dmorepages></A>Adding More Pages, Handling DDV</H3>
      <P>To make this a useful wizard, we'll add a new page for setting =
the=20
      view's background color. This page will also have a checkbox for=20
      demonstrating handling a DDV failure and preventing the user from=20
      continuing on with the wizard. Here's the new page, whose ID is=20
      <CODE>IDD_WIZARD_BKCOLOR</CODE>:</P>
      <P><IMG height=3D304 alt=3D" [Color selection wizard page - 4K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC8/colorpage.png" =
width=3D348=20
      align=3Dbottom border=3D0></P>
      <P>The implementation for this page is in the class=20
      <CODE>CWizBkColorPage</CODE>. Here are the parts relating =
to</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CWizBkColorPage :
    <SPAN class=3Dcpp-keyword>public</SPAN> =
CPropertyPageImpl&lt;CWizBkColorPage&gt;,
    <SPAN class=3Dcpp-keyword>public</SPAN> =
CWinDataExchange&lt;CWizBkColorPage&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    <SPAN class=3Dcpp-comment>// some stuff removed for =
brevity...</SPAN>

    BEGIN_DDX_MAP(CWizBkColorPage)
        DDX_RADIO(IDC_BLUE, m_nColor)
        DDX_CHECK(IDC_FAIL_DDV, m_bFailDDV)
    END_DDX_MAP()

    <SPAN class=3Dcpp-comment>// Notification handlers</SPAN>
    <SPAN class=3Dcpp-keyword>int</SPAN> OnSetActive();
    BOOL OnKillActive();

    <SPAN class=3Dcpp-comment>// DDX vars</SPAN>
    <SPAN class=3Dcpp-keyword>int</SPAN> m_nColor;

<SPAN class=3Dcpp-keyword>protected</SPAN>:
    <SPAN class=3Dcpp-keyword>int</SPAN> m_bFailDDV;
};</PRE>
      <P><CODE>OnSetActive()</CODE> works similarly to the intro page, =
it=20
      enables both the <I>Back</I> and <I>Next</I> buttons.=20
      <CODE>OnKillActive()</CODE> is a new handler, it invokes DDX then =
checks=20
      the value of <CODE>m_bFailDDV</CODE>. If that is TRUE, meaning the =

      checkbox was checked, <CODE>OnKillActive()</CODE> prevents the =
wizard from=20
      going to the next page.</P><PRE><SPAN =
class=3Dcpp-keyword>int</SPAN> CWizBkColorPage::OnSetActive()
{
    SetWizardButtons ( PSWIZB_BACK | PSWIZB_NEXT );
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}

<SPAN class=3Dcpp-keyword>int</SPAN> CWizBkColorPage::OnKillActive()
{
    <SPAN class=3Dcpp-keyword>if</SPAN> ( !DoDataExchange(<SPAN =
class=3Dcpp-keyword>true</SPAN>) )
        <SPAN class=3Dcpp-keyword>return</SPAN> TRUE;    <SPAN =
class=3Dcpp-comment>// prevent deactivation</SPAN>

    <SPAN class=3Dcpp-keyword>if</SPAN> ( m_bFailDDV )
        {
        MessageBox (
          _T(<SPAN class=3Dcpp-string>"Error box checked, wizard will =
stay on this page."</SPAN>),
          _T(<SPAN class=3Dcpp-string>"PSheets"</SPAN>), MB_ICONERROR );

        <SPAN class=3Dcpp-keyword>return</SPAN> TRUE;    <SPAN =
class=3Dcpp-comment>// prevent deactivation</SPAN>
        }

    <SPAN class=3Dcpp-keyword>return</SPAN> FALSE;       <SPAN =
class=3Dcpp-comment>// allow deactivation</SPAN>
}</PRE>
      <P>Note that the logic in <CODE>OnKillActive()</CODE> could =
certainly have=20
      been put in <CODE>OnWizardNext()</CODE> instead, since both =
handlers have=20
      the ability to keep the wizard on the current page. The difference =
is that=20
      <CODE>OnKillActive()</CODE> is called when the user clicks =
<I>Back</I> or=20
      <I>Next</I>, while <CODE>OnWizardNext()</CODE> is only called when =
the=20
      user clicks <I>Next</I> (as the name signifies).=20
      <CODE>OnWizardNext()</CODE> is also used for other purposes; it =
can direct=20
      the wizard to a different page instead of the next one in order, =
if some=20
      pages need to be skipped.</P>
      <P>The wizard in the sample project has two more pages,=20
      <CODE>CWizBkPicturePage</CODE> and <CODE>CWizFinishPage</CODE>. =
Since they=20
      are similar to the two pages above, I won't cover them in detail =
here, but=20
      you can check out the sample code to get all the details.</P>
      <H2><A name=3Dotherui></A>Other UI Considerations</H2>
      <H3><A name=3Dcentersheet></A>Centering a sheet</H3>
      <P>The default behavior of sheets and wizards is to appear near =
the=20
      upper-left corner of their parent window:</P>
      <P><IMG height=3D326 alt=3D" [sheet position - 8K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC8/sheetpos.png" =
width=3D410=20
      align=3Dbottom border=3D0></P>
      <P>This looks rather sloppy, but fortunately we can remedy it. The =
first=20
      approach I thought of was to override=20
      <CODE>CPropertySheetImpl::PropSheetCallback()</CODE> and center =
the sheet=20
      in that function. <CODE>PropSheetCallback()</CODE> is a callback =
function=20
      described in MSDN as <CODE>PropSheetProc()</CODE>. The OS calls =
this=20
      function when the sheet is being created, and WTL uses this time =
to=20
      subclass the sheet window. So our first attempt might =
be:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CAppPropertySheet : =
<SPAN class=3Dcpp-keyword>public</SPAN> =
CPropertySheetImpl&lt;CAppPropertySheet&gt;
{
<SPAN class=3Dcpp-comment>//...</SPAN>
    <SPAN class=3Dcpp-keyword>static</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN> CALLBACK PropSheetCallback(HWND hWnd, =
UINT uMsg, LPARAM lParam)
    {
    <SPAN class=3Dcpp-keyword>int</SPAN> nRet =3D =
CPropertySheetImpl&lt;CAppPropertySheet&gt;::PropSheetCallback (
                                                        hWnd, uMsg, =
lParam );
=20
        <SPAN class=3Dcpp-keyword>if</SPAN> ( PSCB_INITIALIZED =3D=3D =
uMsg )
            {
            <SPAN class=3Dcpp-comment>// center sheet... somehow?</SPAN>
            }
=20
        <SPAN class=3Dcpp-keyword>return</SPAN> nRet;
    }
};</PRE>
      <P>As you can see, we're stuck. <CODE>PropSheetCallback()</CODE> =
is a=20
      static method, so we have no <CODE><SPAN=20
      class=3Dcpp-keyword>this</SPAN></CODE> pointer to access the sheet =
window=20
      with. OK, so how about copying the code from=20
      <CODE>CPropertySheetImpl::PropSheetCallback()</CODE> and then =
adding our=20
      own? Putting aside for the moment how this ties our code to this=20
      particular version of WTL (which should already be a tip-off that =
this=20
      isn't a good approach), the code would be:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CAppPropertySheet : <SPAN =
class=3Dcpp-keyword>public</SPAN> =
CPropertySheetImpl&lt;CAppPropertySheet&gt;
{
<SPAN class=3Dcpp-comment>//...</SPAN>
    <SPAN class=3Dcpp-keyword>static</SPAN> <SPAN =
class=3Dcpp-keyword>int</SPAN> CALLBACK PropSheetCallback(HWND hWnd, =
UINT uMsg, LPARAM)
    {
        <SPAN class=3Dcpp-keyword>if</SPAN>(uMsg =3D=3D =
PSCB_INITIALIZED)
        {
            <B><SPAN class=3Dcpp-comment>// Code copied from WTL and =
tweaked to use CAppPropertySheet</SPAN>
            <SPAN class=3Dcpp-comment>// instead of T:</B></SPAN>
            ATLASSERT(hWnd !=3D NULL);
            CAppPropertySheet* pT =3D (CAppPropertySheet*)
                                        _Module.ExtractCreateWndData();
            <SPAN class=3Dcpp-comment>// subclass the sheet =
window</SPAN>
            pT-&gt;SubclassWindow(hWnd);
            <SPAN class=3Dcpp-comment>// remove page handles =
array</SPAN>
            pT-&gt;_CleanUpPages();
=20
            <B><SPAN class=3Dcpp-comment>// Our own code follows:</SPAN>
            pT-&gt;CenterWindow ( pT-&gt;m_psh.hwndParent );</B>
        }
=20
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
};</PRE>
      <P>This looks good in theory, but when I tried it, the sheet's =
position=20
      did not change. Apparently, the common controls code repositions =
the sheet=20
      again after our call to <CODE>CenterWindow()</CODE>.</P>
      <P>So, having given up on a nice solution that's entirely =
encapsulated in=20
      the sheet class, I fell back on having the sheet and the pages =
cooperate=20
      to center the sheet. I added a user-defined message called=20
      <CODE>UWM_CENTER_SHEET</CODE>:</P><PRE><SPAN =
class=3Dcpp-preprocessor>  #define UWM_CENTER_SHEET WM_APP</SPAN></PRE>
      <P><CODE>CAppPropertySheet</CODE> handles this message in its =
message=20
      map:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CAppPropertySheet : <SPAN class=3Dcpp-keyword>public</SPAN> =
CPropertySheetImpl&lt;CAppPropertySheet&gt;
{
<SPAN class=3Dcpp-comment>//...</SPAN>
    BEGIN_MSG_MAP(CAppPropertySheet)
        MESSAGE_HANDLER_EX(UWM_CENTER_SHEET, OnPageInit)
        CHAIN_MSG_MAP(CPropertySheetImpl&lt;CAppPropertySheet&gt;)
    END_MSG_MAP()
=20
    <SPAN class=3Dcpp-comment>// Message handlers</SPAN>
    LRESULT OnPageInit ( UINT, WPARAM, LPARAM );
=20
<SPAN class=3Dcpp-keyword>protected</SPAN>:
    <SPAN class=3Dcpp-keyword>bool</SPAN> m_bCentered;  <SPAN =
class=3Dcpp-comment>// set to false in the ctor</SPAN>
};
=20
LRESULT CAppPropertySheet::OnPageInit ( UINT, WPARAM, LPARAM )
{
    <SPAN class=3Dcpp-keyword>if</SPAN> ( !m_bCentered )
        {
        m_bCentered =3D <SPAN class=3Dcpp-keyword>true</SPAN>;
        CenterWindow ( m_psh.hwndParent );
        }
=20
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}</PRE>
      <P>Then, the <CODE>OnInitDialog()</CODE> method of each page sends =
this=20
      message to the sheet:</P><PRE>BOOL =
CBackgroundOptsPage::OnInitDialog ( HWND hwndFocus, LPARAM lParam )
{
    <B>GetPropertySheet().SendMessage ( UWM_CENTER_SHEET );</B>
=20
    DoDataExchange(<SPAN class=3Dcpp-keyword>false</SPAN>);
    <SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}</PRE>
      <P>The <CODE>m_bCentered</CODE> flag in the sheet ensures that =
only the=20
      first <CODE>UWM_CENTER_SHEET</CODE> message is acted on.</P>
      <H3><A name=3Daddicons></A>Adding icons to pages</H3>
      <P>To use other features of sheets and pages that are not already =
wrapped=20
      by member functions, you'll need to access the relevant structures =

      directly: the <CODE>PROPSHEETHEADER</CODE> member =
<CODE>m_psh</CODE> in=20
      <CODE>CPropertySheetImpl</CODE>, or the <CODE>PROPSHEETPAGE</CODE> =
member=20
      <CODE>m_psp</CODE> in <CODE>CPropertyPageImpl</CODE>.</P>
      <P>For example, to add an icon to the Background page of the =
options=20
      property sheet, we need to add a flag and set a couple other =
members in=20
      the page's <CODE>PROPSHEETPAGE</CODE> =
struct:</P><PRE>CBackgroundOptsPage::CBackgroundOptsPage()
{
    m_psp.dwFlags |=3D PSP_USEICONID;
    m_psp.pszIcon =3D MAKEINTRESOURCE(IDI_TABICON);
    m_psp.hInstance =3D _Module.GetResourceInstance();
}</PRE>
      <P>And here's the result:</P>
      <P><IMG height=3D67 alt=3D" [Tab icon - 2K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC8/tabicon.png" =
width=3D163=20
      align=3Dbottom border=3D0></P>
      <H2><A name=3Dupnext></A>Up Next</H2>
      <P>In Part 9, I'll cover WTL's utility classes, and its wrappers =
for GDI=20
      object and common dialogs.=20
      <H2><A name=3Drevisionhistory></A>Revision History</H2>
      <P>September 13, 2003: Article first published.=20
      <!-- Article Ends --></P></DIV>
      <H2>About Michael Dunn</H2>
      <TABLE width=3D"100%" border=3D0>
        <TBODY>
        <TR vAlign=3Dtop>
          <TD class=3DsmallText noWrap><IMG=20
            =
src=3D"http://www.codeproj

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -