• ベストアンサー

CTreeCtrlのHitTestメソッドについて

環境:WinXP VS2005 MFC使用 CTreeCtrlに階層のあるアイテムを複数個設定しています。 ノード開閉時にカーソル位置にあるアイテムをGetCorsorPos()+HitTest()関数を使用し、取得していました。これは正しいアイテムのハンドルが返ってきています。 ところが、ある程度ノードを開いていき、表示しきれなくなるとスクロールが表示されますが、一番下までスクロールしている状態だとアイテムがうまく取得できていないようです。 おそらく、GetCursorPosが画面上の相対座標を取得するのに対し、HitTestで設定するのはツリーコントロール自体の相対座標なので、スクロールしている分だけずれてしまっているのではないかと思っているのですが、スクロールしているサイズを取得する方法がわかりませんでした。ご存じの方いましたらご教授をお願いします。 ※ソース抜粋 void CTestTreeCtrl::OnTvnItemexpanded(NMHDR *pNMHDR, LRESULT *pResult) { CPoint point; GetCursorPos(&point); ScreenToClient(&point); // マウスカーソルの位置からアイテムのハンドルを取得する HTREEITEM hItem = HitTest(point);           ・           ・           ・

質問者が選んだベストアンサー

  • ベストアンサー
  • WizTaka
  • ベストアンサー率53% (7/13)
回答No.1

yutyantyan さんが本当に取得したいのは "どれだけスクロールしたか" ではなくて "スクロールした状態でのツリーのアイテム" ですよね?? "ツリーのアイテムが選択された" ときには TVN_SELCHANGED イベントをキャッチすることができます. また,そのメッセージハンドラの中は以下のようになっています. //------------------------------------------------------------ LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); // TODO: ここにコントロール通知ハンドラ コードを追加します。 *pResult = 0; //------------------------------------------------------------ この TODO の下で   HTREEITEM hItem = pNMTreeView->itemNew.hItem; とすれば,選択したアイテムを取得できます. このようにすれば,スクロールした距離を取得する必要もなければ,マウスの座標から HitTest でアイテムを取得する必要もなくなります. スクロールしている距離を取得する方法の回答にはなっていませんが,この方法ではダメですか?

yutyantyan
質問者

お礼

なるほど。。。 今までスクロール周りの制御しか見ていなかったので、イベントそのものを変えるという発想が出てきませんでした。 大変参考になりました。さっそく試してみます。 貴重なご意見ありがとうございました。

その他の回答 (1)

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

動作検証している時間がありませんが… CTreeCtrl::GetFirstVisibleItem()でTreeViewの先頭に表示されているアイテムを取得、 CTreeCtrl::GetItemRect()で、そのアイテムの表示されているRECTを取得して、 RECT.leftとRECT.topをHitTestする際のPOINTに加算してみてはどうでしょうか? 先頭のアイテムが一部だけ表示されている状態の時にズレが出るような気もしますが……。

yutyantyan
質問者

お礼

貴重なご意見ありがとうございます。 参考にさせていただきます。

関連するQ&A

  • LVM_HITTEST

    マウス位置に存在するエクスプローラ内のアイテムを取得しようと思っております。 エクスプローラの左側のフォルダ一覧(クラス名:SysTreeView32)と右側のファイルとフォルダ名の一覧(クラス名:SysTreeView32)において、そのSysListView32内のマウス位置に存在するアイテムを取得したいのです。 なぜかというと、オリジナルアプリ内のリストビューにFTPサーバのファイル一覧を出力し、リストビューからエクスプローラへの直接ドラッグにより、サーバからローカル\TempにDLして、ドラッグ先にDLしたファイルを移動したいのです。 現状としてはLVM_HITTESTをエクスプローラ内のSysListView32に送っているのですが、こちらが送ったLVHITTESTINFO構造体のXYと、SpyでみたXYの値が違っているのです。結果としてアイテムインデックスを得ることができませんでした。 参考までに、LVM_GETITEMCOUNTはエクスプローラからも取得できました・・・ どのようにしたら、マウス位置のアイテムを取得することができるのでしょうか? 簡単に処理内容を記します。 ドラッグ時に GetCursorPos:マウス位置を取得 WindowFromPoint:マウス位置のハンドル取得 GetClassName:マウス位置のハンドルよりそのオブジェクトのクラス名を取得 以下は[クラス名=SysListView32]のときのみの処理 ScreenToClient:SysListView32をベースとした座標に変換 SendMessage: TVM_HITTESTと、LVHITTESTINFO構造体を送る 以上です。 本当は・・・ アプリはVBにて製作中なのですが、この手の質問はこちらのCの掲示板の方が回答を望めるかもと思って、こちらに質問させていただきました。Cで答えていただいて結構です。こちらでコンバートしますので。。。 どうぞよろしくお願いいたします。m(__)m

  • DirectInputでの現在のマウス座標は・・?

    DirectInputでマウス座標を取得したいのですが、 lX lY による移動量の取得方法しかわからず、 初回起動時に下のコードで現在座標を取得して扱っているのですが、 ----------------------------------- GetCursorPos(&point); ScreenToClient(hWnd, &point); input_mpos[0] = float(point.x); input_mpos[1] = float(point.y); ----------------------------------- 問題点 1.クライアント領域を抜け、モニターの隅までマウスカーソルが行っても移動量が加算され続け狂ってしまう 2.タイトルバーをダブルクリックして擬似フルスクリーンにすると移動量そのものが通用しない 3.フォーカスが飛んだり、ダイアログボックスが出ると現在座標が狂ってしまう に悩まされています。 常に確実にクライアント内の座標を捕らえ続けられる計算式というか、 定番の手順というものが有ったりするのでしょうか? それとも、マウス座標はDirectXで取得しようとする事そのものが間違いだったりするのでしょうか? 経験者様いらっしゃいましたら、ヒント程度でも構いませんので教えて頂けると幸いです。 orz

  • VBAで ScreenToClient を使いたい

    Excel VBA で、ユーザーフォームをクリックしたときのポインタのクライアント座標を取得し、フォーム上のラベルに表示するというスクリプトを作ろうと思っています。 ウェブで探し当てたVBのソースなどを参考にして、スクリーン座標を取得するところまではうまくいきましたが、「ScreenToClient」関数の書式がVB のソースと同じでは動かないようで、「コンパイルエラー:メソッドまたはデータメンバがみつかりません」というエラー表示が出て止まってしまいます(「Me」を「UserForm1」に代えても結果は同じでした)。 以下は実際のVBAソースです。どのようにすれば動くようになるのか、ご教示頂けませんでしょうか。宜しくお願いします。 'カーソルの位置座標をスクリーン座標で取得するAPI関数 Private Declare Function GetCursorPos Lib "user32" _ (lpPoint As POINT) As Long 'カーソルの位置座標をスクリーン座標からクライアント座標へ変換するAPI関数 Private Declare Function ScreenToClient Lib "user32" _ (ByVal hWnd As Long, lpPoint As POINT) As Long 'カーソルの位置座標用変数 Private CuP As POINT '位置座標を受け取る構造体 Private Type POINT x As Long y As Long End Type Private Sub UserForm_Click() 'スクリーン座標を取得 GetCursorPos CuP Label1.Caption = "クリック位置のスクリーン座標 X=" & CuP.x & " Y=" & CuP.y '↑ここまではうまく動いています 'クライアント座標に変換 ret = ScreenToClient(Me.hWnd, CuP) Label2.Caption = "クリック位置のクライアント座標 X=" & CuP.x & " Y=" & CuP.y End Sub

  • Visual C++ 2008 Express Editionでの カーソル座標取得

    こんにちは.素人の質問ですがどなたか教えてください. Visual C++ 2008 Express EditionのWindowsフォームアプリケーションで,マウスカーソルの位置座標を取得して,その値を画面に表示させることをやりたいと思っています.マウスカーソルの位置座標取得にはGetCursorPos()関数を使用すると調べたのですが,Windowsフォームアプリケーションのプログラム中でどのように使用すれば良いのか分かりません. 宜しくお願いします.

  • マウス位置の色を得る

    マウス位置は lParam にあるらしいから  typedef struct tagPOINT {   LONG x_zahyo_long;   LONG y_zahyo_long;  }POINT;  POINT p;  char x_zahyo[5], y_zahyo[5]; として、  case WM_RBUTTONDOWN:   p.x_zahyo_long = LOWORD(lParam);   p.y_zahyo_long = HIWORD(lParam);   sprintf(x_zahyo,"%04d", p.x_zahyo_long);   sprintf(y_zahyo,"%04d", p.y_zahyo_long);   SetWindowText(hrs, x_zahyo);   SetWindowText(hrs, y_zahyo);  break; でやってたけど、得られた座標は常に 0001,0001 でした。 本題とは別だけど、4桁表示のやり方で、もっといいソースがあったら 教えてください。 bcc32 では lParam からマウス位置取得は無理ですか? lParam が使えなかったから、  POINT p = { 0,0 }; として、  GetCursorPos( &p ); で座標を得ました。 それで、ウインドウ上のマウスの位置の色を取得するにはどうしたら いいんですか? getPixel( ) の引数やソースの書式を教えてほしいです。

  • 動的に切り替わる指定座標へ、スムーススクロール

    window.scrollTo("0",Y);で、 ウインドウを指定位置に移動させているのですが、 これをスムーススクロール対応するには、 どうすればよいでしょうか? Yは、指定座標(モニタ上の絶対位置)で、 任意のタイミングで、動的に取得してます。 イメージとしては、 関数みたいなのに、Y座標を渡して、 その都度、スムーススクロールさせるような使い方を想定してます。 jQueryとか、プラグインを使ってもいいですが、 なるべくシンプルに行きたいと思ってます。 また、結果的に、ページ内リンクも、スムーススクロールすることになったとしても別に構いませんが、 やりたいのは、リンクをスムーススクロールすることではなくて、 「動的に、都度切り替わる、Y座標へ、スムーススクロールしたい」ってことです。 難しいようであれば、 厳密なスムーススクロールじゃなくても、 何となくそれっぽく見えれば構いません。

  • ひし形のあたり判定について

    C言語でクォータービューのRPGを作っているのですが、ひし形をマップの座標からウィンドウへ描画する座標については自力で解決できたのですが、マウスの位置を取得してそこにカーソルを重ねるときにひし形のあたり判定の仕方がわからないのですが、どなたかご存知ないでしょうか? 教えてくださいお願いします。

  • リストコントロールのデータの変更を検知したい

    リストコントロールのデータの変更時に呼び出されるイベントが分かりません、 OnLvnItemchangedList()であっているのでしょうか?もっと簡単に実現できるのなら、 教えてください。 VC++2010 MFC です。 削除のときは、条件なしに、OnLvnDeleteitemList()内でいいのですが、 追加も pNMLV->uChanged == 4 にすれば問題ないです。でもその他は、厳しくしすぎると クリックしただけで、データが変更されたと判断されたり、・・・でうまく行きません。 【リスト上のデータが変更されるケース】 データが変更される場合は、非選択状態から「すべてを置換」するケースや 一個一個 検索(選択)しながら、「置換」するケースがあります。 後は、リストコントロールにエディットボックスを張り付かせて、「編集」(エンターで確定) して、データを変更するケースがあります。 ただし、「すべてを置換」する場合でも、既に選択状態のデータを処理する場合もあり、困っています。 自分で作ったプログラムなのですから、各機能終了時に変更されたか?されてないか?は 分かっているのですが、勉強のため、質問をしました。 PreTranslateMessage()で出来るのでしょうか? (参考サイト: http://isobe.exblog.jp/996027/ ) 【目的】 起動時 から(前回保存時から)リストデータに変化がない場合、何もせずに終了したい 【やりたいこと】 リストの文字が変わったら、キャプションを FileListCreator(*) にすると ともに、ListDataNoChange_FLG = FALSE; にする。 保存ややリカバリ(復帰)を行ったら (*) を取って、 ListDataNoChange_FLG = TRUE; にする。 if ( ListDataNoChange_FLG == TRUE ) //保存処理をスキップする。 【できれば】 あとは、pNMLV->uChanged などの 4とか8とか、定数で記述したいです。 lParamが何を意味しているか?分からないです。教えて下さい。 void CFileListCreatorDlg::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult) {   LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);   // TODO: ここにコントロール通知ハンドラー コードを追加します。   if (( pNMLV->uChanged == 4 && pNMLV->uNewState == 0 && pNMLV->uOldState == 0 ) //リストコントロールにアイテムが追加した時     || ( pNMLV->uChanged == 8 && pNMLV->uNewState == 3 && pNMLV->uOldState == 0)){ //「すべてを置換」「置換」ボタンを押した時 //「検索」ボタンで検索しただけでも選択状態になる     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 1 )     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 2 )     //|| ( pNMLV->uChanged == 8 && pNMLV->uNewState == 0 && pNMLV->uOldState == 3 )){     ListDataNoChange_FLG = FALSE;//追加 2012.05.13          CFileListCreatorDlg* m_Dlg = (CFileListCreatorDlg*)AfxGetMainWnd();     if( (m_Dlg==NULL)||(m_Dlg->GetSafeHwnd()==NULL) ){       return;     }     m_Dlg->SetWindowText(_T("FileListCreator (*)"));   }   //CString tempStr;   //tempStr.Format(_T("OnLvnItemchangedList iItem: %d, lParam: %d, uChanged: %d, uNewState: %d, uOldState: %d\n"), pNMLV->iItem, pNMLV->lParam, pNMLV->uChanged, pNMLV->uNewState, pNMLV->uOldState);   //MessageBox(tempStr);   *pResult = 0; } void CFileListCreatorDlg::OnLvnDeleteitemList(NMHDR *pNMHDR, LRESULT *pResult) {   LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);   // TODO: ここにコントロール通知ハンドラー コードを追加します。   ListDataNoChange_FLG = FALSE;//追加 2012.05.13   CFileListCreatorDlg* m_Dlg = (CFileListCreatorDlg*)AfxGetMainWnd();   if( (m_Dlg==NULL)||(m_Dlg->GetSafeHwnd()==NULL) ){     return;   }   m_Dlg->SetWindowText(_T("FileListCreator(*)"));   *pResult = 0; } ご教授下さい。

  • ダイアログ内コントロールの位置取得について

    いつもお世話になっております。 ダイアログ内に配置されているコントロールの位置の取得方法について ご教授頂きたく質問させていただきました。 私が試したところGetWindowRect( コントロールハンドル, &rc ); とするとありえないぐらい大きな座標が帰ってきます。 上記の方法ではうまくいきません。 ご教授よろしくお願いいたします。

  • ブラウザの外にあるマウスの情報を取得する方法

    例えば、googlemap だとDrag&Drop で地図をぐりぐりと動かすことが出来るのですが、その際にカーソルがブラウザの外に行っても地図はぐりぐりと動き続けますし、マウスボタンを離せばそれも認識して地図のスクロールは止まります。 つまり、ブラウザ外のマウスの座標とボタンイベントが取得できているのだと思いますが、これは当たり前のようでいて当たり前には出来ません。 ソースは読んでみましたが挫折しました。 どなたかこの技法について分かる方いらっしゃいましたら教えてください。

専門家に質問してみよう