case WM_CONTEXTMENU:
{
RECT rc={0};
GetWindowRect(g_hList,&rc);
ClientToScreenRect(&rc);
POINT pt;
pt.x=LOWORD(lParam);
pt.y=HIWORD(lParam);
BOOL bRet=TRUE;
bRet=PtInRect(&rc,pt);
if(bRet)
{
ClientToScreen(g_hList,&pt);
m_menu=LoadMenu(g_hInst,MAKEINTRESOURCE(IDR_MENU1));
pt.x=LOWORD(lParam);
pt.y=LOWORD(lParam);
ClientToScreen(g_hList,&pt);
GetCursorPos(&pt);
TrackPopupMenuEx(GetSubMenu(m_menu,0),TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,pt.x,pt.y,g_hList,NULL);
}
else
{
return 0;
}
CTreeCtrl结点拖动实现(与后台联动)1
原理:把一个结点机器下面的所有结点在需要释放的位置拷贝,释放后再把原来位置的结点删掉,结点拖动主要用到三个系统消息。
1. OnBeginDrag:选中要拖动的结点,建立拖动阴影(即拖动时和鼠标一起移动的那个阴影图标)
2. OnMouseMove:将拖动阴影与鼠标绑定,使其同鼠标一起移动。
3. LButtonUp:鼠标释放,结点拷贝,删除
如果单纯实现页面效果以上就足够了,但是如果要和后台联动,尝试在不同的情况下变幻图表或文字那还要自己写几个函数。这里提空两个函数例子,MoveBarch:用于移动结点。OnConnectStateCall:改变图标
实现步骤:
结合函数说明
void CHvrTree::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
CPoint pt;
ST_TREE_NODE *pDragNode = NULL;
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
g_pLogger->Debug( "<%s(%d)> OnBegindrag(): Enter", D_PC_LOG_NAME_HVRTREE, __LINE__ );
//////////////////////////////////////////////////////////////////////////
// 要移动的结点
m_hItemDragS = pNMTreeView->itemNew.hItem;
// 建立结点图标列
m_pDragImage = CreateDragImage( m_hItemDragS );
if( m_pDragImage == NULL )
{
// 错误提示在Log中
g_pLogger->Error( "<%s(%d)> OnBegindrag(): トラックイメージ取得失敗, err - %d",
D_PC_LOG_NAME_HVRTREE, __LINE__, GetLastError() );
g_pLogger->Debug( "<%s(%d)> OnBegindrag(): Leave", D_PC_LOG_NAME_HVRTREE, __LINE__ );
return;
}
//////////////////////////////////////////////////////////////////////////
// 拖动开始,首先县判断要拖动的结点是否存在
if( m_mapNode.Lookup( m_hItemDragS, (void*&)pDragNode ) == FALSE )
{
// 取得しない場合
// エラーログ
g_pLogger->Error( "<%s(%d)> OnBegindrag(): ノード情報取得失敗, err - %d",
D_PC_LOG_NAME_HVRTREE, __LINE__, GetLastError() );
g_pLogger->Debug( "<%s(%d)> OnBegindrag(): Leave", D_PC_LOG_NAME_HVRTREE, __LINE__ );
}
// 拖动检验,采用储存在映射表中的结点类型来分类可拖动和不可拖动的结点
// 2段カテゴリノード、物件ノードとカメラノードのみトラック許可
if( (pDragNode->nType == D_PC_NODE_CATE_1)||(pDragNode->nType == D_PC_NODE_CATE_2)
|| (pDragNode->nType == D_PC_NODE_HVR)
|| (pDragNode->nType == D_PC_NODE_CAM) )
{
//////////////////////////////////////////////////////////////////////////
// トラック開始
m_bDragging = TRUE; // 拖动标志位
m_pDragImage->BeginDrag( 0, CPoint(8,8) ); // 开始拖动的图标索引和图标位置的设定
pt = pNMTreeView->ptDrag; // 拖动起点位置
ClientToScreen( &pt );
m_pDragImage->DragEnter( AfxGetMainWnd(), pt ); // 在指定的垫上显示图标阴影
SetCapture(); // 获得鼠标焦点
SetTimer( D_PC_TIMER_HVRTREE_SCROLL, D_PC_TIMER_HVRTREE_SCROLL_TIME_OUT, NULL ); // 这个计时器用来设定当拖动的结点到达空间边缘却没有被释放时则该控件自动上移或下移
}
g_pLogger->Debug( "<%s(%d)> OnBegindrag(): Leave", D_PC_LOG_NAME_HVRTREE, __LINE__ );
*pResult = 0;
}
void CHvrTree::OnMouseMove(UINT nFlags, CPoint point)
{
HTREEITEM hItem; // 目標項目判断
UINT flags;
CString DeviceName;
if(m_bDragging)
{
// トラック状態
CPoint pt = point;
CRect rcHvrInfoView, rcMainFrame;
AfxGetMainWnd()->GetWindowRect(&rcMainFrame);
ClientToScreen(&rcMainFrame);
GetWindowRect(&rcHvrInfoView);
ClientToScreen(&rcHvrInfoView);
pt.x += rcHvrInfoView.left-rcMainFrame.left;
pt.y += rcHvrInfoView.top-rcMainFrame.top;
CImageList::DragMove(pt);
CImageList::DragShowNolock(false);
// 移动点判断。在控件内时如果移动到该结点的父结点则鼠标变为不可释放图标
if( ( hItem = HitTest( point, &flags ) ) != NULL )
{
// 元の目標設定
if ( ::LoadCursor(NULL, IDC_NO) != ::GetCursor() )
{
// アイコー設定
SetCursor(::LoadCursor(NULL, IDC_NO));
SelectDropTarget(NULL);
}
// トラップ目標設定
if ( GetParentItem(m_hItemDragS) != hItem )
{
// 鼠标图标设定
if (::LoadCursor(NULL, IDC_ARROW) != ::GetCursor()) ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
SelectDropTarget(hItem);
}
m_hItemDragD = hItem;
}
// 在控件外时,鼠标图标也作相应处理
hItem = HitTest( point, &flags );
if( hItem == NULL )
{
::SetCursor(::LoadCursor(NULL, IDC_ARROW));
}
CImageList::DragShowNolock(true);
}
CTreeCtrl::OnMouseMove(nFlags, point);
}
// 这里是拖动的重要环节。因为涉及到众多状态判断,所以大胆使用了goto,因为只在一个函数内使用所影响还不是很大。要是那位有更好的办法请赐教
void CHvrTree::OnLButtonUp(UINT nFlags, CPoint point)
{
BOOL bSuc;
ST_TREE_NODE *pNode = NULL; // 映射表中的结构初始化
ST_TREE_NODE *pDestNode = NULL; // 目標ノード情報
ST_TREE_NODE *pParentNode = NULL; // 親ノード情報
ST_DRAG_NODE_INFO *pDragInfo = NULL; // トラック情報
HTREEITEM hItem; // 目標項目判断
UINT nFlagsEx;
HTREEITEM hChild;
ST_TREE_NODE *pChildNode = NULL;
INT nRet;
HTREEITEM hNewDragItem; // 移动后的结点
g_pLogger->Debug( "<%s(%d)> OnLButtonUp: Enter", D_PC_LOG_NAME_HVRTREE, __LINE__ );
//SelectDropTarget(NULL); // 结点不要重画,否则会出现不规则的蓝条,原因是拖动释放的位置不见得就正好是要拖放位置的左上角,如果这时重画节点就会出现描画不完全的情况
SetItemState(m_hOld,0,TVIS_SELECTED|LVIS_FOCUSED);
// 拖放标志位。要不是执行拖动操作就直接退出
if( !m_bDragging )
{
goto LBTNUP;
}
//////////////////////////////////////////////////////////////////////////
// トラック中止
m_bDragging = FALSE; // トラック状態変更
CImageList::DragLeave(this); // ロック解除
CImageList::EndDrag(); // トラック終了
ReleaseCapture(); // マウスイベントリリース
// トラックイメージをクリア
delete m_pDragImage;
m_pDragImage = NULL;
KillTimer( D_PC_TIMER_HVRTREE_SCROLL ); // スクロールタイマ削除
SelectDropTarget(NULL); // ドラッグ&ドロップされたノードを描面しない