В зависимости от значений в виртуальном списке, необходимо его покрасить, например, если первая колонка = "error", то необходимо покрасить строку цветом.
Для сведения:
1. Строки для отображения в виртуальном списке создаются в $LVN_ODCACHEHINT - Кэш-массив $aResult
2. В $LVN_GETDISPINFOW данные из Кэш-массива $aResult непосредственно отображаются в виртуальном списке
3. Покраска строк происходит в $CDDS_ITEMPREPAINT
Проблема в том, что при покраске списка в $CDDS_ITEMPREPAINT, не удается правильно обратиться к источнику виртуального списка (базе данных), т.е. к кэш-массиву $aResult.
Пытался использовать переменную $n для этого, но до конца не получилось.
Например, при первом старте программы, при прорисовке строк в виртуальном списке, строка, где первая колонка = "error" красится.
Но если кликнуть покрашенную строку, а потом строку выше то выделение пропадает.
Я вижу (ConsoleWrite), что переменная $n (строка кэш-массива $aResult) не совпадает с индексом $iItem в $LVN_ODCACHEHINT, но не пойму как это исправить
Если кликнуть по покрашенной строке, потом кликнуть строку ниже, потом кликнуть снова первоначальную, то будет покрашено две строки, все по той же причине.
* При первом запуске примера, создается база данных в SQLite
Для сведения:
1. Строки для отображения в виртуальном списке создаются в $LVN_ODCACHEHINT - Кэш-массив $aResult
2. В $LVN_GETDISPINFOW данные из Кэш-массива $aResult непосредственно отображаются в виртуальном списке
3. Покраска строк происходит в $CDDS_ITEMPREPAINT
Проблема в том, что при покраске списка в $CDDS_ITEMPREPAINT, не удается правильно обратиться к источнику виртуального списка (базе данных), т.е. к кэш-массиву $aResult.
Пытался использовать переменную $n для этого, но до конца не получилось.
Например, при первом старте программы, при прорисовке строк в виртуальном списке, строка, где первая колонка = "error" красится.
Но если кликнуть покрашенную строку, а потом строку выше то выделение пропадает.
Я вижу (ConsoleWrite), что переменная $n (строка кэш-массива $aResult) не совпадает с индексом $iItem в $LVN_ODCACHEHINT, но не пойму как это исправить
Если кликнуть по покрашенной строке, потом кликнуть строку ниже, потом кликнуть снова первоначальную, то будет покрашено две строки, все по той же причине.
* При первом запуске примера, создается база данных в SQLite
Код:
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <SQLite.au3>
#include <Timers.au3>
#include <Color.au3>
; Create structure $tagNMLVCACHEHINT
Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
Global $hListView
; DB
$sFileDB = @ScriptDir & '\Data.db'
$TableName='lvdata'
; Load SQLite3.dll
_SQLite_Startup()
If @error Then Exit MsgBox(16, "SQLite Error", "SQLite3.dll Can't be Loaded")
; Create DB if not exist
If Not FileExists($sFileDB) Then ; Recreate data base
TrayTip('Создание БД','Подождите...',30,1)
$hStarttime=_Timer_Init()
_SQLite_Open( $sFileDB )
_SQLite_Exec( -1, "PRAGMA synchronous = OFF;" )
$sExec = 'Create Table lvdata (' & _
'[item_id] INTEGER PRIMARY KEY AUTOINCREMENT,' & _
'[f1] TEXT,' & _
'[f2] TEXT,' & _
'[f3] TEXT,' & _
'[f4] TEXT,' & _
'[f5] TEXT);'
_SQLite_Exec( -1, $sExec )
_SQLite_Exec( -1, "BEGIN TRANSACTION;" )
Local $Row=500000
Local $sData='test_value'
Local $sValues=''
Local $j=1
For $i=1 To $Row
$sValues&= "(" & $i & _
",'" & $sData & "'" & _
",'" & $sData & "'" & _
",'" & $sData & "'" & _
",'" & $sData & "'" & _
",'" & $sData & "')"
; Добавляем порциями по 100 строк для скорости
If $j=100 Then
_SQLite_Exec( -1, "INSERT INTO lvdata VALUES " & $sValues & ";" )
$sValues=''
$j=1
Else
$j+=1
If $i<>$Row Then $sValues&=','
EndIf
Next
If $sValues<>'' Then _SQLite_Exec( -1, "INSERT INTO lvdata VALUES " & $sValues & ";" )
_SQLite_Exec( -1, "COMMIT TRANSACTION;" )
_SQLite_Close( -1 )
ConsoleWrite(@CRLF&'Create DB, create strings, fill table: '&_Timer_Diff($hStarttime)/1000&@CRLF)
TrayTip('','',Default)
EndIf
; Open DB
$hDB=_SQLite_Open($sFileDB)
If @error Then Exit MsgBox(16, "SQLite Error", "Can't create a memory Database!")
; Test - Specially delete 5 records
_SQLite_Exec($hDB, 'Delete From '&$TableName&' Where item_id > 5 And item_id <= 10 ;')
; Test - for highlight color
_SQLite_Exec($hDB, 'UPDATE '&$TableName&' SET f1='&_SQLite_FastEscape('error')&' Where item_id = 5 ;')
; После удаления из таблицы записей (item_id > 5 и item_id <= 10), то первичный ключ будет не по порядку
; Для правильного отображения в ListView необходимо установить уникальную связь между строками в списке и строками в таблице
; 1. Создать БД DisplayMemDb в памяти,
; 2. Создать таблицу в памяти tRowRelation, UpdateVirtualListView()
; 3. "INNER JOIN" в сообщении $LVN_ODCACHEHINT в WM_NOTIFY()
; Create memory database DisplayMemDb
_SQLite_Exec($hDB, "ATTACH DATABASE ':memory:' AS DisplayMemDb;")
; GUI
$Form1 = GUICreate("Virtual ListViews", 520, 524, -1, -1)
; Virtual ListViews - $LVS_OWNERDATA, Reduces flicker - $LVS_EX_DOUBLEBUFFER
$ListView1 = GUICtrlCreateListView("", 8, 16, 500, 462, BitOR($LVS_OWNERDATA,$LVS_SHOWSELALWAYS), BitOR( $LVS_EX_GRIDLINES, $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT ))
$hListView = GUICtrlGetHandle($ListView1) ; Handle
; Add Columns
For $i = 0 To 5
_GUICtrlListView_AddColumn( $hListView, "Col" & $i, 75 )
Next
$Button1 = GUICtrlCreateButton("Button1", 200, 488, 75, 25)
GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
GUISetState(@SW_SHOW)
UpdateVirtualListView()
While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
EndSwitch
WEnd
; Update Virtual ListView
Func UpdateVirtualListView($SelectedPrimaryKey='')
_GUICtrlListView_BeginUpdate($hListView)
; Delete Table tRowRelation in memory database DisplayMemDb
_SQLite_Exec(-1,"DROP TABLE IF EXISTS DisplayMemDb.tRowRelation;")
; Create Table tRowRelation in memory database DisplayMemDb
Local $sExec='CREATE TABLE DisplayMemDb.tRowRelation AS SELECT item_id FROM lvdata;'
_SQLite_Exec(-1,$sExec)
; Update Virtual ListView
GUICtrlSendMsg( $ListView1, $LVM_SETITEMCOUNT, DB_Count(), 0 )
_GUICtrlListView_EndUpdate($hListView)
EndFunc
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
Local $tNMHDR, $hWndFrom, $iIDFrom, $iCode
Local $tInfo, $iIndex, $iSubItem
$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
$iCode = DllStructGetData($tNMHDR, "Code")
$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
$iIndex = DllStructGetData($tInfo, "Index")
$iSubItem = DllStructGetData($tInfo, "SubItem")
Local Static $aResult, $iRows, $iFrom
Local Static $n
Switch $hWndFrom
Case $hListView
Switch $iCode
; Уведомления $LVN_ODCACHEHINT и структура $tagNMLVCACHEHINT используется для вставки строк в кэш массива прежде чем они отобразятся с сообщениями $LVN_GETDISPINFO
Case $LVN_ODCACHEHINT
Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $ilParam ), $sSQL, $iColumns
$iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
; lvdata - название таблицы в БД
; item_id - первичный ключ
Local $sSQL = "SELECT lvdata.* FROM lvdata " & _
"INNER JOIN tRowRelation ON tRowRelation.item_id = lvdata.item_id " & _
"WHERE tRowRelation.rowid BETWEEN " & $iFrom + 1 & _
" And " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) + 1 & ";"
; Создает двумерный массив $aResult, содержащий имена столбцов и данные выполненного запроса
; $aResult является кэшом массива. Цель кэша - ограничить число строк SELECT выборки - это максимальное количество пунктов, которое может поместится в данном ListView
_SQLite_GetTable2d( -1, $sSQL, $aResult, $iRows, $iColumns )
ConsoleWrite(' --- UBound = '&UBound($aResult)&@CRLF)
$n=1
; View Records
Case $LVN_GETDISPINFOW
; Установить размерность данных в ячейках для виртуального списка
Local Static $tText = DllStructCreate("wchar[4094]") ; Колонка в ListView ограничена 4094 символами, поэтому нет смысла указывать больше
Local Static $pText = DllStructGetPtr($tText) ; Указатель на структуру
Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $ilParam )
If BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then
Local $nRow = DllStructGetData( $tNMLVDISPINFO, "Item" ) - $iFrom + 1 ; number row
Local $nCol = DllStructGetData($tNMLVDISPINFO, "subitem") ; number column
If $nRow > 0 And $nRow < $iRows + 1 Then
Local $sItem = $aResult[$nRow][DllStructGetData($tNMLVDISPINFO,"SubItem")]
DllStructSetData( $tText, 1, $sItem ) ; Текст в ячейке
DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) ; Указатель на строку, содержащую текст элемента
DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) ; Длина строки. Количество байтов в буфере, на которое указывает текст, включая ограничитель строки
EndIf
EndIf
Case $NM_CUSTOMDRAW
; Флаг изменений цвета в списке
Local Static $DRAWChange=0
Local $tNMLVCD = DllStructCreate($tagNMLVCUSTOMDRAW, $ilParam)
Local $iDrawStage = DllStructGetData($tNMLVCD, 'dwDrawStage')
Local $iItem = DllStructGetData($tNMLVCD, 'dwItemSpec') ; Индекс пункта
Local $iSubItem = DllStructGetData($tNMLVCD, 'iSubItem') ; Индекс подпункта
Switch $iDrawStage
Case $CDDS_PREPAINT
Return $CDRF_NOTIFYITEMDRAW
Case $CDDS_ITEMPREPAINT
; Вернуть значения по умолчанию, если были изменен: цвет
If $DRAWChange=1 Then
DllStructSetData($tNMLVCD, 'clrText', 0x000000) ; Black Текст
DllStructSetData($tNMLVCD, 'clrTextBk', 0xFFFFFF) ; White Фон
$DRAWChange=0 ; Флаг изменений цвета или шрифта в списке
EndIf
; Покрасить строку
If $iRows>0 And $n<$iRows+1 Then
ConsoleWrite('=== n = '&$n&' -> '&$aResult[$n][0]&' Index = '&$iItem &@CRLF)
If $aResult[$n][1]='error' Then ; Первая колонка
ConsoleWrite(' красим ---> '&$aResult[$n][0]&' Index = '&$iItem &@CRLF)
DllStructSetData($tNMLVCD, 'clrTextBk', _ColorSetCOLORREF(_ColorGetRGB(0xffffb5)))
$DRAWChange=1
EndIf
$n+=1
EndIf
Return $CDRF_NOTIFYSUBITEMDRAW
Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)
; Красим подпункты
Return $CDRF_NEWFONT
EndSwitch
EndSwitch
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
; Number of rows
Func DB_Count()
Local $aRow, $iRows = 0
_SQLite_QuerySingleRow( -1, "SELECT COUNT(*) FROM lvdata LIMIT 1;", $aRow )
If IsArray( $aRow ) Then $iRows = $aRow[0] + 1
Return $iRows
EndFunc