リストビューにおけるサブアイテムを直接編集する方法

[戻る]
BCD 2009/08/05(水) 21:43:28
開発環境 WinXP(SP2) VC++6 MFC

リストビューにおけるサブアイテムを直接編集する方法を探しております。
私なりに調べた結果を以下に記述しましたので、間違いがございましたらご指摘くださ
い。また、お勧めのサイトがありましたら教えてください。


まず、目的ですが、既存のソフトで使用しているリストビューに直接編集機能を付加する
ことです。そのソフトは、ダイアログベースで作られております。メインダイアログのメ
ニューで変数表示を選択すると、内部変数表示用のダイアログが別に開き、ダイアログ上
のリストビューに変数名・値が表示されます。このリストビューのサブアイテムに直接編
集機能を付加し、値を直接書きかえられるようにしたいわけです。

過去ログを検索したところ、サブアイテムの直接編集についての記事で、今回の要望と
マッチした質問が2件、見つかりました。

http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200212/02120003.txt
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200409/04090024.txt

その中にサンプルソースの在りかも載っており、ダウンロードし動作確認しました。

http://www.codeguru.com/Cpp/controls/listview/editingitemsandsubitem/article.php/c1077

その他ネットで集めた情報を以下に示します。

・リストビューのスタイルにLVS_REPORTとLVS_OWNERDRAWFIXEDは必須。
・リストビューのサブアイテムをお手軽に直接編集できる関数はMFCにはない。
・自力でサブアイテム上にエディットボックスをかぶせ、それに入力する方法が一般的。
・エディットボックスはサブクラス化しなければならない。
・エディットボックスの元あった場所を描画する人はいないので、ところどころ文字が消
える。そのため、メインダイアログでオーナードローする必要がある。

このように、情報はある程度集まったのですが、私自信、リストビューを一度も作ったこ
とがなく、サブクラス化・オーナードローについても理解できておりません(現在、調べ
中)。

ひとまず、直接編集機能の肝らしきOnEndLabelEdit()とOnBeginLabelEdit()を眺め、エ
ディットボックスの位置を調整したり、入力した文字を反映させていることを理解しまし
た。しかし、その他は分からなかったため、とりあえずサンプルソースの
ListEditView.cppとListEditView.hとStdAfx.hをソフトに移植。その後、コンパイルエ
ラーはでませんでしたが、当然、それだけでは機能しませんでした。次に、
OnEndLabelEdit()とOnBeginLabelEdit()も呼ばれていないようなので、メッセージマップ
を確認しました。

    ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit)
    ON_NOTIFY_REFLECT(LVN_BEGINLABELEDIT, OnBeginLabelEdit)    

ON_WM_LBUTTONDOWNなどは分かるのですが、ON_NOTIFY_REFLECTという見慣れない文字が。
MSDNによるとメッセージリフレクションというそうですが、これが一体、何を意味するも
のか分からず、立ち往生しています。


以上、いろいろツッコミどころは多いと思いますが、どうかよろしくお願い致します。

wclrp ( 'o') 2009/08/06(木) 03:13:49
ON_NOTIFY_REFLECTについてのみの回答

MFCでは発生元の子ウィンドウのメッセージマップにON_NOTIFY_REFLECTがある場合、
親ウィンドウがWM_NOTIFYメッセージを受け取ったら
発生元の子ウィンドウにMFC独自のメッセージを送る。

これにより本来親ウィンドウが処理するWM_NOTIFYを
発生元である子ウィンドウに処理させることができる。

子ウィンドウがすべき処理を子ウィンドウが処理する。
クラスの役割がごちゃごちゃにならずプログラム構造がすっきりする。
#無論、子ウィンドウが行った方がいい処理の場合

BCD 2009/08/06(木) 19:48:52
ON_NOTIFY_REFLECTの件、ありがとうございます。

どうやら、DrawItemのオーバーライドのために使っているようですね。ですが、そのまま
移植しただけではオーバーライドされず、ASSERT(FALSE)に突入してしまいます。メイン
ダイアログのメッセージマップにDrawItemを移せばいいかとも思いましたが、リスト
ビューのクラスはCListViewから派生しておらず、そのまま移すことはできませんでした。

あと、サンプルの CListEditView を CListCtrl から派生すればうまくいくようですが、
基底クラスをCListViewからCListCtrlに変えただけではコンパイルエラーが山のように発
生しました。もうどこから手をつけていいのやら・・・。

