Jump to content

Virtual listviews for huge number of rows


Recommended Posts

Here you are:

#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <SQLite.au3>
#include <Timers.au3>
#include <Array.au3>

Opt( "MustDeclareVars", 1 )

Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
Global $TableName, $hListView, $hListView2, $hInput, $idInputChange

Example()

Func Example()
  _SQLite_Startup()
  If @error Then Exit MsgBox(16, "Error SQLite", "SQLite.dll")

  $TableName = 'table1'
  Local $sFileDB = @ScriptDir & '\Data.db', $iRows=100000
  If Not FileExists($sFileDB) Then
    Local $hStarttime=_Timer_Init(), $Line='tuysdufysdfsduyfiusydfisdyfiusfdsdf', $sData
    Local $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 );'
    ConsoleWrite( @CRLF & 'Create database ... : ' )
    ; Create string
    For $i=0 To $iRows-1
        $sData=StringMid($Line,Random(5,25,1))
        $sExec &= 'INSERT INTO '&$TableName&' (f_1,f_2,f_3,f_4,f_5) VALUES ("' & $sData&'","'&$sData&'","'&$sData&'","'&$sData&'","'&$sData& '");'
    Next
    $sExec &= 'COMMIT;'
    ; Create Table
    Local $hDB = _SQLite_Open($sFileDB), $hStarttime=_Timer_Init()
    _SQLite_Exec( -1, "PRAGMA synchronous = OFF;" )
    _SQLite_Exec($hDB, $sExec)
    _SQLite_Close($hDB)
    ConsoleWrite( _Timer_Diff($hStarttime) / 1000 & @CRLF )
  EndIf
  _SQLite_Open($sFileDB)
  _SQLite_Exec( -1, "ATTACH DATABASE ':memory:' AS DisplayMemDb;" )
  _SQLite_Exec( -1, "CREATE TABLE DisplayMemDb.SearchRes AS SELECT * FROM " & $TableName & " WHERE UPPER(ID) like UPPER('5555%');" )
  #cs
  Local $aMyResult, $iMyRows, $iMyColumns, $aRow
  _SQLite_GetTable2d( -1, "SELECT rowid,* FROM DisplayMemDb.SearchRes;", $aMyResult, $iMyRows, $iMyColumns )
  _SQLite_QuerySingleRow( -1, "SELECT COUNT(*) FROM DisplayMemDb.SearchRes;", $aRow ) ; Item count
  If IsArray( $aRow ) Then ConsoleWrite( "$iRows = " & $aRow[0] & @CRLF )
  _ArrayDisplay( $aMyResult )
  #ce

  Local $Form1 = GUICreate("Form1", 803, 457, -1, -1)

  Local $idListView = GUICtrlCreateListView("", 8, 24, 785, 383, BitOR($LVS_OWNERDATA,$LVS_SHOWSELALWAYS))
  _GUICtrlListView_SetExtendedListViewStyle(-1, BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
  _GUICtrlListView_AddColumn( $idListView, "Column1",  50 )
  _GUICtrlListView_AddColumn( $idListView, "Column2",  100 )
  _GUICtrlListView_AddColumn( $idListView, "Column3",  100 )
  _GUICtrlListView_AddColumn( $idListView, "Column4",  100 )
  _GUICtrlListView_AddColumn( $idListView, "Column5",  100 )
  _GUICtrlListView_AddColumn( $idListView, "Column6",  100 )
  $hListView = GUICtrlGetHandle( $idListView )

  Local $idListView2 = GUICtrlCreateListView("", 8, 24, 785, 383, BitOR($LVS_OWNERDATA,$LVS_SHOWSELALWAYS))
  _GUICtrlListView_SetExtendedListViewStyle(-1, BitOR($LVS_EX_DOUBLEBUFFER, $LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))
  _GUICtrlListView_AddColumn( $idListView2, "Column1",  50 )
  _GUICtrlListView_AddColumn( $idListView2, "Column2",  50 )
  _GUICtrlListView_AddColumn( $idListView2, "Column3",  100 )
  _GUICtrlListView_AddColumn( $idListView2, "Column4",  100 )
  _GUICtrlListView_AddColumn( $idListView2, "Column5",  100 )
  _GUICtrlListView_AddColumn( $idListView2, "Column6",  100 )
  _GUICtrlListView_AddColumn( $idListView2, "Column7",  100 )
  $hListView2 = GUICtrlGetHandle( $idListView2 )
  GUICtrlSetState( $idListView2, $GUI_HIDE )

  Local $idInput = GUICtrlCreateInput("", 8, 416, 249, 21)
  GUICtrlSetState(-1,$GUI_FOCUS)
  $hInput = GUICtrlGetHandle( $idInput )
  $idInputChange = GUICtrlCreateDummy()
  GUIRegisterMsg( $WM_COMMAND, "WM_COMMAND" )

  GUISetState()
  GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
  GUICtrlSendMsg( $idListView, $LVM_SETITEMCOUNT, $iRows, 0 )

  Local $bFirst = True
  While 1
    Switch GUIGetMsg()
      Case $idInputChange
        Local $sInput = GUICtrlRead( $idInput ) ; Get control data
        If $sInput Then
          If $bFirst Then
            GUICtrlSetState( $idListView, $GUI_HIDE )
            GUICtrlSetState( $idListView2, $GUI_SHOW )
            $bFirst = False
          EndIf
          Local $aRow
          _SQLite_Exec( -1, "DROP TABLE DisplayMemDb.SearchRes;" )
          _SQLite_Exec( -1, 'CREATE TABLE DisplayMemDb.SearchRes AS SELECT * FROM ' & $TableName & ' WHERE UPPER(ID) like UPPER("'&$sInput&'%");' )
          _SQLite_QuerySingleRow( -1, "SELECT COUNT(*) FROM DisplayMemDb.SearchRes;", $aRow ) ; Item count
          GUICtrlSendMsg( $idListView2, $LVM_SETITEMCOUNT, Int($aRow[0]), 0 )
        Else
          GUICtrlSetState( $idListView2, $GUI_HIDE )
          GUICtrlSetState( $idListView, $GUI_SHOW )
          $bFirst = True
        EndIf

      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd

  GUIDelete( $Form1 )
  Exit
EndFunc

; Change $hInput
Func WM_COMMAND( $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( $idInputChange ) ; => Case $idInputChange
      EndSwitch
  EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc

Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
  Local Static $tText = DllStructCreate( "wchar[100]" )
  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 $hListView
      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   ; number row
            Local $nCol = DllStructGetData($tNMLVDISPINFO, "subitem")               ; number column
            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

        Case $LVN_ODCACHEHINT
          Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam ), $iColumns
          $iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
          _SQLite_GetTable2d( -1, "SELECT * FROM " & $TableName & " WHERE ID BETWEEN " & $iFrom + 1 & " And " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) + 1 & ";", $aResult, $iRows, $iColumns )
      EndSwitch

    Case $hListView2
      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   ; number row
            Local $nCol = DllStructGetData($tNMLVDISPINFO, "subitem")               ; number column
            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

        Case $LVN_ODCACHEHINT
          Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam ), $iColumns
          $iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
          _SQLite_GetTable2d( -1, "SELECT rowid,* FROM DisplayMemDb.SearchRes WHERE rowid BETWEEN " & $iFrom + 1 & " And " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) + 1 & ";", $aResult, $iRows, $iColumns )
      EndSwitch
 EndSwitch
  Return $GUI_RUNDEFMSG
