Announcement

Collapse
No announcement yet.

Add Checkbox into a virtual listview

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

  • Add Checkbox into a virtual listview

    Hi

    I would like to add checkboxes into a virtual listview so that when a user click on a checkbox in a listview row and then that particular
    row would be highlighted.

    I have also modified the program at https://forum.powerbasic.com/forum/u...cell-selection
    to incorporate a status bar.

    Can anyone please help me?

    Code:
    ' Virtual ListView Highlight.bas
    
    #COMPILER PBWIN 10
    #COMPILE EXE
    #DIM ALL
    %Unicode=1
    #INCLUDE "win32api.inc"  'Jose Roca includes
    
    ENUM Equates SINGULAR
       IDC_ListView     = 500
       IDC_STATUSBAR1
    END ENUM
    
    GLOBAL hDlg, hListView AS DWORD, SortDirection AS LONG
    GLOBAL CurrentRow, CurrentCol, OrigLVProc AS LONG
    GLOBAL D() AS STRING
    
    
    '_____________________________________________
    FUNCTION PBMAIN() AS LONG
       DIALOG NEW PIXELS, 0, "Virtual ListView ",300,300,400,220, %WS_OVERLAPPEDWINDOW TO hDlg
    
       CONTROL ADD LISTVIEW, hDlg, %IDC_ListView,"", 10,10,380,180, _
         %LVS_OWNERDATA OR %LVS_REPORT OR %WS_TABSTOP OR %LVS_SHOWSELALWAYS _
         OR %LVS_SINGLESEL, %WS_EX_CLIENTEDGE
    
       CONTROL HANDLE hDlg, %IDC_ListView TO hListView
       LISTVIEW SET STYLEXX hDlg, %IDC_ListView,%LVS_EX_GRIDLINES OR %LVS_EX_FULLROWSELECT
    
        CONTROL ADD STATUSBAR, hDlg, %IDC_STATUSBAR1, "  Cell :", 0, 0, 0, 0
      STATUSBAR SET PARTS hDlg, %IDC_STATUSBAR1, 100, 100, 9999
    
       DIALOG SHOW MODAL hDlg CALL DlgProc
    
    END FUNCTION
    
    
    '____________________________________________
    CALLBACK FUNCTION DlgProc() AS LONG
       LOCAL i,j,iRow,iCol AS LONG, pLVDI AS LV_DISPINFO PTR, lplvcd AS NMLVCUSTOMDRAW PTR
       LOCAL LpLvNm AS NM_LISTVIEW PTR, tmp$$
    
       SELECT CASE CB.MSG
          CASE %WM_INITDIALOG
             'initialize data/location
             CreateLVData
             ListView_SetItemCountEx(hListView, UBOUND(D,1), %LVSICF_noInvalidateAll) 'max rows
             CurrentRow = 1 : CurrentCol = 1
             UpdateStatus
             OrigLVProc = SetWindowLong(hListView, %GWL_WndProc, CODEPTR(NewLVProc))  'subclass LV
    
          CASE %WM_DESTROY
             SetWindowLong hListView, %GWL_WNDPROC, OrigLVProc
          CASE %WM_NOTIFY
             SELECT CASE CB.NMID
                CASE %IDC_ListView
                   SELECT CASE CB.NMCODE
                      CASE %LVN_ITEMCHANGED   'turns off row selection
                         LpLvNm = CB.LPARAM
                         ListView_SetItemState hListView, @LpLvNm.iItem, 0, %LVIS_Focused OR %LVIS_Selected
                      CASE %NM_CLICK
                         LpLvNm = CB.LPARAM
                         CurrentRow = @LpLvNm.iiTem + 1
                         CurrentCol = @LpLvNm.iSubItem + 1
                         CONTROL REDRAW hDlg, %IDC_ListView
                         UpdateStatus
                      CASE %NM_CUSTOMDRAW        'sets the selected cell colors
                           lpLvCd = CBLPARAM
                           SELECT CASE @lplvcd.nmcd.dwDrawStage
                              CASE %CDDS_PREPAINT, %CDDS_ITEMPREPAINT
                                 FUNCTION = %CDRF_NOTIFYSUBITEMDRAW
                              CASE %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM
                                 IF  @lplvcd.nmcd.dwItemSpec = CurrentRow-1 THEN
                                    IF @lpLvCd.iSubItem <> CurrentCol-1 THEN
                                       @lpLvCd.clrTextBk = %WHITE
                                    ELSE
                                       @lpLvCd.clrTextBk = %GREEN
                                    END IF
                                 END IF
                               FUNCTION = %CDRF_NEWFONT
                           END SELECT
                      CASE %LVN_GETDISPINFO               'notification to ask for data
                         pLVDI = CB.LPARAM                'pointer to LVDISPINFO structure for requested subitem
                         iRow = @pLVDI.item.iItem+1       'row being asked for
                         iCol = @pLVDI.item.iSubItem+1    'sub item being asked for (columns)
                         tmp$$ = D(iRow,iCol)
                         @pLVDI.item.pszText = STRPTR(tmp$$) 'text sent to ListView
                   END SELECT
             END SELECT
       END SELECT
    END FUNCTION
    
    
    '_______________________________________
    SUB CreateLVData
       LOCAL i,j AS LONG
       REDIM D(550,10)
       FOR i = 1 TO UBOUND(D,2)
          LISTVIEW INSERT COLUMN hDlg, %IDC_ListView, i, "Col" + TRIM$(STR$(i)), 100, 0
       NEXT i
       FOR i = 1 TO UBOUND(D,1)
          FOR j = 1 TO UBOUND(D,2)
             D(i,j) = "Row" + TRIM$(STR$(i)) + " Col" + TRIM$(STR$(j))
          NEXT j
       NEXT i
    END SUB
    
    '______________________________
    ' updates the status bar
    SUB UpdateStatus
      ' Dialog Set Text hDlg, "Virtual ListView :  " + " Row " + Str$(CurrentRow) + "  Col " +Str$(CurrentCol)
       STATUSBAR SET TEXT hDlg, %IDC_StatusBar1, 2, 0, FORMAT$(CurrentRow,"  #,###,##0") + " : " + FORMAT$(CurrentCol," #,###,##0")
    END SUB
    
    
    '_______________________________
    FUNCTION NewLVProc(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, _
             BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
       LOCAL hdnptr AS HD_NOTIFY PTR, hdiptr AS HD_ITEM PTR, w,iResult AS LONG
       LOCAL LpLvNm AS NM_LISTVIEW PTR, LVHT AS LVHitTestInfo
    
       SELECT CASE Msg
          CASE %WM_KEYDOWN
             SELECT CASE wParam
                CASE %VK_Up
                   CurrentRow = MAX(1,CurrentRow-1)
                   UpdateStatus
                   CONTROL REDRAW hDlg, %IDC_ListView
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
    
                CASE %VK_Down
                   CurrentRow = MIN(UBOUND(D,2),CurrentRow+1)
                   UpdateStatus
                   CONTROL REDRAW hDlg, %IDC_ListView
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
    
                CASE %VK_Left
                   CurrentCol = MAX(1,CurrentCol-1)
                   UpdateStatus
                   CONTROL REDRAW hDlg, %IDC_ListView
    
                CASE %VK_Right
                   CurrentCol = MIN(UBOUND(D,2),CurrentCol+1)
                   UpdateStatus
                   CONTROL REDRAW hDlg, %IDC_ListView
    
                CASE %VK_Pgup
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
                   CONTROL REDRAW hDlg, %IDC_ListView
                   UpdateStatus
    
                CASE %VK_PgDn
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
                   CONTROL REDRAW hDlg, %IDC_ListView
                   UpdateStatus
                CASE %VK_Home
                   CurrentCol = 1
                   IF GetKeyState(%VK_Control) AND &H8000 THEN CurrentRow = 1
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
                   CONTROL REDRAW hDlg, %IDC_ListView
                   UpdateStatus
    
                CASE %VK_End
                   CurrentCol = UBOUND(D,2)
                   IF GetKeyState(%VK_Control) AND &H8000 THEN CurrentRow = UBOUND(D,2)
                   LISTVIEW VISIBLE hDlg, %IDC_ListView, CurrentRow
                   CONTROL REDRAW hDlg, %IDC_ListView
                   UpdateStatus
    
            END SELECT
       END SELECT
       FUNCTION = CallWindowProc(OrigLVProc, hWnd, Msg, wParam, lParam)
    END FUNCTION



  • #2
    Assuming that you have somewhere to record the checked state of each item, you just need a bit of code like this:

    Code:
    sub togglecheckedstate(byval lparam as long)
                    local l, n as long
                    local pnmlv as nmlistview ptr
                    local LVI as LVITEM
    
                    pnmlv = lparam
                    n = @pnmlv.iitem + 1
                    l = checkstate(n)
                    l = (l = 0)
                    checkstate(n) = l
                    listview_update(hLV, n - 1)
    end sub
    It is called in response to a WM_NOTIFY message notifying the double click

    Code:
           case %wm_notify
                select case as long cb.nmid
                    case %MY_LISTVIEW_CONTROL_ID
                        select case as long cb.nmcode
                           '..... action other values of cb.nmcode
                           '
                            case %nm_dblclk ' double-click action is to check the box
                                togglecheckedstate( cb.lparam)
                        end select

    Comment


    • #3
      Tim try out this
      https://forum.powerbasic.com/forum/u...ontrol?t=10343

      Comment


      • #4
        I still can't figure out why I couldn't add checkboxes at the front in column 0 for each row

        Please help me! I maybe just a hop away from a decent solution?

        Code:
         'Conv VListview Statusbar.bas
        
         ' Added statusbar
        
        
        
        
        #COMPILE EXE
        #DIM ALL
        
        #INCLUDE "Win32Api.inc"
        #INCLUDE "PBForms.inc"
        
        
        'Old Listview callback procedure pointer
        GLOBAL OldLVProc AS LONG
        GLOBAL NumRow, NumCol AS LONG
        
         GLOBAL HTIMER  AS LONG
         GLOBAL hDlg AS DWORD 'Handle to the dialog
         GLOBAL CurrentRow , CurrentCol AS LONG
         GLOBAL hctl AS DWORD
         GLOBAL lvfilescheck() AS LONG
         GLOBAL sData() AS STRING
        
          %ID_LABEL    = 1000 'Id of the label control
          %ID_LISTVIEW = 1001 'id of the ListView control
          %IDC_Statusbar = 1011
          %ID_tmStb  = 1016
        
        
           'Add the XP Manifest resrouce file
            #RESOURCE MANIFEST, 1, "XpTheme.xml"
        
        
        
        
        '_______________________________________________________________________________
        FUNCTION PBMAIN()AS LONG
        
         LOCAL i    AS LONG  'Column counter variable
         LOCAL j    AS LONG  'Row counter variable
        
             LOCAL tlvc    AS lv_column
             LOCAL tlvi    AS lv_item
             LOCAL szbuf   AS WSTRINGZ * 100
        
          'Number of rows in the ListView
          NumRow      = 200
          'Number of columns in the ListView
          NumCol      = 3
        
        
         DIALOG NEW %HWND_DESKTOP, "Virtual ListView", , , 314, 225, _
         %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR _
         %WS_SYSMENU OR %WS_MINIMIZEBOX 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 LABEL, hDlg, %ID_LABEL, _
          " with Statusbar ", _
          1, 1, 313, 8, %SS_CENTER
          CONTROL SET COLOR hDlg, %ID_LABEL, %RGB_FIREBRICK, %RGB_LIGHTYELLOW
        
         'Tim 01: First change the style to OR %LVS_OWNERDATA.
         'Now we will have to show where ise the data to the listview
         CONTROL ADD LISTVIEW, hDlg, %ID_LISTVIEW, "", 1, 14, 312, 190, _
         %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP  OR %LVS_REPORT OR  %LVS_EX_CHECKBOXES OR _
         %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL OR %LVS_OWNERDATA '<<<<<<<<<<<<<<<< Added LVS_OWNERDATA
        
         ' ListView  headers
        ' FOR i = 1 TO NumCol
           '  LISTVIEW INSERT COLUMN hDlg, %ID_LISTVIEW, i, "   Column " + FORMAT$(i), 100, 0
        ' NEXT i
        
        
             ' first we set the first column which holds the checkboxes
             tlvc.mask    = %lvcf_width
             tlvc.fmt     = %lvcfmt_left
             tlvc.psztext = VARPTR(szbuf)
        
        
             ' column 0 - we only want show the checkboxes here.
             szbuf        = "    "  ' nothing
             '  set the width for the first column (column 0) for the checkbox
             tlvc.cx      = 20
             tlvc.iorder  = 0
             listview_insertcolumn GetDlgItem(hDlg, %ID_LISTVIEW), 0, tlvc
        
             ' and now the rest of the column headers
             tlvc.mask    = %lvcf_text OR %lvcf_fmt OR %lvcf_subitem OR %lvcf_width
             tlvc.cx      = 150   ' here we set the width for all other columns
        
             FOR i = 1 TO NumCol
                  szbuf       =   USING$("Column #", i) +NUL$(0)    ' " Column " + FORMAT$(i)   '
                  tlvc.iorder = i
                  tlvc.psztext = VARPTR(szbuf)
                  listview_insertcolumn GetDlgItem(hDlg, %ID_LISTVIEW), i, tlvc
             NEXT lcol
        
        
        
        
         'Tim 02: No LISTVIEW INSERT/SET because the data won't be in the listview but in our array
         'FOR i = 1 TO NumRow
         ' LISTVIEW INSERT ITEM hDlg, %ID_LISTVIEW, i, 0, "Row #" + FORMAT$(i, "000") + " Item #01"
         ' FOR j = 2 TO NumCol
         '   LISTVIEW SET TEXT hDlg, %ID_LISTVIEW, i, j, "Row #" + FORMAT$(i, "000") + " Item #" + FORMAT$(j, "00")
         ' NEXT j
         'NEXT i
        
         'Tim 03: Build some data in a global array
         REDIM lvfilescheck(0 TO NumRow )
         REDIM sData(0 TO NumRow, 0 TO NumRow)
         FOR j = 1 TO NumRow
           FOR i = 1 TO NumCol
             sData(j, i) = UCODE$("Row #" & FORMAT$(j,"000") & "   Col #" + FORMAT$(i))
           NEXT
         NEXT
        
         'Tim 04: Tell the listview how many item it have to manage
         LISTVIEW_SETITEMCOUNT(GetDlgItem(hDlg, %ID_LISTVIEW), NumRow)
        
        
           CONTROL ADD STATUSBAR, hDlg, %IDC_StatusBar, "   Cell ", _
                0,0,0,0,%CCS_BOTTOM,%WS_EX_WINDOWEDGE
                 STATUSBAR SET PARTS hDlg, %IDC_StatusBar, 55,99999
        
        
        
         DIALOG SHOW MODAL hDlg, CALL DlgProc
        
        END FUNCTION
        
        
        '_______________________________________________________________________________
        
        CALLBACK FUNCTION DlgProc
        
         SELECT CASE AS LONG CB.MSG
        
           CASE %WM_INITDIALOG
             '  Subclass the listview control so we can receive %WM_LButtonDown and %WM_KeyDown messages
                OldLVProc = SetWindowLongW(GetDlgItem(CB.HNDL, %ID_LISTVIEW),_
                          %GWL_WNDPROC, BYVAL CODEPTR(LVProc))
             '  Set timer to redraw statusbar every 0.1 secs but for 1 iteration only
             '  otherwise the statusbar will flicker
                HTIMER = SETTIMER(CBHNDL, %ID_tmStb, 100, 0)
                CurrentRow = 1 : CurrentCol = 1
                UpdateStatus
        
        
           CASE %WM_NOTIFY
             LOCAL nmLvPtr AS NM_LISTVIEW POINTER
             nmLvPtr = CBLPARAM
        
             SELECT CASE @nmLvPtr.hdr.idFrom
                 'SELECT CASE CBNMID
        
               CASE %ID_LISTVIEW
                 SELECT CASE @nmLvPtr.hdr.Code
                      'SELECT CASE CBNMCODE
        
                   CASE %LVN_GETDISPINFO, %LVN_GETDISPINFOW
                     LOCAL pLVDI AS LV_DISPINFO POINTER
                     pLVDI = CBLPARAM
                     'Tim 05: Every time the listview want to show data on
                     ' screen, it have to ask where to take it
                     @pLVDI.item.pszText = STRPTR(sData(@pLVDI.item.iItem + 1, @pLVDI.item.iSubItem + 1))
        
                   'Tim 06: LVN_ITEMCHANGED section added
                   CASE %LVN_ITEMCHANGED
                       'turns off row selection
                     STATIC RowLV AS LONG
                     STATIC ColLV AS LONG
                     nmLvPtr = CBLPARAM
                     LISTVIEW_SETITEMSTATE(GetDlgItem(CBHNDL, %ID_LISTVIEW),_
                          @nmLvPtr.iItem, 0, %LVIS_Focused OR %LVIS_Selected)
                     RowLV = @nmLvPtr.iItem
                     LOCAL LVHT AS LVHITTESTINFO
                     LOCAL pt   AS POINTAPI
                      'Get mouse position
                     GetCursorPos(lvht.pt)
                     ScreenToClient(CB.HNDL, lvht.pt)
                      'Get column under mouse
                     SendMessageW(GetDlgItem(CB.HNDL, %ID_LISTVIEW),_
                              %LVM_SUBITEMHITTEST, BYVAL 0, BYVAL VARPTR(LVHT))
                      ColLV = LVHT.iSubItem
                      CurrentRow = RowLV + 1
                      CurrentCol = ColLV  + 1
                      UpdateStatus
        
        
        
        
                   'Tim 07: NM_CUSTOMDRAW section added
                   CASE %NM_CUSTOMDRAW
                       'Sets the selected cell colors
                        LOCAL lplvcd AS NMLVCUSTOMDRAW POINTER
                        lpLvCd = CBLPARAM
        
                     SELECT CASE @lplvcd.nmcd.dwDrawStage
        
                       CASE %CDDS_PREPAINT
                         FUNCTION = %CDRF_NOTIFYITEMDRAW
        
                       CASE %CDDS_ITEMPREPAINT
                         FUNCTION = %CDRF_NOTIFYSUBITEMDRAW
        
                       CASE %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM
                         IF @lplvcd.nmcd.dwItemSpec = RowLV AND @lpLvCd.iSubItem = ColLV THEN
                          ' highlight the selected cell
                           @lpLvCd.clrTextBk = GetSysColor(%COLOR_HIGHLIGHT)
                           @lpLvCd.clrText   = GetSysColor(%COLOR_HIGHLIGHTTEXT)
                         ELSE
                           @lpLvCd.clrTextBk = GetSysColor(%COLOR_WINDOW)
                           @lpLvCd.clrText   = GetSysColor(%COLOR_WINDOWTEXT)
                         END IF
                         FUNCTION = %CDRF_NEWFONT
        
                     END SELECT
        
                END SELECT
            END SELECT
        
        
           CASE %WM_TIMER
                    LOCAL timer_iterations AS LONG
        '           Redraw statusbar for initial 0.1 second for 1 iteration only
        '           otherwise the statusbar gets overwritten by background image
                    CONTROL REDRAW CBHNDL, %IDC_Statusbar
                    DIALOG GET USER CB.HNDL, 1 TO timer_iterations
                    IF timer_iterations >= 1 THEN
                      KILLTIMER CBHNDL, %ID_tmStb
                    ELSE
                       DIALOG SET USER CB.HNDL, 1, timer_iterations + 1
                    END IF
        
        
        
        
          CASE %WM_DESTROY
            'Restore the listview controls original callback procedure
            SetWindowLongW(GetDlgItem(CB.HNDL, %ID_LISTVIEW), %GWL_WNDPROC, OldLVProc)
            KILLTIMER CBHNDL, %ID_tmStb
        
        
        END SELECT
        END FUNCTION
        
        
        
        '_______________________________________________________________________________
        ' Blank out the status bar to facilitate scrolling action
        ' Note that we cannot use  wSTRINGz for the blank text
        ' as it will display chinese characters instead
        SUB BlankStatusBar
            STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 1, 0, " Cell "
            STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, &H0200,"  "
        END SUB
        
        
        
        '_______________________________________________________________________________
        ' The status bar displaying the current position of cursor
        SUB UpdateStatus
            IF CurrentRow = 0  THEN
               BlankStatusBar
               EXIT SUB
            END IF
          '  IF CurrentCol = 0 THEN
                ' when user click the check box -- show only the row numbers
             '   STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, 0," Row " + FORMAT$(CurrentRow ,"  #,###,##0")
             '  EXIT SUB
           ' END IF
            STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 1, 0, " Cell "
            STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, 0," Row " + _
                     FORMAT$(CurrentRow ,"  #,###,##0") + _
                     " : Col " + FORMAT$(CurrentCol," #,###,##0")
        END SUB
        
        
        
        '_______________________________________________________________________________
        'ListView callback procedure
        FUNCTION LVProc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
             BYVAL wParam AS LONG, BYVAL lParam AS LONG)AS LONG
        
         STATIC Colpr AS LONG 'Selected column
         STATIC Rowpr AS LONG 'Selected row
         LOCAL NumRpage AS LONG 'Number of rows per page
         'Contains information about a mouse clik on the ListView
         LOCAL LVHT AS LVHITTESTINFO
        
        
         SELECT CASE AS LONG wMsg
        
           CASE %WM_LBUTTONDOWN
             lvht.pt.x = LO(WORD, lparam)'X coordinate of mouse left button down
             lvht.pt.y = HI(WORD, lparam)'Y coordinate of mouse left button down
             'Find the listview item and subitem at these X, Y coordinates
             SendMessageW(hwnd, %LVM_SUBITEMHITTEST, BYVAL 0, BYVAL VARPTR(LVHT))
             'Did we find a listview item at these coordinates?
             IF lVHT.iItem<> - 1 THEN
               'Update the ListView with the new selection
               UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, lVHT.iItem + 1, LVHT.iSubItem + 1)
             END IF
             'We handled this message, so we need to return a zero
             'and not call the the original listview callback.
             FUNCTION = 0
             EXIT FUNCTION
        
           CASE %WM_KEYDOWN
        
             SELECT CASE AS LONG wParam
        
               CASE %VK_UP
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr - 1, Colpr)
        
               CASE %VK_DOWN
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr + 1, Colpr)
        
               CASE %VK_RIGHT
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr, Colpr + 1)
        
               CASE %VK_LEFT
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr, Colpr - 1)
        
               CASE %VK_PGUP
                 'Get the number of rows per page in the ListView
                 NumRpage = SendMessageW(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0)
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr - NumRpage, Colpr)
        
               CASE %VK_PGDN
                 'Get the number of rows per page in the ListView
                 NumRpage = SendMessageW(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0)
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr + NumRpage, Colpr)
        
               CASE %VK_HOME
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, 1, 1)
        
               CASE %VK_END
                 'Update the ListView with the new selection
                 UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, NumRow, 1)
        
             END SELECT
             'We handled this message, so we need to return a zero
             'and not call the the original listview callback.
             FUNCTION = 0
             EXIT FUNCTION
         END SELECT
         'if we did not handle this message, pass the message on to the
         'original callback for the listview control.
         FUNCTION = CallWindowProcW(OldLVProc, hWnd, wMsg, wParam, lParam)
        END FUNCTION
        
        
        '_______________________________________________________________________________
        'Unselect the previous listview selection,
        'select the new item and then ensure the new
        'item is visible.
        SUB UpdateLVSelect(BYVAL hDlg AS LONG, BYREF RowUp AS LONG,_
                 BYREF ColUp AS LONG, BYVAL NewRow AS LONG, BYVAL NewCol AS LONG)
         'Make sure the new row is within range
         IF NewRow<1 THEN
           NewRow = 1
           ELSEIF NewRow>NumRow THEN
           NewRow = NumRow
         END IF
         'Make sure the new column is within range
         IF NewCol<1 THEN
           NewCol = 1
           ELSEIF NewCol>NumCol THEN
           NewCol = NumCol
         END IF
         'If the previous and new selection are the same then do nothing
         IF(RowUp = NewRow)AND(ColUp = NewCol)THEN EXIT SUB
         'Unselect the previous selection, required when seleting subitems
         'even if the ListView contains the %LVS_SINGLESEL style
         LISTVIEW UNSELECT hDlg, %ID_LISTVIEW, RowUp, ColUp
         'Update the Row and Column variables
         RowUp = NewRow
         ColUp = NewCol
         'Select the new ListView item
         LISTVIEW SELECT hDlg, %ID_LISTVIEW, RowUp, ColUp
        
         'Tim 08
         CONTROL REDRAW hDlg, %ID_LISTVIEW
        
         'Ensure the new ListView item is visible
         LISTVIEW VISIBLE hDlg, %ID_LISTVIEW, RowUp
        END SUB

        Comment


        • #5
          Hi Tim,
          With LVS_EX_CHECKBOXES style applied to the ListView, you will have space to draw CheckBoxs via DrawFrameControl() in CDDS_ITEMPREPAINT.

          If I got some time, I will cleanup my code and post a little demo, it should looks like this...

          Click image for larger version

Name:	ListView01.png
Views:	1
Size:	20.7 KB
ID:	774982
          Last edited by Pierre Bellisle; 19 Sep 2018, 01:05 AM.

          Comment


          • #6
            I'll try to help. First, I suggest adding a global variable for the ListView handle.
            Code:
             GLOBAL hListView AS DWORD
            Next, %LVS_EX_CHECKBOXES is an EX style that needs to be set with the LISTVIEW SET STYLEXX command, like:
            Code:
             CONTROL ADD LISTVIEW, hDlg, %ID_LISTVIEW, "", 1, 14, 312, 190, _
             %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP  OR %LVS_REPORT OR _
             %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL OR %LVS_OWNERDATA '<<<<<<<<<<<<<<<< Added LVS_OWNERDATA
            
              LISTVIEW SET STYLEXX hDlg, %ID_LISTVIEW, %LVS_EX_CHECKBOXES OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES
              CONTROL HANDLE hDlg, %ID_LISTVIEW TO hListView
            And first column mask needs both %lvcf_text OR %lvcf_width to respond to width.

            Now comes the tricky parts. Under SELECT CASE @nmLvPtr.hdr.Code, insert:
            Code:
                       CASE %NM_CLICK
                           IF @nmLvPtr.iSubItem = 0 THEN   ' Toggle CheckBox State if first column is clicked
                               LvFilesCheck(@nmLvPtr.iItem) = NOT LvFilesCheck(@nmLvPtr.iItem)
                               IF LvFilesCheck(@nmLvPtr.iItem) THEN
                                   Listview_SetItemState (hListView, @nmLvPtr.iItem, %LVIS_SELECTED OR %LVIS_FOCUSED, _
                                                                                     %LVIS_SELECTED OR %LVIS_FOCUSED)
                               ELSE
                                   Listview_SetItemState (hListView, @nmLvPtr.iItem, NOT(%LVIS_SELECTED OR %LVIS_FOCUSED), _
                                                                                       %LVIS_SELECTED OR %LVIS_FOCUSED)
                               END IF
                               ListView_Update(hListView, @nmLvPtr.iItem)
                           END IF
            And finally, under CASE %LVN_GETDISPINFO, %LVN_GETDISPINFOW, after text has been set, insert:
            Code:
                         '-------------------------------------------------------
                         IF (@pLVDI.item.mask AND %LVIF_IMAGE) THEN
                             @pLVDI.item.mask = %LVIF_STATE OR %LVIF_TEXT
                             @pLVDI.item.statemask = %LVIS_STATEIMAGEMASK
                         END IF
            
                         IF (@pLVDI.item.mask AND %LVIF_STATE) THEN
                             SELECT CASE LvFilesCheck(@pLVDI.item.iItem)
                             CASE 0  : @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(1)
                             CASE -1 : @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(2)
                             END SELECT
                         END IF
                         '-------------------------------------------------------
            Think that should give you checkboxes, but did you want full row select or not? There's a lot of extra code there I don't understand, but if you uncomment LISTVIEW_SETITEMSTATE under CASE %LVN_ITEMCHANGED, you should get full row select. I paste your code with the above changes here to make things clearer... than mud. Hope you can get it working. Then of course, Pierre's solution looks much nicer, with 3-d boxes, but this is also a way:
            Code:
             'Conv VListview Statusbar.bas
            
             ' Added statusbar
            
            
            
            
            #COMPILE EXE
            #DIM ALL
            
            #INCLUDE "Win32Api.inc"
            #INCLUDE "PBForms.inc"
            
            
            'Old Listview callback procedure pointer
            GLOBAL OldLVProc AS LONG
            GLOBAL NumRow, NumCol AS LONG
            
             GLOBAL HTIMER  AS LONG
             GLOBAL hDlg AS DWORD 'Handle to the dialog
             GLOBAL CurrentRow , CurrentCol AS LONG
             GLOBAL hctl AS DWORD
             GLOBAL lvfilescheck() AS LONG
             GLOBAL sData() AS STRING
             GLOBAL hListView AS DWORD
            
              %ID_LABEL    = 1000 'Id of the label control
              %ID_LISTVIEW = 1001 'id of the ListView control
              %IDC_Statusbar = 1011
              %ID_tmStb  = 1016
            
            
               'Add the XP Manifest resrouce file
            '    #RESOURCE MANIFEST, 1, "XpTheme.xml"
            
            
            
            
            '_______________________________________________________________________________
            FUNCTION PBMAIN()AS LONG
            
             LOCAL i    AS LONG  'Column counter variable
             LOCAL j    AS LONG  'Row counter variable
            
                 LOCAL tlvc    AS lv_column
                 LOCAL tlvi    AS lv_item
                 LOCAL szbuf   AS WSTRINGZ * 100
            
              'Number of rows in the ListView
              NumRow      = 200
              'Number of columns in the ListView
              NumCol      = 3
            
            
             DIALOG NEW %HWND_DESKTOP, "Virtual ListView", , , 314, 225, _
             %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR _
             %WS_SYSMENU OR %WS_MINIMIZEBOX 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 LABEL, hDlg, %ID_LABEL, _
              " with Statusbar ", _
              1, 1, 313, 8, %SS_CENTER
              CONTROL SET COLOR hDlg, %ID_LABEL, %RGB_FIREBRICK, %RGB_LIGHTYELLOW
            
             'Tim 01: First change the style to OR %LVS_OWNERDATA.
             'Now we will have to show where ise the data to the listview
            ' CONTROL ADD LISTVIEW, hDlg, %ID_LISTVIEW, "", 1, 14, 312, 190, _
            ' %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP  OR %LVS_REPORT OR _
            ' %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL OR %LVS_OWNERDATA '<<<<<<<<<<<<<<<< Added LVS_OWNERDATA
            
             CONTROL ADD LISTVIEW, hDlg, %ID_LISTVIEW, "", 1, 14, 312, 190, _
             %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP  OR %LVS_REPORT OR _
             %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL OR %LVS_OWNERDATA '<<<<<<<<<<<<<<<< Added LVS_OWNERDATA
            
              LISTVIEW SET STYLEXX hDlg, %ID_LISTVIEW, %LVS_EX_CHECKBOXES OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES
              CONTROL HANDLE hDlg, %ID_LISTVIEW TO hListView
            
             ' ListView  headers
            ' FOR i = 1 TO NumCol
               '  LISTVIEW INSERT COLUMN hDlg, %ID_LISTVIEW, i, "   Column " + FORMAT$(i), 100, 0
            ' NEXT i
            
            
                 ' first we set the first column which holds the checkboxes
                 tlvc.mask    = %lvcf_text OR %lvcf_width
                 tlvc.fmt     = %lvcfmt_left
                 tlvc.psztext = VARPTR(szbuf)
            
            
                 ' column 0 - we only want show the checkboxes here.
                 szbuf        = "    "  ' nothing
                 '  set the width for the first column (column 0) for the checkbox
                 tlvc.cx      = 20
                 tlvc.iorder  = 0
                 listview_insertcolumn hListView, 0, tlvc
            
                 ' and now the rest of the column headers
                 tlvc.mask    = %lvcf_text OR %lvcf_fmt OR %lvcf_subitem OR %lvcf_width
                 tlvc.cx      = 150   ' here we set the width for all other columns
            
                 FOR i = 1 TO NumCol
                      szbuf       =   USING$("Column #", i) +NUL$(0)    ' " Column " + FORMAT$(i)   '
                      tlvc.iorder = i
                      tlvc.psztext = VARPTR(szbuf)
                      listview_insertcolumn hListView, i, tlvc
                 NEXT lcol
            
            
            
            
             'Tim 02: No LISTVIEW INSERT/SET because the data won't be in the listview but in our array
             'FOR i = 1 TO NumRow
             ' LISTVIEW INSERT ITEM hDlg, %ID_LISTVIEW, i, 0, "Row #" + FORMAT$(i, "000") + " Item #01"
             ' FOR j = 2 TO NumCol
             '   LISTVIEW SET TEXT hDlg, %ID_LISTVIEW, i, j, "Row #" + FORMAT$(i, "000") + " Item #" + FORMAT$(j, "00")
             ' NEXT j
             'NEXT i
            
             'Tim 03: Build some data in a global array
             REDIM lvfilescheck(0 TO NumRow )
             REDIM sData(0 TO NumRow, 0 TO NumRow)
             FOR j = 1 TO NumRow
               FOR i = 1 TO NumCol
                 sData(j, i) = UCODE$("Row #" & FORMAT$(j,"000") & "   Col #" + FORMAT$(i))
               NEXT
             NEXT
            
             'Tim 04: Tell the listview how many item it have to manage
             LISTVIEW_SETITEMCOUNT(hListView, NumRow)
            
            
               CONTROL ADD STATUSBAR, hDlg, %IDC_StatusBar, "   Cell ", _
                    0,0,0,0,%CCS_BOTTOM,%WS_EX_WINDOWEDGE
                     STATUSBAR SET PARTS hDlg, %IDC_StatusBar, 55,99999
            
            
            
             DIALOG SHOW MODAL hDlg, CALL DlgProc
            
            END FUNCTION
            
            
            '_______________________________________________________________________________
            
            CALLBACK FUNCTION DlgProc
            
             SELECT CASE AS LONG CB.MSG
            
               CASE %WM_INITDIALOG
                 '  Subclass the listview control so we can receive %WM_LButtonDown and %WM_KeyDown messages
            '        OldLVProc = SetWindowLongW(hListView,_
            '                  %GWL_WNDPROC, BYVAL CODEPTR(LVProc))
                 '  Set timer to redraw statusbar every 0.1 secs but for 1 iteration only
                 '  otherwise the statusbar will flicker
                    HTIMER = SETTIMER(CBHNDL, %ID_tmStb, 100, 0)
                    CurrentRow = 1 : CurrentCol = 1
                    UpdateStatus
            
            
               CASE %WM_NOTIFY
                 LOCAL nmLvPtr AS NM_LISTVIEW POINTER
                 nmLvPtr = CBLPARAM
            
                 SELECT CASE @nmLvPtr.hdr.idFrom
                     'SELECT CASE CBNMID
            
                   CASE %ID_LISTVIEW
                     SELECT CASE @nmLvPtr.hdr.Code
                          'SELECT CASE CBNMCODE
                       CASE %NM_CLICK
                           IF @nmLvPtr.iSubItem = 0 THEN   ' Toggle CheckBox State if first column is clicked
                               LvFilesCheck(@nmLvPtr.iItem) = NOT LvFilesCheck(@nmLvPtr.iItem)
                               IF LvFilesCheck(@nmLvPtr.iItem) THEN
                                   Listview_SetItemState (hListView, @nmLvPtr.iItem, %LVIS_SELECTED OR %LVIS_FOCUSED, _
                                                                                     %LVIS_SELECTED OR %LVIS_FOCUSED)
                               ELSE
                                   Listview_SetItemState (hListView, @nmLvPtr.iItem, NOT(%LVIS_SELECTED OR %LVIS_FOCUSED), _
                                                                                       %LVIS_SELECTED OR %LVIS_FOCUSED)
                               END IF
                               ListView_Update(hListView, @nmLvPtr.iItem)
                           END IF
            
            
                       CASE %LVN_GETDISPINFO, %LVN_GETDISPINFOW
                         LOCAL pLVDI AS LV_DISPINFO POINTER
                         pLVDI = CBLPARAM
                         'Tim 05: Every time the listview want to show data on
                         ' screen, it have to ask where to take it
                         @pLVDI.item.pszText = STRPTR(sData(@pLVDI.item.iItem + 1, @pLVDI.item.iSubItem + 1))
            
                         '-------------------------------------------------------
                         IF (@pLVDI.item.mask AND %LVIF_IMAGE) THEN
                             @pLVDI.item.mask = %LVIF_STATE OR %LVIF_TEXT
                             @pLVDI.item.statemask = %LVIS_STATEIMAGEMASK
                         END IF
            
                         IF (@pLVDI.item.mask AND %LVIF_STATE) THEN
                             SELECT CASE LvFilesCheck(@pLVDI.item.iItem)
                             CASE 0  : @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(1)
                             CASE -1 : @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(2)
                             END SELECT
                         END IF
                         '-------------------------------------------------------
            
                       'Tim 06: LVN_ITEMCHANGED section added
                       CASE %LVN_ITEMCHANGED
                           'turns off row selection
                         STATIC RowLV AS LONG
                         STATIC ColLV AS LONG
                         nmLvPtr = CBLPARAM
            '             LISTVIEW_SETITEMSTATE(hListView,_
            '                  @nmLvPtr.iItem, 0, %LVIS_Focused OR %LVIS_Selected)
                         RowLV = @nmLvPtr.iItem
                         LOCAL LVHT AS LVHITTESTINFO
                         LOCAL pt   AS POINTAPI
                          'Get mouse position
                         GetCursorPos(lvht.pt)
                         ScreenToClient(CB.HNDL, lvht.pt)
                          'Get column under mouse
                         SendMessageW(hListView,_
                                  %LVM_SUBITEMHITTEST, BYVAL 0, BYVAL VARPTR(LVHT))
                          ColLV = LVHT.iSubItem
                          CurrentRow = RowLV + 1
                          CurrentCol = ColLV  + 1
                          UpdateStatus
            
            
                       'Tim 07: NM_CUSTOMDRAW section added
                       CASE %NM_CUSTOMDRAW
                           'Sets the selected cell colors
                            LOCAL lplvcd AS NMLVCUSTOMDRAW POINTER
                            lpLvCd = CBLPARAM
            
                         SELECT CASE @lplvcd.nmcd.dwDrawStage
            
                           CASE %CDDS_PREPAINT
                             FUNCTION = %CDRF_NOTIFYITEMDRAW
            
                           CASE %CDDS_ITEMPREPAINT
                             FUNCTION = %CDRF_NOTIFYSUBITEMDRAW
            
                           CASE %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM
                             IF @lplvcd.nmcd.dwItemSpec = RowLV AND @lpLvCd.iSubItem = ColLV THEN
                              ' highlight the selected cell
                               @lpLvCd.clrTextBk = GetSysColor(%COLOR_HIGHLIGHT)
                               @lpLvCd.clrText   = GetSysColor(%COLOR_HIGHLIGHTTEXT)
                             ELSE
                               @lpLvCd.clrTextBk = GetSysColor(%COLOR_WINDOW)
                               @lpLvCd.clrText   = GetSysColor(%COLOR_WINDOWTEXT)
                             END IF
                             FUNCTION = %CDRF_NEWFONT
            
                         END SELECT
            
                    END SELECT
                END SELECT
            
            
               CASE %WM_TIMER
                        LOCAL timer_iterations AS LONG
            '           Redraw statusbar for initial 0.1 second for 1 iteration only
            '           otherwise the statusbar gets overwritten by background image
                        CONTROL REDRAW CBHNDL, %IDC_Statusbar
                        DIALOG GET USER CB.HNDL, 1 TO timer_iterations
                        IF timer_iterations >= 1 THEN
                          KILLTIMER CBHNDL, %ID_tmStb
                        ELSE
                           DIALOG SET USER CB.HNDL, 1, timer_iterations + 1
                        END IF
            
            
            
            
              CASE %WM_DESTROY
                'Restore the listview controls original callback procedure
                SetWindowLongW(hListView, %GWL_WNDPROC, OldLVProc)
                KILLTIMER CBHNDL, %ID_tmStb
            
            
            END SELECT
            END FUNCTION
            
            
            
            '_______________________________________________________________________________
            ' Blank out the status bar to facilitate scrolling action
            ' Note that we cannot use  wSTRINGz for the blank text
            ' as it will display chinese characters instead
            SUB BlankStatusBar
                STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 1, 0, " Cell "
                STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, &H0200,"  "
            END SUB
            
            
            
            '_______________________________________________________________________________
            ' The status bar displaying the current position of cursor
            SUB UpdateStatus
                IF CurrentRow = 0  THEN
                   BlankStatusBar
                   EXIT SUB
                END IF
              '  IF CurrentCol = 0 THEN
                    ' when user click the check box -- show only the row numbers
                 '   STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, 0," Row " + FORMAT$(CurrentRow ,"  #,###,##0")
                 '  EXIT SUB
               ' END IF
                STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 1, 0, " Cell "
                STATUSBAR SET TEXT hDlg, %IDC_StatusBar, 2, 0," Row " + _
                         FORMAT$(CurrentRow ,"  #,###,##0") + _
                         " : Col " + FORMAT$(CurrentCol," #,###,##0")
            END SUB
            
            
            
            '_______________________________________________________________________________
            'ListView callback procedure
            FUNCTION LVProc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                 BYVAL wParam AS LONG, BYVAL lParam AS LONG)AS LONG
            
             STATIC Colpr AS LONG 'Selected column
             STATIC Rowpr AS LONG 'Selected row
             LOCAL NumRpage AS LONG 'Number of rows per page
             'Contains information about a mouse clik on the ListView
             LOCAL LVHT AS LVHITTESTINFO
            
            
             SELECT CASE AS LONG wMsg
            
               CASE %WM_LBUTTONDOWN
                 lvht.pt.x = LO(WORD, lparam)'X coordinate of mouse left button down
                 lvht.pt.y = HI(WORD, lparam)'Y coordinate of mouse left button down
                 'Find the listview item and subitem at these X, Y coordinates
                 SendMessageW(hwnd, %LVM_SUBITEMHITTEST, BYVAL 0, BYVAL VARPTR(LVHT))
                 'Did we find a listview item at these coordinates?
                 IF lVHT.iItem<> - 1 THEN
                   'Update the ListView with the new selection
                   UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, lVHT.iItem + 1, LVHT.iSubItem + 1)
                 END IF
                 'We handled this message, so we need to return a zero
                 'and not call the the original listview callback.
                 FUNCTION = 0
                 EXIT FUNCTION
            
               CASE %WM_KEYDOWN
            
                 SELECT CASE AS LONG wParam
            
                   CASE %VK_UP
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr - 1, Colpr)
            
                   CASE %VK_DOWN
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr + 1, Colpr)
            
                   CASE %VK_RIGHT
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr, Colpr + 1)
            
                   CASE %VK_LEFT
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr, Colpr - 1)
            
                   CASE %VK_PGUP
                     'Get the number of rows per page in the ListView
                     NumRpage = SendMessageW(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0)
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr - NumRpage, Colpr)
            
                   CASE %VK_PGDN
                     'Get the number of rows per page in the ListView
                     NumRpage = SendMessageW(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0)
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, Rowpr + NumRpage, Colpr)
            
                   CASE %VK_HOME
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, 1, 1)
            
                   CASE %VK_END
                     'Update the ListView with the new selection
                     UpdateLVSelect(GetParent(hWnd), Rowpr, Colpr, NumRow, 1)
            
                 END SELECT
                 'We handled this message, so we need to return a zero
                 'and not call the the original listview callback.
                 FUNCTION = 0
                 EXIT FUNCTION
             END SELECT
             'if we did not handle this message, pass the message on to the
             'original callback for the listview control.
             FUNCTION = CallWindowProcW(OldLVProc, hWnd, wMsg, wParam, lParam)
            END FUNCTION
            
            
            '_______________________________________________________________________________
            'Unselect the previous listview selection,
            'select the new item and then ensure the new
            'item is visible.
            SUB UpdateLVSelect(BYVAL hDlg AS LONG, BYREF RowUp AS LONG,_
                     BYREF ColUp AS LONG, BYVAL NewRow AS LONG, BYVAL NewCol AS LONG)
             'Make sure the new row is within range
             IF NewRow<1 THEN
               NewRow = 1
               ELSEIF NewRow>NumRow THEN
               NewRow = NumRow
             END IF
             'Make sure the new column is within range
             IF NewCol<1 THEN
               NewCol = 1
               ELSEIF NewCol>NumCol THEN
               NewCol = NumCol
             END IF
             'If the previous and new selection are the same then do nothing
             IF(RowUp = NewRow)AND(ColUp = NewCol)THEN EXIT SUB
             'Unselect the previous selection, required when seleting subitems
             'even if the ListView contains the %LVS_SINGLESEL style
             LISTVIEW UNSELECT hDlg, %ID_LISTVIEW, RowUp, ColUp
             'Update the Row and Column variables
             RowUp = NewRow
             ColUp = NewCol
             'Select the new ListView item
             LISTVIEW SELECT hDlg, %ID_LISTVIEW, RowUp, ColUp
            
             'Tim 08
             CONTROL REDRAW hDlg, %ID_LISTVIEW
            
             'Ensure the new ListView item is visible
             LISTVIEW VISIBLE hDlg, %ID_LISTVIEW, RowUp
            END SUB

            Comment


            • #7
              Thank you Borje and Pierre
              Actually I w'd like single cell select rather than a full row, as it will give better display whenever the mouse is click
              over a particular cell.
              Let me check if this can be done

              Comment


              • #8
                Hi Borje

                when I ran the code, the headers only show a single character "C" instead of "Column 1" , etc
                and the cells displayed are one column less, is there a way to remedy this ?

                It is my bad, that I don't understand the structure of this Virtual Listview and still learning to digest it. Thank you

                Click image for larger version

Name:	Listview.png
Views:	1
Size:	4.2 KB
ID:	774986

                Comment


                • #9
                  Hm, I just grabbed your last example code and see same there. Try using ASCIIZ instead of WSTRINGZ in PBMAIN - it seems to help. First column is checkmark column, if you widen it you see text.
                  The code is a bit confusing - what exactly is it you want to achieve? Should first column be just for checkmark, or be wider and include text, etc?

                  Comment


                  • #10
                    In CommCtrl.inc LV_COLUMN converts to LVCOLUMNA, If you use LV_COLUMNW as TYPE for variable tlvc, then WSTRINGZ in PBMAIN should be okay (unless I missed another use of szbuf).

                    ((the other byte in wide "C" (in column header) looks like a terminating $nul in a UDT variable expecting an ASCIIZ))

                    Cheers,
                    Dale

                    Comment


                    • #11
                      Thanks Borje just need the column 1 as checkbox and have individual cell highlighted

                      Comment


                      • #12
                        There are samples on the forums (eg in post #3) which reserve the first column for check boxes, add no data to that column and resize it to just fit the checkbox.

                        This example doesn't do that - it uses the first column for Checkboxes and data. %LVS_EX_CHECKBOXES

                        In either case, to support checkboxes in a virtual listview, your app will have to store the checked / unchecked states as well as the item data external to the listview.

                        The virtual listview does have a built-in imagelist (of two icons) for checkboxes.
                        In this example, the index of the icon required for each row is stored in an array, ready for use when requested (by %LVN_GetDispInfo notification).

                        In PB10 DDT ListViews are Unicode controls so use of wide strings and defining %UNICODE=1 at the top of the source is required to avoid truncated Column Names or "Chinese" characters in the items text.
                        Code:
                        #Compiler PBWin 10
                        #Compile Exe
                        #Dim All
                        %Unicode=1
                        #Include "win32api.inc"
                        #RESOURCE MANIFEST, 1, "C:\PBWin10\samples\DDT\Address\XPTheme.xml"
                        
                        %IDC_ListView     = 500
                        %IDC_StatusBar    = 1011
                        
                        Global hDlg, hListView As Dword
                        Global CurrentRow, CurrentCol, OrigLVProc As Long
                        Global D() As String
                        Global CS() As Long
                        '------------------/   Or %LVS_Ex_FullRowSelect
                        
                        Function PBMain() As Long
                          Dialog New Pixels, 0, "ListView As Grid",300,300,400,240, %WS_OverlappedWindow To hDlg
                            Control Add ListView, hDlg, %IDC_ListView,"", 10,10,380,200, %LVS_OwnerData Or %LVS_Report Or %WS_TabStop _
                                                                          Or %LVS_ShowSelAlways Or %LVS_SingleSel, %WS_Ex_ClientEdge
                              Control Handle hDlg, %IDC_ListView To hListView
                              ListView Set StyleXX hDlg, %IDC_ListView, %LVS_Ex_GridLines Or %LVS_Ex_FullRowSelect Or %LVS_Ex_CheckBoxes  ' << want CheckBoxes
                            CONTROL ADD STATUSBAR, hDlg, %IDC_StatusBar, "   Cell ",0,0,0,0, %CCS_BOTTOM, %WS_EX_WINDOWEDGE
                              STATUSBAR SET PARTS hDlg, %IDC_StatusBar, 45,99999
                          Dialog Show Modal hDlg Call DlgProc
                        End Function
                        '------------------/PBMain
                        
                        CallBack Function DlgProc() As Long
                           Local i,j,iRow,iCol,iResult As Long
                           Local tmp$$
                        
                           Select Case Cb.Msg
                              Case %WM_InitDialog
                                 'initialize data/location
                                 Call CreateLVData                       ' Set Columns, Create D(), CS() - Data and Checkbox state arrays
                                 ListView_SetItemCountEx(hListView, (UBound(D,1)-LBound(D,1))+1, %LVSICF_noInvalidateAll) 'max rows in Virtual ListView
                                 CurrentRow = 1 : CurrentCol = 1
                         '         UpdateCaption
                                 OrigLVProc = SetWindowLong(hListView, %GWL_WndProc, CodePtr(NewLVProc))  ' subclass ListView to catch keystrokes
                        
                              Case %WM_Destroy
                                 SetWindowLong hListView, %GWL_WNDPROC, OrigLVProc                        ' cleanup
                        
                              Case %WM_Notify
                                 Select Case Cb.NmId
                                    Case %IDC_ListView
                                       Select Case Cb.NmCode
                                          Case %LVN_ItemChanged  'turn off row selection here?
                                             Local LpLvNm As NM_LISTVIEW Ptr
                                               LpLvNm = Cb.LParam
                         '                       ListView_SetItemState hListView, @LpLvNm.iItem, 0, %LVIS_Focused Or %LVIS_Selected
                        
                                          Case %NM_Click
                                             Local pNMIACT As NMITEMACTIVATE Ptr
                                               pNMIACT = Cb.LParam
                                               Local lRet As Long, lvhti As LVHITTESTINFO
                                                If (@pNMIACT.iItem >= 0) And (@pNMIACT.iSubItem = 0) Then   ' Click was on iItem
                                                  lvhti.pt.x = @pNMIACT.ptAction.x                          ' coord of click to Hit Test struct
                                                  lvhti.pt.y = @pNMIACT.ptAction.x
                                                    SendMessage(Cb.NmHwnd, %LVM_HitTest, 0, ByVal VarPtr(lvhti))            ' Get HitTest info
                                                    If (lvhti.flags And (%LVHT_ONITEMSTATEICON OR %LVHT_ONITEMICON)) = %LVHT_ONITEMSTATEICON Then ' hit on CheckBox?
                                                       ' Toggle checkbox icon index number  1 is UnChecked, 2 is Checked    ' set array value
                                                       CS(@pNMIACT.iItem+1) = IIf(CS(@pNMIACT.iItem+1) = &H01000, &H02000, &H01000)
                                                       ListView_Update(Cb.NmHwnd, @pNMIACT.iItem)    ' Update listview
                                                       Exit Function
                                                    Else
                         '                              WinBeep 300,200
                                                    End If
                                                End If
                                             CurrentRow = @pNMIACT.iiTem + 1
                                             CurrentCol = @pNMIACT.iSubItem + 1
                                             Control ReDraw hDlg, %IDC_ListView
                                             UpdateCaption
                        
                                          Case %NM_CustomDraw                     ' sets the selected cell colors
                                            Local lplvcd As NMLVCUSTOMDRAW Ptr
                                               lpLvCd = CbLParam
                                               Select Case @lplvcd.nmcd.dwDrawStage
                        
                                                Case %CDDS_PrePaint
                                                   Function = %CDRF_NOTIFYITEMDRAW : Exit Function
                        
                                                Case %CDDS_ItemPrePaint 'Or %CDDS_SUBITEM
                                                  '  check if checked row
                                                  If CS(@lplvcd.nmcd.dwItemSpec+1) = &h02000 Then  ' Checked
                                                      ' Color the background for checked rows only
                                                       @lplvcd.clrTextBk = %rgb_PaleTurquoise
                                                       @lplvcd.clrText = %Black
                                                   Else
                                                      @lplvcd.clrTextBk = %White
                                                      @lplvcd.clrText = %Black
                                                   End If
                                                    Function = %CDRF_DODEFAULT    ' Tell the list view to draw itself
                                                    Exit Function
                                               End Select
                        
                                          Case %LVN_GetDispInfo                   ' notification to ask for data
                                            Local pLVDI As NMLVDISPINFO Ptr
                                             pLVDI = Cb.LParam
                                             iRow = @pLVDI.item.iItem+1           ' row being asked for
                                             iCol = @pLVDI.item.iSubItem+1        ' subitem (column) being asked for
                                             tmp$$ = D(iRow,iCol)                 ' access D() array for
                                             @pLVDI.item.pszText = StrPtr(tmp$$)  ' text to be shown in ListView
                        
                                             If (@pLVDI.item.mask And %LVIF_IMAGE) Then         ' image member is required
                                                @pLVDI.item.mask =%LVIF_STATE Or %LVIF_TEXT     ' both state image and text to be updated
                                                @pLVDI.item.statemask =%LVIS_STATEIMAGEMASK     ' bits 12 to 15 give image index
                                                @pLVDI.item.state = CS(@pLVDI.item.iItem+1)     ' access CS() values for Checkbox image index
                                             End If
                        
                                       End Select
                                 End Select
                           End Select
                        End Function
                        '------------------/DlgProc
                        
                        Sub CreateLVData                      ' load up arrays with listview data and icon indexes
                           Local i,j As Long
                           ReDim D(1 To 50,1 To 10) : ReDim CS(1 To 50)
                           For i = 1 To UBound(D,2)
                              ListView Insert Column hDlg, %IDC_ListView, i, "    Col" + Trim$(Str$(i)), 100, 0
                           Next i
                           For i = 1 To UBound(D,1)
                              CS(i) = &H01000                 ' initial setting is for 'Unchecked' icon image index
                              For j = 1 To UBound(D,2)
                                 D(i,j) = "Row" + Trim$(Str$(i)) + " Col" + Trim$(Str$(j))   ' sample text
                              Next j
                           Next i
                        End Sub
                        '------------------/CreateLVData
                        
                        Sub UpdateCaption     ' / StatusBar
                         Local swTemp As wString
                           Dialog Set Text hDlg, Using$("ListView Grid Demo:  & &", Str$(CurrentRow), Str$(CurrentCol))
                           ListView Get Text hDlg, %IDC_ListView, CurrentRow, CurrentCol To swTemp
                           StatusBar Set Text hDlg, %IDC_StatusBar, 2, 0, Using$("Row # : Col #  = ' & '", CurrentRow, CurrentCol, swTemp)
                        End Sub
                        '------------------/UpdateCaption
                        
                        Function NewLVProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
                           Select Case Msg
                              Case %WM_KeyDown
                                 Select Case wParam
                                    Case %VK_Up
                                       CurrentRow = Max(1,CurrentRow-1)
                                       UpdateCaption
                                       Control ReDraw hDlg, %IDC_ListView
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                    Case %VK_Down
                                       CurrentRow = Min(UBound(D,1),CurrentRow+1)
                                       UpdateCaption
                                       Control ReDraw hDlg, %IDC_ListView
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                    Case %VK_Left
                                       CurrentCol = Max(1,CurrentCol-1)
                                       UpdateCaption
                                       Control ReDraw hDlg, %IDC_ListView
                                    Case %VK_Right
                                       CurrentCol = Min(UBound(D,2),CurrentCol+1)
                                       UpdateCaption
                                       Control ReDraw hDlg, %IDC_ListView
                                    Case %VK_Pgup
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                       Control ReDraw hDlg, %IDC_ListView
                                       UpdateCaption
                                    Case %VK_PgDn
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                       Control ReDraw hDlg, %IDC_ListView
                                       UpdateCaption
                                    Case %VK_Home
                                       CurrentCol = 1
                                       If GetKeyState(%VK_Control) And &H8000 Then CurrentRow = 1
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                       Control ReDraw hDlg, %IDC_ListView
                                       UpdateCaption
                                    Case %VK_End
                                       CurrentCol = UBound(D,2)
                                       If GetKeyState(%VK_Control) And &H8000 Then CurrentRow = UBound(D,2)
                                       ListView Visible hDlg, %IDC_ListView, CurrentRow
                                       Control ReDraw hDlg, %IDC_ListView
                                       UpdateCaption
                        
                                End Select
                           End Select
                           Function = CallWindowProc(OrigLVProc, hWnd, Msg, wParam, lParam)
                        End Function
                        '------------------/NewLVProc
                        Rgds, Dave

                        Comment


                        • #13
                          Hold on!

                          listview_insertcolumn uses LVCOLUMN. Can't find a wide version of listview_insertcolumn.

                          So back to STRINGZ (or ASCIIZ) in PBMain instead of WSTRINGZ.
                          Dale

                          Comment


                          • #14
                            BTW, why ownerdata style? Code would be so much cleaner using ordinary ListView with %LVS_Ex_CheckBoxes style and usually fast enough unless we are talking of many, many thousands of lnes of data
                            .

                            Comment


                            • #15
                              Many Thanks all of you, I w'd need to have virtual listview (ownerdata style) to accomodate say 100,000 rows and 7 columns of data

                              BTW, Dave in your code, how do I

                              1. Allow the highlight of the entire row if the check box is clicked ( currently is done)
                              2. To highlight only a single cell rather than an entire row when user click on that cell
                              ( currently the enire row is highlighted)

                              Comment


                              • #16
                                Hi Tim,

                                Looking through the sample code available on the forums (esp. Garry Beene, Pedro Ramirez, Pierre, Borje et al) it looks like highlighting individual rows and single selected cells can be achieved in the %NM_CustomDraw part of the Dialog Callback function.

                                Try this replacement code for %NM_CustomDraw and %LVN_ItemChanged in the sample code from post #12
                                Code:
                                                  Case %LVN_ItemChanged  'turn off row selection here?
                                                     Local LpLvNm As NM_LISTVIEW Ptr
                                                       LpLvNm = Cb.LParam
                                                       ListView_SetItemState hListView, @LpLvNm.iItem, 0, %LVIS_Focused Or %LVIS_Selected
                                
                                                  Case %NM_CustomDraw                         ' (list view) notification to parent re drawing operations
                                                    Local lplvcd As NMLVCUSTOMDRAW Ptr        ' Structure contains info re identifier of item being drawn etc
                                                      lpLvCd = Cb.LParam
                                
                                                      Select Case @lplvcd.nmcd.dwDrawStage
                                                        Case %CDDS_PREPAINT
                                                          Function = %CDRF_NOTIFYITEMDRAW     ' notify any item-related drawing
                                
                                                        Case %CDDS_ITEMPREPAINT
                                                          Function = %CDRF_NOTIFYSUBITEMDRAW  ' notify for each subitem-related drawing
                                
                                                        Case %CDDS_ITEMPREPAINT Or %CDDS_SUBITEM
                                                          If @lplvcd.nmcd.dwItemSpec = CurrentRow-1 And @lpLvCd.iSubItem = CurrentCol-1 Then
                                                           ' highlight the selected cell
                                                            @lpLvCd.clrTextBk = GetSysColor(%COLOR_HIGHLIGHT)
                                                            @lpLvCd.clrText   = GetSysColor(%COLOR_HIGHLIGHTTEXT)
                                                          Else
                                                            If CS(@lplvcd.nmcd.dwItemSpec+1) = &h02000 Then  ' Checked
                                                             ' Color the background for checked rows only
                                                              @lplvcd.clrTextBk = %rgb_PaleTurquoise
                                                              @lplvcd.clrText   = %Black
                                                            Else
                                                              @lpLvCd.clrTextBk = GetSysColor(%COLOR_WINDOW)
                                                              @lpLvCd.clrText   = GetSysColor(%COLOR_WINDOWTEXT)
                                                            End If
                                                          End If
                                                          Function = %CDRF_DODEFAULT          ' control draws itself
                                
                                                        End Select
                                Rgds, Dave

                                Comment


                                • #17
                                  Excellent work, Dave this is exactly what I needed

                                  Thanks for the comments Dave, I appreciate it.

                                  Comment


                                  • #18
                                    Hey Börje, I liked the idea of LVIS_STATEIMAGEMASK, it is more elegant than drawing the checkbox. So I borrowed it! ;-)


                                    Click image for larger version

Name:	ListView02.png
Views:	1
Size:	21.9 KB
ID:	775029

                                    Code:
                                    'Sortable OwnerData ListView with CheckBox and individual cell selection.
                                    'Dialog is sizable
                                    'Each cell will be selected indivually
                                    'Each column is sortable up and down based on index, alpha order, and numeric order. A sort arrow will be shown in the ListView header.
                                    'Key Control-PageUp / Control-Page-Down / PageUp / PageDown / Up / Down / Left / Right / Home / End now work as expected.
                                    'It's a quick demo, there is a lot of details I did not double check but I think the idea is there.
                                    
                                    #COMPILE EXE
                                    #DIM ALL
                                    %Unicode = 1
                                    #INCLUDE "Win32Api.inc"
                                    #INCLUDE "CommCtrl.inc"
                                    #RESOURCE MANIFEST, 1, "XPTheme.xml" 'Need a manifest for CommonControl_6 for sort arrow to be visible.
                                    '#RESOURCE "SomeManifest.pbr"        'Need a manifest for CommonControl_6 for sort arrow to be visible.
                                    
                                    $AppName   = "ListView Virtual OwnerData with checkbox"
                                    %ListView  = 101
                                    %StatusBar = 201
                                    
                                    %RowCount  = 10 'Set as desired
                                    %ColCount  = 06 'Set as desired
                                    
                                    TYPE ListViewInfoType
                                      index    AS LONG  'Sorting index
                                      Checked  AS LONG  'Row check state
                                      'lParam  AS LONG  'Reference, lParam is no available with LVS_OWNERDATA.
                                    END TYPE
                                    
                                    GLOBAL hDlg           AS DWORD
                                    GLOBAL RowSelected    AS LONG
                                    GLOBAL ColSelected    AS LONG
                                    GLOBAL SortDirection  AS LONG
                                    GLOBAL SortColumn     AS LONG
                                    GLOBAL ListviewData() AS STRING 'Multi dimension string sata array for row and column.
                                    GLOBAL ListViewInfo() AS ListViewInfoType 'To sort fast on index and keep CheckBox state.
                                    '______________________________________________________________________________
                                    
                                    SUB UpdateStatusBar
                                    
                                     STATUSBAR SET TEXT hDlg, %StatusBar, 1, 0, "Cell: " & FORMAT$(RowSelected) & " : " & FORMAT$(ColSelected)
                                    
                                    END SUB
                                    '______________________________________________________________________________
                                    
                                    FUNCTION ListviewProc(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, _ 'ListView SubClass proc
                                                          BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                                     STATIC pListviewProc AS DWORD 'No global needed
                                    
                                     SELECT CASE Msg
                                    
                                       CASE %WM_NULL
                                         IF hWnd = 0 THEN pListviewProc = wParam : EXIT FUNCTION 'hWnd is never 0 except in this specific case
                                    
                                       CASE %WM_KEYDOWN
                                         SELECT CASE wParam
                                    
                                           CASE %VK_UP
                                             RowSelected = MAX(0, RowSelected - 1)
                                    
                                           CASE %VK_DOWN
                                             RowSelected = MIN(%RowCount - 1, RowSelected + 1)
                                    
                                           CASE %VK_LEFT
                                             ColSelected = MAX(0, ColSelected - 1)
                                    
                                           CASE %VK_RIGHT
                                             ColSelected = MIN(%ColCount - 1, ColSelected + 1)
                                    
                                           CASE %VK_PGUP
                                             RowSelected = MAX(0, RowSelected - SendMessage(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0))
                                    
                                           CASE %VK_PGDN
                                             RowSelected = MIN(%RowCount - 1, RowSelected + SendMessage(hWnd, %LVM_GETCOUNTPERPAGE, 0, 0))
                                    
                                           CASE %VK_HOME
                                              IF (GetKeyState(%VK_CONTROL) AND &H8000) THEN 'Control key is down
                                               RowSelected = 0
                                             ELSE 'Control key is up
                                               ColSelected = 0
                                             END IF
                                    
                                           CASE %VK_END
                                              IF (GetKeyState(%VK_CONTROL) AND &H8000) THEN 'Control key is down
                                               RowSelected = %RowCount - 1
                                             ELSE 'Control key is up
                                               ColSelected = %ColCount - 1
                                             END IF
                                    
                                         END SELECT
                                         PostMessage(hWnd, %LVM_ENSUREVISIBLE, RowSelected, %FALSE)
                                         UpdateStatusBar
                                         InvalidateRect(hWnd, BYVAL %NULL, 0) : UpdateWindow(hWnd)
                                    
                                       CASE %WM_DESTROY
                                    
                                       CASE %WM_NCDESTROY
                                         SetWindowLong(hWnd, %GWL_WNDPROC, pListviewProc) 'Unsubclass listview
                                    
                                     END SELECT
                                     FUNCTION = CallWindowProc(pListviewProc, hWnd, Msg, wParam, lParam)
                                    
                                    END FUNCTION
                                    '______________________________________________________________________________
                                    
                                    FUNCTION ListViewSort(Param1 AS ListViewInfoType, Param2 AS ListViewInfoType) AS LONG 'Sorting column
                                    
                                     SELECT CASE SortColumn
                                    
                                       CASE 0 'Sort via index
                                         IF Param1.index > Param2.index THEN
                                           FUNCTION = -1 * SortDirection
                                         ELSEIF Param1.index < Param2.index THEN
                                           FUNCTION = 1 * SortDirection
                                         END IF
                                    
                                       CASE 3 'Numeric sort
                                         FUNCTION = SortDirection * _
                                                    (2 - CompareString(%LOCALE_USER_DEFAULT, %SORT_DIGITSASNUMBERS, _
                                                                       BYVAL STRPTR(ListviewData(Param1.index, SortColumn)), LEN(ListviewData(Param1.index, SortColumn)),_
                                                                       BYVAL STRPTR(ListviewData(Param2.index, SortColumn)), LEN(ListviewData(Param2.index, SortColumn))))
                                       CASE ELSE 'Alpha sort
                                         FUNCTION = SortDirection * _
                                                    (2 - CompareString(%LOCALE_USER_DEFAULT, %SORT_STRINGSORT OR %NORM_IGNORECASE, _
                                                                       BYVAL STRPTR(ListviewData(Param1.index, SortColumn)), LEN(ListviewData(Param1.index, SortColumn)),_
                                                                       BYVAL STRPTR(ListviewData(Param2.index, SortColumn)), LEN(ListviewData(Param2.index, SortColumn))))
                                    
                                         'CSTR_LESS_THAN = 1 (str 1 is less than 2), CSTR_EQUAL = 2 (equal str), CSTR_GREATER_THAN = 3 (str 2 less than 1)
                                    
                                     END SELECT
                                    
                                    END FUNCTION
                                    '______________________________________________________________________________
                                    
                                    CALLBACK FUNCTION DlgProc() AS LONG
                                     LOCAL  pListviewCustomDraw AS NMLVCUSTOMDRAW POINTER
                                     LOCAL  pItemActivate       AS NMITEMACTIVATE POINTER
                                     LOCAL  pListviewDispInfo   AS LV_DISPINFO POINTER
                                     LOCAL  pListviewMsg        AS NM_LISTVIEW POINTER
                                     LOCAL  ListViewHitTest     AS LVHITTESTINFO
                                     LOCAL  ListViewColum       AS LV_COLUMN
                                     LOCAL  HeaderItem          AS HDITEM
                                     LOCAL  ListviewItem        AS LVITEM
                                     LOCAL  sText               AS STRING
                                     STATIC hListView           AS DWORD
                                     STATIC hListviewHeader     AS DWORD
                                     STATIC SortedColumn        AS LONG '%HDF_SORTDOWN = &H00000200 Version 6.00. Draws a down-arrow
                                     STATIC SortArrowUpDown     AS LONG '%HDF_SORTUP   = &H00000400 Version 6.00. Draws an up-arrow
                                     LOCAL  ClientSizeX         AS LONG
                                     LOCAL  ClientSizeY         AS LONG
                                     LOCAL  ROW                 AS LONG
                                     LOCAL  COL                 AS LONG
                                    
                                     SELECT CASE CBMSG
                                    
                                       CASE %WM_INITDIALOG
                                         hListView       = GetDlgItem(hDlg, %ListView)
                                         hListviewHeader = SendMessage(hListview, %LVM_GETHEADER, 0, BYVAL 0)
                                         SendMessage(hListView, %LVM_SETITEMCOUNT, %RowCount, %LVSICF_NOINVALIDATEALL OR %LVSICF_NOSCROLL) 'Tell the ListView how much row we got
                                         SortDirection = 0 - 1 'Column sort up or down
                                         FOR ROW = 0 TO %RowCount - 1 'Create an ordered index for sorting
                                           ListViewInfo(ROW).index = ROW
                                         NEXT
                                    
                                         'Initialize Column
                                         FOR COL = 0 TO %ColCount - 1
                                           SELECT CASE COL
                                             CASE 0
                                               sText              = UCODE$("Index sort 0")
                                               ListViewColum.mask = %LVCF_TEXT OR %LVCF_WIDTH
                                               ListViewColum.fmt  = %LVCFMT_LEFT
                                               ListViewColum.cx   = 105
                                             CASE 1
                                               sText              = UCODE$("Alpha sort " & FORMAT$(COL))
                                               ListViewColum.mask = %LVCF_TEXT OR %LVCF_FMT OR %LVCF_SUBITEM OR %LVCF_WIDTH
                                               ListViewColum.fmt  = %LVCFMT_CENTER
                                               ListViewColum.cx   = 90
                                             CASE 2
                                               sText              = UCODE$("Alpha sort " & FORMAT$(COL))
                                               ListViewColum.cx   = 75
                                             CASE 3
                                               sText              = UCODE$("Numeric sort 3")
                                               ListViewColum.cx   = 85
                                             CASE 4
                                               sText              = UCODE$("Alpha sort " + FORMAT$(COL))
                                               ListViewColum.cx   = 75
                                             CASE ELSE
                                               sText              = UCODE$("Alpha sort " + FORMAT$(COL))
                                               ListViewColum.cx   = 90
                                            END SELECT
                                           ListViewColum.iorder = COL
                                           ListViewColum.psztext = STRPTR(sText)
                                           SendMessage(hListView, %LVM_INSERTCOLUMN, COL, VARPTR(ListViewColum))
                                         NEXT
                                    
                                         'Initialize row and column string data
                                         FOR ROW = 0 TO %RowCount - 1
                                           FOR COL = 0 TO %ColCount - 1
                                             SELECT CASE COL
                                               CASE 2    : ListviewData(ROW, COL) = UCODE$(CHR$(RND(65, 90)))
                                               CASE 3    : ListviewData(ROW, COL) = UCODE$(FORMAT$(RND(0, 29), "0"))
                                               CASE 4    : ListviewData(ROW, COL) = UCODE$(FORMAT$(RND(0, 29), "0"))
                                               CASE ELSE : ListviewData(ROW, COL) = UCODE$("Row " + FORMAT$(ROW, "00") + " Col " + FORMAT$(COL, "00"))
                                             END SELECT
                                           NEXT
                                         NEXT
                                    
                                         'Preset
                                         RowSelected = 5
                                         ColSelected = 0
                                         ListViewInfo(RowSelected).Checked = 1
                                    
                                         UpdateStatusBar 'Zero based
                                    
                                         ListviewProc(0, %WM_NULL, SetWindowLong(hListView, %GWL_WNDPROC, CODEPTR(ListviewProc)), 0) 'Subclass listview in one line, no global
                                    
                                       CASE %WM_NOTIFY
                                         SELECT CASE CBNMID
                                           CASE %ListView
                                             SELECT CASE CBNMCODE
                                    
                                               CASE %NM_CLICK
                                                 pItemActivate = CBLPARAM 'MHDR: hwndFrom; idFrom; code;
                                                 RowSelected   = ListViewInfo(@pItemActivate.iiTem).index
                                                 ColSelected   = @pItemActivate.iSubItem
                                    
                                                 IF ColSelected = 0 THEN 'See if click was on CheckBox
                                                   ListViewHitTest.pt = @pItemActivate.ptAction
                                                   SendMessage(hListView, %LVM_HITTEST, 0, VARPTR(ListViewHitTest))
                                                   IF (ListViewHitTest.flags AND %LVHT_ONITEMSTATEICON) THEN
                                                     ListViewInfo(@pItemActivate.iItem).Checked XOR= 1 'Flip checkbox state
                                                   END IF
                                                 END IF
                                                 UpdateStatusBar
                                                 InvalidateRect(hListView, BYVAL %NULL, 0) : UpdateWindow(hListView)
                                    
                                               CASE %NM_CUSTOMDRAW 'Sets the selected cell colors
                                                 pListviewCustomDraw = CBLPARAM 'NMLVCUSTOMDRAW
                                                 SELECT CASE @pListviewCustomDraw.nmcd.dwDrawStage
                                    
                                                   CASE %CDDS_PREPAINT, %CDDS_ITEMPREPAINT
                                                     FUNCTION = %CDRF_NOTIFYSUBITEMDRAW
                                    
                                                   CASE %CDDS_ITEMPREPAINT OR %CDDS_SUBITEM
                                    
                                                     'Set selected and non-selected color
                                                     IF (ListViewInfo(@pListviewCustomDraw.nmcd.dwItemSpec).index = RowSelected) AND _ '
                                                        (@pListviewCustomDraw.iSubItem = ColSelected) THEN 'If it is the selected cell
                                                       @pListviewCustomDraw.clrTextBk = GetSysColor(%COLOR_HIGHLIGHT)
                                                       @pListviewCustomDraw.clrText   = GetSysColor(%COLOR_HIGHLIGHTTEXT)
                                                     ELSE 'It is not the selected cell
                                                       @pListviewCustomDraw.clrTextBk = GetSysColor(%COLOR_WINDOW)
                                                       @pListviewCustomDraw.clrText   = GetSysColor(%COLOR_WINDOWTEXT)
                                                     END IF
                                                     FUNCTION = %CDRF_NEWFONT
                                    
                                                 END SELECT
                                    
                                               CASE %LVN_GETDISPINFO
                                    
                                                 'Give a text pointer to ListView
                                                 pListviewDispInfo = CBLPARAM                         'LV_DISPINFO pointer
                                                 ROW               = @pListviewDispInfo.item.iItem    'Row
                                                 COL               = @pListviewDispInfo.item.iSubItem 'Column
                                                 @pListviewDispInfo.item.pszText = STRPTR(ListviewData(ListViewInfo(ROW).index, COL)) 'Text sent to ListView
                                    
                                                 'Set checkbox state, thank you Börje, The Master ;-)
                                                 IF COL = 0 THEN 'Set checkbox
                                                   IF (@pListviewDispInfo.item.mask AND %LVIF_IMAGE) THEN
                                                     @pListviewDispInfo.item.mask      = %LVIF_STATE OR %LVIF_TEXT
                                                     @pListviewDispInfo.item.statemask = %LVIS_STATEIMAGEMASK
                                                   END IF
                                                   IF (@pListviewDispInfo.item.mask AND %LVIF_STATE) THEN
                                                     IF ListViewInfo(ROW).Checked THEN
                                                       @pListviewDispInfo.item.state = INDEXTOSTATEIMAGEMASK(2)
                                                     ELSE
                                                       @pListviewDispInfo.item.state = INDEXTOSTATEIMAGEMASK(1)
                                                     END IF
                                                   END IF
                                                 END IF
                                    
                                               CASE %LVN_ITEMCHANGED 'Reset row selection
                                                 pListviewMsg           = CBLPARAM
                                                 ListviewItem.iItem     = @pListviewMsg.iItem
                                                 ListviewItem.mask      = %LVIF_STATE 'Which state bits to change
                                                 ListviewItem.stateMask = %LVIS_SELECTED OR %LVIS_FOCUSED 'Highlight
                                                 ListviewItem.state     = 0 'New value of field pointed by .mask
                                                 SendMessage(hListView, %LVM_SETITEMSTATE, ListviewItem.iItem, VARPTR(ListviewItem)) 'Reset full row select
                                    
                                               CASE %LVN_COLUMNCLICK 'Sort on column header click
                                                 pListviewMsg = CBLPARAM
                                                 IF @pListviewMsg.iSubItem > -1 THEN 'Not on column if -1
                                                   SortColumn = @pListviewMsg.iSubItem
                                    
                                                   'Section to draw the sort arrow in the listview header
                                                   HeaderItem.mask = %HDI_FORMAT 'Ask for sort arrow
                                                   SendMessage(hListviewHeader, %HDM_GETITEM, SortedColumn, VARPTR(HeaderItem)) 'Gets previous header HDI_FORMAT info
                                                   HeaderItem.fmt = HeaderItem.fmt AND &HFFFFF9FF 'Remove HDF_SORTDOWN (0x200) / HDF_SORTUP 0x400) arrow
                                                   SendMessage(hListviewHeader, %HDM_SETITEM, SortedColumn, VARPTR(HeaderItem)) 'Update previous header with no arrow
                                                   SendMessage(hListviewHeader, %HDM_GETITEM, SortColumn, VARPTR(HeaderItem))   'Gets current column header HDI_FORMAT info
                                                   IF SortedColumn <> SortColumn THEN 'Clicked on a new column
                                                     SortArrowUpDown = %HDF_SORTUP 'Click on new column so sort ascend
                                                     SortDirection = -1
                                                   ELSE
                                                     IF SortDirection > 0 THEN
                                                       SortArrowUpDown = %HDF_SORTDOWN
                                                     ELSE
                                                       SortArrowUpDown = %HDF_SORTUP
                                                     END IF
                                                   END IF
                                                   SortedColumn   = SortColumn 'Set SortedColumn to current column that will become previous column for next sort
                                                   HeaderItem.fmt = (HeaderItem.fmt OR SortArrowUpDown) 'Set format to HDF_SORTDOWN (0x200) / HDF_SORTUP 0x400)
                                                   SendMessage(hListviewHeader, %HDM_SETITEM, SortedColumn, VARPTR(HeaderItem)) 'Update current column header arrow
                                    
                                                   'Sort the index
                                                   ARRAY SORT ListViewInfo(), CALL ListViewSort()
                                    
                                                   SortDirection = 0 - SortDirection 'Toggle SortDirection
                                                   InvalidateRect(hListView, BYVAL %NULL, 0) : UpdateWindow(hListView) 'Refresh the listview
                                    
                                                 END IF
                                    
                                               CASE %LVN_ODCACHEHINT 'lParam is a pointer to an NMLVCACHEHINT structure containing information about the range of items to be cached.
                                               'Handling this message allows the application to update the item information held in cache so
                                               'that it is readily available when an LVN_GETDISPINFO notification code is sent.
                                               'According to MSDN, you should override OnChildNotify and add the handler in this function.
                                    
                                               CASE %LVN_ODFINDITEM 'Param is a pointer to an NMLVFINDITEM structure that includes information to be used for the search.
                                               'Sent by a virtual list-view control when it needs the owner to find a particular callback item.
                                               'For example, the control will send this notification code when it receives shortcut keyboard input or
                                               'when it receives an LVM_FINDITEM message.
                                    
                                            END SELECT
                                          END SELECT
                                    
                                       CASE %WM_SIZE 'Dialog size have changed
                                         'CBWPARAM = Resizing requested: SIZE_MAXHIDE SIZE_MAXIMIZED SIZE_MAXSHOW SIZE_MINIMIZED SIZE_RESTORED
                                         'LO(WORD, CBLPARAM) is client area width  in pixels.
                                         'HI(WORD, CBLPARAM) is client area height in pixels.
                                         IF CBWPARAM <> %SIZE_MINIMIZED THEN
                                           ClientSizeX = LO(WORD, CBLPARAM)
                                           ClientSizeY = HI(WORD, CBLPARAM)
                                    
                                           LOCAL StatusRec AS RECT
                                           GetWindowRect(GetDlgItem(CBHNDL, %StatusBar), StatusRec)
                                           MoveWindow(hListview, 2, 2, ClientSizeX - 4, ClientSizeY - 4 - (StatusRec.nBottom - StatusRec.nTop), %TRUE)
                                         END IF
                                    
                                     END SELECT
                                    
                                    END FUNCTION
                                    '______________________________________________________________________________
                                    
                                    FUNCTION PBMAIN() AS LONG
                                     LOCAL hIcon AS DWORD
                                    
                                     DIM ListViewInfo(0 TO %RowCount - 1) AS GLOBAL ListViewInfoType
                                     DIM ListviewData(0 TO %RowCount - 1, 0 TO %ColCount - 1) AS GLOBAL STRING
                                    
                                     DIALOG NEW PIXELS, %HWND_DESKTOP, $AppName, , , 540, 235, %WS_OVERLAPPEDWINDOW TO hDlg
                                     hIcon = ExtractIcon(GetModuleHandle(""), "%SystemRoot%\system32\Shell32.dll", 144)
                                     SetClassLong(hDlg, %GCL_HICON, hIcon)
                                    
                                     CONTROL ADD LISTVIEW, hDlg, %ListView, "", 10, 10, 380, 180, _
                                     %LVS_OWNERDATA OR %LVS_REPORT OR %WS_TABSTOP OR %LVS_SHOWSELALWAYS OR %LVS_SINGLESEL, %WS_EX_CLIENTEDGE
                                     LISTVIEW SET STYLEXX hDlg, %ListView, %LVS_EX_GRIDLINES OR %LVS_EX_FULLROWSELECT OR %LVS_EX_CHECKBOXES
                                    
                                     CONTROL ADD STATUSBAR, hDlg, %StatusBar, "", 0, 0, 0, 0, %SBS_SIZEGRIP
                                     STATUSBAR SET PARTS hDlg, %StatusBar, 100, -1
                                    
                                     DIALOG SHOW MODAL hDlg CALL DlgProc
                                     DestroyIcon(hIcon)
                                    
                                    END FUNCTION
                                    '______________________________________________________________________________
                                    '

                                    Comment


                                    • #19
                                      Brilliant Pierre!

                                      Comment

                                      Working...
                                      X