ホーム ATL/WTL
ウィザードモード
ドキュメント種別 ATL/WTL に関する文書
最終更新日 2004/05/04
PR
 前回は通常のプロパティシートを作成しましたが、 CPropertySheetImplクラスのメンバ関数であるSetWizardMode() を呼び出すことによってウィザードタイプのプロパティシートを作成することができます。


CPropertyPage<IDD_PROPPAGE_VERSION> page;

CPropertySheet sheet;
sheet.AddPage(page);

sheet.SetWizardMode();  // ウィザードモードに設定

sheet.DoModal();
			

まず、前回作成したプロパティページ用のダイアログリソースIDD_PROPPAGE_VERSION を指定してプロパティページを作成し、それをプロパティシートに追加します。 そしてSetWizardMode()によってウィザードモードにします。 また、ダイアログリソースのタイトル文字列がウィザードのタイトルとして表示されます。 このように、ウィザードモードのプロパティシートの作成は通常のプロパティシートの場合とあまり変わりありません。

 ところで、上の例では[完了]ボタンがありません。 また、プロパティページ上のコントロールがある条件を満たした場合だけ [次へ]ボタンを有効にしたいということがあるでしょう。 そのような場合は、CPropertyPageImplクラスから派生させた独自のプロパティーページクラスを作成し、 その中でSetWizardButtons()を呼び出してボタンの状態を設定します。

 次に示すのは、CPropertySheetImplクラスやCPropertyPageImplクラスから派生クラスを作成し、 独自のウィザードモードプロパティシートを作成する例です。



まずプロジェクトにプロパティページ用のダイアログリソースを2つ追加し、 それぞれIDをIDD_PROPPAGE_CUSTOMIDD_PROPPAGE_FINISHに変更します。 1つ目のダイアログリソース(ID:IDD_PROPPAGE_CUSTOM)にはIDがIDC_CHECK_NEXT のチェックボックスを追加します。

次に、CustomWizard.hというヘッダファイルを用意し、 そこにCCustomPageCFinishPageというプロパティページクラスと、 CCustomWizardというプロパティシートクラスを定義します。

// CustomWizard.h内
class CCustomPage : public CPropertyPageImpl<CCustomPage>
{
    CButton m_button_topmost;

public:
    enum { IDD = IDD_PROPPAGE_CUSTOM };

    // コンストラクタ
    CCustomPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
        : CPropertyPageImpl<CCustomPage>(title)
    {}

    BEGIN_MSG_MAP_EX(CCustomPage)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_ID_HANDLER_EX(IDC_CHECK_NEXT, OnCheckNext)
        CHAIN_MSG_MAP(CPropertyPageImpl<CCustomPage>)
    END_MSG_MAP()

    LRESULT OnInitDialog(HWND hWnd, LPARAM lParam){
        m_button_topmost = GetDlgItem(IDC_CHECK_NEXT);

        return TRUE;
    }

    void OnCheckNext(UINT uNotifyCode, int nID, HWND hWndCtl){
        OnSetActive();
    }

    BOOL OnSetActive(){
        // チェックボックスがチェックされている場合は[次へ]ボタンを有効にし、
        // そうでなければ無効にする。[戻る]ボタンは常に無効。
        SetWizardButtons(m_button_topmost.GetCheck() ? PSWIZB_NEXT : 0);

        return TRUE;
    }
};

class CFinishPage : public CPropertyPageImpl<CFinishPage>
{
public:
    enum { IDD = IDD_PROPPAGE_FINISH };

    // コンストラクタ
    CFinishPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
        : CPropertyPageImpl<CFinishPage>(title)
    {}

    BEGIN_MSG_MAP_EX(CFinishPage)
        CHAIN_MSG_MAP(CPropertyPageImpl<CFinishPage>)
    END_MSG_MAP()

    BOOL OnSetActive(){
        // [戻る]ボタンと[完了]ボタンを有効にする。
        // なお、[次へ]ボタンは[完了]ボタンに置き換えられる。
        SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);

        return TRUE;
    }
};

class CCustomWizard : public CPropertySheetImpl<CCustomWizard>
{
public:
    CCustomPage m_pageCustom;
    CFinishPage m_pageFinish;

    // コンストラクタ
    CCustomWizard(ATL::_U_STRINGorID title = (LPCTSTR)NULL,
        UINT uStartPage = 0, HWND hWndParent = NULL)
        : CPropertySheetImpl<CCustomWizard>(title, uStartPage, hWndParent)
    {
        SetWizardMode();  // ウィザードモードに設定
        AddPage(m_pageCustom);
        AddPage(m_pageFinish);
    }

