子ダイアログ中のリストビューをソートするには?

解決


ムーディー  2007-07-02 20:53:49  No: 65553

VS 2005, C++, MFC, SDI アプリです。

呼び出す子ダイアログにリストビューを設け、レポートスタイルで一覧表を表示しています。
各列のコラムをクリックしてソートするようにしたいのです。
ソートについて、ここを参考にして作りました。
http://homepage3.nifty.com/mitui707/VisualC/VClistview_sort.html/

ビルドはエラーなく出来たのですが、実行してコラムをクリックすると、
次のデバッグメッセージが出て終了します。
”Debug Assetion Failed!
・・・・・\VC\altmfc\src\mfc\winctrl2.cpp
Line:544”
ちなみに、このファイルの544行には「ASSERT(::IsWindow(m_hWnd));」と書かれています。
動作エラーになるのは、前記サンプルでいうと、CALLBACK関数内の次の箇所です。
CListview_sortView* pDlg = (CListview_sortView*)AfxGetMainWnd();
CString str1 = pDlg->m_list1.GetItemText((int)param1, sCol);

リストコントロールをゲット出来ていない感じがします。
前記のサンプルは、CFormViewベースアプリの親自体にリストビューを設けた場合のようで、この通り作ったら勿論OKでした。
子ダイアログの場合、どういう変更をしたらいいか、教えてください。
どなたか、よろしくお願いいたします。


Blue  2007-07-02 21:19:36  No: 65554

>AfxGetMainWnd
が何を指しているのかヘルプで確認してみてはどうでしょうか?

単にリストビューの載っているダイアログを取得するならば、

this->GetParent(); // 親ウィンドウの取得

とかではないでしょうか?


ムーディー  2007-07-02 22:17:47  No: 65555

Blue 様、早速のご教示、有り難うございます。

しかし、this->GetParent(); でビルドするとエラーとなり、
「静的なメンバ関数は 'this' ポインタをアクセスすることができません。」とメッセージが出ます。
前記のサンプルにも、次の記述があります。
「//■ staticメンバ関数なので、GetParent()で親ウィンドウを取得することはできない」

自分はまだ、static や CALLBACK の取り扱いが未熟なようで、このフォーラムにすがろうと考えた次第です。済みません。


Blue  2007-07-03 00:14:21  No: 65556

子から親を意識するようなつくりはあまり好ましくないです。
データ部分とコントロール部分を分けて設計すべきです。

とりあえず、アプリケーションクラス(CXXXApp)にでも親となるウィンドウの
ポインタを覚えさせておいて、それを参照するとか。


ムーディー  2007-07-03 01:11:41  No: 65557

ありがとうございます。

ご回答を戴くまでの間にネット上を検索していたら、全く同じ問題にぶつかった人の記事を見付けました。
http://forums.belution.com/ja/vc/000/196/07s.shtml
このページの最後のところに、「コールバック関数に、引数で渡すようにしたらできました。」と書いてありました。

そうか!  と思い、やってみようと思いましたが、コールバック関数に引数で渡すやりかたが判りません。(苦笑)
static int CALLBACK CompareFunc(LPARAM param1, LPARAM param2, LPARAM param3, CDialog* pDlg);  ←違うようです。
ご教授にある「親となるウィンドウのポインタを覚えさせておいて、それを参照する」。このやり方も出来るかどうか。  m(_ _)m


Blue  2007-07-03 02:03:40  No: 65558

CListCtrl::SortItems

のヘルプを見るとわかると思いますが、2番目の引数で
「比較関数に渡されるアプリケーション定義の値。」
を指定できます。

よって一番最初のサイトの
>m_list1.SortItems(CompareFunc, bSort);
を変更します。
おそらく

m_list1.SortItems(CompareFunc, reinterpret_cast<DWORD>this);

となるでしょう。

そして、CompareFuncの三番目の引数でSortItemsの二番目の引数がわたってくるので、

CXXXDlg* pDlg = reinterpret_cast<CXXXDlg*>(param3);

とすることで取得できます。

http://www.paw.hi-ho.ne.jp/ynagata/softknowhow/cpp/cppdoc6.htm
が参考になるでしょう。


Blue  2007-07-03 02:05:55  No: 65559

>m_list1.SortItems(CompareFunc, reinterpret_cast<DWORD>this);
括弧が抜けていました。

m_list1.SortItems(CompareFunc, reinterpret_cast<DWORD>(this));

>とりあえず、アプリケーションクラス(CXXXApp)にでも親となるウィンドウの
>ポインタを覚えさせておいて、それを参照するとか。
は単に CXXXApp クラスにメンバ変数として CXXXDlg*型の値を用意して
どこかで

static_cast<CXXXApp*>(AfeGetApp())->m_pXXDlg = this;

と入れておくって方法です。
まぁ、SortItemsの2番目の引数を使うのが一般的でしょうけど。


ムーディー  2007-07-03 02:51:57  No: 65560

勉強させて戴きました。
出来ました!
SortItemsの2番目の引数にリストコントロールのポインタを入れました。
昇順・降順の bSort はグローバル変数で定義しました。

void CDlg1::OnLvnColumnclickList1(NMHDR *pNMHDR, LRESULT *pResult)
{
    ・・・
    CListCtrl* pLC = &m_list1;
    m_list1.SortItems(CompareFunc, (LPARAM)pLC);
    if (bSort == FALSE) bSort = TRUE;
    else bSort = FALSE;
}

int CALLBACK CDlg1::CompareFunc(LPARAM param1, LPARAM param2, LPARAM param3)
{
    CListCtrl* pLC = (CListCtrl*) param3;
    CString str1 = pLC->GetItemText((int)param1, sCol);
    CString str2 = pLC->GetItemText((int)param2, sCol);
    int iReturn;
    if(!bSort) iReturn = wcscmp(str1, str2); 
    else iReturn = wcscmp(str2, str1); 
    return iReturn;
}

これでバッチリです。
ご親切にご教授、ありがとうございました。


Blue  2007-07-03 03:04:40  No: 65561

>昇順・降順の bSort はグローバル変数で定義しました。
だったら、親ウィンドウのメンバ変数に指定しまえばどうでしょうか?

また
>    if (bSort == FALSE) bSort = TRUE;
>    else bSort = FALSE;
なら単に

bSort = !bSort;

でよさげ。


Blue  2007-07-03 03:09:25  No: 65562

訂正

>だったら、親ウィンドウのメンバ変数に指定しまえばどうでしょうか?
はパラメタでthisを指定するときはでしたね。

ついでに
>    int iReturn;
>    if(!bSort) iReturn = wcscmp(str1, str2); 
>    else iReturn = wcscmp(str2, str1); 
も、変数使わないで

if (!bSort) return wcscmp(str1, str2);
return wcscmp(str2, str1);

でもいいですね。

というか、CString の変数を対称にしているのであれば、
> wcscmp
ではなく、_tcscmpもしくはCString::Compareを使うべきでしょう。


ムーディー  2007-07-03 05:07:00  No: 65563

有り難うございます。
CString::Compare を使うことにします。
_tcscmp 系統は、UNICODE とかマルチバイトとかで使い分けが厄介に思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加