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

CMFCShellListCtrlの表示項目 その2

 前回はカラム名を変更する方法を紹介しましたが、今回は列数を減らし、好みの項目だけを表示する方法を紹介します。
 単純に「SetColumnOrderArray」を使って並び替え、要らない列を削除すれば出来るのですが、ここでは別の方法を紹介します。

 まず、前回紹介した方法でカラム名を変更します。
 今回は、1列目に「ファイル名」、2列目に「更新日時」を表示させていきます。
 ちなみに、列の並び替えをせず、間の2・3列目を削除して上記の並び順にした場合、最初はきちんと表示されますが、階層を変えるなどした場合、当然ですが違うアイテムが入ります。

 そこで、リストにアイテムを入れるときに好みの列に入れるように改良します。
 方法は、「CMFCShellListCtrl」クラスを派生させ(ここでは「CMyMFCShellListCtrl」)、仮想関数「OnGetItemText」をオーバライドし、そこで入れる列を変更させます。
ヘッダファイル
    virtual CString OnGetItemText(int iItem, int iColumn, LPAFX_SHELLITEMINFO pItem);
cppファイル
CString CMyMFCShellListCtrl::OnGetItemText(int iItem, int iColumn, LPAFX_SHELLITEMINFO pItem)
{
    return CMFCShellListCtrl::OnGetItemText(iItem, iColumn == 1 ? 3 : iColumn, pItem);
}
 上記の様にコードはすごく簡単ですが、ここでちょっと説明すると、列を指定する「iColumn」が、今回変更する「更新日時」の"3"のときだけ、変更先である"1"にして呼び出すようにし、その他のときはそのまま呼び出すようにしてあります。
 この方法と同様に、違う列の内容を別の列に入れたい場合にも使えます。

 その他に、特定の列に独自の項目を入れたい場合も、ここで処理すればいろいろ改良することが出来ます。
 例えば、2列目に「作成日時」を入れたい場合は、「iColumn」が"1"のときに「pItem」から作成日時を取得し、文字列(CString)に変換して返せばいいです。
    if(iColumn == 1)
    {
        TCHAR szPath[MAX_PATH];
        if(SHGetPathFromIDList(pItem->pidlFQ, szPath))
        {
            CFileStatus fs;
            if(CFile::GetStatus(szPath, fs))
            {
                CString str;
                OnFormatFileDate(fs.m_ctime, str);
                return str;
            }
        }
    }
ランキングへ     posted by 遠雷 | Comment(0) | コントロール

CMFCShellListCtrlの表示項目

 「CMFCShellListCtrl」クラスをデフォルトで使うと、左の列から順に「Name」「Size」「Type」「Modified」となっていますが、まずはこれらのカラム名を変更する方法を紹介します。

 やり方は、「CMFCShellListCtrl」クラスを派生させ(ここではCMyMFCShellListCtrl)、仮想関数「OnSetColumns」をオーバライドし、その中でカラム名の変更をしていきます。
ヘッダファイル
    virtual void OnSetColumns();
cppファイル
void CMyMFCShellListCtrl::OnSetColumns()
{
    CMFCShellListCtrl::OnSetColumns();

    LVCOLUMN lv;
    lv.mask = LVCF_TEXT;
    lv.pszText = _T("ファイル名");
    SetColumn(0, &lv);
}
 上記の例は、0番目のカラム名を「Name」から「ファイル名」に変更します。
 列の並び順を変えたい場合は、この関数内で「SetColumnOrderArray」を使って並び替えます。

 この他に、
void CMyMFCShellListCtrl::OnSetColumns()
{
    InsertColumn(0, _T("ファイル名"), LVCFMT_LEFT, 150, 0);
    InsertColumn(1, _T("ファイルサイズ"), LVCFMT_RIGHT, 120, 1);
}
 とすれば、2列だけになります。
 しかし、この方法だと2列目にファイルタイプを持ってきたり、更新日時を持ってきたりすることが出来ません。
 前述のように列の並び替えをして、不要な列を削除すれば出来ないことはないのですが、もう少しスマート?な方法があるので、次回、その方法を紹介したいと思います。
ランキングへ     posted by 遠雷 | Comment(0) | コントロール

プログレスバーのMARQUEE

 プログレスバーをマーキー表示させる方法。
 マーキー表示とは、バーが端から徐々に埋まっていくのではなく、短いバーが繰り返しスライドするものです。

 まず、プログレスバーのスタイルをリソースエディタなら、プログレスバーのプロパティから「Marquee」の項目を「True」にする。
 動的作成ならスタイルに「PBS_MARQUEE」を設定する。

 ここで、このスタイルは、
#if (_WIN32_WINNT >= 0x0501)
#define PBS_MARQUEE             0x08
#endif       // _WIN32_WINNT >= 0x0501
 と宣言されている通り、Windows XP以降でしか有効にならない。
 さらに、コモンコントロールV6.0以降でしか動作しないので、文字セットをマルチバイトにした場合、意図的にV6.0を使うようにしないといけない。
 SetMarquee関数は文字セットをマルチバイトにした場合、コンパイルエラーになるので、
    m_progress.SendMessage(PBM_SETMARQUEE, (WPARAM)TRUE, (LPARAM)100);
とする。
 ここで、WPARAMにスタート/停止のBOOL値を、LPARAMに動作スピードのInterval値を入れる。

 使用場面は、何かの処理中に動作させることがほとんどだと思うので、
void CXXXlDlg::OnBnClickedButton()
{
    m_progress.SetMarquee(TRUE, 100);    // m_progressはメンバ変数
    while(...)
    {
        // 何らかの処理
    }
}
 としたいところですが、これだとOnBnClickedButtonを抜けない限りバーは動きません。
 そこで、while文の中に、
MSG msg;
if(PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE))
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
のように、メッセージポンプを動かすようにすれば一応動くのですが、ダイアログ上でカーソルをぐるぐる動かすなど、処理するメッセージが多かったり、一周の処理が長いとやはりうまく動きません。
 さらに、while文を抜けた後の通常の処理部分では止まってしまいます。

 それならどうやるのか?というと、マルチスレッドを使い、別スレッドでやりたい処理をするのがいいのでは?と思います。
 しかし、この関数内でWaitFor〜などで処理終了を待ってしまうと、結局、同様に待っている間メッセージポンプを動かさないとバーは動きません。

 以上のように、結論としては、とにかく、メインスレッドは動かしておかないとダメ!ということみたいです。
ランキングへ     posted by 遠雷 | Comment(0) | コントロール