Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

ATL/WTLプログラミング 6:ズームスクロールウィンドウ

ATL/WTLを利用したVisual C++のWindowsプログラミング

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2006/05/26 00:00

Windowsアプリケーションを作成するためのC++クラスライブラリといえば、Microsoftが提供するMFCが有名ですが、同社が提供するライブラリATLを利用して作成することもできます。本稿では、マルチペインステータスバーやペインコンテナ、ズームスクロールウィンドウの使い方について解説します。

目次

はじめに

 前回は、スプリッタウィンドウを利用したプログラムを作成しました。今回は、前回のプログラムを拡張してマルチペインステータスバーやペインコンテナ、ズームスクロールウィンドウの使い方について説明します。

対象読者

 ATL/WTLによるWindowsプログラミングに興味があり、C++やWin32APIによるWindowsプログラミングの基本的な知識がある方。

必要な環境

 サンプルはVisual C++ 6.0で作成し、Windows 2000で動作確認しています。

マルチペインステータスバー

 「マルチペインステータスバー」とは、複数のペインを持つステータスバーのことです。WTLは、簡単にステータスバーに複数ペインを設定できる機能を備えたCMultiPaneStatusBarCtrlを用意しています。

マルチペインステータスバー
マルチペインステータスバー

 前回作成したプログラムのステータスバーを、CMultiPaneStatusBarCtrlに置き換えた例を示します。

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

