kk_lee69 发表于 2018-4-8 12:46:43

回复 15# chzj589

你的理解錯誤重頭到尾都沒讀取 只是知道筆數

然後 當要顯示的時候才讀取該顯示的部分

chzj589 发表于 2018-4-8 12:55:56

回复 16# kk_lee69

没读取数据?那数据条不应该是这样子

kk_lee69 发表于 2018-4-8 13:43:47

本帖最后由 kk_lee69 于 2018-4-8 13:46 编辑

回复 17# chzj589

是阿 這時候只讀取1-14條數據
其他的數據都沒有讀取

不相信 你把

                              Case $LVN_ODCACHEHINT
                                        Local $tNMLVCACHEHINT = DllStructCreate($tagNMLVCACHEHINT, $lParam), $iColumns
                                        $iFrom = DllStructGetData($tNMLVCACHEHINT, "iFrom")
                                        Local $sSQL = "SELECT * FROM lvdata WHERE item_id >= " & $iFrom & _
                                                      " AND item_id <= " & DllStructGetData($tNMLVCACHEHINT, "iTo") & ";"
                                        GUICtrlSendMsg($hLV, $LVM_DELETEALLITEMS, 0, 0)
                                        _SQLite_GetTable2d(-1, $sSQL, $aResult, $iRows, $iColumns)
                                        Local $iFromg = ConsoleWrite($iFrom & " " & DllStructGetData($tNMLVCACHEHINT, "iTo") & @CRLF)

這一行
_SQLite_GetTable2d(-1, $sSQL, $aResult, $iRows, $iColumns)
註釋掉   就不會有任何資料出現

chzj589 发表于 2018-4-8 13:51:43

回复 18# kk_lee69
没错。
下面就有读取与没读取的对比




是这句:
GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
;---------------------------------------------------------
        While 1
                Switch GUIGetMsg()
                        Case $idTab
                                If $iRows Then _SQLite_Close(-1);关闭打开的数据库
                                Switch GUICtrlRead($idTab)
                                        Case 0
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows1

                                                If $iRows Then _SQLite_Open("Test1.db")
                                                ;GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                                        Case 1
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows2

                                                If $iRows Then _SQLite_Open("Test2.db")
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                                        Case 2
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows3

                                                If $iRows Then _SQLite_Open("Test3.db")
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                                EndSwitch
                                ;GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)

                        Case $GUI_EVENT_CLOSE
                                ExitLoop
                EndSwitch
        WEnd

chzj589 发表于 2018-4-8 13:57:08

回复chzj589

是阿 這時候只讀取1-14條數據
其他的數據都沒有讀取

那是窗口大小,你把窗口改大,       
GUICreate("Virtual ListViews", 850, 600)
Local $idLV = GUICtrlCreateListView("", 20, 40, 850 - 40, 600 - 60, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT))
$hLV = GUICtrlGetHandle($idLV)
显示就不是1-14条数据?

kk_lee69 发表于 2018-4-8 14:41:52

本帖最后由 kk_lee69 于 2018-4-8 14:49 编辑

回复 20# chzj589

你沒有加入
ConsoleWrite($iFrom&" "&DllStructGetData( $tNMLVCACHEHINT, "iTo" )&@CRLF)

這行吧你加入了你就會知道 放大後所需要的就不會是 0-14它會自己變化 可能是 0-35   那就是 一次讀取35筆資料 往後也是一筆一筆增加

所以你就會重新讀取 幾筆資料

kk_lee69 发表于 2018-4-8 14:51:09

回复 19# chzj589

資料不是從這裡抓取的
   

