关于listview虚表直接读取数据库的方法,求助修改范例成MSSQL的!!
本帖最后由 kk_lee69 于 2018-4-1 23:48 编辑关于listview虚表直接读取数据库的方法,求助修改范例成SQL的!!
官网有个范例 是listview虚表 直接拿SQLlite 的数据库 当作 listview虚表的数据 直接使用,这样的好处是 即使你的数据再多 也是分次 读取 就不会卡了
无奈 小弟 对于 SQLLITE的 UDF 实在没辙,我研究了半天 总是搞不懂原理
无法改成 把SQL DB 当作数据库来源的方法 ,所以上来求助
listview虚表 我已经很熟了所以理论上不应该是我不会使用,只是以前的方法都是读进
数组然后 利用数组 当作listview虚表 的数据源
只是最近遇到了 数据太多 读进数组太慢想要改成 分次读取 分次秀出的方法
所以才把脑筋动到了 数据库上……
以下是 范例程序 与 数据库麻烦 高手帮我改个范例
資料庫檔案如下:
或者 也可以利用 下面的檔案 建立資料庫
範例程式如下:
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <SQLite.au3>
Opt( "MustDeclareVars", 1 )
Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
Global $hLV
Example()
Func Example()
_SQLite_Startup()
; Check databases
Local $iRows1 = CheckDB( "Test1.db" )
Local $iRows2 = CheckDB( "Test2.db" )
Local $iRows3 = CheckDB( "Test3.db" )
Local $iRows
; Create GUI
GUICreate( "Virtual ListViews", 850, 400 )
; Create Tab
Local $idTab = GUICtrlCreateTab( 10, 10, 850-20, 400-20 )
GUICtrlCreateTabItem( "Test1.db: " & Format( $iRows1 ) & " rows" )
GUICtrlCreateTabItem( "Test2.db: " & Format( $iRows2 ) & " rows" )
GUICtrlCreateTabItem( "Test3.db: " & Format( $iRows3 ) & " rows" )
GUICtrlCreateTabItem( "" )
; Create ListView
Local $idLV = GUICtrlCreateListView( "", 20, 40, 850-40, 400-60, $LVS_OWNERDATA, BitOR( $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT ) )
$hLV = GUICtrlGetHandle( $idLV ) ; Virtual listview Reduces flicker
For $i = 0 To 9
_GUICtrlListView_AddColumn( $hLV, "Col" & $i, 75 )
Next
GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
GUISetState( @SW_SHOW )
; Data for first tab
$iRows = $iRows1
If $iRows Then _SQLite_Open( "Test1.db" )
GUICtrlSendMsg( $idLV, $LVM_SETITEMCOUNT, $iRows, 0 )
; Message loop
While 1
Switch GUIGetMsg()
Case $idTab
If $iRows Then _SQLite_Close( -1 )
Switch GUICtrlRead( $idTab )
Case 0
$iRows = $iRows1
If $iRows Then _SQLite_Open( "Test1.db" )
Case 1
$iRows = $iRows2
If $iRows Then _SQLite_Open( "Test2.db" )
Case 2
$iRows = $iRows3
If $iRows Then _SQLite_Open( "Test3.db" )
EndSwitch
GUICtrlSendMsg( $idLV, $LVM_SETITEMCOUNT, $iRows, 0 )
Case $GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd
If $iRows Then _SQLite_Close( -1 )
_SQLite_Shutdown()
GUIDelete()
EndFunc
Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
Local Static $tText = DllStructCreate( "wchar" )
Local Static $pText = DllStructGetPtr( $tText )
Local Static $aResult, $iRows, $iFrom
Local $tNMHDR, $hWndFrom, $iCode
$tNMHDR = DllStructCreate( $tagNMHDR, $lParam )
$hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) )
$iCode = DllStructGetData( $tNMHDR, "Code" )
Switch $hWndFrom
Case $hLV
Switch $iCode
Case $LVN_GETDISPINFOW
Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam )
If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then
Local $iIndex = DllStructGetData( $tNMLVDISPINFO, "Item" ) - $iFrom + 1
If $iIndex > 0 And $iIndex < $iRows + 1 Then
Local $sItem = $aResult[$iIndex]
DllStructSetData( $tText, 1, $sItem )
DllStructSetData( $tNMLVDISPINFO, "Text", $pText )
DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) )
EndIf
EndIf
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" ) & ";"
_SQLite_GetTable2d( -1, $sSQL, $aResult, $iRows, $iColumns )
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func CheckDB( $sDBname )
Local $aRow, $iRows = 0
If FileExists( $sDBname ) Then
_SQLite_Open( $sDBname )
_SQLite_QuerySingleRow( -1, "SELECT max(item_id) FROM lvdata;", $aRow )
_SQLite_Close( -1 )
EndIf
If IsArray( $aRow ) Then _
$iRows = $aRow + 1
Return $iRows
EndFunc
Func Format( $iInt )
Return StringRegExpReplace( $iInt, "(\A\d{1,3}(?=(\d{3})+\z)|\d{3}(?=\d))", "\1," )
EndFunc
回复 1# kk_lee69
最近一直用MYsql ,感觉很方便 。mssql还不会 既然這題 沒辦法改成 MSSQL那有沒有人 可以 改變一下 不要一次取的一筆資料我希望一次可以讀取一 百筆資料當作緩衝呢??? 回复 2# chzj589
就用SQL LISTE 好了 能否將範例中 每次讀取一筆到兩筆的緩衝 改成每次讀取100筆嗎?? 回复 5# kk_lee69
你有看一下 CreateDB.au3吗?
範例程式,是读取三个数据库
Local $iRows1 = CheckDB( "Test1.db" )
Local $iRows2 = CheckDB( "Test2.db" )
Local $iRows3 = CheckDB( "Test3.db" )
数据库里有几笔,就读几笔,不是吗? 回复 6# chzj589
當然數據庫有幾筆 就讀取幾筆
但是這個虛擬表的概念是先決定資料庫有 幾筆假設有1萬筆 就先設定 有一萬筆資 料
然後第一次 讀取 0-15 資料往後 你往下滑一格它就往後讀取資料庫裡面的下一筆資料
一次只讀取一筆然後 你往上了 捲動了 就從資料庫裡 再往前 讀取 一筆 資料
我不要一次 只讀取一筆資料這樣對資料庫來說重複的讀取 負擔太重
我希望一次 可以讀取 100筆資料 回复 7# kk_lee69
哪个範例程式? 回复 8# chzj589
就是上面的範例程式 回复 9# kk_lee69
不理解。
上面的範例程式历,不就是读取三个数据库?
我没安装SQL LISTE数据库编辑器,不知道建立的"Test1.db"是什么结构。 回复 10# chzj589
你沒有實際跑資料庫....你下載 資料庫3 就好跟我的範例程式放在一起
執行後切換到 第三個 TAB你就會知道 回复 11# kk_lee69
还是不理解,有什么不同
本帖最后由 kk_lee69 于 2018-4-7 21:48 编辑
回复 12# chzj589
你有注意到
WM_NOTIFY 裡面的$LVN_ODCACHEHINT 這個變化嗎??
你在 $LVN_ODCACHEHINT 下面 加上
ConsoleWrite($iFrom&" "&DllStructGetData( $tNMLVCACHEHINT, "iTo" )&@CRLF)
你就會看到一開始是
015
15 16
16 17
17 18
你每按往下它就會從資料庫裡面抓一筆資料出來
所以上面的程式 才能做到資料庫裡面幾十萬筆資料但是都不會卡頓
因為它一次只抓一筆資料 回复 13# kk_lee69
主要控制是这里:
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
传递包含执行查询的列名和数据的 2 维数组.
#include <SQLite.au3>
_SQLite_GetTable2d ( $hDB, $sSQL, ByRef $aResult, ByRef $iRows, ByRef $iColumns [, $iCharSize = -1 [, $bSwichDimensions = False]] )
参 数
$hDB 打开的数据库, 如为 -1, 则使用最后打开的数据库
$sSQL 要执行的 SQL 语句
$aResult 传递的结果
$iRows 传递的数据行数
$iColumns 传递的列数
$iCharSize [可选] 指定数据字段的最大尺寸
$bSwichDimensions [可选] 切换 $aResult 尺寸 回复 14# chzj589
我的理解是本来己经全部读取,只是控制显示条目而己。
不知对不?