ListView虚表 使用sql分页查询的方法动态加载Sqlite数据库数据示例
本帖最后由 298311657 于 2018-4-11 17:20 编辑看到有坛友留言给我,询问当数据库数据过大,使用listview虚表时,若还一次性把所有数据都读取到数组内,再显示出来,效率很慢,要如何解决此种问题。我的想法是使用sql的分页功能解决问题。
将数据库内的数据通过sql分页查询的方式,通过多次查询,将数据库的数据加载到数组内,然后再显示在listview表格上。
具体的看代码吧,语音组织能力有限。
#Region ;**** 编译指令由 AutoIt3Wrapper 选项编译窗口创建 ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** 编译指令由 AutoIt3Wrapper 选项编译窗口创建 ****
#cs ____________________________________
Au3 版本: 3.3.14.2
脚本作者: CrossDoor
电子邮件: 382869232@qq.com
QQ/TM: 382869232
#ce _______________脚本开始_________________
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <GuiEdit.au3>
#include <array.au3>
#include <SQLite.au3>
Local $tText = DllStructCreate("wchar Text");建个结构,用来放listview列数据
Local $iPage = 1, $iPageCount = 1000, $bPage = True;数据分页变量$iPage每页显示数据数量变量$iPageCount
Local $GUI, $aShowdata[$iPageCount]
;==========生成数据库数据
Local $hQuery, $aRow
_SQLite_Startup(@ScriptDir & "\sqlite3.dll")
_SQLite_Open() ; 打开 :内存: 数据库
_SQLite_Exec(-1, "CREATE TABLE aTest (a,b,c);") ; 创建一个表
_SQLite_Exec(-1, "BEGIN TRANSACTION;");开启一个事务,在大量数据操作时可增加效率
For $i = 0 To 9999;一万数据
_SQLite_Exec(-1, "INSERT INTO aTest(a,b,c) VALUES ('(列一)" & $i & "','(列二)" & $i & "','(列三)" & $i & "');")
If @error Then
_SQLite_Exec(-1, "ROLLBACK TRANSACTION;");回滚事务
ExitLoop
EndIf
Next
_SQLite_Exec(-1, "COMMIT TRANSACTION;");提交事务
ConsoleWrite("数据生成结束" & @CRLF)
;==========完毕
GetData()
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
$hGUI = GUICreate("ListView虚表 动态加载数据库数据示例 By_Crossdoor", 500, 350)
$hListView = GUICtrlCreateListView("Item1|nSubItem1|nSubItem2", 2, 2, 494, 294, $LVS_SHOWSELALWAYS + $LVS_OWNERDATA, $LVS_EX_GRIDLINES + $LVS_EX_FULLROWSELECT + $LVS_EX_DOUBLEBUFFER + $LVS_EX_CHECKBOXES)
;设置列宽
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 0, 150)
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 1, 150)
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 2, 150)
GUICtrlSendMsg($hListView, $LVM_SETITEMCOUNT, $iPageCount, 0);设定数据总数
GUISetState()
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case -3
ExitLoop
EndSwitch
WEnd
GUIDelete()
_SQLite_Exec(-1, "DROP TABLE aTest;") ; 删除表
_SQLite_Close()
_SQLite_Shutdown()
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
#forceref $hWnd, $iMsg, $iwParam
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo, $s
$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Local $iIndex = DllStructGetData($tNMHDR, 'Index')
Switch $iIDFrom
Case $hListView
Switch $iCode
Case $NM_CLICK;单击
$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
$iIndex = DllStructGetData($tInfo, "Index")
$x = DllStructGetData($tInfo, "X")
If ($x < 16) And (3 < $x) And (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES) Then;使用x坐标来判断是否在复选框上点击
If $aShowdata[$iIndex] = 4096 Then
$aShowdata[$iIndex] = 8192;4096未选中 8192选中
Else
$aShowdata[$iIndex] = 4096;4096未选中 8192选中
EndIf
$tInfo = DllStructCreate($tagNMLVDISPINFO, $ilParam)
DllStructSetData($tInfo, "State", $aShowdata[$iIndex]);设置复选框状态
;====立刻刷新复选框显示状态 重绘$iIndex-1到$iIndex+20的项
GUICtrlSendMsg($hListView, $LVM_REDRAWITEMS, $iIndex - 1, $iIndex + 20)
EndIf
Case -150, -177 ;$LVN_GETDISPINFOA = -150, $LVN_GETDISPINFOW = -177 请求显示数据
If Not IsArray($aShowdata) Then ContinueCase
$tInfo = DllStructCreate($tagNMLVDISPINFO, $ilParam)
$iIndex = Int(DllStructGetData($tInfo, "Item"))
$iSub = Int(DllStructGetData($tInfo, "SubItem"))
If $iIndex >= UBound($aShowdata)-1 And $bPage Then
GetData();listview被拉到底部时,请求加载新的数据
GUICtrlSendMsg($hListView, $LVM_SETITEMCOUNT, UBound($aShowdata), 0);新数据加载后,修改虚表显示的数据总数
EndIf
If (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES) Then
;===============设置复选框信息
DllStructSetData($tInfo, "Mask", BitOR($LVIF_STATE,DllStructGetData($tInfo, "Mask")))
DllStructSetData($tInfo, "StateMask", $LVIS_STATEIMAGEMASK)
DllStructSetData($tInfo, "State", $aShowdata[$iIndex])
EndIf
DllStructSetData($tText, "Text", $aShowdata[$iIndex][$iSub]);列数据放入$tText结构
DllStructSetData($tInfo, "Text", DllStructGetPtr($tText));用$tText结构的指针来设置列数据
DllStructSetData($tInfo, "TextMax", StringLen($aShowdata[$iIndex][$iSub]));设置列数据长度
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY
Func GetData()
;==========采用分页模式取数据库数据,先取 $iPage 页的数据到数组内
Local $i = $iPageCount*($iPage-1), $b =True
_SQLite_Query(-1, "SELECT * FROM aTest limit "& $iPageCount & " offset " & $iPageCount*($iPage-1) & ";", $hQuery)
For $k = 0 To $iPageCount - 1
If _SQLite_FetchData($hQuery, $aRow) = $SQLITE_OK Then; 依次获取行
If $b Then
ReDim $aShowdata[$iPage * $iPageCount]
$iPage+=1;取一次数据分页数加1
$b = False
EndIf
$aShowdata[$i] = $aRow
$aShowdata[$i] = $aRow
$aShowdata[$i] = $aRow
$aShowdata[$i] = 4096;复选框状态 4096未选中 8192选中
$i+=1
Else
ConsoleWrite("表数据已经读取到底,将分页数据读取标志变量$bPage = False" & @CRLF)
$bPage = False
ExitLoop
EndIf
Next
_SQLite_QueryFinalize($hQuery)
;==========完毕
EndFunc
这个不错,有时间再研究研究。 回复 1# 298311657
我研究看看 感謝啦!! 回复 3# kk_lee69
还有一种方法是根据LVN_ODCACHEHINT消息来请求数据,这种方法会在后台一直请求缓存数据直到数据全部读取完毕,而我上面的代码则是当先前请求的数据全部显示完毕才会请求新的数据,两种方法各有利弊,你可以自行选择。
关于分页查询,sqlite数据库使用的limit-offset指令;MySql数据库提供了分页的函数limit m,n;sqlserver数据库分页查询的方式比较多,NOT IN关键字、MAX(ID)函数、Server2005中的ROW_NUMBER、SQL Server 2012中的OFFSET-FETCH等。
不论使用哪种数据库,改变的都只是查询数据的sql语句,listview显示数据的方式都是一样的。
#Region ;**** 编译指令由 AutoIt3Wrapper 选项编译窗口创建 ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** 编译指令由 AutoIt3Wrapper 选项编译窗口创建 ****
#cs ____________________________________
Au3 版本: 3.3.14.2
脚本作者: CrossDoor
电子邮件: 382869232@qq.com
QQ/TM: 382869232
#ce _______________脚本开始_________________
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>
#include <WindowsConstants.au3>
#include <WinAPISys.au3>
#include <GuiEdit.au3>
#include <array.au3>
#include <SQLite.au3>
Local $tText = DllStructCreate("wchar Text");建个结构,用来放listview列数据
Local $iPage = 1, $iPageCount = 100, $bPage = True;数据分页变量$iPage每页显示数据数量变量$iPageCount
Local $GUI, $aShowdata[$iPageCount]
_SQLite_Startup(@ScriptDir & "\sqlite3.dll")
_SQLite_Open() ; 打开 :内存: 数据库
_SQLite_Exec(-1, "CREATE TABLE aTest (a,b,c);") ; 创建一个表
;==========生成数据库数据
_SQLite_Exec(-1, "BEGIN TRANSACTION;");开启一个事务,在大量数据操作时可增加效率
For $i = 0 To 9999;一万数据
_SQLite_Exec(-1, "INSERT INTO aTest(a,b,c) VALUES ('(列一)" & $i & "','(列二)" & $i & "','(列三)" & $i & "');")
If @error Then
_SQLite_Exec(-1, "ROLLBACK TRANSACTION;");回滚事务
ExitLoop
EndIf
Next
_SQLite_Exec(-1, "COMMIT TRANSACTION;");提交事务
ConsoleWrite("数据生成结束" & @CRLF)
;==========完毕
GetData()
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
$hGUI = GUICreate("ListView虚表 动态加载数据库数据示例 By_Crossdoor", 500, 350)
$hListView = GUICtrlCreateListView("Item1|nSubItem1|nSubItem2", 2, 2, 494, 294, $LVS_SHOWSELALWAYS + $LVS_OWNERDATA, $LVS_EX_GRIDLINES + $LVS_EX_FULLROWSELECT + $LVS_EX_DOUBLEBUFFER + $LVS_EX_CHECKBOXES)
;设置列宽
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 0, 150)
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 1, 150)
GUICtrlSendMsg($hListView, $LVM_SETCOLUMNWIDTH, 2, 150)
GUICtrlSendMsg($hListView, $LVM_SETITEMCOUNT, $iPageCount, 0);设定数据总数
GUISetState()
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case -3
ExitLoop
EndSwitch
WEnd
GUIDelete()
_SQLite_Exec(-1, "DROP TABLE aTest;") ; 删除表
_SQLite_Close()
_SQLite_Shutdown()
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
#forceref $hWnd, $iMsg, $iwParam
Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo, $s
$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
Local $iIndex = DllStructGetData($tNMHDR, 'Index')
Switch $iIDFrom
Case $hListView
Switch $iCode
Case $NM_CLICK;单击
$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
$iIndex = DllStructGetData($tInfo, "Index")
$x = DllStructGetData($tInfo, "X")
If ($x < 16) And (3 < $x) And (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES) Then;使用x坐标来判断是否在复选框上点击
If $aShowdata[$iIndex] = 4096 Then
$aShowdata[$iIndex] = 8192;4096未选中 8192选中
Else
$aShowdata[$iIndex] = 4096;4096未选中 8192选中
EndIf
$tInfo = DllStructCreate($tagNMLVDISPINFO, $ilParam)
DllStructSetData($tInfo, "State", $aShowdata[$iIndex]);设置复选框状态
;====立刻刷新复选框显示状态 重绘$iIndex-1到$iIndex+20的项
GUICtrlSendMsg($hListView, $LVM_REDRAWITEMS, $iIndex - 1, $iIndex + 20)
EndIf
Case -150, -177 ;$LVN_GETDISPINFOA = -150, $LVN_GETDISPINFOW = -177 请求显示数据
If Not IsArray($aShowdata) Then ContinueCase
$tInfo = DllStructCreate($tagNMLVDISPINFO, $ilParam)
$iIndex = Int(DllStructGetData($tInfo, "Item"))
$iSub = Int(DllStructGetData($tInfo, "SubItem"))
If (BitAND(_GUICtrlListView_GetExtendedListViewStyle($hListView), $LVS_EX_CHECKBOXES) = $LVS_EX_CHECKBOXES) Then
;===============设置复选框信息
DllStructSetData($tInfo, "Mask", BitOR($LVIF_STATE,DllStructGetData($tInfo, "Mask")))
DllStructSetData($tInfo, "StateMask", $LVIS_STATEIMAGEMASK)
DllStructSetData($tInfo, "State", $aShowdata[$iIndex])
EndIf
DllStructSetData($tText, "Text", $aShowdata[$iIndex][$iSub]);列数据放入$tText结构
DllStructSetData($tInfo, "Text", DllStructGetPtr($tText));用$tText结构的指针来设置列数据
DllStructSetData($tInfo, "TextMax", StringLen($aShowdata[$iIndex][$iSub]));设置列数据长度
Case $LVN_ODCACHEHINT;缓冲数据
If $bPage Then
GetData();listview被拉到底部时,请求加载新的数据
GUICtrlSendMsg($hListView, $LVM_SETITEMCOUNT, UBound($aShowdata), 0);新数据加载后,修改虚表显示的数据总数
EndIf
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY
Func GetData()
;==========采用分页模式取数据库数据
Local $hQuery, $aRow
Local $i = $iPageCount*($iPage-1), $b =True
_SQLite_Query(-1, "SELECT * FROM aTest limit "& $iPageCount & " offset " & $iPageCount*($iPage-1) & ";", $hQuery)
For $k = 0 To $iPageCount - 1
If _SQLite_FetchData($hQuery, $aRow) = $SQLITE_OK Then; 依次获取行
If $b Then
ReDim $aShowdata[$iPage * $iPageCount]
$iPage+=1;取一次数据分页数加1
$b = False
EndIf
$aShowdata[$i] = $aRow
$aShowdata[$i] = $aRow
$aShowdata[$i] = $aRow
$aShowdata[$i] = 4096;复选框状态 4096未选中 8192选中
$i+=1
Else
ConsoleWrite("表数据已经读取到底,将分页数据读取标志变量$bPage = False" & @CRLF)
$bPage = False
ExitLoop
EndIf
Next
_SQLite_QueryFinalize($hQuery)
;==========完毕
EndFunc
这个不错,有时间再研究研究。
页:
[1]