Announcement

Collapse
No announcement yet.

Treeview question

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Treeview question

    I'm using a treeview as a menu where the root level are really section headers and the nodes that call programs are in the first child level.

    Is it possible to cause the item navigated to or single clicked in the root level to auto move to the first child node and highlight it? A root node will always have child nodes.

    I would still like the normal behaviour of double-clicking the root node to open or close the first level of child nodes.

    Bob Mechler
    Last edited by BOB MECHLER; 10 Mar 2009, 12:36 PM. Reason: More info

  • #2
    Is it possible to cause the item navigated to or single clicked
    Code:
     WM_NOTIFY/TVN_SELCHANGED
    
    If new_selection = "Root item" THEN 
       Treeview_Select (First child of same) 
    ....
    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      This does what I want. The double-clicking of the root node toggles between expanded and/or collapsed but the single click of the + or the - doesn't respond. Might be ok this way, just checking.

      Code:
        IF (@lpNmh.Code = %TVN_SELCHANGED) AND (@lpNmh.idFrom = %ID_TREE2) THEN
          lpTV = CBLPARAM
          IF TreeView_GetParent(htree&(2),@lpTV.ItemNew.hItem) = 0 THEN 'on a header item
            SetWindowText hdlg,"On a header item"     
            TreeView_Expand(hTree&(2),@lpTV.ItemNew.hItem,%TVE_EXPAND)
            TreeView_Select(htree&(2),TreeView_GetNextItem(htree&(2),@lpTV.ItemNew.hItem,%TVGN_CHILD),%TVGN_DROPHILITE)
            EXIT FUNCTION
          ELSE  
            SetWindowText hdlg,"On a child item"     
          END IF
      END IF
      Bob Mechler

      Comment


      • #4
        The treeview_Expand should not be needed, as TreeView_select should automatically expand the item if necessary to make it visible.

        >IF TreeView_GetParent(htree&(2),@lpTV.ItemNew.hItem)

        What is hTree&(2)?

        When processing WM_NOTIFY, @lpnmh.hWndfrom is a handle to the control sending the message; that is, there is n need to maintain that in a STATIC or GLOBAL array.

        If you need a handle to another treeview control on the screen while processing the message from this treeview, you can always use GetDlgItem(hWnd,%ID_OTHER_TREEVIEW).

        In window procedures, you virtually never have to maintain window handles in STATIC or GLOBAL variables.. beacuse given the Hwnd passed as parm one to callback, you can get just about anywhere you need. (the plethora of "GLOBAL hDlg" in the help file notwithstanding)

        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Helpful info.
          htree&(2) is what I used not knowing how to get it using @lpnmh.hWndfrom.

          I put in the expand part because it didn't auto expand for me.

          After some testing, this code works about half the time. It sometimes fires twice and I get the second child down and the first child is gone so I'll just leave it a while and test in a test area.

          I was also unsure about the EXIT FUNCTION. I was trying to get it to go to the first child then assumed the %TVN_SELCHANGED would fire again. Not real clear on how I can programmatically walk the tree without getting into trouble.

          Thanks,

          Bob Mechler

          Comment


          • #6
            Return value/Exit function?

            [from TVN_SELCHANGED]
            ...
            Return Value

            The return value is ignored.
            As far as selecting, I don't think you want the drop highlight flag....

            flag
            Action flag. This parameter can be one of the following values:
            TVGN_CARET
            Sets the selection to the given item. The control's parent window receives the TVN_SELCHANGING and TVN_SELCHANGED notification messages.
            And expanding?
            Remarks

            If the specified item is the child of a collapsed parent item, the parent's list of child items is expanded to reveal the specified item. In this case, the parent window receives the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages.
            I think changing that flag ought to do wonders for you.

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              I found this code and modified a portion under TVN_SELCHANGED to illustrate what I want to do. I'm about halfway there. I can tell when I'm on a 'Parent or Section Header node based on the text and don't want the user to be able to highlight it since it won't be doing anything in the production code. It is however supposed to allow for expanding and collapsing the child items level.

              Initially when you click on any of the parent nodes it will currently detect that and get the first child, expanding the node as needed. I've also trapped the up and down arrow keys to allow the up and down arrow to 'skip' over the parent node. The only thing I lack is the ability to close up the node. I've locked that action from happening somehow. I'm thinking I'll need to do that in the TVN_SELCHANGING EVENT but I'm not sure how to do that.

              Any help please

              Bob Mechler


              Code:
              'MESSAGE http://www.powerbasic.com/support/forums/Forum7/HTML/003114.html
              'FORUM:  Source Code
              'TOPIC:  Basic TreeView LPStr_TextCallBack Demo
              'NAME:   Tonny Bjorn, Member
              'DATE:   March 05, 2007 09:51 AM
              
              
              '==============================================================================
              ' Basic demo on using large amounts of data into TreeView using %LPSTR_TEXTCALLBACK
              ' and %TVN_GETDISPINFO for better performance. NB: %LVN_GETDISPINFO for ListView
              '------------------------------------------------------------------------------
              ' Used Compiler: PB/WIN 8.03
              ' WIN32API Date: 01*Feb*2005 (Updated 27 January 2005)
              ' COMMCTRL Date: 01*Feb*2005 (Updated 27 October 2003)
              ' Prg tested on: Windows 2000 SP3, Windows XP Pro SP2
              '==============================================================================
              #COMPILE EXE
              #DIM ALL
              
              %USEMACROS = 1
              
              #INCLUDE "WIN32API.INC"
              #INCLUDE "COMMCTRL.INC"
              
              '==============================================================================
              %ID_TREEVIEW            = 100
              
              '==============================================================================
              GLOBAL hTreeView        AS LONG     ' TreeView Handle
              GLOBAL TVTextArray()    AS STRING   ' TreeView Text Label Storage
              
              '==============================================================================
              ' Get the text from the selected item in the TreeView
              '------------------------------------------------------------------------------
              ' hTree     - TreeView Handle
              ' hTVItem   - Selected TreeView item
              '==============================================================================
              FUNCTION TVGetText(BYVAL hTree AS LONG, BYVAL hTVItem AS LONG) AS STRING
                  LOCAL zText AS ASCIIZ * 255
                  LOCAL lTVItem AS TV_ITEM
                  lTVItem.hItem = hTVItem
                  lTVItem.Mask = %TVIF_TEXT
                  lTVItem.pszText = VARPTR(zText)
                  lTVItem.cchTextMax = 255
                  TreeView_GetItem(hTree, lTVItem)
                  FUNCTION = zText
              END FUNCTION
              
              '==============================================================================
              ' Insert an item in the TreeView using LPSTR_TEXTCALLBACK for improved speed
              '------------------------------------------------------------------------------
              ' hTree     - TreeView handle
              ' hParent   - Handle for position type (root, parent child) in the tree
              ' lItemNum  - Indicator coresponding to the text in the TVTextArray for the TreeView
              ' lTextMax  - Length of the string being added
              '==============================================================================
              FUNCTION TVInsertLPSTRItem(BYVAL hTree AS LONG, BYVAL hParent AS LONG, BYVAL lItemNum AS LONG, BYVAL lTextMax AS LONG) AS LONG
                  LOCAL tTVInsert   AS TV_INSERTSTRUCT
                  LOCAL tTVItem     AS TV_ITEM
                  IF hParent THEN
                      tTVItem.mask        = %TVIF_CHILDREN OR %TVIF_HANDLE
                      tTVItem.hItem       = hParent
                      tTVItem.cchildren   = 1
                      TreeView_SetItem(hTree, tTVItem)
                  END IF
                  tTVInsert.hParent           = hParent
                  tTVInsert.Item.Item.mask    = %TVIF_TEXT OR %TVIF_PARAM
                  tTVInsert.Item.Item.pszText = %LPSTR_TEXTCALLBACK
                  tTVInsert.Item.Item.cchTextMax = lTextMax
                  tTVInsert.Item.Item.lParam  = lItemNum
                  FUNCTION = TreeView_InsertItem(hTree, tTVInsert)
              END FUNCTION
              
              '==============================================================================
              FUNCTION FillTreeViewTest(BYVAL lCount AS LONG) AS LONG
                  LOCAL hTopRoot  AS DWORD
                  LOCAL hRoot     AS DWORD
                  LOCAL hParent   AS DWORD
                  LOCAL hChild    AS DWORD
                  LOCAL g         AS LONG
                  LOCAL h         AS LONG
                  LOCAL i         AS LONG
                  LOCAL j         AS LONG
                  LOCAL k         AS LONG
                  LOCAL sBuffer   AS STRING
              
                  k = 0
              
                  ' =======================================================================
                  ' Test if array is big enough to hold string, else REDIM and add a
                  ' little extra to minimize slow redim process time. The extra array
                  ' overhead is balanced out by improved speed.
                  IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
              
                  ' Add string to array for %LPSTR_TEXTCALLBACK
                  TVTextArray(k) = "Root"
              
                  ' Insert the item in the TreeView
                  hTopRoot = TVInsertLPSTRItem(hTreeView, 0, k, LEN(TVTextArray(k)))
                  ' =======================================================================
              
                  FOR i = 1 TO lCount
              
                      ' Add Parent
                      sBuffer = "Parent Pos #" & FORMAT$(i)
              
                      INCR k
              
                      IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
              
                      TVTextArray(k) = sBuffer
              
                      hRoot = TVInsertLPSTRItem(hTreeView, hTopRoot, k, LEN(TVTextArray(k)))
              
                      ' Add Childs
                      FOR j = 1 TO 5
              
                          INCR k
              
                          IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
              
                          TVTextArray(k) = "Child1 Pos #" & FORMAT$(j)
              
                          hParent = TVInsertLPSTRItem(hTreeView, hRoot, k, LEN(TVTextArray(k)))
              
                          ' Add Childs
                          FOR h = 1 TO 5
              
                              INCR k
              
                              IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
              
                              TVTextArray(k) = "Child2 Pos #" & FORMAT$(h)
              
                              hChild = TVInsertLPSTRItem(hTreeView, hParent, k, LEN(TVTextArray(k)))
              
                              ' Add Subs
                              FOR g = 1 TO 3
              
                                  INCR k
              
                                  IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                                  TVTextArray(k) = "Sub Pos #" & FORMAT$(g)
                                  TVInsertLPSTRItem(hTreeView, hChild, k, LEN(TVTextArray(k)))
              
                              NEXT
              
                          NEXT
              
                      NEXT
              
                  NEXT
              
                  FUNCTION = k
              
                  DIALOG DOEVENTS
              
              END FUNCTION
              
              '==============================================================================
              CALLBACK FUNCTION DialogProc()
                  LOCAL lpTV          AS NM_TREEVIEW PTR
                  LOCAL pTVDI         AS TV_DISPINFO PTR
                  LOCAL lpNmh         AS NMHDR PTR
                  STATIC hTreeItem    AS LONG
                  LOCAL lTime1        AS LONG
                  LOCAL lTime2        AS LONG
                  LOCAL lCount        AS LONG
                  LOCAL TVtxt         AS STRING
                  STATIC hChild       AS LONG
                  STATIC hSectionFlag AS LONG
                  LOCAL kKey          AS TV_KEYDOWN PTR
              [COLOR="Red"]    STATIC kKeylastkey  AS LONG[/COLOR]    
                  SELECT CASE AS LONG CBMSG
              
                      CASE %WM_INITDIALOG
              
                          ' Pre DIM the array for encreased speed.
                          'DIM TVTextArray(100000)
              
                          ' Kick it in motion
                          POSTMESSAGE CBHNDL, %WM_USER + 1000, 0, 0
              
                      CASE %WM_USER + 1000
              
                          ' Fill the TreeView with Test Data doing x loops
                          lTime1 = TIMER
                          lCount = FillTreeViewTest( 1000 )
                          lTime2 = TIMER
              
                          MSGBOX FORMAT$(lCount) & " items added to the TreeView in ~" & FORMAT$(lTime2 - lTime1) & " sec.",,"Info"
              
                      CASE %WM_NOTIFY
              
                          lpNmh = CBLPARAM
                          lpTV = CBLPARAM
              
                          SELECT CASE CBCTL
              
                              CASE %ID_TREEVIEW
              
                                  SELECT CASE @lpNmh.Code
              
                                      ' Get the text in TVTextArray to be displayed.
                                      CASE %TVN_GETDISPINFO
              
                                          pTVDI = CBLPARAM
              
                                          IF (@pTVDI.item.mask AND %TVIF_TEXT) THEN
                                              POKE$ @pTVDI.item.pszText, LEFT$( TVTextArray( @pTVDI.item.lParam ), @pTVDI.item.cchTextMax)
                                          END IF
              
                                          FUNCTION = 0
                                          EXIT FUNCTION
              
                                      ' The TreeView is changing
              [COLOR="Red"]                        CASE %TVN_KEYDOWN
                                        kKey = CBLPARAM
                                        kKeylastkey = @kKey.wVKey[/COLOR]                        CASE %TVN_SELCHANGING
              
                                          FUNCTION = 0
                                          EXIT FUNCTION
              
                                      ' Get and select item when [+] is clicked
                                      CASE %TVN_SELCHANGED
              [COLOR="red"]                            lpTV = CBLPARAM
                                          hTreeItem = @lpTV.ItemNew.hItem
                                          TVtxt$ = TVGetText(hTreeView, hTreeItem)
                                          IF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey <> 38 THEN
                                            hChild = SendMessage(hTreeView, %TVM_GETNEXTITEM, %TVGN_CHILD, hTreeItem)
                                            TreeView_SelectItem(hTreeView, hChild)
                                          ELSEIF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey = 38 THEN
                                            hChild = SendMessage(hTreeView, %TVM_GETNEXTITEM, %TVGN_PREVIOUSVISIBLE, hTreeItem)
                                            TreeView_SelectItem(hTreeView, hChild)
                                          END IF
                                          kKeylastkey = 0[/COLOR]                        
                                      CASE %TVN_ITEMEXPANDED
              
                                          ' Get selected item
                                          hTreeItem = @lpTV.ItemNew.hItem
              
                                          ' Select the item where [+] was clicked
                                          TreeView_Select(hTreeView, hTreeItem, %TVGN_CARET)
              
                                          FUNCTION = 0
                                          EXIT FUNCTION
              
                                  END SELECT
              
                          END SELECT
              
                      CASE %WM_COMMAND
              
                          SELECT CASE AS LONG CBCTL
              
                              CASE %IDCANCEL
              
                                  ' End
                                  DIALOG END CBHNDL, 0
              
                          END SELECT
              
                      CASE %WM_DESTROY
              
                          ' Nuke the array just to make sure
                          ERASE TVTextArray()
              
                  END SELECT
              
              END FUNCTION
              
              '==============================================================================
              FUNCTION PBMAIN() AS LONG
                  LOCAL hDlg AS DWORD
              
                  DIALOG NEW 0, "LPSTR_TEXTCALLBACK TreeView Demo", , , 300, 260, _
                      %WS_CHILD OR %WS_SYSMENU OR %WS_MAXIMIZEBOX OR %WS_MINIMIZEBOX OR %WS_CAPTION TO hDlg
              
                  CONTROL ADD "SysTreeView32", hDlg, %ID_TREEVIEW, "", 10, 10, 280, 245, _
                      %WS_CHILD OR %WS_VISIBLE OR %WS_CLIPCHILDREN _
                      OR %TVS_HASBUTTONS _       '+/- buttons for parent nodes with children
                      OR %TVS_HASLINES _         'shows connector lines & buttons for tree structure (below the root)
                      OR %TVS_LINESATROOT _      'shows connector lines & buttons at root level of tree structure
                      OR %TVS_DISABLEDRAGDROP _  'does not send dragdrop notifications
                      OR %TVS_SHOWSELALWAYS _    'Show selected item even when treeview does NOT have focus
                      , %WS_EX_CLIENTEDGE
                      'OR %TVS_TRACKSELECT _      'Underlines item where mouse cursor points
              
                  CONTROL HANDLE hDlg, %ID_TREEVIEW TO hTreeView
              
                  DIALOG SHOW MODAL hDlg CALL DialogProc
              
              END FUNCTION

              Comment


              • #8
                Code:
                lpNmh = CBLPARAM
                            lpTV = CBLPARAM
                
                            SELECT CASE [B][COLOR="Red"]CBCTL[/COLOR][/B]
                CBCTL is not the correct way to identify control ID under WM_NOTIFY.

                You want ot use @lpnmh.idFrom or the new CB.NMID
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  That part was from the sample code I borrowed, but you're right it needs to be idFrom. It wasn't causing a problem though in this sample.

                  Bob Mechler

                  Comment


                  • #10
                    >CONTROL ADD "SysTreeView32", hDlg, %ID_TREEVIEW, "", 10, 10, 280, 245,

                    As a general rule, CBCTL is meaningless when the control is added with CONTROL ADD "classname" because DDT has no way knowing how "classname" sends its notification messages to the dialog's CALLBACK FUNCTION. Does it use WM_COMMAND? WM_NOTIFY? Something else?

                    Essentially all you can count on being valid in this case is CBHNDL, CBMSG, CBLPARAM and CBWPARAM.

                    Lots of things might "work" but I must refer you, too, to the current thread on "forgiving" at http://www.powerbasic.com/support/pb...ad.php?t=40098

                    MCM
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      Working example

                      So far this is the best I can come up with starting with Tonny's code. I've changed a place or two where Michael rightly questioned the use of CBCTL in WM_NOTIFY.

                      The program is supposed to react to a click on the parent node by expanding the child nodes and highlighting the first one. Using the down arrow and coming up on another parent node will auto expand that node. Please do that will several nodes. Once several are open, use the up and down arrows and it should jump over the Parent nodes.

                      The mouse works to collapse or expand any parent node that doesn't have a highlighted item in it.

                      The left arrow will collapse every node it's on when pressed and the same is true of the right arrow.

                      The action I'm looking for is similar to a panel control where the sub items sit directly beneath the section headers which look like buttons that float up and down based on expanding or collapsing. This method however allows many nodes to be open at the same time with a scroll bar.


                      Please see notes in comment section and especially the code in TVN_SELCHANGED area.

                      Bob Mechler
                      Code:
                      'MESSAGE http://www.powerbasic.com/support/forums/Forum7/HTML/003114.html
                      'FORUM:  Source Code
                      'TOPIC:  Basic TreeView LPStr_TextCallBack Demo
                      'NAME:   Tonny Bjorn, Member
                      'DATE:   March 05, 2007 09:51 AM
                      
                      
                      '==============================================================================
                      ' Basic demo on using large amounts of data into TreeView using %LPSTR_TEXTCALLBACK
                      ' and %TVN_GETDISPINFO for better performance. NB: %LVN_GETDISPINFO for ListView
                      '------------------------------------------------------------------------------
                      ' Used Compiler: PB/WIN 8.03
                      ' WIN32API Date: 01*Feb*2005 (Updated 27 January 2005)
                      ' COMMCTRL Date: 01*Feb*2005 (Updated 27 October 2003)
                      ' Prg tested on: Windows 2000 SP3, Windows XP Pro SP2
                      ' 03/11/09 by Bob Mechler
                      'changed slightly to test skipping level one nodes and opening up access to
                      ' the child nodes as in a Menu where section headers divide up the menu into
                      ' logical divisions and serve as a place to expand or collapse a long menu
                      ' in other words the Parent node level should only expand or collapse the next
                      ' level
                      ' Looking for any comments
                      '==============================================================================
                      #COMPILE EXE 
                      #DIM ALL
                      
                      %USEMACROS = 1
                      
                      #INCLUDE "WIN32API.INC"
                      #INCLUDE "COMMCTRL.INC"
                      
                      '==============================================================================
                      %ID_TREEVIEW            = 100
                      
                      '==============================================================================
                      GLOBAL hTreeView        AS LONG     ' TreeView Handle
                      GLOBAL TVTextArray()    AS STRING   ' TreeView Text Label Storage
                      
                      '==============================================================================
                      ' Get the text from the selected item in the TreeView
                      '------------------------------------------------------------------------------
                      ' hTree     - TreeView Handle
                      ' hTVItem   - Selected TreeView item
                      '==============================================================================
                      FUNCTION TVGetText(BYVAL hTree AS LONG, BYVAL hTVItem AS LONG) AS STRING
                          LOCAL zText AS ASCIIZ * 255
                          LOCAL lTVItem AS TV_ITEM
                          lTVItem.hItem = hTVItem
                          lTVItem.Mask = %TVIF_TEXT
                          lTVItem.pszText = VARPTR(zText)
                          lTVItem.cchTextMax = 255
                          TreeView_GetItem(hTree, lTVItem)
                          FUNCTION = zText
                      END FUNCTION
                      
                      '==============================================================================
                      ' Insert an item in the TreeView using LPSTR_TEXTCALLBACK for improved speed
                      '------------------------------------------------------------------------------
                      ' hTree     - TreeView handle
                      ' hParent   - Handle for position type (root, parent child) in the tree
                      ' lItemNum  - Indicator coresponding to the text in the TVTextArray for the TreeView
                      ' lTextMax  - Length of the string being added
                      '==============================================================================
                      FUNCTION TVInsertLPSTRItem(BYVAL hTree AS LONG, BYVAL hParent AS LONG, BYVAL lItemNum AS LONG, BYVAL lTextMax AS LONG) AS LONG
                          LOCAL tTVInsert   AS TV_INSERTSTRUCT
                          LOCAL tTVItem     AS TV_ITEM
                          IF hParent THEN
                              tTVItem.mask        = %TVIF_CHILDREN OR %TVIF_HANDLE
                              tTVItem.hItem       = hParent
                              tTVItem.cchildren   = 1
                              TreeView_SetItem(hTree, tTVItem)
                          END IF
                          tTVInsert.hParent           = hParent
                          tTVInsert.Item.Item.mask    = %TVIF_TEXT OR %TVIF_PARAM
                          tTVInsert.Item.Item.pszText = %LPSTR_TEXTCALLBACK
                          tTVInsert.Item.Item.cchTextMax = lTextMax
                          tTVInsert.Item.Item.lParam  = lItemNum
                          FUNCTION = TreeView_InsertItem(hTree, tTVInsert)
                      END FUNCTION
                      
                      '==============================================================================
                      FUNCTION FillTreeViewTest(BYVAL lCount AS LONG) AS LONG
                          LOCAL hTopRoot  AS DWORD
                          LOCAL hRoot     AS DWORD
                          LOCAL hParent   AS DWORD
                          LOCAL hChild    AS DWORD
                          LOCAL g         AS LONG
                          LOCAL h         AS LONG
                          LOCAL i         AS LONG
                          LOCAL j         AS LONG
                          LOCAL k         AS LONG
                          LOCAL sBuffer   AS STRING
                      
                          k = 0
                      
                          ' =======================================================================
                          ' Test if array is big enough to hold string, else REDIM and add a
                          ' little extra to minimize slow redim process time. The extra array
                          ' overhead is balanced out by improved speed.
                          IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                      
                          ' Add string to array for %LPSTR_TEXTCALLBACK
                          'TVTextArray(k) = "Root"
                      
                          ' Insert the item in the TreeView
                          'hTopRoot = TVInsertLPSTRItem(hTreeView, 0, k, LEN(TVTextArray(k)))
                          hTopRoot = 0
                          ' =======================================================================
                      
                          FOR i = 1 TO lCount
                      
                              ' Add Parent
                              sBuffer = "Parent Pos #" & FORMAT$(i)
                      
                              INCR k
                      
                              IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                      
                              TVTextArray(k) = sBuffer
                      
                              hRoot = TVInsertLPSTRItem(hTreeView, hTopRoot, k, LEN(TVTextArray(k)))
                      
                              ' Add Childs
                              FOR j = 1 TO 5
                      
                                  INCR k
                      
                                  IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                      
                                  TVTextArray(k) = "Child1 Pos #" & FORMAT$(j)
                      
                                  hParent = TVInsertLPSTRItem(hTreeView, hRoot, k, LEN(TVTextArray(k)))
                      
                                  ' Add Childs
                                  FOR h = 1 TO 5
                      
                                      INCR k
                      
                                      IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                      
                                      TVTextArray(k) = "Child2 Pos #" & FORMAT$(h)
                      
                                      hChild = TVInsertLPSTRItem(hTreeView, hParent, k, LEN(TVTextArray(k)))
                      
                                      ' Add Subs
                                      FOR g = 1 TO 3
                      
                                          INCR k
                      
                                          IF UBOUND(TVTextArray) < k THEN REDIM PRESERVE TVTextArray(k + 100)
                                          TVTextArray(k) = "Sub Pos #" & FORMAT$(g)
                                          TVInsertLPSTRItem(hTreeView, hChild, k, LEN(TVTextArray(k)))
                      
                                      NEXT
                      
                                  NEXT
                      
                              NEXT
                      
                          NEXT
                      
                          FUNCTION = k
                      
                          DIALOG DOEVENTS
                      
                      END FUNCTION
                      
                      '==============================================================================
                      CALLBACK FUNCTION DialogProc()
                          LOCAL lpTV          AS NM_TREEVIEW PTR
                          LOCAL pTVDI         AS TV_DISPINFO PTR
                          LOCAL lpNmh         AS NMHDR PTR
                          STATIC hTreeItem    AS LONG
                          LOCAL lTime1        AS LONG
                          LOCAL lTime2        AS LONG
                          LOCAL lCount        AS LONG
                          LOCAL TVtxt         AS STRING
                          STATIC hChild       AS LONG
                          STATIC hSectionFlag AS LONG
                          LOCAL kKey          AS TV_KEYDOWN PTR
                          STATIC kKeylastkey  AS LONG
                          SELECT CASE AS LONG CBMSG
                      
                              CASE %WM_INITDIALOG
                      
                                  ' Pre DIM the array for encreased speed.
                                  'DIM TVTextArray(100000)
                      
                                  ' Kick it in motion
                                  POSTMESSAGE CBHNDL, %WM_USER + 1000, 0, 0
                      
                              CASE %WM_USER + 1000
                      
                                  ' Fill the TreeView with Test Data doing x loops
                                  lTime1 = TIMER
                                  lCount = FillTreeViewTest( 1000 )
                                  lTime2 = TIMER
                      
                                  MSGBOX FORMAT$(lCount) & " items added to the TreeView in ~" & FORMAT$(lTime2 - lTime1) & " sec.",,"Info"
                      
                              CASE %WM_NOTIFY
                      
                                  lpNmh = CBLPARAM
                                  lpTV = CBLPARAM
                      
                                  SELECT CASE @lpNmh.idFrom
                      
                                      CASE %ID_TREEVIEW
                      
                                          SELECT CASE @lpNmh.Code
                      
                                              ' Get the text in TVTextArray to be displayed.
                                              CASE %TVN_GETDISPINFO
                      
                                                  pTVDI = CBLPARAM
                      
                                                  IF (@pTVDI.item.mask AND %TVIF_TEXT) THEN
                                                      POKE$ @pTVDI.item.pszText, LEFT$( TVTextArray( @pTVDI.item.lParam ), @pTVDI.item.cchTextMax)
                                                  END IF
                      
                                                  FUNCTION = 0
                                                  EXIT FUNCTION
                      
                                              CASE %TVN_KEYDOWN
                                                kKey = CBLPARAM
                                                kKeylastkey = @kKey.wVKey
                                              CASE %TVN_SELCHANGING
                                              ' Get and select item when [+] is clicked
                                              CASE %TVN_SELCHANGED
                                                  lpTV = CBLPARAM
                                                  hTreeItem = @lpTV.ItemNew.hItem
                                                  TVtxt$ = TVGetText(hTreeView, hTreeItem)
                                                  IF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey <> 39 AND kKeylastkey <> 38 AND kKeylastkey <> 37 THEN
                                                    hChild = SendMessage(hTreeView, %TVM_GETNEXTITEM, %TVGN_CHILD, hTreeItem)
                                                    TreeView_SelectItem(hTreeView, hChild)
                                                  ELSEIF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey = 38 THEN
                                                    hChild = SendMessage(hTreeView, %TVM_GETNEXTITEM, %TVGN_PREVIOUSVISIBLE, hTreeItem)
                                                    TreeView_SelectItem(hTreeView, hChild)
                                                  ELSEIF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey = 37 THEN
                                                    TreeView_Expand(hTreeView,hTreeItem,%TVE_COLLAPSE)
                                                  ELSEIF INSTR(TVtxt$,"Parent") > 0 AND kKeylastkey = 39 THEN
                                                    TreeView_Expand(hTreeView,hTreeItem,%TVE_EXPAND)
                                                  END IF
                                                  kKeylastkey = 0
                                              CASE %TVN_ITEMEXPANDED
                                                  ' Get selected item
                                                  hTreeItem = @lpTV.ItemNew.hItem
                      
                                                  ' Select the item where [+] was clicked
                                                  'TreeView_Select(hTreeView, hTreeItem, %TVGN_CARET)
                                                  FUNCTION = 0
                                                  EXIT FUNCTION
                      
                                          END SELECT
                      
                                  END SELECT
                      
                              CASE %WM_COMMAND
                      
                                  SELECT CASE AS LONG CBCTL
                      
                                      CASE %IDCANCEL
                      
                                          ' End
                                          DIALOG END CBHNDL, 0
                      
                                  END SELECT
                      
                              CASE %WM_DESTROY
                      
                                  ' Nuke the array just to make sure
                                  ERASE TVTextArray()
                      
                          END SELECT
                      
                      END FUNCTION
                      
                      '==============================================================================
                      FUNCTION PBMAIN() AS LONG
                          LOCAL hDlg AS DWORD
                      
                          DIALOG NEW 0, "Skip Section Headers", , , 300, 260, _
                              %WS_CHILD OR %WS_SYSMENU OR %WS_MAXIMIZEBOX OR %WS_MINIMIZEBOX OR %WS_CAPTION TO hDlg
                      
                          CONTROL ADD "SysTreeView32", hDlg, %ID_TREEVIEW, "", 10, 10, 280, 245, _
                              %WS_CHILD OR %WS_VISIBLE OR %WS_CLIPCHILDREN _
                              OR %TVS_HASBUTTONS _       '+/- buttons for parent nodes with children
                              OR %TVS_HASLINES _         'shows connector lines & buttons for tree structure (below the root)
                              OR %TVS_LINESATROOT _      'shows connector lines & buttons at root level of tree structure
                              OR %TVS_DISABLEDRAGDROP _  'does not send dragdrop notifications
                              OR %TVS_SHOWSELALWAYS _    'Show selected item even when treeview does NOT have focus
                              OR %TVS_TRACKSELECT _      'Underlines item where mouse cursor points
                              , %WS_EX_CLIENTEDGE
                      
                          CONTROL HANDLE hDlg, %ID_TREEVIEW TO hTreeView
                      
                          DIALOG SHOW MODAL hDlg CALL DialogProc
                      
                      END FUNCTION

                      Comment


                      • #12
                        You know, you don't have to handle the keys yourself with the standard treeview control; the left, right, up and down arrows all do expand/collapse navigate.

                        As far as "select (or simply 'highlight') the first child of the selected item (via click or keyboard)", that you *do* have to do yourself, as the default behavior is to select the node clicked or to which you have navigated.

                        I learned all this when I had to replace a standard treeview control with "something else"; I spent a lot of time playing with the standard treeview so I could emulate its behavior. Yes, I *was* surprised by all the stuff it does with the arrow keys.

                        MCM
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment

                        Working...
                        X