EndFunc

The example shows a way to implement a search box. You can search for numbers in the first column: 1 - 100000. As soon as you enter a number into the search box the listview is replaced with a new listview with an additional column. Column 1 is the row numbers. Columns 2-7 are the result of the search. If you search for the number 1001 the result is the numbers 1001 and 10010 - 10019. A total of 11 rows.

Edited by LarsJ
Explanation below code
Link to post
Share on other sites
  • Replies 139
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

Virtual listviews are lightning fast and can handle millions of rows. Virtual listviews are of interest when you have to insert more than 10,000 rows. When there are less than 10,000 rows, the st

Of course +1 must be added to $iFrom and $iTo. Because your item_id's starts at item_id = 1 and my item_id's starts at item_id = 0.   Sorting columns by clicking the column header. I would do i

You certainly can. Your code is well structured. Easy to read and understand. I like that. There are a few minor issues and one major issue. A virtual listview must include the $LVS_OWNERDATA sty

Posted Images

pvnn, You are welcome.

 

There is one more major issue in the code in posts 34 and 35: There is not defined a primary key in the database table. The lack of a primary key has serious performance implications when there are more than 62 rows for each treeview item. This is evident in the code in post 35 with 6200 rows for each treeview item. If you select a row in the listview, navigating with the arrow keys is extremely slow.

In the examples below the name-field is set as primary key, and the performance is much, much better. Especially the JOIN clause in the SQL SELECT statement for $LVN_ODCACHEHINT events performs significantly better when a primary key is defined.

This is a copy of the code from post 35, and a primary key is added to the SSDB table (delete a previous database before you run the code):

#include <GuiListView.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiTreeView.au3>
#include <SQLite.au3>
#include <Math.au3>

Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
Global $aListView, $hListView, $TreeView_SelTitle

ConsoleWrite( "Initializing database ..." & @CRLF )
DBInit()

