Announcement

Collapse
No announcement yet.

Treeview Checkbox Hittest help sought

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

  • Treeview Checkbox Hittest help sought

    In the attached code (compiles with PBWin 8.04), the objective is to toggle the checked state of all siblings if the "*" item is checked. However, the Treeview_hittest does not discriminate between a click in the checkbox and a click on the node text, which might confuse the user - it certainly has me foxed. Any suggestions?

    Code:
    '
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "commctrl.inc"
    #INCLUDE "comdlg32.inc"
    
    %IDC_DBB_DONE_BN       = 1316
    %idc_DBB_lab1          = 1317
    %idc_DBB_lab2          = 1318
    %idc_DBB_lab3          = 1319
    %IDC_DBB_TREEVIEW      = 1320
    %IDC_main_bn           = 1321
    %idc_listbox           = 1322
    %OURMSG_EDITORHANDLE   = %WM_USER + 100
    
    
    DECLARE FUNCTION DBBrowser(BYVAL hParent AS DWORD) AS LONG
    DECLARE FUNCTION mainwindow  ( BYVAL hParent AS DWORD ) AS LONG
    
    GLOBAL gsDBPath AS STRING
    GLOBAL gEditWnd AS DWORD
    GLOBAL gchecked, gunchecked      AS DWORD
    
    FUNCTION PBMAIN () AS LONG
    
        InitCommonControls
        gchecked   = 2: SHIFT LEFT gchecked,   12
        gunchecked = 1: SHIFT LEFT gunchecked, 12
        DBBrowser(0)
        mainwindow(0)
    
    END FUNCTION
    '------------------------------------------------------------------------------
    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))
            CALL SampleTreeViewInsertItem(hCtl, hRoot, "*")
            FOR j = 1 TO lCount
                hParent = SampleTreeViewInsertItem(hCtl, hRoot, USING$("Item#", j))
                CALL SampleTreeViewInsertItem(hCtl, hParent, "*")
                FOR k = 1 TO lCount
                    CALL SampleTreeViewInsertItem(hCtl, hParent, USING$("SubItem#_.#", j, k))
                NEXT k
            NEXT j
        NEXT i
    END FUNCTION
    '------------------------------------------------------------------------------
    ' this sub ascends the tree from the current item, setting the checked state to "checked"
    ' as it goes. Assumption: that the hItem part of the structure pointed to by 2nd param
    ' is valid. Note that the item pointed to does not have its checkstate changed by this code
    '
    SUB CheckParent ( hTVWnd AS DWORD, dwItem AS DWORD)
        LOCAL TreeItem AS TV_ITEM
        LOCAL i AS DWORD
    
        TreeItem.hItem = TreeView_GetParent ( hTVWnd, dwitem)
        WHILE TreeItem.hItem <> %NULL
            TreeItem.mask = %TVIF_STATE OR %TVIF_HANDLE
            TreeItem.stateMask = %TVIS_STATEIMAGEMASK
            TreeItem.state = gchecked
            Treeview_setItem (hTVWnd, BYVAL VARPTR(TreeItem))
            TreeItem.hItem = TreeView_GetParent ( hTVWnd , TreeItem.hitem)
        WEND
    END SUB
    '------------------------------------------------------------------------------
    ' Called when the text of the checked item is "*".
    ' check all its siblings
    SUB CheckAll ( hTVWnd AS DWORD, BYVAL pTV AS TV_ITEM PTR)
        LOCAL TreeItem AS TV_ITEM
        LOCAL i        AS LONG
        LOCAL checked  AS DWORD
        LOCAL sz AS ASCIZ * 256
    '    local psz as asciz ptr
        
        TreeItem = @pTV
        checked = TreeItem.state
        IF (checked AND gchecked) = gchecked THEN
            checked = gunchecked
        ELSE
            checked = gchecked
        END IF
        TreeItem.hItem = TreeView_GetNextSibling ( hTVWnd , TreeItem.hitem)
    
        WHILE TreeItem.hItem <> %NULL
            TreeItem.mask = %TVIF_STATE OR %TVIF_HANDLE
            TreeItem.stateMask = %TVIS_STATEIMAGEMASK
            TreeItem.state     = checked
            IF Treeview_setItem(hTVWnd, BYVAL VARPTR(TreeItem)) <> %TRUE THEN
                ? "failed to update treeview"
            END IF
            TreeItem.hItem = TreeView_GetNextSibling ( hTVWnd , TreeItem.hitem)
        WEND
    
    END SUB
    '------------------------------------------------------------------------------
    ' function prototype for walkies "onHit" fn
    ' first param is treeview window handle
    ' second param is pointer to TV_ITEM
    ' 3rd param is path
    DECLARE FUNCTION TVfnPrototype  ( hTVWnd AS DWORD, BYVAL pTV AS TV_ITEM PTR, BYVAL psz AS ASCIZ PTR) AS LONG
    '------------------------------------------------------------------------------
    FUNCTION Our_TVITEM_proc ( hTVWnd AS DWORD, BYVAL pTV AS TV_ITEM PTR, BYVAL psz AS ASCIZ PTR) AS LONG
        ' this line sends the TV item name to a listbox
        sendmessage geditWnd, %LB_ADDSTRING, 0, psz ' send it on, prefixed by parent id
    END FUNCTION
    '------------------------------------------------------------------------------
    ' walk tree, execute OnHitfn when a checked item is encountered
    ' params are treeview control window handle,
    '            OnHitFn address
    '            TV item handle
    '            parent identifier (text of parent TV item)
    '
    FUNCTION walkies ( hTVWnd AS DWORD, OnHitfn AS DWORD, hTVItem AS DWORD, BYVAL pszParent AS ASCIZ PTR  ) AS LONG
        LOCAL sz AS ASCIZ * 1024
        LOCAL hti AS tv_item PTR
        LOCAL treeItem AS TV_ITEM
        LOCAL pTVITEM AS tv_item PTR
        LOCAL i AS LONG
    
        TreeItem.HItem = hTVItem
        pTVITEM = VARPTR(TreeItem)
        WHILE TreeItem.HItem <> %NULL
            TreeItem.mask       = %TVIF_TEXT OR %TVIF_STATE OR %TVIF_HANDLE
            TreeItem.stateMask  = %TVIS_STATEIMAGEMASK
            TreeItem.cchTextMax = SIZEOF(sz)
            TreeItem.pszText    = VARPTR(sz)
            TReeView_getItem( hTVWnd, BYVAL pTVITEM) ' get item
            ' is it checked?
    '        ? str$(gchecked)+ ":" + str$(TreeItem.state)
            IF (TreeItem.state AND gchecked) = gchecked THEN
                IF @pszParent <> "" THEN sz = @pszParent + "." + sz
                CALL DWORD OnHitFn USING TVfnPrototype (hTVWnd, BYVAL pTVITEM, BYVAL VARPTR(sz))
                CALL walkies(hTVWnd, OnHitFn, TreeView_GetChild(hTVwnd, TreeItem.hitem), BYVAL VARPTR(sz))
            END IF
            TreeItem.HItem = Treeview_GetNextSibling(hTVWnd, TreeItem.hItem)
        WEND
    END FUNCTION
    
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION DBBrowser_dialogProc()
        STATIC hmenu, hparent, hTVWnd AS DWORD
        LOCAL r             AS rect
        LOCAL s, s1         AS STRING
        LOCAL hDB, l, lresult AS LONG
        LOCAL sz            AS ASCIIZ*256
        LOCAL psz           AS ASCIZ PTR
        LOCAL lpNmh         AS NMHDR PTR
        LOCAL lpTV          AS NM_TREEVIEW PTR
        LOCAL treeItem      AS TV_ITEM
        LOCAL pTVITEM       AS tv_item PTR
        LOCAL TVdi          AS TV_DISPINFO
        LOCAL TVht          AS TV_HITTESTINFO
        LOCAL DWPOS         AS DWORD
        
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                hTVWnd = getdlgitem(CBHNDL, %IDC_DBB_TREEVIEW)
                CONTROL ADD LABEL, CBHNDL, %idc_DBB_lab1,"check boxes press button" & s ,5, 2, 175,12
    
                SampleTreeView(CBHNDL, %IDC_DBB_TREEVIEW,20)
             '
             CASE %WM_NOTIFY
                 lpNmh = CBLPARAM
                 SELECT CASE @lpNmh.Code
                    CASE %TVN_SELCHANGED
                       'get selected text
                       lpTV = CBLPARAM
                       TreeItem.hItem = @lpTV.ItemNew.hItem
                       TreeItem.mask = %TVIF_TEXT
                       TreeItem.cchTextMax = SIZEOF(sz)
                       TreeItem.psztext    = VARPTR(sz)
                       pTVITEM = VARPTR(TreeItem)
                       TreeView_GetItem( hTVWnd, BYVAL pTVITEM)
    
                    CASE %NM_CLICK
                      IF @lpNmh.idFrom = %IDC_DBB_TREEVIEW THEN
                        ' This will ensure that when the user either clicks the checkbox or the
                        ' buttons (+/-) the item/node will be selected. You get a strange flashing
                        ' experience if you do not do this, comment out this code and then use a
                        ' checkbox or the buttons and see what occurs. (found this code on MSDN)
                        dwPos = GetMessagePos          ' Get the mouse position
                        TVht.pt.x = LO(WORD, dwPos)    ' Store the mouse x pos in the hittest udt
                        tvht.pt.y = HI(WORD, dwPos)    ' Store the mouse y pos in the hittest udt
                        MapWindowPoints(%HWND_DESKTOP, @LPnMH.hwndFrom, TVht.pt, 1)
    
                        ' Get the TreeView item/node returned in the hittest udt member of hItem
                        TreeView_HitTest( hTVWnd, BYVAL VARPTR(TVht))
                        ' get item
                        TreeItem.mask       = %TVIF_STATE OR %TVIF_HANDLE OR %TVIF_TEXT
                        TreeItem.stateMask  = %TVIS_STATEIMAGEMASK
                        TreeItem.cchTextMax = SIZEOF(sz)
                        TreeItem.psztext    = VARPTR(sz)
                        TreeItem.hItem      = TVHT.Hitem
                        TreeView_GetItem (hTVWnd, BYVAL VARPTR(TreeItem))
                        IF TRIM$(sz) = "*" THEN
                            CheckAll (hTVWnd, BYVAL VARPTR(TreeItem))
                        END IF
                        CheckParent (hTVWnd, TreeItem.Hitem)
                        ' Select the TreeView item/node that was clicked on (returned above)
                        TreeView_SelectItem(hTVWnd, TreeItem.hItem)
                      END IF
                 END SELECT
    
            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_LBUTTONDOWN
                SendMessage CBHNDL, %WM_NCLBUTTONDOWN, %HTCAPTION, BYVAL %NULL  ' force drag
    
            CASE %WM_COMMAND
            SELECT CASE CBCTL  ' <- look at control's id
               CASE %IDC_DBB_DONE_BN
                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                      walkies ( hTVWnd, CODEPTR(Our_TVITEM_proc), TreeView_GetRoot( hTVWnd), BYVAL %null)
                  END IF
            END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION DBBrowser(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
        LOCAL s AS STRING
    
        DIALOG NEW hParent, "", 10, 100, 140, 205, %WS_POPUP OR %WS_THICKFRAME OR _
            %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_TOOLWINDOW OR _
            %WS_EX_TOPMOST OR %WS_EX_LEFT OR %WS_EX_LTRREADING TO hdlg
        DIALOG  SET COLOR   hDlg, -1, RGB(255, 255, 155)
        CONTROL ADD BUTTON,  hDlg, %IDC_DBB_DONE_BN, "Send selection", 70, 190, 70, 15
        CONTROL ADD "SysTreeView32", hDlg,%IDC_DBB_TREEVIEW, "SysTreeView32_1", 5, 15, 135, 175, %WS_CHILD OR %WS_VISIBLE OR _
            %WS_TABSTOP OR %TVS_HASBUTTONS OR %TVS_HASLINES OR %TVS_CHECKBOXES OR %TVS_LINESATROOT OR %TVS_SHOWSELALWAYS, %WS_EX_CLIENTEDGE OR _
            %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
        DIALOG SHOW MODELESS hDlg, CALL DBBrowser_dialogProc TO lRslt
    
        FUNCTION = lRslt
    END FUNCTION
    '--------------------------------------------------------------------------------
    CALLBACK FUNCTION mainwindowproc()
        LOCAL sz AS ASCIZ * 64
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_COMMAND
            SELECT CASE CBCTL  ' <- look at control's id
               CASE %IDC_MAIN_BN
                  IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                      DIALOG END CBHNDL, 0
                  END IF
            END SELECT
        END SELECT
    END FUNCTION
    
    '--------------------------------------------------------------------------------
    FUNCTION mainwindow  ( BYVAL hParent AS DWORD ) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
    
        DIALOG NEW hParent, "", 180, 100, 200, 210, %WS_POPUP OR %WS_THICKFRAME OR _
            %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR _
            %WS_EX_TOPMOST OR %WS_EX_LEFT OR %WS_EX_LTRREADING TO hdlg
    
    
        CONTROL ADD LISTBOX, hdlg, %IDC_LISTBOX,, 0,0,200,200, _
        %WS_CHILD OR %WS_TABSTOP OR %WS_VISIBLE OR %WS_VSCROLL OR %LBS_NOTIFY, _
        %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    
        gEditWnd = getdlgitem(hdlg, %IDC_LISTBOX)
    
        CONTROL ADD BUTTON,  hDlg, %IDC_main_bn, "exit", 170, 195, 30, 15
    
        DIALOG SHOW MODAL hdlg CALL mainwindowproc
    END FUNCTION

  • #2
    Treeview_hittest does not discriminate between a click in the checkbox and a click on the node text
    ???

    Sure it does. Flags member of TVHITTESTINFO includes
    TVHT_ONITEM: On the bitmap or label associated with an item
    TVHT_ONITEMICON: On the bitmap associated with an item.
    TVHT_ONITEMLABEL: On the label (string) associated with an item

    Test the bits of interest and you know if a point is on the item text, the item icon, or either.

    As far as the check box...

    TVHT_ONITEMBUTTON: Doc says, "On the button associated with an item", which I think would be any checkbox, since a checkbox is a button control. Worth a try anyway.
    Michael Mattias
    Tal Systems Inc. (retired)
    Racine WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      However, the Treeview_hittest does not discriminate between a click in the checkbox and a click on the node text
      It does. You have to check the flags returned by TVM_HITTEST.

      For example, the following code tests for a click on the state image(checkbox if treeview has the TVS_CHECKBOXES style):
      Code:
      IF (ttvht.flags AND %TVHT_ONITEMSTATEICON) = %TVHT_ONITEMSTATEICON THEN
      Dominic Mitchell
      Phoenix Visual Designer
      http://www.phnxthunder.com

      Comment


      • #4
        > TVHT_ONITEMSTATEICON

        I missed that one, didn't I?
        Michael Mattias
        Tal Systems Inc. (retired)
        Racine WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Thanks, both! Don't know how I missed looking at the TV_HITTESTINFO structure, just practice I suppose...

          Comment

          Working...
          X