ツリービューでマウス右・左クリック

  

ここに紹介するプログラムは、WIN XP 2003/Windows 7 (32bits) - OS 環境でマイクロソフトのVisual Studio 2010 で作ったものです。
Windows XP/ Windows 7(32bits) での動作は確認済みですが…

ツリービューでマウス右・左クリックの機能を持たせると色々な事が出来そうです。


このプログラムでは、以下の機能を持たせて見ました。

ツリービューのノードをマウスで左クリック

マウスで違うノードが選定されると、TV_SELECTEDCHANGEDメッセージが送られます。

クラス・ウイザードのメッセージマップでこのメッセージを選択すると、OnSelchanged関数が自動的に作成されます。

この関数にその時の処理をコーディングします。

 

/////////////////////////////////////////
// Left View でマウスの操作
#include "MainFrm.h"
void CLeftView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
  BOOL bRet = FALSE;
  int n = 0;
  int nImage = 0;
  int nSelectedImage = -1;

  NM_TREEVIEW* pNMTreeView = ( NM_TREEVIEW* )pNMHDR; ツリービューのハンドルを取得
  HTREEITEM hItem = pNMTreeView->itemNew.hItem; 選定したノードのハンドルを取得

  CTreeCtrl& Tree = GetTreeCtrl();
  Tree.GetItemImage( hItem, nImage, nSelectedImage ); 選定されたノードのアイコンに付けられた固有の番号取得
  CAutoACDoc* pDoc = GetDocument();

  CDWordArray contents;
  int count = GetContents( hItem, &contents ); データが保存されているアレー内の番号取得

  if( m_bSelect == FALSE ){
    switch( nImage ) { アイコンに付けられた固有の番号による動作を選択する
      case 12:
      case 4: // 負荷計算の関数
        if( count != 0 ) n = contents.GetAt( 0 ); // ROOMアイテムのIdex番号
        pDoc->ACLoadCalcu( n ); 負荷計算の関数を呼び出す
          if( pDoc->m_Result.GetSize()>0 && pDoc->m_Result[n].m_bIndex == TRUE ){
            Tree.SetItemImage( hItem, 12, 12 );ツリービューノードのアイコンを変更する
          }
        break;
      case 6: // 壁のデータ入力
      必要な処理を書く
        break;
      case 8: // 窓のデータ入力
      必要な処理を書く
        break;
      case 10: // その他のデータ入力
      必要な処理を書く
        break;
    }
    HTREEITEM hRoot = Tree.GetRootItem( );
    Tree.SelectItem( hRoot ); // 計算後ルートItemに戻る

    ツリービューのルートノードに戻るようにしておかないと再度同じノードをマウスでクリックしても     この関数が呼ばれず、違うノードしか選定できなくなる。

    CMainFrame* pWnd = (CMainFrame*)GetActiveWindow();
    pWnd->Active_RightView(); // AutoACView をアクティブにしツールバーのプレビューがアクティブをする
  }
  *pResult = 0;
}

 

 

暫く、このOnSelchanged()関数でマウスの左クリックに対応していましたが、一度アイコンを左クリックし動作させた後、更に同じアイコンをクリックしても動作しないのが使いにくく思われました。 これは、選定アイコンが変更されたときに動作する関数で当然なのですが。 そこで、何度でもクリックした時に動作をする関数OnLButtonDown()に書き換えました。

  

/////////////////////////////////////////
// Left View でマウス左ダウンの操作
void CLeftView::OnLButtonDown(UINT nFlags, CPoint point)
{
   UINT flag; // マウスが指しているポイントがアイコンかラベルかなどの判断
   int nImage = -1;
   int nSelectedImage = -1;

   CTreeCtrl& Tree = GetTreeCtrl();
   HTREEITEM hItem = Tree.HitTest( point, &flag );// この関数を使うのが味噌です
   Tree.GetItemImage( hItem, nImage, nSelectedImage );

   CDWordArray contents;
   int count = GetContents( hItem, &contents );

   CAutoACDoc* pDoc = GetDocument();
   BOOL bRet = FALSE;
   nFlags = MK_RBUTTON;
   int n = 0;

   if( flag & TVHT_ONITEMLABEL ){ // ラベルをクリックした時のみ
      switch( nImage ){
      case 12:
      case 4: // 負荷計算の関数
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // ROOMアイテムのIdex番号
         pDoc->ACLoadCalcu( n );
         if( pDoc->m_Result.GetSize()>0 && pDoc->m_Result[n].m_bIndex == TRUE ){
            Tree.SetItemImage( hItem, 12, 12 );
         }
        break;
     case 6: // 壁のデータ入力
        Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // ROOMアイテムのIdex番号
         bRet = pDoc->CreateWallDataArray( n );
         if( bRet == TRUE ){
            Tree.SetItemImage(Tree.GetParentItem(hItem), 4, 5);
         }
         break;
      case 8: // 窓のデータ入力
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // ROOMアイテムのIdex番号
         bRet = pDoc->CreateGlassDataArray( n );
         if( bRet == TRUE ){
            Tree.SetItemImage(Tree.GetParentItem(hItem), 4, 5);
         }
         break;
      case 10: // その他のデータ入力
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // ROOMアイテムのIdex番号
         bRet = pDoc->CreateOtherData( n );
         if( bRet == TRUE ){
            Tree.SetItemImage(Tree.GetParentItem(hItem), 4, 5);
         }
         break;
      }
   }
   CTreeView::OnLButtonDown(nFlags, point);
}

 

 

OnLButtonDown( )関数は、UINT nFlags と CPoint point2つの引数しか持たないので、ツリーのノード情報は自動的に

取得できません。

そこで、CTreeCtrl の HitTest( ) 関数を使い選択ノードのハンドルを取得しています。これで何度でも同じノードの選択が出来るようになりました。

マウス右ボタンの動作

右ボタンの動作は、OnRButtonDown( ) 関数を使いほぼ同様なコードで対応できます。

 

/////////////////////////////////////////////////
// Left View でマウス右ダウンの操作
void CLeftView::OnRButtonDown(UINT nFlags, CPoint point)
{
   UINT flag; // マウスが指しているポイントがアイコンかラベルかなどの判断
   int nImage = -1;
   int nSelectedImage = -1;

   CTreeCtrl& Tree = GetTreeCtrl();
   HTREEITEM hItem = Tree.HitTest( point, &flag );
   Tree.GetItemImage( hItem, nImage, nSelectedImage );

   CDWordArray contents;
   int count = GetContents( hItem, &contents );

   CAutoACDoc* pDoc = GetDocument();
   int n = 0;

   if( flag & TVHT_ONITEMLABEL ){ // ラベルをクリックした時のみ
      switch( nImage ){
      case 0:
         pDoc->AllACLoad();
        break;
      case 6:
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // アイテムのIdex番号
         TreeMenu( point, nImage, n );
         break;
      case 8:
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // アイテムのIdex番号
         TreeMenu( point, nImage, n );
         break;
      case 10:
         Tree.Select( hItem, TVGN_CARET ); // ノードを選択状態にする
         if( count != 0 ) n = contents.GetAt( 0 ); // アイテムのIdex番号
         TreeMenu( point, nImage, n );
         break;
      }
   }
   m_bSelect = FALSE;

   CTreeView::OnRButtonDown(nFlags, point);
}

 

 

ツリーのノードをクリックしたときのポップアップメニューを出すコードです。

 

//////////////////////////////////////////////////////
// TreeView Menu
void CLeftView::TreeMenu(CPoint point, int nImage, int nIndex)
{
   CMenu menu;
   POINT lpPt;

   menu.LoadMenu( IDR_TREEMENU );

   CMenu *pContextMenu = menu.GetSubMenu(0);
   lpPt.x = point.x;
   lpPt.y = point.y;
   ClientToScreen( &lpPt );
   m_nNode = nImage;
   m_nIndex = nIndex;

   if( m_nCopyNode != 0 ) menu.EnableMenuItem( IDR_TREEMENU_PASTE, MF_ENABLED | MF_BYCOMMAND );
   else menu.EnableMenuItem( IDR_TREEMENU_PASTE, MF_GRAYED | MF_BYCOMMAND );

   CWnd* pWork = this->GetParent();
   pContextMenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON, lpPt.x, lpPt.y, pWork );
}

 

マウスの左・右クリックやダブルクリックによる動作は、ほぼこれと同じコードで自由にプログラムできると思います。

次回は、もっとウインドウライクなドラッグアンドドロップなどを勉強するつもりです。

 


ページ先頭に戻る
最終更新日: 2020/02/04