dポイントプレゼントキャンペーン実施中!

VC++2005のMFC環境でプログラムを作成しています。
リストコントロールのイベント(LVN_KEYDOWN)よりハンドラを作成し、
下記のような実装を行い、最下行からさらに下キーを押下した際に、
最上行に選択フォーカスを移動させたいのですが、
青いフォーカスは上に移動しますが、点線のボックスが最下行に
そのまま残ってしまい、その後もおかしな動きをしてしまいます。
何か実装で間違っている点があるのでしょうか?
解決策をご存知の方おられましたら、ご教示お願いいたします。
下記が問題のソースコードです。

void CtestListDlg::OnLvnKeydownList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LV_KEYDOWN *pNMLV = reinterpret_cast<LV_KEYDOWN*>(pNMHDR);
int ret = m_listTest.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
if(ret==-1) return;
if(pNMLV->wVKey==VK_UP){
if(ret==0){
int count = m_listTest.GetItemCount();
m_listTest.SetItemState(count-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED);
}
else{
m_listTest.SetItemState(ret-1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED);
}
}
if(pNMLV->wVKey==VK_DOWN){
int count = m_listTest.GetItemCount();
if(ret==count-1){
m_listTest.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED);
}
else{
m_listTest.SetItemState(ret+1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED);
}
}
*pResult = 0;
}

「リストビューで最下行から最上行にスクロー」の質問画像

A 回答 (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;
}

この回答への補足

ご回答ありがとうございます。
確かにご提示頂いた方法で、期待動作をさせることが出来ました。
ありがとうございました。
ここからは、方法についての疑問点なのですが、
>pResultに1を入れて直ちに制御を戻します。其れ以外の場合は、pResultは0です。

とありますが、pResultの値が0と1とでは、
どのような意味の違いがあるのかが分かりません。
もし宜しければ、お手数おかけしますが、
こちらの疑問点につきましても、お答え願えませんでしょうか?

補足日時:2009/07/05 17:26
    • good
    • 0

 こんにちは。

補足頂きました。此れを説明するのは困難です。

 http://msdn.microsoft.com/ja-jp/library/1ssc6038 …

 イベントハンドラの種類やコントロールの種類によってまちまちですので、一概には言えないのですが、少なくともLVN_KEYDOWNイベントハンドラにおいて、簡単に言えば、pResult = 0でデフォルト処理へ渡され、pResult = 1で、自分自身の行った処理が全てになる、と言う事でしょうか。

 其の侭デフォルト処理が行われると、折角自前で行った処理が上重ねされてしまい、台無しになる事があります。
 例えば提示したサンプル中のpResult = 1の部分をpResult = 0にした場合、移動すると、もう一つ分余計に移動してしまいます(2個分移動してしまう)。

 要は、自前で「最上行⇔最下行」へ移動する処理を自前で行っておきながら、デフォルト処理へ渡してしまうと、其の中でも移動処理が成される為、一つ分余計に移動する現象が起きる、と言った具合です。

 MFCに関わらず、WindowsAPI関連の実装は、常にこの様な病的な現象が呪いの如くについて回ります。
 此れに太刀打ちするは、経験や体験、実験を重ねる事でしかないと思っています。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
確かにpResult = 1の部分をpResult = 0にした場合、
期待動作をさせることは出来ませんでした。
勉強になりました。ありがとうございました。

お礼日時:2009/07/05 21:46

SetItemState()は「見た目」しか変わりません。

見た目だけ変えても「今、本当に選ばれているもの」は変化しません。

「今、本当に選ばれているもの」はSetHotItem()じゃないと変わりません。

つまり、現状のままでは「見た目だけ最上行⇔最下行に行き来してるように見えるけど、本当に選ばれているものは何も変わってないから、その後もおかしな動きをしているように見える」のです。

試してないですが、SetHotItem()を行うと、自動的に見た目も変わるかも知れません(SetItemState()を呼ばなくても良いかも知れない?)

なお、SetHotItem()を行う時に「選ぼうとしたアイテムがリストの外にスクロールアウトして見えてない状態」の時は、自動でスクロールしてくれないかも知れないので、その場合、EnsureVisible()を使って、選ぼうとしたアイテムがリスト内に表示されるようにすれば、スクロールインしてくると思います。

まとめると、選択アイテムを変更する場合は

SetItemState()で見た目を変える。
SetHotItem()で選択アイテムを変える。
EnsureVisible()で必ず見える状態にする。

と言う3つの処理をセットで行わないと駄目だと思います。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
複数処理を組み合わせることで、実現可能なのですね。
また検証してみたいと思います。

お礼日時:2009/07/05 21:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!