Announcement

Collapse
No announcement yet.

Treeview Reselect Problem

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

  • Treeview Reselect Problem

    The following code illustrates a problem using treeviews. If you select a node it sends a %TVN_SELCHANGING message to the WM_NOTIFY event handler. If you want to click the same treeview item again no message is sent. You have to move to another item in the treeview and then back again to make it fire (when using the mouse or using enter). Someone may know the answer without the code below.

    To see the problem run the program and click a treenode. The caption bar will show the time. If you click a different node the time will change. If you click the same node twice several seconds apart the time will not change. How do you get around this?

    Thanks,

    Bob Mechler
    Code:
    #PBFORMS CREATED V1.51
    #COMPILE EXE
    #DIM ALL
    
    '------------------------------------------------------------------------------
    '   ** Includes **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN INCLUDES
    #IF NOT %DEF(%WINAPI)
      #INCLUDE "WIN32API.INC"
    #ENDIF
    #IF NOT %DEF(%COMMCTRL_INC)
      #INCLUDE "COMMCTRL.INC"
    #ENDIF
    #INCLUDE "PBForms.INC"
    #PBFORMS END INCLUDES
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Constants **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN CONSTANTS
    %IDD_DIALOG1         =  101
    %TRV_SYSTREEVIEW32_1 = 1001
    #PBFORMS END CONSTANTS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Declarations **
    '------------------------------------------------------------------------------
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION SampleTreeViewInsertItem(BYVAL hTree AS DWORD, BYVAL hParent _
      AS DWORD, sItem AS STRING) AS LONG
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    #PBFORMS DECLARATIONS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Main Application Entry Point **
    '------------------------------------------------------------------------------
    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
    FUNCTION PBMAIN()
      PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _
        %ICC_INTERNET_CLASSES)
    
      ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** CallBacks **
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
    STATIC hTreeItem AS LONG,hTreeView AS LONG
    DIM lpNmh AS NMHDR PTR
      SELECT CASE AS LONG CBMSG
        CASE %WM_INITDIALOG
          ' Initialization handler
    
        CASE %WM_NCACTIVATE
          STATIC hWndSaveFocus AS DWORD
          IF ISFALSE CBWPARAM THEN
            ' Save control focus
            hWndSaveFocus = GetFocus()
          ELSEIF hWndSaveFocus THEN
            ' Restore control focus
            SetFocus(hWndSaveFocus)
            hWndSaveFocus = 0
          END IF
        CASE %WM_NOTIFY
          SELECT CASE CBCTL
            CASE %TRV_SYSTREEVIEW32_1
              CONTROL HANDLE CBHNDL, %TRV_SYSTREEVIEW32_1 TO hTreeView&
              lpNmh = CBLPARAM
              IF @lpNmh.code = %TVN_SELCHANGING THEN
                SetWindowText CBHNDL, TVGetText(hTreeView&, hTreeItem&) + TIME$
              END IF
          END SELECT
        CASE %WM_COMMAND
          ' Process control notifications
          SELECT CASE AS LONG CBCTL
            CASE %TRV_SYSTREEVIEW32_1
          END SELECT
      END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Sample Code **
    '------------------------------------------------------------------------------
    FUNCTION SampleTreeViewInsertItem(BYVAL hTree AS DWORD, BYVAL hParent AS _
      DWORD, sItem AS STRING) AS LONG
      LOCAL tTVItem   AS TV_ITEM
      LOCAL tTVInsert AS TV_INSERTSTRUCT
    
      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
      tTVInsert.Item.Item.pszText    = STRPTR(sItem)
      tTVInsert.Item.Item.cchTextMax = LEN(sItem)
    
      FUNCTION = TreeView_InsertItem(hTree, tTVInsert)
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    FUNCTION SampleTreeView(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lCount _
      AS LONG) AS LONG
      LOCAL i       AS LONG
      LOCAL j       AS LONG
      LOCAL k       AS LONG
      LOCAL hCtl    AS DWORD
      LOCAL hRoot   AS DWORD
      LOCAL hParent AS DWORD
    
      CONTROL HANDLE hDlg, lID TO hCtl
    
      FOR i = 1 TO lCount
        hRoot = SampleTreeViewInsertItem(hCtl, %NULL, USING$("Root#", i))
        FOR j = 1 TO lCount
          hParent = SampleTreeViewInsertItem(hCtl, hRoot, USING$("Item#", j))
          FOR k = 1 TO lCount
            CALL SampleTreeViewInsertItem(hCtl, hParent, USING$("SubItem#_.#", j, _
              k))
          NEXT k
        NEXT j
      NEXT i
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
      LOCAL lRslt AS LONG
    
    #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
      LOCAL hDlg  AS DWORD
    
      DIALOG NEW hParent, "Dialog1", 90, 69, 399, 304, %WS_POPUP OR %WS_BORDER OR _
        %WS_DLGFRAME OR %WS_SYSMENU OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR _
        %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
        %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
        %WS_EX_RIGHTSCROLLBAR, TO hDlg
      CONTROL ADD "SysTreeView32", hDlg, %TRV_SYSTREEVIEW32_1, "SysTreeView32_1", _
        44, 28, 252, 184, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _
        %TVS_HASBUTTONS OR %TVS_HASLINES OR %TVS_LINESATROOT OR _
        %TVS_SHOWSELALWAYS, %WS_EX_LEFT OR %WS_EX_CLIENTEDGE OR _
        %WS_EX_RIGHTSCROLLBAR
    #PBFORMS END DIALOG
    
      SampleTreeView hDlg, %TRV_SYSTREEVIEW32_1, 3
    
      DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    
    #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
    #PBFORMS END CLEANUP
    
      FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------

  • #2
    Adding the following code just before TVN_SELCHANGING explicitly sends the TVN_SELCHANGING message if the same node is clicked once and then again.

    Code:
              IF @lpNmh.Code = %NM_CLICK  THEN
                TreeView_SelectItem hTreeView&, hTreeItem&
              END IF
    Maybe this help someone else.

    Credit: researched old posts and found something Michael Matthias said that I didn't get at the time. Thanks, Michael.

    Bob Mechler

    Comment


    • #3
      >To see the problem



      I don't believe there IS a problem.

      TVN_SELCHANGING is sent when the selection is about to change. Clicking on the already-selected item is not going to change the selection.



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

      Comment


      • #4
        Try the program with and without the code I posted. You'll see that the caption bar is not updated with new information without this additional code.

        This occurs only in the situation where the user clicks the same node a couple of seconds apart.

        In my actual production code, the clicking of the node the first time would bring up a confirmation box that asks the user if he really wanted to run the selected program. If he clicks no by mistake and then clicks the same node again, nothing happens. this is because the node was already selected. No TVN_SELCHANGED message is issued. Control Spy confirms it as well as all the TREEVIEW demo programs I found in the archives, so it is a problem.

        In one of your posts you brought this up and the win api doc does indicate that the selectitem issues a TVN_SELCHANGED message, which triggers the code.

        There may be another way to do it but my tests show it works great. I can click the same node over and over again and it will fire regardless now. Before it would fire the correct event the first time only. I could click it additional times and nothing would happen. If I went to another node and came back it would fire, but who wants to be limited that way.

        Bob Mechler

        Comment


        • #5
          Bob,

          I've been playing around with your example (never used TreeView before). the trouble I'm having (or not understanding) is TVGetText is not returning anything. I thought it would return the Item name (Root#, Item#, or SubItem#).

          ======================
          Afternoon tea
          Teddy Bear takes
          three sugars
          C. William Hinderliter
          ======================
          It's a pretty day. I hope you enjoy it.

          Gösta

          JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
          LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

          Comment


          • #6
            There may be another way to do it but my tests show it works great. I can click the same node over and over again and it will fire regardless now. Before it would fire the correct event the first time only. I could click it additional times and nothing would happen.
            I must be missing something.

            Of course your "fix" works because now you are processing 'click' notifications which occur every time the user clicks, and before you were processing on "selection about to change" notifications, which only occur when a click or keystroke was about to change the current selection.

            BTW, I hope you noticed... by processing only NM_CLICK, your keyboard interface won't work; on a treeview control, the arrow keys traverse the tree as well as expand/contract the current node.

            You are going to want to add processing for WM_NOTIFY/TVN_KEYDOWN to handle that.

            (Your keys will still traverse the tree and expand/contract, but your timer thing won't occur).


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

            Comment


            • #7
              Tvn_SelChang isn't needed at all.
              Code:
                  Case %WM_NOTIFY
                    Select Case CbCtl
                      Case %TRV_SYSTREEVIEW32_1
                        Control Handle CbHndl, %TRV_SYSTREEVIEW32_1 To hTreeView&
                        lpNmh = CbLParam  
                        Select Case @lpNmh.Code 
                          Case %NM_CLICK 
                             Dialog Set Text CbHndl, Time$ & " NmClick" 
                          Case %TVN_KEYDOWN
                             Dialog Set Text CbHndl, Time$ & " %TVN_KEYDOWN" 
                        End Select              
                    End Select
                  Case %WM_COMMAND
                    ' Process control notifications
                    Select Case As Long CbCtl
                      Case %TRV_SYSTREEVIEW32_1 
                       ? Str$(CbCtl),, "at %TRV_SYSTREEVIEW32_1" '<< never gets hit
                    End Select
                End Select
              My problem is finding out which "cell" the cursor is on. Wm_Command isn't getting hit.
              It's a pretty day. I hope you enjoy it.

              Gösta

              JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
              LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

              Comment


              • #8
                My problem is finding out which "cell" the cursor is on. Wm_Command isn't getting hit
                The treeview control does not send WM_COMMAND. Like all the rest of the Microsoft Common Controls it communicates with its owner window via WM_NOTIFY

                You might look at the Treeview_GetSelection macro if you want the currently-selected item.

                However, if you want to know which treeview item the cursor is over regardless of current selection, you will have to go the long way: GetCursorPos + ScreenToClient + TreeView_HitTest

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

                Comment


                • #9
                  Originally posted by Michael Mattias View Post
                  You might look at the Treeview_GetSelection macro if you want the currently-selected item.
                  I Looked at it but it returns zero (Cell_Num).
                  Code:
                            Select Case @lpNmh.Code 
                              Case %NM_CLICK 
                                 Local Cell_Num As Dword
                                 Cell_Num = TreeView_GetSelection(CbHndl)
                                 Dialog Set Text CbHndl, Time$ & " %NmClick" & Str$(Cell_Num)

                  However, if you want to know which treeview item the cursor is over regardless of current selection, you will have to go the long way: GetCursorPos + ScreenToClient + TreeView_HitTest

                  MCM
                  That would be an awful long way for me without a code example to look at. I have to actually see how things work. Never very good at visualization.
                  It's a pretty day. I hope you enjoy it.

                  Gösta

                  JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                  LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                  Comment


                  • #10
                    > Cell_Num = TreeView_GetSelection(CbHndl)

                    CBHNDL is not a handle to the treeview control. That's why it don't work.
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      Originally posted by Michael Mattias View Post
                      > Cell_Num = TreeView_GetSelection(CbHndl)

                      CBHNDL is not a handle to the treeview control. That's why it don't work.
                      Then what would work?
                      It's a pretty day. I hope you enjoy it.

                      Gösta

                      JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                      LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                      Comment


                      • #12
                        >>CBHNDL is not a handle to the treeview control. That's why it don't work.
                        > Then what would work?

                        A handle to the treeview control.
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          If anyone else can direct me, it would be appreciated. Dealing with MCM in this situation just isn't getting it (instructive or constructive) for me.
                          It's a pretty day. I hope you enjoy it.

                          Gösta

                          JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                          LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                          Comment


                          • #14
                            Hint: "control Handle"
                            Michael Mattias
                            Tal Systems (retired)
                            Port Washington WI USA
                            [email protected]
                            http://www.talsystems.com

                            Comment


                            • #15
                              Originally posted by Michael Mattias View Post
                              Hint: "control Handle"
                              Thanks your reply Michael, but I'm finished chasing my tail for your amusement on this one. At least until someone can actually show some code on how to do it.
                              Last edited by Gösta H. Lovgren-2; 13 Dec 2008, 12:46 PM.
                              It's a pretty day. I hope you enjoy it.

                              Gösta

                              JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                              LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                              Comment


                              • #16
                                Gosta,
                                In the code supplied by Bob Mechler in the first post, do a search on "CONTROL HANDLE".
                                I could be a way off base here but I believe that this is what MCM is referring to.
                                Rod
                                In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

                                Comment


                                • #17
                                  Originally posted by Rodney Hicks View Post
                                  Gosta,
                                  In the code supplied by Bob Mechler in the first post, do a search on "CONTROL HANDLE".
                                  I could be a way off base here but I believe that this is what MCM is referring to.
                                  Thanks, Rod. I have already "investigated" that but came up craps as far as identifying which "cell" is clicked on. I found an example of what I'm looking for
                                  'http://www.powerbasic.com/support/pbforums/showthread.php?t=36417&highlight=treeview
                                  ' TREEVIEW WALKER
                                  ' by Chris Holbrook 15-Feb-2008 public domain
                                  but I'm unable to follow it to get the Cell Id (not Chris' shortcoming, my own {sigh}).

                                  ===================================
                                  "I love Mickey Mouse more
                                  than any woman I have ever known."
                                  Walt Disney (1901-1966)
                                  ===================================
                                  It's a pretty day. I hope you enjoy it.

                                  Gösta

                                  JWAM: (Quit Smoking): http://www.SwedesDock.com/smoking
                                  LDN - A Miracle Drug: http://www.SwedesDock.com/LDN/

                                  Comment


                                  • #18
                                    Originally posted by Michael Mattias View Post
                                    BTW, I hope you noticed... by processing only NM_CLICK, your keyboard interface won't work; on a treeview control, the arrow keys traverse the tree as well as expand/contract the current node.

                                    (Your keys will still traverse the tree and expand/contract, but your timer thing won't occur).


                                    MCM
                                    I'm not processing only the NM_CLICK. I left the TVN_SELCHANGED code in there.

                                    The example navigates fine with the arrows up and down, expanding and collapsing. In the PB Forms example the Click works just fine also.

                                    It seems if the mouse click is used to select a different node than the current one, it generates a TVN_SELCHANGED AND a NM_CLICK. If the mouse is used to click the same one it just did then only the NM_CLICK is generated.
                                    The code
                                    Code:
                                        TreeView_SelectItem htree&(2), pItem.hitem
                                    just makes sure the TVN_SELCHANGED event is always fired. In the one unique situation where the someone clicks the same tree node twice, it re-selects the node and sends the TVN_SELCHANGED message. Otherwise it was not responding to the second hit.

                                    Works fine, no hiccups. Generally treeviews would not have a noticeable problem with second clicks on the same node cause whatever they did the first time would still be there.

                                    Bob Mechler

                                    Comment


                                    • #19
                                      In Post #5 Gosta pointed out that "TVGetText is not returning anything. I thought it would return the Item name (Root#, Item#, or SubItem#)".
                                      I though that's what the code was doing too - 'til i tried it myself
                                      It seems that hTreeItem& is not being set in the original code.

                                      Here's a small mod which takes care of that (Note: It also uses %TVN_SELCHANGED instead of %TVN_SELCHANGING)
                                      Code:
                                          CASE %WM_NOTIFY
                                            SELECT CASE CBCTL
                                              CASE %TRV_SYSTREEVIEW32_1
                                                CONTROL HANDLE CBHNDL, %TRV_SYSTREEVIEW32_1 TO hTreeView          ' <* Treeview handle
                                                lpNmh = CBLPARAM
                                                IF @lpNmh.Code = %NM_CLICK  THEN
                                                  TreeView_SelectItem hTreeView, 0    '  If hitem is NULL, selection is removed from currently selected item, if any.
                                                END IF
                                                IF @lpNmh.code = %TVN_SELCHANGED Then
                                                  hTreeItem = Treeview_GetSelection(hTreeView)                    ' <*  used here
                                                  SetWindowText CBHNDL, TVGetText(hTreeView, hTreeItem) + TIME$   ' <*   "    "
                                                END IF
                                            END SELECT
                                      With this mod, the code still works for both Mouse and Keyboard navigation of the TreeView control and responds to a second click on an item that is already selected as Bob intended.
                                      Rgds, Dave

                                      Comment


                                      • #20
                                        Code:
                                        CASE %WM_NOTIFY
                                              SELECT CASE CBCTL
                                        According to the PB/9 Help file, CBCTL (now being replaced by CB.CTL), is
                                        The notification message is sent to the callback as the low-order word of the wParam& parameter. Therefore, CBCTL is functionally equivalent to LO(WORD, wParam&) in a conventional Callback Function, and equivalent to LO(WORD, CBWPARAM) in a DDT Callback Function.
                                        For messages send under WM_NOTIFY, LOWRD(wParam) is not the control ID, as stated by Microsoft:
                                        idCtrl
                                        Identifier of the common control sending the message. This identifier is not guaranteed to be unique. An application should use the hwndFrom or idFrom member of the NMHDR structure (passed as the lParam parameter) to identify the control. [italics mine]
                                        This suggests CB.CTL/CBCTL should not be used here; rather, one should use the CB.NMID (Pb/win 9+) function; or, with a prior version of compiler, the idFrom member of the NMHDR structure sent in lparam.

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

                                        Comment

                                        Working...
                                        X