Доброго времени суток. Необходима помощь специалистов.
Есть виртуальный ListView.
Источником данных является база данных SQLite.
Есть интерактивный поиск по Column1.
Если не использовать поиск, то тормозов нет. Однако если начать поиск, то перемещения по самому ListView происходит с тормозами.
Например, набираю в строке поиска 5555, отображается всего 10 записей, если кликнуть по ним мышкой и попробовать переместиться курсорными клавишами вверх-вниз, возникают жуткие тормоза.
Есть виртуальный ListView.
Источником данных является база данных SQLite.
Есть интерактивный поиск по Column1.
Если не использовать поиск, то тормозов нет. Однако если начать поиск, то перемещения по самому ListView происходит с тормозами.
Например, набираю в строке поиска 5555, отображается всего 10 записей, если кликнуть по ним мышкой и попробовать переместиться курсорными клавишами вверх-вниз, возникают жуткие тормоза.
Код:
#include <Timers.au3>
#include <SQLite.au3>
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <GUIListBox.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
_SQLite_Startup()
If @error Then Exit MsgBox(16, "Ошибка SQLite", "Не удалось загрузить SQLite.dll")
$sFileDB = @ScriptDir & '\Data.db'
$TableName='table1'
$TableView='View1'
Global $sSQL ; Неполный Текст SQL-запроса
; Структура $tagNMLVCACHEHINT используется для вставки строки в массиве кэша, прежде чем отобразиться с сообщениями $LVN_GETDISPINFO (WM_NOTIFY)
Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom"
; Создание тестовой БД
;~ FileDelete(@ScriptDir & '\Data.db') ; Чтобы пересоздать БД
If Not FileExists($sFileDB) Then
$Row=70000
$hStarttime=_Timer_Init()
$Line='дарановтрансовковранвичыээысывжыхгорsdcsd'
$sExec = 'BEGIN; Create Table table1 ([ID] INTEGER PRIMARY KEY AUTOINCREMENT, [f_1] TEXT,[f_2] TEXT,[f_3] TEXT,[f_4] TEXT,[f_5] TEXT );'
; Составить строку данных
For $i=0 To $Row-1
$ind=Random(5,25,1)
$sData=StringMid($Line,$ind)
$sExec &= 'INSERT INTO '&$TableName&' (f_1,f_2,f_3,f_4,f_5) VALUES ("' & $sData&'","'&$sData&'","'&$sData&'","'&$sData&'","'&$sData& '");'
Next
$sExec &= 'COMMIT;'
ConsoleWrite(@CRLF&'Создание строки: '&_Timer_Diff($hStarttime)/1000&@CRLF)
; Заполнить таблицу
$hStarttime=_Timer_Init()
$hDB = _SQLite_Open($sFileDB)
_SQLite_Exec( -1, "PRAGMA synchronous = OFF;" ) ; sqlite не будет ждать подтверждения записи
_SQLite_Exec($hDB, $sExec)
_SQLite_Close($hDB)
ConsoleWrite(@CRLF&'Добавление записей в БД: '&_Timer_Diff($hStarttime)/1000&@CRLF)
EndIf
; GUI
$Form1 = GUICreate("Form1", 803, 457, -1, -1)
Global $hListView= GUICtrlCreateListView("", 8, 24, 785, 383, BitOR($LVS_OWNERDATA,$LVS_SHOWSELALWAYS))
_GUICtrlListView_SetExtendedListViewStyle(-1, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES))
$hLV = GUICtrlGetHandle( $hListView ) ; Virtual listview Reduces flicker
_GUICtrlListView_AddColumn( $hLV, "Column1", 50 )
_GUICtrlListView_AddColumn( $hLV, "Column2", 100 )
_GUICtrlListView_AddColumn( $hLV, "Column3", 100 )
_GUICtrlListView_AddColumn( $hLV, "Column4", 100 )
_GUICtrlListView_AddColumn( $hLV, "Column5", 100 )
_GUICtrlListView_AddColumn( $hLV, "Column6", 100 )
; Поиск данных
$InpRecord = GUICtrlCreateInput("", 8, 416, 249, 21)
GUICtrlSetState(-1,$GUI_FOCUS) ; Фокуc на поле
GUICtrlSetBkColor(-1, 0xFFFFE1)
$hInput = GUICtrlGetHandle( $InpRecord )
$InputChange = GUICtrlCreateDummy() ; Идентификатор (controlID) нового элемента
GUIRegisterMsg( $WM_COMMAND, "ON_Change") ; "ON_Change" - возможность динамического чтения данных из контрола во время ввода данных
$hStarttime=_Timer_Init()
GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
GUISetState(@SW_SHOW)
; Выполнить SQL-запрос
Query('SELECT * FROM '&$TableName&';')
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $InputChange
$sInput = GUICtrlRead( $InpRecord ) ; Считать данные из контрола
Query('SELECT * FROM '&$TableName&' WHERE UPPER(id) like UPPER("'&$sInput&'%")'&' ;')
$IndexListView=_GUICtrlListView_GetSelectedIndices($hListView) ; Определяем Индекс выделенной записи
If StringLen($IndexListView)=0 Then _GUICtrlListView_SetItemSelected($hListView,0 ,True) ; Выделить пункт
EndSwitch
WEnd
; Создаем событие при изменении элемента $hInput
Func ON_Change( $hWnd, $iMsg, $wParam, $lParam )
Local $hWndFrom = $lParam
Local $iCode = BitShift( $wParam, 16 ) ; High word
Switch $hWndFrom
; Input
Case $hInput
Switch $iCode
Case $EN_CHANGE ; Изменение данных в контроле
GUICtrlSendToDummy( $InputChange ) ; Посылает сообщения элементу Dummy => Case $InputChange
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func Query($sQuery)
Local $aRow, $iRows = 0
ConsoleWrite(@CRLF&$sQuery)
; Создать представление
_SQLite_Open($sFileDB)
ConsoleWrite(@CRLF&'DROP VIEW IF EXISTS '&$TableView&'; CREATE VIEW '&$TableView&' AS '&$sQuery)
_SQLite_Exec (-1, 'DROP VIEW IF EXISTS '&$TableView&'; CREATE VIEW '&$TableView&' AS '&$sQuery) ; Создать Представление
; Отобразить результат Представления
$sSQL='SELECT * FROM '&$TableView
ConsoleWrite(@CRLF&$sSQL)
; Узнать Общее количество строк для полосы прокрутки
_SQLite_QuerySingleRow( -1, 'SELECT COUNT(*) FROM '&$TableView&' LIMIT 1;', $aRow )
_SQLite_Close( -1 )
If IsArray( $aRow ) Then $iRows = $aRow[0] + 1
If $iRows Then $hDB=_SQLite_Open($sFileDB)
ConsoleWrite(@CRLF&'Количество записей: '&$iRows&@CRLF)
; Обновить Virtual ListView
GUICtrlSendMsg( $hListView, $LVM_SETITEMCOUNT, $iRows, 0 ) ; Указать количество строк для отображения в виртуальном ListView
EndFunc
Func CheckRows($Table)
Local $aRow, $iRows = 0
_SQLite_Open($sFileDB)
_SQLite_QuerySingleRow( -1, 'SELECT COUNT(*) FROM '&$Table&' LIMIT 1;', $aRow )
_SQLite_Close( -1 )
If IsArray( $aRow ) Then $iRows = $aRow[0] + 1
Return $iRows ; Количество записей в таблице
EndFunc
Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
Local Static $tText = DllStructCreate( "wchar[50]" )
Local Static $pText = DllStructGetPtr( $tText )
Local Static $aResult, $iRows, $iFrom
Local $VisibleRow
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_ODCACHEHINT ; $aResult является кэш массива. Цель кэша, чтобы ограничить число строк. Виртуальный ListView никогда не обновлять более видимой числа строк за один раз.
Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam ), $iColumns
$iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
$VisibleRow=_GUICtrlListView_GetCounterPage($hListView) ; Вычисляет количество пунктов, которые могут вертикально поместиться в видимой области
Local $sSQL2=$sSQL&' limit '&$VisibleRow&' OFFSET '&$iFrom& ';'
_SQLite_GetTable2d( -1, $sSQL2, $aResult, $iRows, $iColumns )
Case $LVN_GETDISPINFOW
Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam )
If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then
Local $iIndex = DllStructGetData($tNMLVDISPINFO, "item") - $iFrom + 1 ; Номер строки
Local $nCol = DllStructGetData($tNMLVDISPINFO, "subitem") ; Номер столбца
If $iIndex > 0 And $iIndex < $iRows + 1 Then
Local $sItem = $aResult[$iIndex][$nCol]
DllStructSetData( $tText, 1, $sItem )
DllStructSetData( $tNMLVDISPINFO, "Text", $pText )
DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) )
EndIf
EndIf
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc