MFC   VC++   Visual Studio   Visual Studio   プログラミング

CMFCPropertyGridCtrl上の値取得

 CMFCPropertyGridCtrlを使い、コントロール上の各設定値などを取得する方法を紹介します。

 値を取得するタイミングはいくつかあるのですが、今回は、設定値が変更された直後ではなく、変更が完全に確定したタイミングについて書いていきたいと思います。
 ここで、変更が完全に確定したタイミングとは、例えば、「True/False」を設定する場合、ドロップダウンリストから選択してすぐではなく、設定し終えて他のコントロールや項目へフォーカスが移動したときのことです。
 VisualStudioを使っているとわかると思うのですが、プロパティの変更が適用されるときと同じタイミングです。

 方法は、「CMFCPropertyGridCtrl」を派生させたクラス(ここではCMyProperty)を作り、そこで仮想関数「ValidateItemData」を処理していきます。
 まずヘッダファイルに、
    virtual BOOL ValidateItemData(CMFCPropertyGridProperty* pProp);
と宣言し、cppファイル内で以下のように書きます。
BOOL CMyProperty::ValidateItemData(CMFCPropertyGridProperty* pProp)
{
    if(pProp)
    {
        CString str = pProp->GetName();        // 設定項目名を取得
        if(str == _T("数値設定"))
        {
            int iNum = (_variant_t)pProp->GetValue();
        }
        else if(str == _T("テキスト設定"))
        {
pProp->OnUpdateValue();
            CString strTxt = pProp->FormatProperty();
        }
        else if(str == _T("BOOL値設定"))
        {
            bool bT = (_variant_t)pProp->GetValue();
        }
    }

    return CMFCPropertyGridCtrl::ValidateItemData(pProp);
}
 ここで少し説明すると、基本的に値は「GetValue」で取得し「_variant_t」にキャストすれば、後は「_variant_t」が自動で色々な型に変換してくれます。
 テキストで取得したい場合は「FormatProperty」を使えば、数値設定だろうがドロップダウンリストだろうが、表示されているテキストが取得できます。
 ※注: この記事にコメントをいただき、テキスト取得時の部分を修正しました。
     今までの方法だと、直接入力のとき値が更新されず、正しい値が取得できませんでした。
     そこで、値取得前に「pProp->OnUpdateValue();」を呼ぶ事により、きちんと値が取得できるようになります。
     修正部分は赤字になっています。


 この他に「CMFCPropertyGridCtrl」では、色設定やフォント設定などが出来ますが、基本的にどれもやり方は同じで、設定項目名で処理を切り替え、そこで「pProp」を使って値を取得していきます。
ランキングへ     posted by 遠雷 | Comment(2) | コントロール

CMFCShellTreeCtrlでのフロッピーへのアクセス制限

 前回は「CMFCShellListCtrl」での方法を紹介しましたが、今回は「CMFCShellTreeCtrl」での方法を紹介したいと思います。
 基本的にはほとんど同じなのですが、アイテムの追加方法など、微妙に違うのでここで紹介します。

 まず、「CMFCShellTreeCtrl」を派生させたクラス(ここではCMyMFCShellTreeCtrl)を作り、そこで「EnumObjects」をオーバライドします。
 ヘッダファイルに以下を追加します。
    HRESULT EnumObjects(HTREEITEM hParentItem, LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent);
 ここでcppファイルのコードなのですが、今回の方法も、コードをすべて掲載すると結構長くなるので、変更する箇所だけ掲載していきます。
 元になるコードは、「afxshelltreectrl.cpp」内の225行目以降を改良していきます。
 「afxshelltreectrl.cpp」ファイルは、「〜Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc」以下にあります。

 まず、「afxshelltreectrl.cpp」内の225行目以降にある「EnumObjects」関数をそのまま自分の派生クラスのcppファイルにコピペします。
 以下、関数内の一番上を1行目として、変更する箇所を書いていきます。
 1行目 CMFCShellTreeCtrl → CMyMFCShellTreeCtrl
 4行目 afxShellManager → theApp.GetShellManager()
34行目 afxShellManager → theApp.GetShellManager()
 ここまでは「CMFCShellListCtrl」の場合とほぼ同じですが、ここから少し違います。