Opt("GUIOnEventMode", 1)
#Region ### START Koda GUI section ### Form=
Global $Form1 = GUICreate("Form1", 881, 516, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")
Global $TreeView = GUICtrlCreateTreeView(8, 16, 319, 489, BitOR($GUI_SS_DEFAULT_TREEVIEW,$TVS_FULLROWSELECT,$WS_HSCROLL,$WS_VSCROLL,$WS_BORDER), BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE))
Global $TreeView_Root_1 = GUICtrlCreateTreeViewItem("root - 1", $TreeView)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_1 = GUICtrlCreateTreeViewItem("111", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_2 = GUICtrlCreateTreeViewItem("222", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_3 = GUICtrlCreateTreeViewItem("333", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_Root_2 = GUICtrlCreateTreeViewItem("root - 2", $TreeView)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_4 = GUICtrlCreateTreeViewItem("444", $TreeView_Root_2)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_5 = GUICtrlCreateTreeViewItem("555", $TreeView_Root_2)
GUICtrlSetOnEvent(-1, "TreeView1Click")
;Global $ListView = GUICtrlCreateListView("Rowid|Name|Time|Category", 336, 16, 538, 486, BitOR($GUI_SS_DEFAULT_LISTVIEW,$LVS_ALIGNLEFT,$WS_HSCROLL,$WS_VSCROLL,$WS_BORDER), BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE,$LVS_EX_FULLROWSELECT))
Global $ListView = GUICtrlCreateListView("Rowid|Name|Time|Category", 336, 16, 538, 486, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE)) ; $LVS_OWNERDATA must be included for a virtual listview
_GUICtrlListView_SetExtendedListViewStyle( $ListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT )
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 200)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 2, 88)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 3, 112)
GUICtrlSetOnEvent(-1, "ListViewClick")
GUIRegisterMsg($WM_NOTIFY, "LWS_WM_NOTIFY")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
$hListView = GUICtrlGetHandle($ListView)
_GUICtrlTreeView_Expand($TreeView, $TreeView_Root_1, True)
While 1
    Sleep(100)
WEnd

Func Form1Close()
    GUIRegisterMsg( $WM_NOTIFY, "" )
    ;
    Exit
EndFunc
;==========================================================================================
Func ListViewClick()

