- ベストアンサー
リストビューで最下行から最上行にスクロールした際の描画問題
- VC++2005のMFC環境でプログラムを作成しています。リストコントロールのイベント(LVN_KEYDOWN)よりハンドラを作成し、最下行から最上行にスクロールする際に描画に問題が発生しています。問題のソースコードは以下のとおりです。
- 青いフォーカスは上に移動しますが、点線のボックスが最下行に残ってしまい、その後もおかしな動きをしてしまいます。この問題を解決する方法をご存知の方はいらっしゃいますか?
- 解決策をご教示いただけると幸いです。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 SetItemStateの最後のフラグが不完全なのでは。 以下ですと、選択状態に成るだけで、フォーカスまでは入らないです。 m_listTest.SetItemState(count-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED); m_listTest.SetItemState(count-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); とすればフォーカスも移動出来ます。 後は「↓または↑」を押して、「最下行⇔最上行へスクロール」する処理を行った場合は、pResultに1を入れて直ちに制御を戻します。 其れ以外の場合は、pResultは0です。 void CTestDlg::OnLvnKeyDown(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLVKEYDOWN pNMLV = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR); // TODO: ここにコントロール通知ハンドラ コードを追加します。 int ret = m_listTest.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED); if(ret==-1) return; int count = m_listTest.GetItemCount(); int LVIS = LVIS_SELECTED | LVIS_FOCUSED; if(pNMLV->wVKey == VK_UP) { //最上行にぶつかったら if(ret == 0) { m_listTest.SetItemState(count-1, LVIS, LVIS); *pResult = 1; return; } } if(pNMLV->wVKey == VK_DOWN) { //最下行にぶつかったら if(ret == count-1) { m_listTest.SetItemState(0, LVIS, LVIS); *pResult = 1; return; } } //其れ以外の位置なら m_listTest.SetItemState(ret, LVIS, LVIS); *pResult = 0; }
その他の回答 (2)
- machongola
- ベストアンサー率60% (434/720)
こんにちは。補足頂きました。此れを説明するのは困難です。 http://msdn.microsoft.com/ja-jp/library/1ssc6038(VS.80).aspx イベントハンドラの種類やコントロールの種類によってまちまちですので、一概には言えないのですが、少なくともLVN_KEYDOWNイベントハンドラにおいて、簡単に言えば、pResult = 0でデフォルト処理へ渡され、pResult = 1で、自分自身の行った処理が全てになる、と言う事でしょうか。 其の侭デフォルト処理が行われると、折角自前で行った処理が上重ねされてしまい、台無しになる事があります。 例えば提示したサンプル中のpResult = 1の部分をpResult = 0にした場合、移動すると、もう一つ分余計に移動してしまいます(2個分移動してしまう)。 要は、自前で「最上行⇔最下行」へ移動する処理を自前で行っておきながら、デフォルト処理へ渡してしまうと、其の中でも移動処理が成される為、一つ分余計に移動する現象が起きる、と言った具合です。 MFCに関わらず、WindowsAPI関連の実装は、常にこの様な病的な現象が呪いの如くについて回ります。 此れに太刀打ちするは、経験や体験、実験を重ねる事でしかないと思っています。
お礼
ご回答ありがとうございます。 確かにpResult = 1の部分をpResult = 0にした場合、 期待動作をさせることは出来ませんでした。 勉強になりました。ありがとうございました。
- chie65536(@chie65535)
- ベストアンサー率44% (8742/19841)
SetItemState()は「見た目」しか変わりません。見た目だけ変えても「今、本当に選ばれているもの」は変化しません。 「今、本当に選ばれているもの」はSetHotItem()じゃないと変わりません。 つまり、現状のままでは「見た目だけ最上行⇔最下行に行き来してるように見えるけど、本当に選ばれているものは何も変わってないから、その後もおかしな動きをしているように見える」のです。 試してないですが、SetHotItem()を行うと、自動的に見た目も変わるかも知れません(SetItemState()を呼ばなくても良いかも知れない?) なお、SetHotItem()を行う時に「選ぼうとしたアイテムがリストの外にスクロールアウトして見えてない状態」の時は、自動でスクロールしてくれないかも知れないので、その場合、EnsureVisible()を使って、選ぼうとしたアイテムがリスト内に表示されるようにすれば、スクロールインしてくると思います。 まとめると、選択アイテムを変更する場合は SetItemState()で見た目を変える。 SetHotItem()で選択アイテムを変える。 EnsureVisible()で必ず見える状態にする。 と言う3つの処理をセットで行わないと駄目だと思います。
お礼
ご回答ありがとうございます。 複数処理を組み合わせることで、実現可能なのですね。 また検証してみたいと思います。
補足
ご回答ありがとうございます。 確かにご提示頂いた方法で、期待動作をさせることが出来ました。 ありがとうございました。 ここからは、方法についての疑問点なのですが、 >pResultに1を入れて直ちに制御を戻します。其れ以外の場合は、pResultは0です。 とありますが、pResultの値が0と1とでは、 どのような意味の違いがあるのかが分かりません。 もし宜しければ、お手数おかけしますが、 こちらの疑問点につきましても、お答え願えませんでしょうか?