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分

解决方案 »

  1.   

    其实很简单,有种virtual模式就可以的啊,你可搜下相应的资料:)
      

  2.   

    楼上大哥,VB6的listview如何使用Virtual模式阿
    搜了搜没找到阿
      

  3.   

    先禁止列表重绘,再添加数据
    自己添加 LockWindowUpdate  api,然后这样:LockWindowUpdate hWndListViewfor xxx
    给列表添加数据
    next
    LockWindowUpdate 0&
      

  4.   

    LockWindowUpdate禁止LV控件重绘,然后开一个循环,不要加DoEvents,就直接添加全部数据,这样速度有显著提升。
      

  5.   

              ' 避免显示区域的闪动现象。
                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来秒钟,基本没有停顿感
      

  6.   

    在显示开始前,还要加这句
        '获 得listview的显示区域。
        Call GetClientRect(cLvwMer.hwnd, rc)rc的定义
    Public Type RECT                 '用来定义一个区域的坐标
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
    End Type
      

  7.   

    10秒钟太久,要求1秒以内最好类似avafind里边那个搜索结果的列表显示,10w的数据也是瞬间显示出来不至于VB做不出这个效果吧,那就完蛋了。
    求各位高手帮忙吧,谢谢各位了阿!
      

  8.   


    VB里边listview的virtual模式不知道怎么用,不是很明白也许他用的是分页,可滚动条如何处理呢?
      

  9.   

    http://topic.csdn.net/u/20071004/10/176b6891-0817-40a5-8895-650ba9619145.html
      

  10.   

    或者自己上网搜索 LVS_OWNERDATA 这个样式!
      

  11.   

    '本程序经过VB6测试,完美实现LISTVIEW动态增加记录的功能。
    'Form1 Code
    Option ExplicitPrivate 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.hwndEnd SubPublic 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 CodeOption 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 FunctionPublic Function LoWord(num As Long) As Integer
        LoWord = num Mod &H10000
    End FunctionPublic Function HiWord(num As Long) As Integer
        HiWord = (num And &HFFFF0000) / &H10000
    End Function
      

  12.   

    17L的不错,我也做过SubClass进行滚动条动态添加,虽然我不怎么喜欢,因为很多时候添加LV项目,比较多的时候都是使用多线程去添加的,只是为了不使界面卡就行了。
    不过LZ的要求,1秒内完成的话只能那样分页了。
      

  13.   

    '分成两次加载
    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
        nextend sub
      

  14.   

    窗体上放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
      

  15.   

    何必强求用Listview呢,用Datagrid就行了^_^
      

  16.   

    1、如果是数据库的应用,会采用直接绑定的方法,如datagrid,mshflexgrid等可以采用类似的方法reco.CursorLocation =adUseClient   '采用客户端游标reco.open sql,cn    '用快速只读set datagrid.datasource=recoreco.close 这种方法优点是加载速度比普通的写要快很多倍
    2、采用Virtual的Listview可以快速加载大量的数据,以下是参考例子http://www.mvps.org/vbvision/_samples/Virtual_ListView_Demo.zip
      

  17.   

    我写过一个,读取txt文本,分页显示,10000行数据显示在listview控件上,耗时68ms。42万行,耗时6s多点。
    不知你想要的是不是这样的?
      

  18.   

    Mark ............闪人了……
      

  19.   

    用LISTVIEW的虚表技术实现。 很简单基本上无耗时实现方法
    1、在父窗体初始化时下一个CBT钩子,拦截listview控件的WM_CREATE消息,然后设置LVS_OWNERDATA样式,并子类化listview窗口
    2、在子类化listview过程中处理LVN_GETDISPINFO消息就
      

  20.   

    本帖最后由 bcrun 于 2010-07-11 10:23:47 编辑
      

  21.   

    非常感谢各位楼上的大哥特别感谢ok999ok给出的代码
    特别感谢vbload的给的例子
    特别感谢bcrun给出链接感激不尽.....由于本人分数较少,只能给了150分,请各位勿怪....
      

  22.   

    分数少是吧,那就给你加精,可奖88分:)
    顺便问一句楼主:)我看您在VB版有4个三角,“个人动态”却只有这一个帖子,是不是有好几年没上CSDN了?
      

  23.   

    配置:
         硬盘:15G
         内存:256M
         IP  :  1个 HK出口(可以提供电信/网通/国际出口)
         Hot backup : 1
    PBS VPS刚买的时候有点担心,因为一个月180块,如果买便宜的VPS,可以买好多个。在买之前我联系了他们试用了两天,打消了我的疑虑。我主要看中了有HK的出口,还有hot backup的功能,而且那里的NOC团队也给我了很大的帮助。在试用的两天,我装了几次系统和遇到了几个问题,他们的NOC团队总是能给我最好的解决。我让我HK和美国的朋友测试一下到我的网站速度,他们的感觉都是好快的。这点我是比较满意的。
    有点不满意的是他们那里提供的VPS只有CentOS版的,我原本想要RHEL版的,不过他那里没有,不过都是相通的,就用了CentOS了。
    好了,大家也可以去试试PBS VPS,有想了解的,可以站内发短信给我。
      

  24.   

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

  25.   

      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
      

  26.   

    之前使用的VPS很不稳定,正好也要到期了,于是我就对了几家的VPS,最终确定是PBS VPS ,套餐选了最廉价的Standard,不过我选到了最想要的机房:HK Mege,这是我目前为止,从HK到国外最快的VPS了。配置:
         硬盘:15G
         内存:256M
         IP  :  1个 HK出口(可以提供电信/网通/国际出口)
         Hot backup : 1
    PBS VPS刚买的时候有点担心,因为一个月180块,如果买便宜的VPS,可以买好多个。在买之前我联系了他们试用了两天,打消了我的疑虑。我主要看中了有HK的出口,还有hot backup的功能,而且那里的NOC团队也给我了很大的帮助。在试用的两天,我装了几次系统和遇到了几个问题,他们的NOC团队总是能给我最好的解决。我让我HK和美国的朋友测试一下到我的网站速度,他们的感觉都是好快的。这点我是比较满意的。
    有点不满意的是他们那里提供的VPS只有CentOS版的,我原本想要RHEL版的,不过他那里没有,不过都是相通的,就用了CentOS了。
    好了,大家也可以去试试PBS VPS,有想了解的,可以站内发短信给我。
      

  27.   

    这个10000行数据还不至于慢到这种程度。楼主应该是添加的时候设置了sorted(排序)属性。每次添加都要排序,速度可想而知。在这种大量添加的时候,应该首先去掉sorted属性,等添加结束后再重新设置sorted属性进行排序。
    这个问题与重绘基本上也是没有关系的,在循环添加的时候,如果不加doevents,那么系统是无法取得重绘消息的,只有等循环结束系统重新掌握控制权的时候,窗口才有时间获得系统消息进行重绘,而且一定是一次性的。
    另外,楼主的问题还在于并没有真正理解ListView,导致很多效率问题。我将楼主的代码和我的代码循环加大为100000,在不设置Sorted属性的情况下楼主可以试试看效率差多少!
    '这是楼主的代码
    Private Sub Command2_Click()
    Dim i As Long
        For i = 0 To 100000
            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
    End Sub'这是我的代码
    Private Sub Command3_Click()
    Dim nItems As ListItems
    Dim nItem As ListItem
    Dim i As Long
        Set nItems = ListView1.ListItems
        For i = 0 To 100000
            Set nItem = nItems.Add(nItems.Count + 1, , nItems.Count + 1)
            nItem.SubItems(1) = ("你好啊")
            nItem.SubItems(2) = ("你好啊")
            nItem.SubItems(3) = ("你好啊")
        Next i
    End Sub
      

  28.   

    建议采用延迟加载的方式,先显示前N条数据,当有mousebuttonscroll事件时,继续显示后续数据
      

  29.   


    仁兄说的sort我用时不会设置的,默认就false,说实话你说的这个方式实在没看出效率高在何处?原理是什么?建议仁兄看看17楼的代码吧这种实现方式还是不错的。http://www.mvps.org/vbvision/Sample_Projects.htm#Virtual_ListView_Demo
    还有22楼给出的这个例子,这才是效率。这次真是学习了
      

  30.   

    你有试过我给你的代码么?你如果确认你的Sorted属性是False,那么请你自己新开一个工程,放上一个新的ListView名为ListView1,将其样式修改为lvwReport,然后添加4列。我给你的代码是添加十万条的,用你原来的代码添加十万条在我的机器上要4314毫秒,而我的代码需要2200毫秒,几乎相差一倍。而问题的原因就在于楼主在每次添加子项的时候都是重新寻找主项的,这个效率无疑是非常浪费的!另外,你说的例子无非就是修改ListView的窗口处理函数,不过说实话在VB中做这些事情并不稳定,不利于程序的调试,还不如直接用VC来做控件给VB调用。其实VB也有简单有效的方法制作虚拟控件,就是使用ListView加上ProgressBar来做一个虚拟的ListView控件,这个其实是很简单的。ListView之所以慢是因为它并没有提供直接添加ListItem之类的接口,否则的话可以先在内存中将ListItem初始化好了以后一次性添加。说句实在话为了提高一点效率使用VB来调用专门为VC设计的API实在是不合算。只要掌握了VB的本质(其实是VC以及对操作系统的了解,这个基本上各个系统都是一样的),你就会在最合适的时候使用最合适的语言,甚至n者混合使用!
      

  31.   

    VB不熟悉
    C++来说
    LISTVIEW有一个虚拟样式,这个样式不需要一个一个向列表中添加。
    可重载内部某一函数(忘了……),每次需要获取某一项数据时,LISTVIEW会访问该函数(消息)进行获取。
    而假如需要差入10W数据,只需要在LISTVIEW中设置一个总数量好象是就可以了。剩下的数据获取操作由你重载的函数提供。不好意思,好久没接触了。具体函数名还是什么都忘记了。你可以上网查查listview 的虚列表
      

  32.   

    VB不熟悉
    C++来说
    LISTVIEW有一个虚拟样式,这个样式不需要一个一个向列表中添加。
    可重载内部某一函数(忘了……),每次需要获取某一项数据时,LISTVIEW会访问该函数(消息)进行获取。
    而假如需要差入10W数据,只需要在LISTVIEW中设置一个总数量好象是就可以了。剩下的数据获取操作由你重载的函数提供。不好意思,好久没接触了。具体函数名还是什么都忘记了。你可以上网查查listview 的虚列表
      

  33.   

    很强大 少下了个dll - -
      

  34.   

    谢谢分享!!!Between persons of Tiny Bikini equal income there is no social sexy bikinis sale distinction except the distinction of Ed Hardy Bikini merit. Money is nothing;character,conduct,and Ralph Lauren Bikini capacity are everything.Instead of sexy bikinis all the workers being leveled down to low wage standards and all the Sinful Bikini rich leveled up to fashionbale income standards,everybody under a system of Lacoste Bikini equal incomes would find his or her own natural level.There would be great Designer Brands Bikini people and ordinary people and little Tiny Ed Hardy Bikini peolpe,but the great would always be those who had done great things,and never the Sexy Ralph Lauren Bikini idiot whose mother had spoiled them and whose father had girl bikini left a hunred thousand a year;and the little would be persons of Louis Vuitton Bikini small minds and mean characters,and not poor persons who had Chanel Bikini never had a chance.That is why idiots are always in favour of inequality of income(their only chance of eminence),and the Ed Hardy Swimsuit really great in favour of equality.
      

  35.   

    光从代码优化来看,个人支持yunyu97,其实如果是使用控件的话用什么编译语言之间的差距不会很大,因为大部分操作是在控件中的代码做的。即使是使用vb,优化好了,速度也是很快的。本例中由于listview现有行数已知,yunyu97的代码还可以进一步优化为:
    Dim nItems As ListItems
    Dim nItem As ListItem
    Dim i As Long
      With ListView1.ListItems
      For i = 0 To 10000
      With .Add(, , i + 1)
      .SubItems(1) = ("ÄãºÃ°¡")
      .SubItems(2) = ("ÄãºÃ°¡")
      .SubItems(3) = ("ÄãºÃ°¡")
      End With
      Next i
      End With
    这个在我的T60机上测试,10000行只要0.18秒。
    当然,如果从设计角度来看,一次向listview加入10000行数据本身不是一个好方案,耗时耗内存。并且用户也不需要同时观看10000条记录,显示器也显示不了,所以分段或者分页加入才是最好的办法。