EndFunc
;==========================================================================================
Func TreeView1Click()
    Local $sQuery, $aResult, $iRows, $iColumns
    Static Local $TreeView_SelTitlePRE = ""

    If $TreeView_SelTitlePRE == "" Then
        $TreeView_Selected = _GUICtrlTreeView_GetFirstChild($TreeView, $TreeView_Root_1)
        _GUICtrlTreeView_ClickItem($TreeView, $TreeView_Selected, "left")
    Else
        $TreeView_Selected = _GUICtrlTreeView_GetSelection($TreeView)
    EndIf
    $TreeView_SelTitle = _GUICtrlTreeView_GetText($TreeView, $TreeView_Selected)
    If $TreeView_SelTitle == $TreeView_SelTitlePRE Then
        Return
    Else
        $TreeView_SelTitlePRE = $TreeView_SelTitle
    EndIf

    ConsoleWrite($TreeView_SelTitle & @CRLF)

    $sQuery = "SELECT count(Title) FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "'"
    _SQLite_GetTable(-1, $sQuery, $aResult, $iRows, $iColumns)
    ;GUICtrlSendMsg( $hListView, $LVM_SETITEMCOUNT, $aResult[2], 0 )
    ConsoleWrite("Rows = " & $aResult[2] & @CRLF)

    _SQLite_Exec( -1, "DROP VIEW DisplayView;" )
    _SQLite_Exec( -1, "DROP TABLE DisplayMemDb.RowRelation;" )

    _SQLite_Exec( -1, "CREATE TEMP VIEW DisplayView AS SELECT Name,Time,Category FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "';" )
    _SQLite_Exec( -1, "CREATE TABLE DisplayMemDb.RowRelation AS SELECT Name FROM DisplayView;" )

    GUICtrlSendMsg( $ListView, $LVM_SETITEMCOUNT, Int($aResult[2]), 0 ) ; GUICtrlSendMsg works with control IDs only, $aResult[2] (string) must be an integer

EndFunc
;==========================================================================================
Func DBInit()
    Local $aResult, $iRows, $iColumns

;------------------------------------------------------------------------------------------
    Local $sPathTo_SSDB = @ScriptDir & "\SSDB.sqlite"
    Local $sPathTo_SQLiteDLL = @ScriptDir & "\sqlite3.dll"
    Global $sSqlBuild_Table = "(Title, Name, Time, Category, column_05, column_06, column_07, column_08)"
;------------------------------------------------------------------------------------------
    _SQLite_Startup($sPathTo_SQLiteDLL)
    If FileExists($sPathTo_SSDB) Then
      $hSSDB = _SQLite_Open($sPathTo_SSDB)
    Else
      $hSSDB = _SQLite_Open($sPathTo_SSDB)
;------------------------------------------------------------------------------------------
      _SQLite_Exec($hSSDB, "CREATE TABLE IF NOT EXISTS SSDB (Title, Name PRIMARY KEY, Time, Category, column_05, column_06, column_07, column_08);")
;------------------------------------------------------------------------------------------
      $sQuery = ""
      For $i = 1 To 5
          $sQuery &= 'INSERT INTO SSDB ' & $sSqlBuild_Table & ' VALUES '
          $sTitle = String($i) & String($i) & String($i)
          If $i = 1 Then
            For $j = 0 To 6200
                $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
                $sQuery &= ",'','','',''),"
            Next
          Else
            For $j = 0 To 6200
                $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
                $sQuery &= ",'','','',''),"
            Next
          EndIf
          $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
          $sQuery &= ",'','','','');"
      Next
      If Not (_SQLite_Exec(-1, $sQuery) = $SQLITE_OK) Then Return SetError(2)
    EndIf

    _SQLite_Exec( -1, "ATTACH DATABASE ':memory:' AS DisplayMemDb;" ) ; <<<<<<<<<<<<<<<<<<<
    _SQLite_Exec( -1, "CREATE TEMP VIEW DisplayView AS SELECT Name,Time,Category FROM SSDB WHERE Title IS '111';" )
    _SQLite_Exec( -1, "CREATE TABLE DisplayMemDb.RowRelation AS SELECT Name FROM DisplayView;" )
EndFunc
;==========================================================================================
Func LWS_WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
    Local Static $tText = DllStructCreate( "wchar[512]" )
    Local Static $pText = DllStructGetPtr( $tText )
    Local Static $aResult, $iRows, $iFrom

    Local $tNMHDR, $hWndFrom, $iCode, $tInfo, $VKey
    $tNMHDR = DllStructCreate( $tagNMHDR, $lParam )
    $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) )
    $iCode = DllStructGetData( $tNMHDR, "Code" )

    Switch $hWndFrom
        Case $hListView
            Switch $iCode

                Case $NM_CUSTOMDRAW
                    Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $dwDrawStage = DllStructGetData($tNMLVCUSTOMDRAW, "dwDrawStage")
                    Local $dwItemSpec  = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec")

                    Switch $dwDrawStage                ; Holds a value that specifies the drawing stage

                        Case $CDDS_PREPAINT
                            ; Before the paint cycle begins
                            Return $CDRF_NOTIFYITEMDRAW    ; Notify the parent window of any item-related drawing operations

                        Case $CDDS_ITEMPREPAINT
                            ; Before painting an item
                            If Mod( $dwItemSpec, 2 ) = 0 Then
                                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xFFFFFF )
                            Else
                                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xF8FFF8 )
                            EndIf
                            Return $CDRF_NEWFONT           ; $CDRF_NEWFONT must be returned after changing font or colors
                    EndSwitch

                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][DllStructGetData($tNMLVDISPINFO,"SubItem")]
                          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 Name,Time,Category FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "' AND item_id >= " & $iFrom & " AND item_id <= " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) & ";"
                    Local $sSQL = "SELECT RowRelation.rowid,DisplayView.Name,Time,Category FROM DisplayView INNER JOIN RowRelation ON DisplayView.Name = RowRelation.Name WHERE RowRelation.rowid BETWEEN " & $iFrom + 1 & " And " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) + 1 & ";"
                    _SQLite_GetTable2d( -1, $sSQL, $aResult, $iRows, $iColumns )

            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc

 

The importance of a primary key is demonstrated in the example below where a much larger table is created. These For loops are used to create the table:

For $i = 1 To 5
  $sQuery &= 'INSERT INTO SSDB ' & $sSqlBuild_Table & ' VALUES '
  $sTitle = String($i) & String($i) & String($i)
  If $i = 1 Then
    For $j = 0 To 620000
      $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
      $sQuery &= ",'','','',''),"
    Next
  Else
    For $j = 0 To 62000
      $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
      $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
      $sQuery &= ",'','','',''),"
    Next
  EndIf
  $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
  $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
  $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
  $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
  $sQuery &= ",'','','','');"
Next

Note the first loop that creates 620,000 rows. It takes a minute to create the database. It uses 48 MB of disk space. It contains a total of 868,010 rows. When you click the 111-item (620,000 rows) in the treeview it takes a second to fill the listview. Even on my old Windows XP these 620,000 rows are flying over the screen. Both using the mouse and the keyboard.