と、こんな感じで今日一日悪戦苦闘しておりました。結局、オーバーライドでつまずいた
まま先へ進めず・・・。どなたか成功した方がいらっしゃいましたらアドバイスいただけ
ないでしょうか。

PATIO 2009/08/07(金) 18:13:30
CListCtrlとCListViewは全く別物ですよ。
従って置き換えれば何とかなると言うようなものでは有りません。

この辺はC++の言語レベルの話ですから派生とか継承に関して
きちんと勉強される事をお勧めします。
この辺の知識が無いままに進んでも良い結果は出ないと思います。

置き換えてうまく行く為には、少なくともCListViewとCListCtrlが
"is a"の関係になっている時で無いと駄目です。
この辺の用語が分からないようであれば、C++言語の勉強を
ちゃんとした方が良いと思いますよ。

BCD 2009/08/07(金) 18:19:05
ようやくオーバーライドすることができました。
また、いろいろ調べているうちに、自分が間違っていたことに気づいてきました。

まず、私がいじろうとしているのはリストビューではなくリストコントロールだったとい
うことです。(クラスもCListCtrlを基底クラスにしていました。)

また、ON_NOTIFY_REFLECTなしでもDrawItemをオーバーライドできましたので、これも
オーバーライドとは関係ないようです。親ウインドウの処理を子ウインドウが処理すると
いう動きから勝手に思い込んでいました。

なお、オーバーライドに関しては下記のサイトが参考になりました。

http://www.alpha-net.ne.jp/users2/uk413/vc/VCT_LVowner.html

ただ、オーバーライドに成功したものの、別の問題で頭を抱えております。オーバーライ
ドしたDrawItemはCListCtrlから派生させたクラス(CMyList)に追加したのですが、サン
プル内のDrawItemではGetListCtrlなどCListViewクラスのメンバ関数が使用されているた
め、定義されていないとエラーが発生します。そこで、CListViewもCMyListに継承させよ
うとしたのですが、CListViewとCListCtrlはCWndという共通の祖先をもつため、共通する
メンバ関数は派生があいまいというエラーが発生します。これを解決するためには以下の
2つの方法があるようです。

方法1:派生があいまいといわれた関数にスコープ演算子をつけ、どのクラスの関数かを
明示する。

方法2:派生クラスにCWndを指定している箇所にvirtualをつけ仮想基本クラスにする。

<参考サイト>
http://marupeke296.com/CPP_No8_MultiClass.html

ただ、両方とも問題があります。方法1ではコンストラクタ部分で「deleteの派生があい
まいです」とエラーが発生します。コンストラクタ内にdeleteは記述されていないため、
スコープ演算子をつけることができず、解決できません。また、方法2ではMFCのファ
イルを書き換えなければならないため、危険すぎます。

というわけで、CListViewとCListCtrlを多重継承する方法をご存知の方は、どうかお教え
いただけないでしょうか。

BCD 2009/08/07(金) 18:21:31
PATIO さん。アドバイスありがとうございます。

先の返信文を書いている間に送信されたようですので、お礼の言葉が返せませんでした。

PATIO 2009/08/07(金) 19:07:46
えーと、多分、根本のところで考え違いをされていると思います。

CListViewとCListCtrlの関係を正しく理解していれば、
言われているような話は出てこないはずです。

CListViewとCListCtrlの関係はどんな関係でしょう?
また、CListCtrlクラスから派生したクラス内でGetListCtrlを使う必要が
どうしてあるのでしょう?

DrawItemの中のコードを何処から持ってきたのか分かりませんが、
なぜ、GetListCtrlを使っているのかを理解しないと先に進めないと
思いますよ。

PATIO 2009/08/07(金) 19:12:39
釈迦に説法かもしれませんが、

純粋なC++言語の勉強をされた方がいいような気がします。
クラスの概念の部分で知識が足りていない為に返って混乱しているように
見えます。MFCはC++言語が理解できている事が前提ですのでこの辺の知識が
足りない状態でMFCの使用方法だけを勉強されても躓いてしまいます。

色々と事情はあると思いますが、上記の部分は、はしょれない部分だと
私は思います。今後の事を考えるのであれば、今一度立ち返るべきでは
無いかと思います。

BCD 2009/08/07(金) 19:57:44
ご指摘ありがとうございます。

ご忠告どおりもう少し勉強してみることにします。

古いスレッドには追加発言できません。