    BEGIN_MSG_MAP_EX(CCustomWizard)
        CHAIN_MSG_MAP(CPropertySheetImpl<CCustomWizard>)
    END_MSG_MAP()
};
			

CCustomPageクラスはウィザードの1ページ目を表します。 このプロパティページにはチェックボックスが一つあり、 チェックを入れるとSetWizardButtons(PSWIZB_NEXT)が呼び出されて[次へ]ボタンが有効になります。 なお、OnSetActive()はプロパティページがアクティブになるたびに呼び出されますが、 プロパティページが最初に表示されたときはチェックボックスはチェックされていないので、 SetWizardButtons(0)が呼び出されて[戻る]ボタンも[次へ]ボタンも無効になります。

CFinishPageクラスはウィザードの2ページ目を表します。 このプロパティページはスタティックコントロールでメッセージを表示しているだけです。 なお、このページがウィザードの最後なのでOnSetActive()では PSWIZB_FINISHを指定してSetWizardButtons()を呼び出すことにより、 [次へ]ボタンを[完了]ボタンに変更しています。 このように、[次へ]ボタンと[完了]ボタンは共通のボタンを使用します。

CCustomWizardクラスは上記の2つのプロパティページクラスのインスタンスをメンバ変数に持ち、 コンストラクタでAddPage()を呼び出すことによって追加しています。 また、コンストラクタではSetWizardMode()を呼び出してプロパティシートをウィザードモードにしています。

 次に示すのは、CCustomWizardクラスを使用する例です。

// stdafx.h内
#include <atlbase.h>
#include <atlapp.h>
extern CAppModule _Module;
#include <atlwin.h>

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlctrls.h>
#include <atldlgs.h>  // コモンダイアログを使用するため
			

// maindlg.h内
class CMainDlg : public CDialogImpl<CMainDlg>
{
public:
    enum { IDD = IDD_MAINDLG };

    // メッセージマップ
    BEGIN_MSG_MAP_EX(CMainDlg)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_ID_HANDLER_EX(IDC_BUTTON_OPENDLG, OnButtonOpenDlg)
        COMMAND_ID_HANDLER_EX(IDOK, OnOK)
        COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
    END_MSG_MAP()

    LRESULT OnInitDialog(HWND hWnd, LPARAM lParam){
        // スクリーンの中央に配置
        CenterWindow();

        // 大きいアイコン設定
        HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,
            ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));
        SetIcon(hIcon, TRUE);
        
        // 小さいアイコン設定
        HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,
            ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
        SetIcon(hIconSmall, FALSE);

        return TRUE;
    }

    void OnButtonOpenDlg(UINT uNotifyCode, int nID, HWND hWndCtl){
        CCustomWizard wizard;

        if(wizard.DoModal() == IDOK){
            // [完了]ボタンを押して閉じた時の処理
        }
    }

    void OnOK(UINT uNotifyCode, int nID, HWND hWndCtl){
        EndDialog(nID);
    }

    void OnCancel(UINT uNotifyCode, int nID, HWND hWndCtl){
        EndDialog(nID);
    }
};
			

// CommDlg.cpp内
#include "stdafx.h"

#include "resource.h"

#include "CustomWizard.h"
#include "maindlg.h"

CAppModule _Module;

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, int nCmdShow)
{
    HRESULT hRes = ::CoInitialize(NULL);
    ATLASSERT(SUCCEEDED(hRes));

    ::DefWindowProc(NULL, 0, 0, 0L);

    AtlInitCommonControls(ICC_COOL_CLASSES | ICC_WIN95_CLASSES);

    hRes = _Module.Init(NULL, hInstance);
    ATLASSERT(SUCCEEDED(hRes));

    int nRet = 0;
    // BLOCK: アプリケーション実行
    {
        CMainDlg dlgMain;
        nRet = dlgMain.DoModal();
    }

    _Module.Term();
    ::CoUninitialize();

    return nRet;
}
			

 まず、リソースを作成します。ダイアログにボタンコントロールを配置し、 リソースIDを次のように指定します。

コントロール名 リソースID
プッシュボタン IDC_BUTTON_OPENDLG

 次に、stdafx.h内では、atldlgs.hヘッダをインクルードします。

 CMainDlgクラスでは、ボタン用のコマンドメッセージハンドラ OnButtonOpenDlg()を追加し、 そこでCCustomWizardクラスのインスタンスを作成して DoModal()によって独自のウィザードモードプロパティシートを表示します。 なお、表示したウィザードモードのプロパティシートを[完了]ボタンを押して閉じると、 DoModal()はIDOKを返します。

 最後に、CommDlg.cpp内でmaindlg.hヘッダの前にCustomWizard.hヘッダをインクルードします。