Full code (delete the small database before you create the large one):

#include <GuiListView.au3>
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiTreeView.au3>
#include <SQLite.au3>
#include <Math.au3>

Global Const $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
Global $aListView, $hListView, $TreeView_SelTitle

ConsoleWrite( "Initializing database ..." & @CRLF )
DBInit()

Opt("GUIOnEventMode", 1)
#Region ### START Koda GUI section ### Form=
Global $Form1 = GUICreate("Form1", 881, 516, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")
Global $TreeView = GUICtrlCreateTreeView(8, 16, 319, 489, BitOR($GUI_SS_DEFAULT_TREEVIEW,$TVS_FULLROWSELECT,$WS_HSCROLL,$WS_VSCROLL,$WS_BORDER), BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE))
Global $TreeView_Root_1 = GUICtrlCreateTreeViewItem("root - 1", $TreeView)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_1 = GUICtrlCreateTreeViewItem("111", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_2 = GUICtrlCreateTreeViewItem("222", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_3 = GUICtrlCreateTreeViewItem("333", $TreeView_Root_1)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_Root_2 = GUICtrlCreateTreeViewItem("root - 2", $TreeView)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_4 = GUICtrlCreateTreeViewItem("444", $TreeView_Root_2)
GUICtrlSetOnEvent(-1, "TreeView1Click")
Global $TreeView_5 = GUICtrlCreateTreeViewItem("555", $TreeView_Root_2)
GUICtrlSetOnEvent(-1, "TreeView1Click")
;Global $ListView = GUICtrlCreateListView("Rowid|Name|Time|Category", 336, 16, 538, 486, BitOR($GUI_SS_DEFAULT_LISTVIEW,$LVS_ALIGNLEFT,$WS_HSCROLL,$WS_VSCROLL,$WS_BORDER), BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE,$LVS_EX_FULLROWSELECT))
Global $ListView = GUICtrlCreateListView("Rowid|Name|Time|Category", 336, 16, 538, 486, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE,$WS_EX_STATICEDGE)) ; $LVS_OWNERDATA must be included for a virtual listview
_GUICtrlListView_SetExtendedListViewStyle( $ListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT )
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 0, 100)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 1, 200)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 2, 88)
GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, 3, 112)
GUICtrlSetOnEvent(-1, "ListViewClick")
GUIRegisterMsg($WM_NOTIFY, "LWS_WM_NOTIFY")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
$hListView = GUICtrlGetHandle($ListView)
_GUICtrlTreeView_Expand($TreeView, $TreeView_Root_1, True)
While 1
    Sleep(100)
WEnd

Func Form1Close()
    GUIRegisterMsg( $WM_NOTIFY, "" )
    ;
    Exit
EndFunc
;==========================================================================================
Func ListViewClick()