是这句:
GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
;---------------------------------------------------------
      While 1
                Switch GUIGetMsg()
                        Case $idTab
                              If $iRows Then _SQLite_Close(-1);关闭打开的数据库
                              Switch GUICtrlRead($idTab)
                                        Case 0
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows1

                                                If $iRows Then _SQLite_Open("Test1.db")
                                                ;GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                                        Case 1
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows2

                                                If $iRows Then _SQLite_Open("Test2.db")
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                                        Case 2
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                                $iRows = $iRows3

                                                If $iRows Then _SQLite_Open("Test3.db")
                                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
                              EndSwitch
                              ;GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)

                        Case $GUI_EVENT_CLOSE
                              ExitLoop
                EndSwitch
      WEnd

chzj589 发表于 2018-4-8 14:51:55

回复 21# kk_lee69
搞不懂,这样有什么作用?有什么差别?

kk_lee69 发表于 2018-4-8 14:53:58

回复 23# chzj589

你把我上面範例的 第110行註釋掉

你就會看到 不會有任何東西 出現

我用上面的方法 可以在不到一秒內完成一個 有著一千萬筆資料的 LISTVIEW

你用其他方法都不可能達到 可以在 不到一秒內 讀取一千萬筆資料

chzj589 发表于 2018-4-8 15:00:05

回复 22# kk_lee69
把这句:GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iRows, 0)
改为:
GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 15, 0)
那就是0-14行了

chzj589 发表于 2018-4-8 15:04:49

回复 24# kk_lee69
_SQLite_GetTable2d
传递包含执行查询的列名和数据的 2 维数组.
哦,明白了。谢谢

kk_lee69 发表于 2018-4-8 15:17:52

回复 26# chzj589

其實 你使用的資料庫 如果是 SQLLITE 或者 MDB 用我原本範例的方法已經是很完美的方法了

因為是小型資料庫只有你自己使用忙碌點查詢 也沒關係


只是我的資料庫通常是 作為ERP 二次開發 使用不是只有我一個人使用 因為我必須要考慮

頻繁的查詢會不會造成主機忙碌影響其他使用者...

chzj589 发表于 2018-4-11 14:34:12

本帖最后由 chzj589 于 2018-4-11 14:37 编辑

回复 27# kk_lee69
今天又捣鼓了一下,再数据条点击可能不行。
                        Case $Button1
                                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, 0, 0)
                                Local $Rab = 10 ;AND $Ra*30
                                Local $Rab1 = 10
                                Local $Raba
                                For $i = 0 To $Rab1
                                        $Raba +=$Rab
                                Next
                                Local $Msg = GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $Raba, 0)
                                If $iRows Then _SQLite_Open("Test3.db")
这样点击一次就可前进一百条。

298311657 发表于 2018-4-12 16:41:48

回复 1# kk_lee69


这份代码其实还是一样的,只是它的数据请求是在$LVN_ODCACHEHINT消息产生时发生的,但数据也是一次全部请求完毕,使用_SQLite_GetTable2d函数,将全部的数据读取到$aResult数组内,然后在$LVN_GETDISPINFOW消息产生时,再显示在listview控件。
之所以你会感觉速度很快,那是因为_SQLite_GetTable2d函数的效率比较好而已。使用这种方式,并不是解决你遇到的问题的关键所在。
你想要分次读取数据的思路是对的,通过分页查询数据库的方式就可以了,但与这份示例代码的思路并不一样。

yhxhappy 发表于 2018-4-13 11:05:32

本帖最后由 yhxhappy 于 2018-4-13 12:32 编辑

我有类似的方案,不是通过下拉滚动条,而是通过翻页的方式
当数据库中有很多行,没办法一次读取,太费时。
默认先返回前 100 (1-100)行显示在 LV
当用户点击下一页时,清空 LV,再从数据库读取 101-200 行显示在 LV,以此类推
下图是微软的一个工具,原理类似:


原理是:
首先要先知道 数据库 表总共有几行,除以 LV显示行数(假设100) 得出 页数
假如当前页是8,当点击 下一页 按钮时,读取“表” (8+1)*100 = 900~1000行的数据