Wizard97スタイル
 SetHeader()SetWatermark()を呼び出すと PSH_WIZARD97フラグが設定され、ウィザードをWizard97スタイルにすることができます。

 次に示すのは、先ほど作成したウィザードクラスをWizard97スタイルに書き換える例です。



// CustomWizard.h内
class CCustomPage : public CPropertyPageImpl<CCustomPage>
{
    CButton m_button_topmost;

public:
    enum { IDD = IDD_PROPPAGE_CUSTOM };

    // コンストラクタ
    CCustomPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
        : CPropertyPageImpl<CCustomPage>(title)
    {
        // ヘッダタイトルを設定
        SetHeaderTitle(_T("最初のページ"));
        SetHeaderSubTitle(_T("サブタイトル"));
    }

    BEGIN_MSG_MAP_EX(CCustomPage)
        MSG_WM_INITDIALOG(OnInitDialog)
        COMMAND_ID_HANDLER_EX(IDC_CHECK_NEXT, OnCheckNext)
        CHAIN_MSG_MAP(CPropertyPageImpl<CCustomPage>)
    END_MSG_MAP()

    LRESULT OnInitDialog(HWND hWnd, LPARAM lParam){
        m_button_topmost = GetDlgItem(IDC_CHECK_NEXT);

        return TRUE;
    }

    void OnCheckNext(UINT uNotifyCode, int nID, HWND hWndCtl){
        OnSetActive();
    }

    BOOL OnSetActive(){
        // チェックボックスがチェックされている場合は[次へ]ボタンを有効にし、
        // そうでなければ無効にする。[戻る]ボタンは常に無効。
        SetWizardButtons(m_button_topmost.GetCheck() ? PSWIZB_NEXT : 0);

        return TRUE;
    }
};

class CFinishPage : public CPropertyPageImpl<CFinishPage>
{
public:
    enum { IDD = IDD_PROPPAGE_FINISH };

    // コンストラクタ
    CFinishPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
        : CPropertyPageImpl<CFinishPage>(title)
    {
        // ウォーターマークを表示するためにヘッダを非表示にする
        m_psp.dwFlags |= PSP_HIDEHEADER;
    }

    BEGIN_MSG_MAP_EX(CFinishPage)
        CHAIN_MSG_MAP(CPropertyPageImpl<CFinishPage>)
    END_MSG_MAP()

    BOOL OnSetActive(){
        // [戻る]ボタンと[完了]ボタンを有効にする。
        // なお、[次へ]ボタンは[完了]ボタンに置き換えられる。
        SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);

        return TRUE;
    }
};

class CCustomWizard : public CPropertySheetImpl<CCustomWizard>
{
public:
    CCustomPage m_pageCustom;
    CFinishPage m_pageFinish;

    CBitmap bmpHeader;     // ヘッダ用ビットマップ
    CBitmap bmpWatermark;  // ウォーターマーク用ビットマップ

    // コンストラクタ
    CCustomWizard(ATL::_U_STRINGorID title = (LPCTSTR)NULL,
        UINT uStartPage = 0, HWND hWndParent = NULL)
        : CPropertySheetImpl<CCustomWizard>(title, uStartPage, hWndParent)
    {
        // ヘッダ用ビットマップを設定
        bmpHeader.LoadBitmap(IDB_BITMAP_HEADER);
        SetHeader(bmpHeader);

        // ウォーターマーク用ビットマップを設定
        bmpWatermark.LoadBitmap(IDB_BITMAP_WATERMARK);
        SetWatermark(bmpWatermark);

        AddPage(m_pageCustom);
        AddPage(m_pageFinish);
    }

    BEGIN_MSG_MAP_EX(CCustomWizard)
        CHAIN_MSG_MAP(CPropertySheetImpl<CCustomWizard>)
    END_MSG_MAP()
};
			

まず、ヘッダ用に次のようなビットマップリソースをプロジェクトに追加し、IDをIDB_BITMAP_HEADERとします。



また、ウォーターマーク(透かし)用に次のようなビットマップリソースをプロジェクトに追加し、IDをIDB_BITMAP_WATERMARKとします。



これらのビットマップリソースはCCustomWizardクラスのコンストラクタでウィザードに設定します。

ウィザードの1ページ目にはヘッダタイトルを表示します。そのため、 CCustomPageクラスのコンストラクタで SetHeaderTitle()SetHeaderSubTitle()を呼び出します。

ウィザードの2ページ目にはウォーターマークを表示します。 ウォーターマークを表示するためにはヘッダを非表示にする必要があるため、 CFinishPageクラスのコンストラクタでPSP_HIDEHEADERフラグを設定します。