EndFunc
;==========================================================================================
Func TreeView1Click()
    Local $sQuery, $aResult, $iRows, $iColumns
    Static Local $TreeView_SelTitlePRE = ""

    If $TreeView_SelTitlePRE == "" Then
        $TreeView_Selected = _GUICtrlTreeView_GetFirstChild($TreeView, $TreeView_Root_1)
        _GUICtrlTreeView_ClickItem($TreeView, $TreeView_Selected, "left")
    Else
        $TreeView_Selected = _GUICtrlTreeView_GetSelection($TreeView)
    EndIf
    $TreeView_SelTitle = _GUICtrlTreeView_GetText($TreeView, $TreeView_Selected)
    If $TreeView_SelTitle == $TreeView_SelTitlePRE Then
        Return
    Else
        $TreeView_SelTitlePRE = $TreeView_SelTitle
    EndIf

    ConsoleWrite($TreeView_SelTitle & @CRLF)

    $sQuery = "SELECT count(Title) FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "'"
    _SQLite_GetTable(-1, $sQuery, $aResult, $iRows, $iColumns)
    ;GUICtrlSendMsg( $hListView, $LVM_SETITEMCOUNT, $aResult[2], 0 )
    ConsoleWrite("Rows = " & $aResult[2] & @CRLF)

    _SQLite_Exec( -1, "DROP VIEW DisplayView;" )
    _SQLite_Exec( -1, "DROP TABLE DisplayMemDb.RowRelation;" )

    _SQLite_Exec( -1, "CREATE TEMP VIEW DisplayView AS SELECT Name,Time,Category FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "';" )
    _SQLite_Exec( -1, "CREATE TABLE DisplayMemDb.RowRelation AS SELECT Name FROM DisplayView;" )

    GUICtrlSendMsg( $ListView, $LVM_SETITEMCOUNT, Int($aResult[2]), 0 ) ; GUICtrlSendMsg works with control IDs only, $aResult[2] (string) must be an integer

EndFunc
;==========================================================================================
Func DBInit()
    Local $aResult, $iRows, $iColumns

;------------------------------------------------------------------------------------------
    Local $sPathTo_SSDB = @ScriptDir & "\SSDB.sqlite"
    Local $sPathTo_SQLiteDLL = @ScriptDir & "\sqlite3.dll"
    Global $sSqlBuild_Table = "(Title, Name, Time, Category, column_05, column_06, column_07, column_08)"
;------------------------------------------------------------------------------------------
    _SQLite_Startup($sPathTo_SQLiteDLL)
    If FileExists($sPathTo_SSDB) Then
      $hSSDB = _SQLite_Open($sPathTo_SSDB)
    Else
      $hSSDB = _SQLite_Open($sPathTo_SSDB)
;------------------------------------------------------------------------------------------
      _SQLite_Exec($hSSDB, "CREATE TABLE IF NOT EXISTS SSDB (Title, Name PRIMARY KEY, Time, Category, column_05, column_06, column_07, column_08);")
;------------------------------------------------------------------------------------------
      $sQuery = ""
      For $i = 1 To 5
          $sQuery &= 'INSERT INTO SSDB ' & $sSqlBuild_Table & ' VALUES '
          $sTitle = String($i) & String($i) & String($i)
          If $i = 1 Then
            For $j = 0 To 620000
                $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
                $sQuery &= ",'','','',''),"
            Next
          Else
            For $j = 0 To 62000
                $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
                $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
                $sQuery &= ",'','','',''),"
            Next
          EndIf
          $sQuery &= "('" & StringRegExpReplace($sTitle, "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace($sTitle & "_" & $j, "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace("12345", "'", "''") & "'"
          $sQuery &= ",'" & StringRegExpReplace("123", "'", "''") & "'"
          $sQuery &= ",'','','','');"
      Next
      If Not (_SQLite_Exec(-1, $sQuery) = $SQLITE_OK) Then Return SetError(2)
    EndIf

    _SQLite_Exec( -1, "ATTACH DATABASE ':memory:' AS DisplayMemDb;" ) ; <<<<<<<<<<<<<<<<<<<
    _SQLite_Exec( -1, "CREATE TEMP VIEW DisplayView AS SELECT Name,Time,Category FROM SSDB WHERE Title IS '111';" )
    _SQLite_Exec( -1, "CREATE TABLE DisplayMemDb.RowRelation AS SELECT Name FROM DisplayView;" )
EndFunc
;==========================================================================================
Func LWS_WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
    Local Static $tText = DllStructCreate( "wchar[512]" )
    Local Static $pText = DllStructGetPtr( $tText )
    Local Static $aResult, $iRows, $iFrom

    Local $tNMHDR, $hWndFrom, $iCode, $tInfo, $VKey
    $tNMHDR = DllStructCreate( $tagNMHDR, $lParam )
    $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) )
    $iCode = DllStructGetData( $tNMHDR, "Code" )

    Switch $hWndFrom
        Case $hListView
            Switch $iCode

                Case $NM_CUSTOMDRAW
                    Local $tNMLVCUSTOMDRAW = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
                    Local $dwDrawStage = DllStructGetData($tNMLVCUSTOMDRAW, "dwDrawStage")
                    Local $dwItemSpec  = DllStructGetData($tNMLVCUSTOMDRAW, "dwItemSpec")

                    Switch $dwDrawStage                ; Holds a value that specifies the drawing stage

                        Case $CDDS_PREPAINT
                            ; Before the paint cycle begins
                            Return $CDRF_NOTIFYITEMDRAW    ; Notify the parent window of any item-related drawing operations

                        Case $CDDS_ITEMPREPAINT
                            ; Before painting an item
                            If Mod( $dwItemSpec, 2 ) = 0 Then
                                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xFFFFFF )
                            Else
                                DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", 0xF8FFF8 )
                            EndIf
                            Return $CDRF_NEWFONT           ; $CDRF_NEWFONT must be returned after changing font or colors
                    EndSwitch

                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][DllStructGetData($tNMLVDISPINFO,"SubItem")]
                          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 Name,Time,Category FROM SSDB WHERE Title IS '" & $TreeView_SelTitle & "' AND item_id >= " & $iFrom & " AND item_id <= " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) & ";"
                    Local $sSQL = "SELECT RowRelation.rowid,DisplayView.Name,Time,Category FROM DisplayView INNER JOIN RowRelation ON DisplayView.Name = RowRelation.Name WHERE RowRelation.rowid BETWEEN " & $iFrom + 1 & " And " & DllStructGetData( $tNMLVCACHEHINT, "iTo" ) + 1 & ";"
                    _SQLite_GetTable2d( -1, $sSQL, $aResult, $iRows, $iColumns )

            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc

 