以下是我目前正在使用的,用于MSSQL,因为主键不是连续的,所以有点复杂。如果你的表ID列是连续的要简单很多,使用我注释掉的两行查询。
$Field字段,也可以用 *
$ConditionWHERE条件
$StartIndex开始的行索引,比如从第200行开始读取,$StartIndex = 200
$ItemNum要获取多少行Func _MsSQL_GetNumberOfRows2($Obj, $Table, $Field, $Condition, $StartIndex, $ItemNum)                ;返回 表中指定数量的 行
   If Not IsObj($Obj) Then
          SetError(1)
          Return 0
   ElseIf $Table = "" Or $StartIndex = "" Or $ItemNum = "" Or $Field = "" Then
          SetError(2)
          Return 0
   EndIf

   ;$ItemNum -= 1

   $FieldNum = _MsSQL_GetColumnNum($Obj, $Table)        ;取得列的数量
   If @error Or $FieldNum = 0 Then
          SetError(3)
          Return 0
   EndIf

   $RowNum = _MsSQL_GetRowNum($Obj, $Table, $Condition)
   If $RowNum = 0 Then        ;取得行数量,如果为0则退出
          SetError(4)
          Return 0
   EndIf

   ;MsgBox(0,0,$RowNum)
   If $StartIndex > $RowNum Then                        ;如果起始索引大于总行数,则起始索引等于最后一行
          $StartIndex = $RowNum
          $ItemNum = 0
   ElseIf $StartIndex <= 0 Then
          $StartIndex = 1
   EndIf

   If $StartIndex+$ItemNum-1 > $RowNum Then                ;如果开始位数+项目数量,大于总数量,则只能取到最后一个
          $ItemNum = $RowNum-$StartIndex+1
   EndIf
   If $ItemNum <= 0 Then $ItemNum = 1                ;不能小于0

   $WHERE = ""
   If $Condition <> "" Then $WHERE = " WHERE " & $Condition

   $RS = ObjCreate("ADODB.Recordset")
   $RS.ActiveConnection = $Obj

   ;SELECT&nbsp;TOP&nbsp;100 FROM&nbsp;(SELECT&nbsp;TOP&nbsp;300&nbsp;FROM&nbsp;SN_Key&nbsp;ORDER&nbsp;BY&nbsp;ID&nbsp;DESC)&nbsp;AS&nbsp;WK ORDER&nbsp;BY&nbsp;ID&nbsp;ASC
   ;select top 10 * from (select top 30 * from tablename order by id asc) A order by id desc

   ConsoleWrite("SELECT TOP " & $ItemNum & " * FROM (SELECT TOP " & $StartIndex+$ItemNum-1 & " * FROM "& $Table & $WHERE & " ORDER BY " & $Field & " DESC) A ORDER BY " & $Field & " ASC" & @CRLF)
   $RS.Open("SELECT TOP " & $ItemNum & " * FROM (SELECT TOP " & $StartIndex+$ItemNum-1 & " * FROM " & $Table & $WHERE & " ORDER BY " & $Field & " DESC) A ORDER BY " & $Field & " ASC")

   Local $Num = 0, $Array[$FieldNum] = [], $text = ""
   While Not $RS.eof And Not $RS.bof
;          If @error Then ExitLoop
          For $i = 0 To $FieldNum-1                                                        ;循环读取字段值
               $Text &= $RS.Fields($i).value & "|"
          Next

          _ArrayAdd($Array, StringTrimRight($Text, 1))                ;通常会多加一个|,会导致数组维数不对,删除最后一个 |
          $text = ""
          $Num += 1
          ;ToolTip($Num)
          $RS.movenext;下一笔资料
   WEnd
   $RS.close

   If $Num = 0 Then
          SetError(5)
          Return 0
   Else
          $Array = $Num
          $Array = $RowNum
          Return $Array
   EndIf
EndFunc   ;==>_Query
页: 1 [2] 3
查看完整版本: 关于listview虚表直接读取数据库的方法,求助修改范例成MSSQL的!!