Announcement

Collapse
No announcement yet.

Treeview Checkbox Hittest help sought

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

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

    Leave a comment:


  • Michael Mattias
    replied
    > TVHT_ONITEMSTATEICON

    I missed that one, didn't I?

    Leave a comment:


  • Dominic Mitchell
    replied
    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

    Leave a comment:


  • Michael Mattias
    replied
    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.

    Leave a comment:


  • Chris Holbrook
    started a topic Treeview Checkbox Hittest help sought

    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
Working...
X