I have marked the code in post 35 as deprecated but left the code as it is. Then you can see what happens if you forget the primary key.
 

Take a look at the code in post 41. It's a small example (just 100,000 rows) that shows a way to implement a search box.

Link to post
Share on other sites

The easiest way to use AutoIt with other databases besides SQLite is using ADO. You can start by looking at the information in these links:

AutoIt ADO WikiConnecting to a PostgreSQL database and ADO Programmer's Reference.

In post 2 in second link you can find AdoSQL.au3 which contains the function _AdoSQL_GetData2d. I think this is the direct replacement of _SQLite_GetTable2d.

To search the AutoIt forums you can Google in this way:

oracle site:autoitscript.com

If you have more questions related to ADO you'll get better answers in "AutoIt General Help and Support" forum. I'm not at all an ADO expert.

Link to post
Share on other sites
  • 7 months later...
On 12/2/2016 at 4:36 PM, LarsJ said:

You are welcome

Hi Lars,

When you have time i'd like to see an edited example of "LvVirtArraySort" with checkboxes, if is possible. I have study the example on my own, many things are clear but others not:

1) Is possible to sort "Column 0" based on array[x][y]? On the example "LvVirtArrayIcons" the checkbox was stored on the array ( $aItems[$iItem][10] ) and i don't have understood if is possible also with "LvVirtArraySort" when you click on the column since you are sorting before the click, example make an order for checkbox checked-unchecked.

2) Is possible to avoid index 0 of the array when sorting leaving the first row untouched? I have check it out "SortNumbers" and "SortStrings" but is overclomplex for me, editing things like $i = 0 or $j = 0 don't give the expected result.

Thanks in advance

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to post
Share on other sites

Terenz, Here is an example of LvVirtArraySort with checkboxes. The rows are sorted according to checked state and column. Picture to the left. I'm not quite sure if that's what you mean with point 1. If I've misunderstood it, you have to add a new post.

In the next example the first row is left unsorted. It's always the first row.

Untitled_zps6tg4asse.png

To keep code simple I've removed the tab control and some of the functionality of the buttons in the listview header. The sorting is only in the ascending order with respect to the columns.

Now that I've found out how to do it, I'll add the functionality of the header buttons again. I might manage to make a new example till tomorrow.

Virtual ListViews.7z

Edited by LarsJ
Link to post
Share on other sites

I'm not sure about the choice to sort only the flagged item, in my mind was more simple. First column with checkbox, ascending sort by checked item-unchecked item and descending sort by unchecked item-checked item, value sorted by actual order like if was sorted by strings sort also the checked item in that order. Other columns must be independent by the checked state so we don't loose the descending order, if i want to sort by "Intergers" clicking on the column i want to sort everything not only the item i have selected.

I'm not saying you did it wrong or anything like that lol I only had a different idea in mind about the checkbox and sorting, maybe i'm totally astray since i'm treat the checkbox column like any other column.

EDIT: Some images just for be clear, i have forget the static first row.

2emoljb.png

339ro5k.png

2jfn5tf.png

P.S I prefer the simplest example without button-tabs etc. more readable, without ternary is better but is just my little opinion since i never use it.

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to post
Share on other sites

This seems to be a relatively simple sorting. You just sort the rows by one column at a time in ascending order. Only the subitems in this specific column are used for the sorting.

The column with the checkboxes does not contain any text values. This column is sorted by the checked state.

You can implement such a sorting in a normal listview if you create your own sorting function. You don't need a virtual listview for that.

Or will the listview contain a large number of rows? And then you want to use a virtual listview of performance reasons. How many rows and columns do you expect the listview will contain?

What is the data source for the listview? Where do you get the data from?

I've added the checkboxes to an otherwise empty column and created a sorting function for it. I've set some of the checkboxes to the checked state in advance.

Virtual ListViews.7z

The Ternary operator is almost twice as fast as an If...Else...EndIf block. It's very useful in loops and in fast repeated calls of for example VM_Message handler functions.

Edited by LarsJ
Link to post
Share on other sites

My listview has huge number of rows and at least 10 column ( and the array with information is 15! ) is a sort of database of people with personal information and contacts for this reason i'm using the virtual listview. I'll let you know about your example at time i'm testing it, thanks again.

EDIT: Tested, you can add also:

1) The descending sorting

2) Static first row

Thanks

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to post
Share on other sites

Descending sort order and this static row:

Virtual ListViews.7z

Since the structures are only being used for sorting, you can achieve a performance gain by replacing structures with arrays after the sorting. Then you can use arrays in the WM_NOTIFY function instead of structures. An array lookup is at least twice as fast as a structure lookup. The more columns you have, the bigger the performance gain will be. Also the SortChecks function will probably be twice as fast.

