首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

Win32 組合語言教程:TreeView 樹狀檢視控件完整實作與拖放操作

     編輯:組合語言

前言

TreeView(樹狀檢視)是呈現階層式資料的核心控件,廣泛應用於檔案總管、註冊表編輯器等經典介面。本文詳細說明 TreeView 的建立、樣式設定、影像清單關聯、項目插入與擷取、通知訊息處理,並完整實作拖放(Drag-Drop)操作流程,附 MASM 範例碼。

控件建立與基本樣式

透過 CreateWindowEx 指定類別名 SysTreeView32 建立,必須先呼叫 InitCommonControls。常用視窗樣式:

  • TVS_HASBUTTONS:父項目顯示 +/- 按鈕,點擊展開/摺疊
  • TVS_HASLINES:項目間以連線顯示階層關係
  • TVS_LINESATROOT:根節點亦顯示連線(需配合 TVS_HASLINES)

範例組合:WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT

影像清單建立與關聯

TreeView 項目左側圖示來源於影像清單:

invoke ImageList_Create, 16, 16, ILC_COLOR16, 2, 10  ; 16x16, 16色, 初始2張, 最大10張
mov hImageList, eax
invoke LoadBitmap, hInstance, IDB_TREE
invoke ImageList_Add, hImageList, eax, NULL
invoke DeleteObject, eax          ; 釋放位圖控制碼
invoke SendMessage, hwndTreeView, TVM_SETIMAGELIST, TVSIL_NORMAL, hImageList

TVSIL_NORMAL 含一般/選取兩種狀態圖示;TVSIL_STATE 供自訂狀態使用。

項目插入:TVM_INSERTITEM 與 TV_INSERTSTRUCT

核心結構:

TV_INSERTSTRUCT:
  hParent      DWORD ?  ; 父項目控制碼,NULL/TVI_ROOT 表根節點
  hInsertAfter DWORD ?  ; TVI_FIRST/TVI_LAST/TVI_SORT
  item         TVITEM <> ; 項目屬性

TVITEM:
  imask           DWORD ?  ; 有效欄位旗標:TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE...
  hItem           DWORD ?  ; 項目控制碼(由系統指派)
  state           DWORD ?
  stateMask       DWORD ?
  pszText         DWORD ?  ; 項目標籤字串指標
  cchTextMax      DWORD ?  ; 緩衝區大小(查詢時用)
  iImage          DWORD ?  ; 未選取時圖示索引
  iSelectedImage  DWORD ?  ; 選取時圖示索引
  cChildren       DWORD ?
  lParam          DWORD ?  ; 應用程式自訂資料

插入根節點範例:

mov tvinsert.hParent, NULL
mov tvinsert.hInsertAfter, TVI_ROOT
mov tvinsert.item.imask, TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
mov tvinsert.item.pszText, offset Parent
mov tvinsert.item.iImage, 0
mov tvinsert.item.iSelectedImage, 1
invoke SendMessage, hwndTreeView, TVM_INSERTITEM, 0, addr tvinsert
mov hParent, eax          ; 取得根節點控制碼

子節點插入時 hParent = hParent,hInsertAfter = TVI_LAST。

項目資訊擷取:TVM_GETITEM 與 TVM_GETNEXTITEM

若無項目控制碼,可用 TVM_GETNEXTITEM 依關係取得:

  • TVGN_CARET:目前選取項目
  • TVGN_CHILD:第一個子項目
  • TVGN_PARENT:父項目
  • TVGN_NEXT / TVGN_PREVIOUS:同層下一個/上一個
  • TVGN_ROOT:根項目
  • TVGN_DROPHILITE:拖放目標高亮項目

取得 hItem 後,填入 TVITEM.hItem 並設定 imask,發送 TVM_GETITEM 即可擷取資訊。

拖放操作完整流程

TreeView 拖放非自動處理,需手動協調影像清單與滑鼠捕捉:

1. 開始拖放:TVN_BEGINDRAG 通知

.elseif uMsg==WM_NOTIFY
  mov edi, lParam
  assume edi:ptr NM_TREEVIEW
  .if [edi].hdr.code == TVN_BEGINDRAG
    invoke SendMessage, hwndTreeView, TVM_CREATEDRAGIMAGE, 0, [edi].itemNew.hItem
    mov hDragImageList, eax
    invoke ImageList_BeginDrag, hDragImageList, 0, 0, 0  ; 熱點設左上角
    invoke ImageList_DragEnter, hwndTreeView, [edi].ptDrag.x, [edi].ptDrag.y
    invoke SetCapture, hWnd
    mov DragMode, TRUE
  .endif
  assume edi:nothing

TVM_CREATEDRAGIMAGE 回傳含單一拖放圖示的影像清單控制碼。

2. 拖曳中:WM_MOUSEMOVE 處理

.elseif uMsg==WM_MOUSEMOVE
  .if DragMode==TRUE
    ; 解析 lParam 取得 x, y
    mov eax, lParam
    and eax, 0FFFFh
    mov ecx, lParam
    shr ecx, 16
    mov tvhit.pt.x, eax
    mov tvhit.pt.y, ecx

    invoke ImageList_DragMove, eax, ecx
    invoke ImageList_DragShowNolock, FALSE        ; 隱藏拖放圖示以便 HitTest
    invoke SendMessage, hwndTreeView, TVM_HITTEST, 0, addr tvhit
    .if eax != NULL
      invoke SendMessage, hwndTreeView, TVM_SELECTITEM, TVGN_DROPHILITE, eax
    .endif
    invoke ImageList_DragShowNolock, TRUE         ; 恢復顯示
  .endif

關鍵技巧:ImageList_DragShowNolock(FALSE) 暫時隱藏拖放圖示,避免干擾 TVM_HITTEST 判斷滑鼠下方項目;高亮顯示用 TVGN_DROPHILITE。

3. 結束拖放:WM_LBUTTONUP 處理

.elseif uMsg==WM_LBUTTONUP
  .if DragMode==TRUE
    invoke ImageList_DragLeave, hwndTreeView
    invoke ImageList_EndDrag
    invoke ImageList_Destroy, hDragImageList
    invoke SendMessage, hwndTreeView, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0
    invoke SendMessage, hwndTreeView, TVM_SELECTITEM, TVGN_CARET, eax   ; 正式選取
    invoke SendMessage, hwndTreeView, TVM_SELECTITEM, TVGN_DROPHILITE, 0 ; 移除高亮
    invoke ReleaseCapture
    mov DragMode, FALSE
  .endif

必須清理拖放狀態:銷毀拖放影像清單、釋放滑鼠捕捉、將高亮項目轉為正常選取狀態,否則後續選取會出現視覺殘留。

完整範例程式架構

程式包含標準視窗類別註冊、WM_CREATE 建立 TreeView 與影像清單、插入根/子節點、WM_NOTIFY 處理 TVN_BEGINDRAG、WM_MOUSEMOVE/WM_LBUTTONUP 實作拖放邏輯、WM_DESTROY 清理。完整 MASM 碼見原文。

總結

TreeView 是功能豐富但需手工處理細節的控件。掌握 TV_INSERTSTRUCT 項目插入、TVM_GETNEXTITEM 導航、影像清單關聯,以及拖放流程中的 TVM_CREATEDRAGIMAGE/ImageList_Drag* 協作機制,即可構建專業級階層式介面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved