Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Column List Demo

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

  • Column List Demo

    Since there haven't been many class/object demos, I thought I would submit one that might be useful. It is simply a listbox with some headers at the top which can be clicked for sorting, similar to listview controls. The only reason to create it in a class is to keep the data encapsulated. Everything above FUNCTION PBMAIN() could be kept in an include file if desired.

    Code:
    #DIM ALL
    #INCLUDE "win32api.inc"
    '#INCLUDE "debug.inc"
    %ID_List   = 100 'headers use 101, 102, ...
    %ID_Status = 201
    GLOBAL colList AS IColumnList
    
    CLASS CColumnList
       INSTANCE hDlg, listID AS LONG       'handle of listbox parent, ID of listbox
       INSTANCE x, y, xx, yy AS LONG       'location & size of listbox
       INSTANCE numColumns AS LONG         'number of columns in listbox
       INSTANCE numItems AS LONG           'number of items in listbox
       INSTANCE hiLite AS LONG             'high lighted item in listbox 
       INSTANCE ti() AS STRING             'column header titles
       INSTANCE wi() AS LONG               'column header widths (neg for right alligned)
       INSTANCE colType() AS LONG          '1,2,3 for str, val, date column type (neg for right-adjust) 
       INSTANCE items() AS STRING          'row strings with TAB separated columns
       INSTANCE recNo() AS LONG            'record number as originally added
    
       CLASS METHOD showList
          LOCAL i, k AS LONG, s AS STRING 
          LISTBOX RESET hDlg, listID
          FOR i = 1 TO numItems
             s = items(recNo(i))
             IF recNo(i) = hiLite THEN hiLite = i
             REPLACE "," WITH $TAB IN s
             LISTBOX ADD hDlg, listID, s
          NEXT i 
          IF hiLite = 0 THEN hiLite = 1
          CONTROL SEND hDlg, %ID_LIST, %LB_SETCURSEL, hiLite - 1, 0
          showStatus 1: showStatus 2
          CONTROL SET FOCUS hDlg, %ID_LIST
       END METHOD
          
       INTERFACE IColumnList
          INHERIT IUNKNOWN
    
          PROPERTY GET getHandle() AS LONG 
             PROPERTY = hDlg 
          END PROPERTY
    
          PROPERTY GET getNumShown() AS LONG 
             PROPERTY = numItems 
          END PROPERTY
          
          PROPERTY GET getHiLite() AS LONG 
             PROPERTY = hiLite 
          END PROPERTY
          
          PROPERTY SET setHiLite(BYVAL n AS LONG)
             hiLite = n
          END PROPERTY
          
          METHOD getRecordNo(BYVAL i AS LONG) AS LONG
             IF UBOUND(recNo()) >= i THEN
                METHOD = recNo(i)
             END IF
          END METHOD
          
          METHOD createList(hParent AS LONG, ID_List AS LONG, _
                            a AS LONG, b AS LONG, w AS LONG, h AS LONG, _
                            pwi AS DWORD, pti AS DWORD, numCols AS LONG)
             'hParent, ID_List = handle of containing dialog, control id
             'a, b, w, h       = location and size of control including listbox headers (pixels/units from parent)
             'pwi              = pointer to wi(), width of columns (neg value for right adjusted)
             'pti              = pointer to ti(), title of columns (leading chr$(1) for value, chr$(2) for date)
             'numCols          = number of columns
             '-----------------------------------------------------------------------------------------------------     
             LOCAL nStyle, i, j, k, n, hdc, ws, ht, rx, ry, u, nPixels AS LONG
             LOCAL cSize AS SIZEL, r AS RECT, txt AS ASCIIZ*16, s AS STRING
             DIM wi(1 TO numCols) AT pwi
             DIM ti(1 TO numCols) AT pti
             DIM tabstops(numCols - 1) AS LONG
             DIM colType(1 TO numCols) AS INSTANCE LONG
             'determine pixels or dialog units------------------------- 
             hDlg = hParent: listID = ID_list 
             DIALOG GET SIZE hDlg TO rx, ry  
             GetWindowRect  hDlg, r
             IF rx = (r.nRight - r.nLeft) THEN nPixels = 1
             'determine header height and scroll width ----------------
             txt = "0": hdc = GetDC(hDlg)
             GetTextExtentPoint32 hdc, BYVAL VARPTR(txt), LEN(txt), cSize
             ht = 1.2 * cSize.cy: u = cSize.cx
             ws = GetSystemMetrics(%SM_CXVSCROLL)
             IF nPixels = 0 THEN DIALOG PIXELS hDlg, ws, ht TO UNITS ws, ht
             ReleaseDC hDlg, hdc
             'define column types -------------------------------------
             FOR i = 1 TO numCols 
                colType(i) = ASC(LEFT$(ti(i), 1)) + 1 
                IF colType(i) <= 3 THEN ti(i) = MID$(ti(i), 2) ELSE colType(i) = 1
                colType(i) = SGN(wi(i)) * coltype(i): wi(i) = ABS(wi(i)) 
             NEXT i
             'fit last column width -----------------------------------
             j = 0: FOR i = 1 TO numCols - 1: j = j + wi(i): NEXT i
             wi(numCols) = w - j - ws
             'create the listbox --------------------------------------
             x = a: y = b: xx = w: yy = h: numColumns = numCols
             nStyle = %WS_VSCROLL OR %LBS_DISABLENOSCROLL OR %LBS_USETABSTOPS OR %WS_TABSTOP
             CONTROL ADD LISTBOX, hDlg, listID, , x, y+ht, xx, yy-ht, nStyle, %WS_EX_CLIENTEDGE, CALL ListCB
             'define tabstops for listbox -----------------------------
             tabstops(0) = 2
             FOR i = 1 TO numColumns - 1: tabstops(i) = tabstops(i - 1) + wi(i): NEXT i
             tabstops(numColumns - 1) = tabstops(numColumns - 1) - 2
             FOR i = 0 TO numColumns - 1
                IF colType(i + 1) < 0 THEN 'right alligned tabstop
                   tabstops(i) = SGN(colType(i + 1)) * (tabstops(i) + wi(i + 1) - 6)
                END IF
             NEXT i
             IF nPixels THEN 'convert pixels to dialog units for tabstops
                DIALOG PIXELS hDlg, 1000, 0 TO UNITS rx, ry
                FOR i = 0 TO numColumns - 1: tabstops(i) = rx/1000 * tabstops(i): NEXT i
             END IF
             CONTROL SEND hDlg, listID, %LB_SETTABSTOPS, numColumns, VARPTR(tabstops(0))
             'create listbox headers ----------------------------------
             n = %SS_NOTIFY
             j = x
             FOR i = 1 TO numColumns
                IF i > 1 THEN j = j + wi(i - 1)
                IF colType(i) < 0 THEN 
                   s = ti(i) + "  ": nStyle = %SS_RIGHT + n 
                ELSE 
                   s = "  " + ti(i): nStyle = %SS_LEFT + n
                END IF
                CONTROL ADD LABEL, hDlg, listID+i, s, j, y, wi(i), ht, nStyle, %WS_EX_STATICEDGE, CALL ListCB
             NEXT i
          END METHOD
          
          METHOD addItem(itemStr AS STRING, nShow AS LONG)
             'add itemStr to items() and list if nShow > 0
             INCR numItems
             REDIM PRESERVE items(1 TO numItems)
             REDIM PRESERVE recNo(1 TO numItems)
             items(numItems) = itemStr
             recNo(numItems) = numItems
             IF nShow THEN colList.showList
          END METHOD
    
          METHOD convertDate(s AS STRING) AS LONG
             'convert "10/13/1934" to 19341013 
             LOCAL mo AS WORD, day AS WORD, yr AS WORD
             mo = VAL(LEFT$(s, 2))
             day = VAL(MID$(s, 4, 2))
             yr = VAL(RIGHT$(s, 4)) - 1980
             ROTATE RIGHT yr, 7
             ROTATE LEFT mo, 5
             METHOD = yr + mo + day
          END METHOD
          
          METHOD columnSort(nCol AS LONG)
             'this routine toggles the column sort when the column header is clicked.
             'colType() holds the type of column: string=1, value=2, or date=3 
             'the key to this routine is simply to determine the tagged recNo()
             '------------------------------------------------------------------------
             LOCAL i, n, nSort AS LONG, s AS STRING
             DIM sArray(1 TO numItems) AS STRING
             DIM nArray(1 TO numItems) AS LONG
             hiLite = recNo(hiLite)
             n = ABS(colType(nCol)) 'neg colType signals right adjusted
             FOR i = 1 TO numItems 'fill the appropriate array with the specified column
                s = PARSE$(items(recNo(i)), nCol)
                IF n = 2 THEN 'value, use numeric array
                   nArray(i) = VAL(s)
                ELSEIF n = 3 THEN 'date, use numeric array
                   nArray(i) = colList.convertDate(s)
                ELSE 'use string array
                   sArray(i) = s
                END IF   
             NEXT i
             nSort = -1
             IF sArray(numItems) > sArray(1) OR nArray(numItems) > nArray(1) THEN nSort = 1
             IF nSort < 0 THEN 'sort as ascending
                IF n = 1 THEN 'use string array
                   ARRAY SORT sArray(), COLLATE UCASE, TAGARRAY recNo(), ASCEND
                ELSE 'use numeric array
                   ARRAY SORT nArray(), TAGARRAY recNo(), ASCEND
                END IF 
             ELSE 'sort as descending
                IF n = 1 THEN 'use string array
                   ARRAY SORT sArray(), COLLATE UCASE, TAGARRAY recNo(), DESCEND
                ELSE 'use numeric array
                   ARRAY SORT nArray(), TAGARRAY recNo(), DESCEND
                END IF
             END IF
             ME.showList
          END METHOD
          
       END INTERFACE   
    END CLASS
    
    CALLBACK FUNCTION listCB()
       LOCAL top, k, n AS LONG
       SELECT CASE CB.MSG
       CASE %WM_COMMAND
          IF CB.CTL = %ID_List AND CB.CTLMSG = %LBN_SELCHANGE THEN
             CONTROL SEND CB.HNDL, %ID_List, %LB_GETTOPINDEX, 0, 0 TO k
             CONTROL SEND CB.HNDL, %ID_LIST, %LB_GETCURSEL, 0, 0 TO n 
             top = k + 1: colList.setHiLite() = n + 1
          ELSEIF CB.CTL > %ID_List AND CB.CTLMSG = %STN_CLICKED THEN
             colList.columnSort(CB.CTL - %ID_List)
          END IF
       END SELECT
    END FUNCTION
    
    FUNCTION PBMAIN()
       LOCAL hMain, nStyle, n, x, y AS LONG
       LOCAL title AS STRING
       LOCAL wi() AS LONG, ti() AS STRING
       LET colList = CLASS "CColumnList"
       n = 5
       DIM wi(1 TO n), ti(1 TO n)
       wi(1) = 50: wi(2) = 50: wi(3) = 70: wi(4) = 70: wi(5) = -60  'units
    '   wi(1) = 70: wi(2) = 70: wi(3) = 100: wi(4) = 100: wi(5) = -90  'pixels
       ti(1) = CHR$(2) + "Date": ti(2) = "Type": ti(3) = "Descr": ti(4) = "Name": ti(5) = CHR$(1) + "Amount" 
       title = "Column List Demo"
       nStyle = %WS_SYSMENU OR %WS_MINIMIZEBOX
       DIALOG NEW 0, title$,,, 320, 350, nStyle TO hMain
    '   DIALOG NEW PIXELS, 0, title$,,, 450, 350, nStyle TO hMain 
       colList.createList(hMain, %ID_List, 10, 20, 300, 300, VARPTR(wi(1)), VARPTR(ti(1)), 5)
    '   colList.createList(hMain, %ID_List, 10, 20, 430, 300, VARPTR(wi(1)), VARPTR(ti(1)), 5)
       DIALOG GET SIZE hMain TO x, y 
       CONTROL ADD STATUSBAR, hMain, %ID_Status, "", 0, 0, 0, 0
       STATUSBAR SET PARTS hMain, %ID_Status, x - 90, 999
       DIALOG SHOW MODAL hMain CALL mainProc
    END FUNCTION
    
    CALLBACK FUNCTION mainProc()
       LOCAL i, numShown, yr, mo, day, amt AS LONG
       LOCAL sDate, sType, sDescr, sName, sAmt, sItem AS STRING
       SELECT CASE CBMSG
          CASE %WM_INITDIALOG
             numShown = 24: yr = 2000: mo = 6: day = 0: amt = 200
             FOR i = 1 TO numShown
                day = day + 5: IF day > 30 THEN INCR mo: day = 5
                IF mo > 12 THEN INCR yr: mo = 1: day = 5
                sDate = FORMAT$(mo, "00") + "/" + FORMAT$(day, "00") + "/" + FORMAT$(yr, "0000")
                sType = "type" + STR$(i MOD 6)
                sDescr = "description " + FORMAT$(i, "00")
                sName = "name " + FORMAT$(i MOD 16, "00")
                sAmt = TRIM$(STR$(amt + i)) + ".00"
                sItem = sDate + "," + sType + "," + sDescr + "," + sName + "," + sAmt
                colList.addItem(sItem, (i = numShown))
             NEXT i
          CASE %WM_COMMAND
             IF CB.CTL = %ID_List AND CB.CTLMSG = %LBN_SELCHANGE THEN
                showStatus 1: showStatus 2
             ELSEIF CB.CTL > %ID_List AND CB.CTL <= %ID_List + numShown THEN
                IF CB.CTLMSG = %STN_CLICKED THEN showStatus 1   
             END IF
       END SELECT   
    END FUNCTION
    
    SUB showStatus(panelNo AS LONG)
       LOCAL n, k, hDlg AS LONG, s AS STRING
       k = colList.getHiLite
       IF panelNo = 1 THEN 
          n = colList.getRecordNo(k)
          s = "Record number: " + STR$(n)
       ELSEIF panelNo = 2 THEN
          n = colList.getNumShown
          s = STR$(k)+" :"+STR$(n)
       END IF
       hDlg = colList.getHandle
       STATUSBAR SET TEXT hDlg, %ID_Status, panelNo, 0, s
    END SUB
Working...
X