#include <atlcrack.h>
#include <atlmisc.h>
#include <atlctrls.h>
#include <atlctrlx.h>  // CMultiPaneStatusBarCtrlを使用するため
#include <atlctrlw.h>
#include <atlframe.h>
#include <atlsplit.h>
mainfrm.h
class CMainFrame : public CFrameWindowImpl<CMainFrame>,
        public CUpdateUI<CMainFrame>,
        public CMessageFilter, public CIdleHandler
{
public:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

    CSplitterWindow  m_wndSplitter;      // スプリッタウィンドウ
    CFontListView m_viewFontList;        // 左ペイン
    CFontPreviewView m_viewFontPreview;  // 右ペイン

    CCommandBarCtrl m_CmdBar;                // コマンドバー
    CMultiPaneStatusBarCtrl m_wndStatusBar;  // マルチステータスバー

    virtual BOOL PreTranslateMessage(MSG* pMsg){
        if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
            return TRUE;

        // 左ペインのPreTranslateMessageを呼び出す
        if(m_viewFontList.PreTranslateMessage(pMsg))
            return TRUE;

        // 右ペインのPreTranslateMessageを呼び出す
        return m_viewFontPreview.PreTranslateMessage(pMsg);
    }

    virtual BOOL OnIdle(){
        UIUpdateToolBar();
        UIUpdateStatusBar();

        CString strCount;
        strCount.Format(_T("フォント数:%d"),
            m_viewFontList.GetCount());
        m_wndStatusBar.SetPaneText(IDS_PANE_COUNT, strCount);

        return FALSE;
    }

    BEGIN_UPDATE_UI_MAP(CMainFrame)
        UPDATE_ELEMENT(ID_MENUITEM_CHANGEVIEW,
 UPDUI_MENUPOPUP | UPDUI_TOOLBAR)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP_EX(CMainFrame)
        MSG_WM_CREATE(OnCreate)
        COMMAND_CODE_HANDLER_EX(LBN_SELCHANGE, OnListSelChange)
        COMMAND_ID_HANDLER_EX(ID_MENUITEM_CHANGEVIEW, OnMenuChangeView)
        COMMAND_ID_HANDLER_EX(ID_APP_EXIT, OnFileExit)
        CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
    END_MSG_MAP()

    LRESULT OnCreate(LPCREATESTRUCT lpcs){
        // コマンドバーを作成
        HWND hWndCmdBar = m_CmdBar.Create(m_hWnd, rcDefault,
            NULL, ATL_SIMPLE_CMDBAR_PANE_STYLE);

        // コマンドバーに現在のメニューバーのアイテムと画像をセット
        m_CmdBar.AttachMenu(GetMenu());
        m_CmdBar.LoadImages(IDR_MAINFRAME);

        // メニューバーを削除
        SetMenu(NULL);

        // ツールバーを作成
        HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd,
            IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE);

        // リバーを作成
        CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);

        // リバーのバンドにコマンドバーとツールバーを追加
        AddSimpleReBarBand(hWndCmdBar);
        AddSimpleReBarBand(hWndToolBar, NULL, TRUE);

        // ステータスバーを作成
        m_hWndStatusBar = m_wndStatusBar.Create(m_hWnd);
        int nPanes[] = {ID_DEFAULT_PANE, IDS_PANE_COUNT};
        m_wndStatusBar.SetPanes(nPanes, sizeof(nPanes)/sizeof(nPanes[0]));

        UIAddToolBar(hWndToolBar);
        UIAddStatusBar(m_hWndStatusBar);

        UISetCheck(ID_MENUITEM_CHANGEVIEW, 1);

        // スプリッタウィンドウを作成
        m_wndSplitter.Create(m_hWnd, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

        // スプリッタウィンドウ拡張スタイルを設定
        m_wndSplitter.SetSplitterExtendedStyle(0);

        // 左ペインのビューウィンドウを作成
        m_viewFontList.Create(m_wndSplitter, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
            WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY |
            LBS_WANTKEYBOARDINPUT | LBS_SORT, WS_EX_CLIENTEDGE);

        m_wndSplitter.SetSplitterPane(SPLIT_PANE_LEFT, m_viewFontList);

        // 右ペインのビューウィンドウを作成
        m_viewFontPreview.Create(m_wndSplitter, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            WS_EX_CLIENTEDGE);

        m_wndSplitter.SetSplitterPane(
            SPLIT_PANE_RIGHT, m_viewFontPreview);

        m_hWndClient = m_wndSplitter;
        UpdateLayout();

        // 分割バーの位置を設定
        m_wndSplitter.SetSplitterPos(120);

        // メッセージループにメッセージフィルタとアイドルハンドラを追加
        CMessageLoop* pLoop = _Module.GetMessageLoop();
        pLoop->AddMessageFilter(this);
        pLoop->AddIdleHandler(this);

        return 0;
    }

    void OnListSelChange(UINT uNotifyCode, int nID, HWND hWndCtl){
        // 現在選択されているアイテムを取得
        int nIndex = m_viewFontList.GetCurSel();
        if(nIndex != LB_ERR){
            CString strText;
            m_viewFontList.GetText(nIndex, strText);

            // 取得した文字列を右ペインに設定
            m_viewFontPreview.SetFontName(strText);
        }
    }

    void OnMenuChangeView(UINT uNotifyCode, int nID, HWND hWndCtl){
        if(m_wndSplitter.GetSinglePaneMode() == SPLIT_PANE_RIGHT){
            // 両ペイン表示
            m_wndSplitter.SetSinglePaneMode(SPLIT_PANE_NONE);
            UISetCheck(ID_MENUITEM_CHANGEVIEW, 1);
        }else{
            // 右ペインのみ表示
            m_wndSplitter.SetSinglePaneMode(SPLIT_PANE_RIGHT);
            UISetCheck(ID_MENUITEM_CHANGEVIEW, 0);
        }
    }

    void OnFileExit(UINT uNotifyCode, int nID, HWND hWndCtl){
        PostMessage(WM_CLOSE);
    }
};

 まず、プロジェクトに文字列リソース(リソースID:IDS_PANE_COUNT)を追加し、「フォント数:0000」という文字列を割り当てます。

 次に、CMultiPaneStatusBarCtrlを使用するために「stdafx.h」で「atlctrlx.h」をインクルードします。

 残りの変更点はCMainFrameクラス内です。まず、CMainFrameのメンバ変数としてCMultiPaneStatusBarCtrlのインスタンスm_wndStatusBarを宣言します。

 CMainFrameクラスのWM_CREATEメッセージハンドラでは、m_wndStatusBarに対してCreate()を呼び出してステータスバーを作成します。Create()は戻り値としてステータスバーのハンドルを返すので、それをフレームウィンドウのメンバ変数であるm_hWndStatusBarに代入します。

 なお、Create()には2つのバージョンがあり、一方は第2引数に文字列を指定するもの、他方は第2引数に文字列リソースのIDを指定するものです。第2引数を省略した場合は後者のCreate()が呼び出され、デフォルトの文字列リソースIDとしてATL_IDS_IDLEMESSAGEが指定されます。両バージョンとも第1引数に親ウィンドウハンドルを指定し、第3引数にはスタイル、第4引数にはIDを指定できます。第3引数を省略した場合はデフォルトスタイルとしてWS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIPが指定され、第4引数を省略した場合はデフォルトIDとしてATL_IDW_STATUS_BARが指定されます。

 次に、SetPanes()を呼び出してステータスバーにペインを設定します。第1引数には文字列リソースのIDを要素とした配列へのポインタを指定し、第2引数にはペインの数を指定します。SetPanes()は配列内の文字列リソースIDから文字列を取得し、その文字列の幅と同じ大きさのペインを作成します。本稿では、ステータスバーの2番目のペインにフォント数を表示するためにIDS_PANE_COUNTという文字列リソースを追加したので、「フォント数:0000」という文字列が表示できるサイズのペインを作成することを意味します。このペインに文字列を設定するのはOnIdle()SetPaneText()です。

 なお、配列の1番目に指定したID_DEFAULT_PANEはWTLが用意しているIDで、フレームウィンドウのサイズが変更されるたびに、それに合わせて大きさが調整されるペインを意味します。

 本稿ではWM_SIZEメッセージハンドラを削除しました。これは、CMultiPaneStatusBarCtrl内にはWM_SIZEメッセージハンドラがあり、フレームウィンドウのサイズを変更するたびに、ステータスバーのペインが自動的に調節されるためです。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

バックナンバー

連載:ATL/WTLを利用したVisual C++のWindowsプログラミング
All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5