Что нового

Тормозит виртуальный ListView

pvnn

Осваивающий
Сообщения
305
Репутация
32
Доброго времени суток. Необходима помощь специалистов.

Есть виртуальный 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
 
Верх