首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

怎么在VB中利用listview快速显示10000以下的记录

2012-12-30 
如何在VB中利用listview快速显示10000以上的记录listview显示起来美观,可就是速度不行比如下面的方式For i

如何在VB中利用listview快速显示10000以上的记录
listview显示起来美观,可就是速度不行

比如下面的方式
  For i = 0 To 10000
     ListView1.ListItems.Add ListView1.ListItems.Count + 1, , ListView1.ListItems.Count + 1
     ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(1) = ("你好啊")
     ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(2) = ("你好啊")
     ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(3) = ("你好啊")
  Next i

用逐个添加速度很慢,看到一个avafind软件,几万行的数据显示出来只要零点几秒

请问各位高手如何在VB中实现listview的快速显示呢?只要没有停顿感就好。

如果能解决,可再加100分
[解决办法]
其实很简单,有种virtual模式就可以的啊,你可搜下相应的资料:)
[解决办法]
先禁止列表重绘,再添加数据
自己添加 LockWindowUpdate  api,然后这样:

LockWindowUpdate hWndListView

for xxx。。。
给列表添加数据
next


LockWindowUpdate 0&
[解决办法]
LockWindowUpdate禁止LV控件重绘,然后开一个循环,不要加DoEvents,就直接添加全部数据,这样速度有显著提升。
[解决办法]
换个思路,这么多记录,就用分页啊。
[解决办法]
          ' 避免显示区域的闪动现象。
            Call ValidateRect(cLvwMer.hwnd, rc)
            DoEvents
            p = p + 1
            
            If p Mod 1000 = 0 Then
                Call InvalidateRect(cLvwMer.hwnd, rc, True)
                cLvwMer.Refresh
                Call ValidateRect(cLvwMer.hwnd, rc)
            End If

这样可以每1000行显示一次,2,3万行数据也就10来秒钟,基本没有停顿感
[解决办法]
在显示开始前,还要加这句
    '获 得listview的显示区域。
    Call GetClientRect(cLvwMer.hwnd, rc)

rc的定义
Public Type RECT                 '用来定义一个区域的坐标
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
[解决办法]
'本程序经过VB6测试,完美实现LISTVIEW动态增加记录的功能。
'Form1 Code
Option Explicit

Private Sub Form_Load()
  Dim Index As Long
    ListView1.ColumnHeaders.Add , , "Column 1"
    ListView1.LabelEdit = lvwManual
    ListView1.View = lvwReport
    ListView2.ColumnHeaders.Add , , "Column 1"
    ListView2.LabelEdit = lvwManual
    ListView2.View = lvwReport


    For Index = 1 To 1000
        ListView1.ListItems.Add , , "Item " & CStr(Index)
       ' ListView2.ListItems.Add , , "Item " & CStr(Index)
    Next
    ListViewSubClass ListView1.hwnd  '子类化
    'ListViewSubClass ListView2.hwnd

End Sub

Public Sub Add1000() '滚动条移动一次增加1000条记录
    Dim Index As Long
    Dim I As Long
    I = ListView1.ListItems.Count
    If I < 30000 Then 'ListView1中当记录小于30000条时增加记录
        For Index = I + 1 To I + 1000
            ListView1.ListItems.Add , , "Item " & CStr(Index)
            'ListView2.ListItems.Add , , "Item " & CStr(Index)
        Next
    End If
End Sub

'Module1 Code

Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Private lpfnOldWinProcLV       As Long 'old WindowProc address for ListView
Private Const GWL_WNDPROC       As Long = (-4)
Private Const WM_VSCROLL        As Long = &H115
Private Const WM_DESTROY        As Long = &H2
Private Const SB_THUMBPOSITION As Long = 4
Private Const SB_THUMBTRACK As Long = 5
Private Const LVM_FIRST As Long = &H1000
Private Const LVM_SCROLL As Long = (LVM_FIRST + 20)

Public Function ListViewSubClass(hwnd As Long) As Boolean
    'This function enables subclassing
    ListViewSubClass = True
    'Get the address for the previous window procedure
    lpfnOldWinProcLV = GetWindowLong(hwnd, GWL_WNDPROC)
    If lpfnOldWinProcLV = 0 Then
        ListViewSubClass = False


        Exit Function
    End If
    'The return value of SetWindowLong is the address of the previous procedure,
    'so if it's not what we just got above, something went wrong.
    If SetWindowLong(hwnd, GWL_WNDPROC, AddressOf ListViewWndProc) <> lpfnOldWinProcLV Then
        ListViewSubClass = False
    End If
End Function
  
Public Function ListViewUnSubClass(hwnd As Long) As Boolean
    'Restore default window procedure
    If SetWindowLong(hwnd, GWL_WNDPROC, lpfnOldWinProcLV) = 0 Then
        ListViewUnSubClass = False
    Else
        ListViewUnSubClass = True
        lpfnOldWinProcLV = 0
    End If
End Function
  
Private Function ListViewWndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Static bIgnore As Boolean
    ListViewWndProc = CallWindowProc(lpfnOldWinProcLV, hwnd, uMsg, wParam, lParam)
    If bIgnore Then
    Exit Function
    End If
    'Determine the message that was received
    Select Case uMsg
        Case WM_VSCROLL '滚动条事件
            'Debug.Print "1"
            Call Form1.Add1000  '增加记录
        Case WM_DESTROY
            Call CallWindowProc(lpfnOldWinProcLV, hwnd, uMsg, wParam, lParam)
            Call ListViewUnSubClass(hwnd)
            ListViewWndProc = CallWindowProc(lpfnOldWinProcLV, hwnd, uMsg, wParam, lParam)
    End Select
End Function

Public Function LoWord(num As Long) As Integer
    LoWord = num Mod &H10000
End Function

Public Function HiWord(num As Long) As Integer
    HiWord = (num And &HFFFF0000) / &H10000
End Function


[解决办法]
'分成两次加载
sub form_load
    dim i as long
    LockWindowUpdate listview1.hwnd
    For i = 0 To 100
        ListView1.ListItems.Add ListView1.ListItems.Count + 1, ,ListView1.ListItems.Count + 1
        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(1) = ("你好啊")


        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(2) = ("你好啊")
        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(3) = ("你好啊")
    Next i
    me.show
    for i=101 to 10000
        ...
        doevents
    next

end sub
[解决办法]
窗体上放timer控件数组,下标0~9,我本地测试,显示效果为加载50000条数据约1秒,基本达到要求。实际上完全加载完约5秒,不过是分时加载,客户基本感觉不到


Private Sub Form_Load()
  Dim Index As Long, i As Long
  For i = 0 To 9
      Timer1(i).Interval = 10
      Timer1(i).Enabled = True
  Next
End Sub
Private Sub Timer1_Timer(Index As Integer)
    Dim i As Long
    Static num As Long
    Timer1(Index).Enabled = False
    For i = num To num + 4999
        ListView1.ListItems.Add ListView1.ListItems.Count + 1, , ListView1.ListItems.Count + 1
        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(1) = ("你好啊")
        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(2) = ("你好啊")
        ListView1.ListItems.Item(ListView1.ListItems.Count).SubItems(3) = ("你好啊")
    Next i
    num = i
    DoEvents
End Sub


[解决办法]
1、如果是数据库的应用,会采用直接绑定的方法,如datagrid,mshflexgrid等可以采用类似的方法

reco.CursorLocation =adUseClient   '采用客户端游标

reco.open sql,cn    '用快速只读

set datagrid.datasource=reco

reco.close 

这种方法优点是加载速度比普通的写要快很多倍


2、采用Virtual的Listview可以快速加载大量的数据,以下是参考例子

http://www.mvps.org/vbvision/_samples/Virtual_ListView_Demo.zip




[解决办法]
我写过一个,读取txt文本,分页显示,10000行数据显示在listview控件上,耗时68ms。42万行,耗时6s多点。
不知你想要的是不是这样的?
[解决办法]
用LISTVIEW的虚表技术实现。 很简单基本上无耗时

实现方法
1、在父窗体初始化时下一个CBT钩子,拦截listview控件的WM_CREATE消息,然后设置LVS_OWNERDATA样式,并子类化listview窗口
2、在子类化listview过程中处理LVN_GETDISPINFO消息就
[解决办法]
本帖最后由 bcrun 于 2010-07-11 10:23:47 编辑
引用:
VB里边listview的virtual模式不知道怎么用,不是很明白

也许他用的是分页,可滚动条如何处理呢?


http://www.mvps.org/vbvision/Sample_Projects.htm#Virtual_ListView_Demo

另外,你还可以搜一下Virtual_ListView_Demo

热点排行