Announcement

Collapse
No announcement yet.

Listview scrolls too much

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

  • Listview scrolls too much

    I'm trying to use a listview as a 'rolling log file'. It must hold the last 50 or so actions of the program. So if item 50 is added, item 0 must be deleted. So far OK. In the sample (borrowed from Peter Redei with some modifications...) if you press the Add line button, everything goes well (line added, first line deleted.) But if the right scroll bar is in the lowest position, adding a line scrolls the columnheaders off screen. I can solve this by using listview_update, or invalidaterect, but that introduces a lot of screen flickering if there are many lines added to the view. Is there another way to 'freeze' the columnheaders?

    Code:
    '==============================================================================
    '
    ' Testing listview routines
    ' David Morris 23/01/2000
    ' added some routines by Peter Redei
    '==============================================================================
    ' ** Eliminate unnecessary macros
    %NOANIMATE = 1 : %NODRAGLIST = 1 : %NOHEADER = 1 : %NOIMAGELIST = 1
    '%NOLISTVIEW = 1
    %NOTABCONTROL = 1 : %NOTRACKBAR = 1 : %NOTREEVIEW = 1 : %NOUPDOWN = 1
    #Compile Exe
    #Include "WIN32API.INC"
    #Include "COMMCTRL.INC"
    %IDOK = 1
    %IDCANCEL = 2
    %IDTEXT = 100
    %BS_DEFAULT = 1
    %IDLISTVIEW = 101
    '%LVS_EX_TRACKSELECT = &H8 'Should be in your "COMMCTRL.INC"
    '%LVS_EX_GRIDLINES = &H1 'Should be in your "COMMCTRL.INC"
    '------------------------------------------------------------------------------
    ' Global variable to recieve the user name
    Global UserName As String
    Global hListView As Long
    Global lviewSort As Integer
    
    Type dField
      fName As Asciiz * 80
      Size As Integer
      Alignment As Integer
    End Type
    
    Type ListData
      Columns As Integer
      Fields(0 To 80) As dField
    End Type
    '--------------------------------------------------------------------------------------------------
    Function HitColumn (hList As Long, xdim As Long) As Long
      Local i As Long, x As Long, sumx As Long
      sumx = 0
      i = 0
      Do
        x = ListView_GetColumnWidth(hList, i)
        sumx = sumx + x
        If xdim < sumx Then Function = i : Exit Do
        Incr i
      Loop
    End Function
    '--------------------------------------------------------------------------------------------------
    Sub AppendListView (hList As Long, Rec() As String )
      Dim z As Integer, iStatus As Integer, szStr As Asciiz * 300, lvi As LV_ITEM
      Local x As Long
      'this will be the next record
      lvi.iItem = ListView_GetItemCount(hList) '+ 1
      lvi.mask = %LVIF_TEXT
      lvi.stateMask = %LVIS_FOCUSED '%LVIS_SELECTED
      lvi.pszText = VarPtr(szStr)
      For z = 0 To UBound(Rec)
        szStr = Rec(z)
        lvi.iSubItem = z
        lvi.lParam = lvi.iItem
        If z = 0 Then
          lvi.mask = %LVIF_TEXT Or %LVIF_PARAM Or %LVIF_STATE
          iStatus = ListView_InsertItem (hList, lvi)
        Else
          lvi.mask = %LVIF_TEXT
          iStatus = ListView_SetItem (hList, lvi)
        End If
      Next
    End Sub
    '--------------------------------------------------------------------------------------------------
    Sub ResetLParam(hList As Long)
      Local i As Long, recs As Long, lvi As LV_ITEM, x As Long
      lvi.mask = %LVIF_PARAM
      lvi.iSubItem = 0
      recs = ListView_GetItemCount(hList)
      For i = 0 To recs - 1
        lvi.iItem = i
        x = ListView_GetItem (hList, lvi)
        lvi.lParam = lvi.iItem
        x = ListView_SetItem (hList, lvi)
      Next
    End Sub
    '--------------------------------------------------------------------------------------------------
    Function RetrieveLVData(hList As Long, Recno As Long, Fieldno As Long) As String
    %cchTextMax = 300
    Local lvi As LV_ITEM
    Local value As Asciiz * 300
    Local x As Long
    lvi.cchTextMax = %cchTextMax
    lvi.iItem = Recno
    lvi.pszText = VarPtr(value)
    lvi.iSubItem = Fieldno
    lvi.Mask = %LVIF_TEXT
    x = ListView_GetItem (hList, lvi)
    Function = value
    End Function
    '--------------------------------------------------------------------------------------------------
    Function compare(ByVal lParam1 As Long, ByVal lParam2 As Long, _
    ByVal lParamsort As Long) As Integer
    'The lParam1 parameter is the 32-bit value associated with the first item being compared; and the
    'lParam2 parameter is the value associated with the second item. These are the values that were
    'specified In the lParam member of the items' LV_ITEM structure when they were inserted into the
    'list. The lParamSort parameter is the same value passed to the LVM_SORTITEMS message.
    'The comparison function must return a negative value if the first item should precede the second,
    'a positive value if the first item should follow the second, or zero if the two items are
    'equivalent. lParam will carry a pointer to the value in the cell
    
      Local value1 As Asciiz * 300, value2 As Asciiz * 300, j%
      Function = 0
      value1 = RetrieveLVData(hListView, lParam1, lParamsort)
      value2 = RetrieveLVData(hListView, lParam2, lParamsort)
      Select Case lviewSort
        Case 0 'ascending
          j = 1
        Case Else 'descending
          j = -1
      End Select
      If value1 < value2 Then
        Function = -1 * j
      ElseIf value1 = value2 Then
        Function = 0
      Else
        Function = 1 * j
      End If
    End Function
    '--------------------------------------------------------------------------------------------------
    CallBack Function OkButton()
        If ListView_GetItemCount(hListView) > 34 Then  ListView_DeleteItem hListView, 0
        Dim Rec (1) As String
        Rec(0) = "One more"
        Rec(1) = "line added!"
        AppendListView hListView, Rec()
    End Function
    '--------------------------------------------------------------------------------------------------
    CallBack Function CancelButton()
      Dialog End CbHndl, 0
    End Function
    '--------------------------------------------------------------------------------------------------
    CallBack Function ListViewProcess ()
      If CbCtlMsg = %WM_LBUTTONDBLCLK Then
      MsgBox "Double Click",48,"LISTVIEW 'NOT working
    End If
    End Function
    '--------------------------------------------------------------------------------------------------
    CallBack Function tstListView()
    'LOCAL tbab AS TBADDBITMAP
      Local ID As Long, hDlg As Long, lpToolTip As TOOLTIPTEXT Ptr, lData As ListData
      Local my_LpLvNm As NM_LISTVIEW Ptr, hi As LV_HITTESTINFO, itemselect As Long, reclient As rect
      Local pt As POINTAPI, i As Long, sText As String
      Static zText As Asciiz * 255
    'STATIC hBmp AS LONG
      hDlg = CbHndl
      Select Case CbMsg
        Case %WM_INITDIALOG
        Case %WM_NOTIFY
          Select Case LoWrd(CbWparam)
            Case %IDLISTVIEW
              my_LpLvNm = CbLparam
              If @my_LpLvNm.hdr.code = %LVN_COLUMNCLICK Then
                itemselect = @my_LpLvNm.iSubItem 'HitColumn(hListView, hi.pt.x)
                i = (itemselect = -1)
                If i = 0 Then
                  'toggle ascending/descending
                  lviewSort = Not lviewSort
                  ListView_SortItems hListView, CodePtr(compare), itemselect
                  'lparam was set to the original 'recordnumber'
                  'now this changed, we need to set it to the new position
                  ResetLParam hListView
                End If
              ElseIf @my_LpLvNm.hdr.code = %NM_DBLCLK Then 'Now have Mouse Clicks!
                SText = RetrieveLVData(hListView, @my_LpLvNm.iItem, 1) 'Next find where click was
                Control Set Text hDlg&, %IDTEXT, Str$(CbCtlMsg)+Str$(CbWparam)+Str$(CbLparam)' sText
              End If
    '
    '          ElseIf @my_LpLvNm.hdr.code = %NM_DBLCLK Then 'Now have Mouse Clicks!
    '            sText = RetrieveLVData(hListView, 0, 0) 'Next find where click was
    '            MsgBox sText,48,"LISTVIEW"
    '          End If
          End Select
      End Select
    End Function
    '--------------------------------------------------------------------------------------------------
    Function PbMain () As Long
      $Register None
      Local hDlg As Long, result As Long, zText As Asciiz * 255, icc As INIT_COMMON_CONTROLSEX
      Local LVC As LV_COLUMN, i As Long,r As Long, c As Long,IStyle As Long
      %NumCols = 5:%NumRows = 30
      Dim Rec(%NumCols+1)As String
      Local LVI As LV_ITEM
      '%LVS_EX_TRACKSELECT = &H8
      ' InitCommonControls
      icc.dwICC = %ICC_DATE_CLASSES Or %ICC_BAR_CLASSES Or %ICC_LISTVIEW_CLASSES
      icc.dwSize = SizeOf(icc)
      InitCommonControlsEx icc
      ' ** Create a new dialog template
      Dialog New 0, "What is your name?", ,, 460, 250, 0, 0 To hDlg
      ' ** Add controls to it
      Control Add Button, hDlg, %IDOK, "Add a line", 34, 32, 50, 14, %BS_DEFAULT Call OkButton
      Control Add Button, hDlg, %IDCANCEL, "Cancel", 84, 32, 40, 14, 0 Call CancelButton
      '$WC_LISTVIEW
      Control Add "SysListView32", hDlg, %IDLISTVIEW,"",0,50,300,180, _
      %WS_border Or %WS_Child Or %WS_visible Or _
      %LVS_REPORT Or %LVS_SHOWSELALWAYS, _
      %WS_EX_CLIENTEDGE Call ListViewProcess
      Control Handle hDlg,%IDLISTVIEW To hListView
      IStyle = SendMessage (hListView,%LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
      IStyle = IStyle Or %LVS_EX_FULLROWSELECT Or %LVS_EX_TRACKSELECT Or %LVS_EX_GRIDLINES
      SendMessage hListView, %LVM_SETEXTENDEDLISTVIEWSTYLE, 0, ByVal IStyle
      lvC.mask = %LVCF_FMT Or %LVCF_WIDTH Or %LVCF_TEXT Or %LVCF_SUBITEM
      lvC.fmt = %LVCFMT_LEFT
      lvC.cx = 90
      LVC.cchTextMax = 255
      For c = 1 To %NumCols
        zText = "Column " + Format$(c - 1)
        LVC.pszText = VarPtr(zText)
        Control Send hDlg,%IDLISTVIEW,%LVM_INSERTCOLUMN, c, VarPtr(lvc)
      Next
      For r = 1 To %NumRows
        For c = 1 To %NumCols
          rec(c-1) = "Row " + Format$(r) + " Col " + Format$(c-1)
        Next c
        AppendListView hListView, Rec()
      Next r
    
      ' ** Display the dialog
      Dialog Show Modal hDlg Call tstListView To Result
      ' ** Check the result
      If result Then MsgBox "Hello " & UserName
    End Function
    Peter.

    Regards,
    Peter

  • #2
    I tested your code in Win2000 and the column headers don't scroll at all, even if I add 50 items! What O/S are you using?

    While I can't duplicate your problem, when you need to "mass update" a control and don't want the visual flicker, here is a nice little trick:

    Before updating the control, set it %WM_SETREDRAW state to false. Then perform your content update, then finally set the controls %WM_SETREDRAW state back to true and call InvalidateRect(hCtrl, BYVAL %NULL, %TRUE) - with DDT, use CONTROL HANDLE to translate the ID of the control into is actual window handle value (hCtrl).



    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    Lance
    mailto:[email protected]

    Comment


    • #3
      Lance,

      I'm using NT4 WS with sp6(a). The problem only happens if the scrollbar is completely at the bottom. Then when I add an item, the columnheaders just scroll-off together with the rest. (Maybe a bug in the commctrl DLL, solved in WIN2000?) I'll try your refresh-trick!

      Peter.


      ------------------
      Regards,
      Peter

      Comment


      • #4
        I gave it a spin on my weakling P75 Win95 notebook. The only time
        the header flickers is when I use the scroll-up key just when the high light bar is on the first viewable line and I have previously scrolled past the last viewable line. It would be nice just to invalidate the client area below the header only and leave the header alone... hint,hint,wink,wink.

        Regards, Jules

        Best regards
        Jules
        www.rpmarchildon.com

        Comment


        • #5
          It's definitely a micro$oft bug in the Comctl32.dll (i've tested with version 4.72). I've found a version 5.80, which works beautiful! Maybe someone with an old version can confirm this?
          BTW: Is there a way to get the version of a DLL (so I can anticipate this odd behaviour?)
          Peter.
          http://www.microsoft.com/msdownload/...comctrlx86.asp
          ------------------


          [This message has been edited by Peter Lameijn (edited March 09, 2000).]
          Regards,
          Peter

          Comment


          • #6
            See VerQueryValue() - there have been examples posted to this BBS in the past.

            BTW, the version of COMCTL32.DLL installed with my Win2K is 5.81.2920.0

            ------------------
            Lance
            PowerBASIC Support
            mailto:[email protected][email protected]</A>
            Lance
            mailto:[email protected]

            Comment

            Working...
            X