43行目以降に以下を追加、
        TCHAR szPath [MAX_PATH];
        if(SHGetPathFromIDList(pItem->pidlFQ, szPath))
        {
            if(DRIVE_REMOVABLE == GetDriveType(szPath))
            {
                tvItem.cChildren = TRUE;
                // Fill in the TV_INSERTSTRUCT structure for this item:
                TVINSERTSTRUCT tvInsert;

                tvInsert.item = tvItem;
                tvInsert.hInsertAfter = TVI_LAST;
                tvInsert.hParent = hParentItem;

                InsertItem(&tvInsert);
                dwFetched = 0;
                continue;
            }
        }
となります。

 追加部分の詳しい説明は前回のものを見てもらうとして、前回との相違点を説明すると、「tvItem.cChildren = TRUE;」とすることで、ディスプレイ名の左に"+"マークが付き、展開可能アイテムになります。
 後は、ツリーコントロールにアイテムを追加するだけです。

 「CMFCShellTreeCtrl」の場合、「CMFCShellListCtrl」の様にサイズや更新日時などを取得しないので、属性取得部分だけ回避すればいいので、比較的楽に改良できます。
ランキングへ     posted by 遠雷 | Comment(0) | コントロール

CMFCShellListCtrlでのフロッピーへのアクセス制限

 「CMFCShellListCtrl」クラスをデフォルトで使い、マイコンピュータ内を表示させるようにした場合(ParentFolderがNULL)に、フロッピードライブが取り付けてある環境の場合、表示するときにドライブへアクセスするため、あの独特のアクセス音が気になる場合があります。
 そういった場合に、表示時にはフロッピードライブへはアクセスしないようにし、ドライブ内を開こうとしたときにだけアクセスする方法を紹介します。

 まず、「CMFCShellListCtrl」を派生させたクラス(ここではCMyMFCShellListCtrl)を作り、そこで「EnumObjects」をオーバライドします。
 ヘッダファイルに以下を追加します。
    HRESULT EnumObjects(LPSHELLFOLDER pParentFolder, LPITEMIDLIST pidlParent);
 ここでcppファイルのコードなのですが、今回の方法は、コードをすべて掲載すると結構長くなるので、変更する箇所だけ掲載していきます。
 元になるコードは、「afxshelllistctrl.cpp」内の263行目以降を改良していきます。
 「afxshelllistctrl.cpp」ファイルは、「〜Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc」以下にあります。

 まず、「afxshelllistctrl.cpp」内の263行目以降にある「EnumObjects」関数をそのまま自分の派生クラスのcppファイルにコピペします。
 以下、関数内の一番上を1行目として、変更する箇所を書いていきます。
 1行目 CMFCShellListCtrl → CMyMFCShellListCtrl
 4行目 afxShellManager → theApp.GetShellManager()
31行目 afxShellManager → theApp.GetShellManager()
38行目以降に以下を追加、
            SHFILEINFO sfi;
            TCHAR szPath [MAX_PATH];

            if(SHGetPathFromIDList(pItem->pidlFQ, szPath))
            {
                if(DRIVE_REMOVABLE == GetDriveType(szPath))
                {
                    if(SHGetFileInfo((LPCTSTR)pItem->pidlFQ, 0, &sfi, sizeof(sfi),
                        SHGFI_PIDL | SHGFI_DISPLAYNAME | SHGFI_TYPENAME))
                    {
                        lvItem.pszText = sfi.szDisplayName;
                        int pos = InsertItem(&lvItem);
                        SetItemText(pos, 2, OnGetItemText(pos, 2, pItem));
                        dwFetched = 0;
                        continue;
                    }
                }
            }
となります。

 ここで追加部分を詳しく説明すると、「GetDriveType」でドライブの種類を取得し、「DRIVE_REMOVABLE」すなわちリムーバブルドライブの場合に、ディスプレイ名(3.5 インチ FD (A:))とタイプ名(3.5 インチ フロッピー ドライブ)だけをリストに追加するようにしてあります。

 結局、ドライブにアクセスしてあの音が出る処理は、41行目の
            pParentFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &dwAttr);
の属性を取得するところと、64行目の
                    SetItemText(iItem, iColumn, OnGetItemText(iItem, iColumn, pItem));
の「OnGetItemText」関数内のサイズ・更新日時を取得する処理なので、ここを処理させないようにすれば音は出ないという訳です。

 次回は、今回と同じようなクラス「CMFCShellTreeCtrl」での方法を紹介します。
ランキングへ     posted by 遠雷 | Comment(0) | コントロール