But you'll need a little bit of logic to handle the static row.

Edited by LarsJ
Link to post
Share on other sites

Thank you so much. If the structure are used only for sorting, we can't sort directly the array and the show the result in the listview? Maybe require more time sorting an array? Structure are a mystery to me, with array after many years i can unravel, more or less

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to post
Share on other sites
On 13/10/2016 at 1:40 PM, LarsJ said:

Descending sort order and this static row:

Lars a problem with the first static row. I'd like to see the checkbox on the first line ( it have a function ) but if i'll change:

$aItems[$iRows-1][0] = 8192 ; Check mark, 0 = Empty, 4096 = Unchecked, 8192 = Checked

The first row will be involved in the checkbox sorting. Can you resolve please? Thanks

EDIT: I think i have resolved by myself, if i have other issue i'll report.

Edited by Terenz

Nothing is so strong as gentleness. Nothing is so gentle as real strength

 

Link to post
Share on other sites

Sorting. You can test how long it takes to sort the array by a column. If it doesn't take too long, you can sort the array directly. You must re-sort the array when you click a sort button in the listview header.

One way to get around all the sorting issues, is to store the array in a database.
 

 

Cleanup in first post. Added list of examples.

Link to post
Share on other sites
  • 1 month later...

In this example a CSV-file with 100,000 rows and 10 columns is data source for a virtual listview.

Run LvVirtCSVfileCreate.au3 to create the CSV-file. It takes a few seconds.

Run LvVirtCSVfile.au3 to display the CSV-file in the listview. The listview shows up instantly.

The CSV-file is loaded into a 1D-array with FileReadToArray. The caching mechanism (see first post) of the virtual listview is used to split the items (rows) into 10 subitems (columns) and store the subitems in a display array.

The listview is filled with data from the display array through $LVN_GETDISPINFOW notifications.

#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

Opt( "MustDeclareVars", 1 )

Global $hLV, $aItems

Example()


Func Example()
  ; Create GUI
  GUICreate( "Virtual ListViews", 880, 400 )

  ; Create ListView
  Local $idLV = GUICtrlCreateListView( "", 10, 10, 880-20, 400-20, $LVS_OWNERDATA, BitOR( $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT ) )
  $hLV = GUICtrlGetHandle( $idLV ) ;                               Virtual listview                          Reduces flicker
  _GUICtrlListView_AddColumn( $hLV, "Col0", 100 )
  _GUICtrlListView_AddColumn( $hLV, "Col1", 100 )
  _GUICtrlListView_AddColumn( $hLV, "Col2", 100 )
  For $i = 3 To 9
    _GUICtrlListView_AddColumn( $hLV, "Col" & $i, 75 )
  Next

  ; WM_NOTIFY message handler
  GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
  GUISetState( @SW_SHOW )

  ; Load data from CSV-file
  $aItems = FileReadToArray( "LvVirtCSVfile.csv" )
  GUICtrlSendMsg( $idLV, $LVM_SETITEMCOUNT, UBound( $aItems ), 0 )

  ; Message loop
  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd

  GUIDelete()
EndFunc

Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
  Static $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"
  Static $tText = DllStructCreate( "wchar[50]" )
  Static $pText = DllStructGetPtr( $tText )
  Static $aDisplay[100][10], $iRows, $iFrom

  Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam )
  Local $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) )
  Local $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
            If $iIndex >= 0 And $iIndex < $iRows Then
              Local $sItem = $aDisplay[$iIndex][DllStructGetData($tNMLVDISPINFO,"SubItem")]
              DllStructSetData( $tText, 1, $sItem )
              DllStructSetData( $tNMLVDISPINFO, "Text", $pText )
              DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) )
            EndIf
          EndIf

        Case $LVN_ODCACHEHINT
          Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam )
          Local $iTo = DllStructGetData( $tNMLVCACHEHINT, "iTo" ), $aSubItems
          $iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
          $iRows = 0
          For $i = $iFrom To $iTo
            $aSubItems = StringSplit( $aItems[$i], ",", 2 ) ; 2 = $STR_NOCOUNT
            For $j = 0 To 9
              $aDisplay[$iRows][$j] = $aSubItems[$j]
            Next
            $iRows += 1
          Next

      EndSwitch

  EndSwitch

  Return $GUI_RUNDEFMSG
  #forceref $hWnd, $iMsg, $wParam
EndFunc

The two scripts are included in the zip: CSVfile.7z

Edited by LarsJ
Link to post
Share on other sites
  • 3 months later...
  • 3 months later...

Yes, You can use 2-line texts in a virtual listview.

If you need more help than this, please be more specific.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...