Jump to content

How to prepare cache for a Virtual ListView


Recommended Posts

Good morning everyone :)

I'm trying to build, and, first of all, understand, how a Virtual ListView works.
By now, I've already downloaded all the samples from Virtual List View samples provided by @LarsJ, but I still don't understand few things.
What I understood by now, is that the Virtual ListView doesn't need to be filled by object like Items, because it use directly the source to display the data.
I've already understood that the $LVN_ODCACHEHINT Notification Code does provide the range of the items to be displayed, but I don't understand how to fill $iFrom and $iTo which are in the $NMLVCACHEHINT, or who fill them.
And, "finally", I understood that the $LVN_GETDISPINFO is used to fill the ListView with "items".
Can someone please explain to me how do these Virtual ListView controls work?
Thanks in advance.


Best Regards.


 

Edited by FrancescoDiMuro

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

You should start by reading the Microsoft documentation.

Then I suggest you extract all data from the database into an array with _SQLite_GetTable2d. Compared to virtual listviews, an array is the same as a cache. When all data is stored in a cache, there is no need to use the caching technique.

So look at the array examples where only LVN_GETDISPINFO notifications are used.


LVN_ODCACHEHINT notifications are used to fill the cache (the array). When all rows are stored in the cache you don't need them.

LVN_GETDISPINFO notifications contains information about which items/subitems in the listview that should be updated. A LVN_GETDISPINFO notification is send to the listview for each cell to be updated. Then the cell text is read in the cache (the array) and displayed in the cell.


When you receive a DllStruct through the $lParam parameter in the WM_NOTIFY function, data in the DllStruct is filled in by code in the operating system.

Edited by LarsJ
Link to comment
Share on other sites

Hey @LarsJ:)
Thanks for your tips.
I was trying to build my own Virtual ListView, but, I have an errore in my script.
I'd like to show you step by step what I've done...

  1. Catch the $LVN_ODCACHEHINT Notification Code, and create the Struct $tagNMLVCACHEHINT, in which there are information about ListView Items stored in the cache ( and it is iFrom = 0 and iTo = 23 );
  2. Query the DB using iFrom and iTo;
  3. Catch the $LVN_GETDISPINFO Notification Code, and create the Struct $tagNMLVDISPINFO, in which set the Text of the Item, basing on the Item ( row ) and SubItem ( column ) parameters obtained from the Struct  $tagNMLVDISPINFO... 
    But, when I'm in this Notification Code ( LVN_GETDISPINFO ), and I'm setting Text and TextMax for each LV Item, I'm not understaing this passage ( which generates an error ):
    ; Information about how many items should be displayed in the VLV
    $intMaxItemsCount = 28558
    ; Sending $LVM_SETITEMCOUNT... 
    
    Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)
    
    ; Since arrResult[0][n] contains Table headers from the Query, we start from 1 to UBound($arrResult) ?
    Local $intItemRow = DllStructGetData($tNMLVDISPINFO, "Item") -  $intFrom + 1 ; Equals to [0...$intMaxItemsCount] + 0 + 1 = 28559 ?
    
    Local $intItemColumn = DllStructGetData($tNMLVDISPINFO, "SubItem") ; From 0 to 7
    
    ConsoleWrite("$intItemRow: " & $intItemRow & @CRLF & _
                 "$intItemColumn: " & $intItemColumn & @CRLF)
    
    If $intItemRow > 0 And $intItemRow < $intMaxItemsCount + 1 Then ; intItemRow Will be > 0 and < 28559 since it meets the last LV Item, isn't it?
    
        DllStructSetData($tItemText, 1, $arrResult[$intItemRow][$intItemColumn])
        DllStructSetData($tNMLVDISPINFO, "Text", $ptrItemText)
        DllStructSetData($tNMLVDISPINFO, "TextMax", StringLen($tItemText))
    
    EndIf

    The error is correctly:

    (704) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
    DllStructSetData($tItemText, 1, $arrResult[$intItemRow][$intItemColumn])
    DllStructSetData($tItemText, 1, ^ ERROR

     

Thanks for your help :)

EDIT:

Now it works! :)
; Information about how many items should be displayed in the VLV
$intMaxItemsCount = 28558
; Sending $LVM_SETITEMCOUNT... 

Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)

; Since arrResult[0][n] contains Table headers from the Query, we start from 1 to UBound($arrResult) ?
Local $intItemRow = DllStructGetData($tNMLVDISPINFO, "Item") -  $intFrom + 1 ; Equals to [0...$intMaxItemsCount] + 0 + 1 = 28559 ?

Local $intItemColumn = DllStructGetData($tNMLVDISPINFO, "SubItem") ; From 0 to 7

ConsoleWrite("$intItemRow: " & $intItemRow & @CRLF & _
             "$intItemColumn: " & $intItemColumn & @CRLF)

; Error ===> If $intItemRow > 0 And $intItemRow < $intMaxItemsCount + 1 Then ; intItemRow Will be > 0 and < 28559 since it meets the last LV Item, isn't it?

If $intItemRow > 0 And $intItemRow < $intRows + 1 Then ; $intRows is the number of Rows returned by the query!



    DllStructSetData($tItemText, 1, $arrResult[$intItemRow][$intItemColumn])
    DllStructSetData($tNMLVDISPINFO, "Text", $ptrItemText)
    DllStructSetData($tNMLVDISPINFO, "TextMax", StringLen($tItemText))

EndIf


Best Regards.
Edited by FrancescoDiMuro

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

Good morning @LarsJ:)
I was tidying my code a little bit in my WM_NOTIFY function, and I decided to make these changes...
This is the "style" of the Switch..Case...EndSwitch statements beforethe tidy:

Switch $intMessageCode ; Which code has been sent from a ListView
    
    Case $NM_DBLCLK
        Switch $hdlWindowFrom ; From which ListView the Notification Code is sent
        
            Case $hdlListView1
                ConsoleWrite("NM_DBLCLK" & @CRLF)
        EndSwitch
        
        
    Case $LVN_COLUMNCLICK
        Switch $hdlWindowFrom
        
            Case $hdlListView2
                ConsoleWrite("LVN_COLUMNCLICK" & @CRLF) ; It works!
        EndSwitch
        
    Case $LVN_ODCACHEHINT
        Switch $hdlWindowFrom
        
            Case $hdlListView2
                ConsoleWrite("LVN_ODCACHEHINT" & @CRLF) ; It works!
        EndSwitch
        
    Case $$LVN_GETDISPINFO
        Switch $hdlWindowFrom
        
            Case $hdlListView2
                ConsoleWrite("LVN_GETDISPINFO" & @CRLF) ; It works!
        EndSwitch

EndSwitch

And this is after the tidy ( I switched first the ListView which sents the Notification Code, and then the Notification Code sent ):

Switch $hdlWindowFrom       ; From which ListView the Notification Code is sent
    Case $hdlListView1
    
        Switch $intMessaggeCode ; Which code has been sent from this particular ListView
            
            Case $NM_DBLCLK
                ConsoleWrite("NM_DBLCLK" & @CRLF) ; It doesn't work!
        
        EndSwitch ; Message Code
      
    Case hdlListView2
        Switch $intMessaggeCode ; Which code has been sent from this particular ListView
            
            Case $LVN_COLUMNCLICK
                ConsoleWrite("LVN_COLUMNCLICK" & @CRLF) ; It works!
                
            Case $LVN_ODCACHEHINT
                ConsoleWrite("LVN_ODCACHEHINT" & @CRLF) ; It doesn't work!
                
            Case $LVN_GETDISPINFO
                ConsoleWrite("LVN_GETDISPINFO" & @CRLF) ; It doesn't work!
        
        EndSwitch ; Message Code
        
EndSwitch ; Window From

Some Notification Codes work and some not.
Can you please tell me if is this normal? :)
Thank you very much :)


Best Regards.

 

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

The listviews receives notifications.

Notifications related to the virtual listview should be placed in top of the Switch statements. I'm sure you are clicking very fast. But not that fast. Put your click notifications in the bottom.

And you have remembered to add the $LVS_OWNERDATA (virtual listview) style to the listview?

Your code should look like this:

Switch $hdlWindowFrom       ; From which ListView the Notification Code is received
    Case hdlListView2
        Switch $intMessaggeCode ; Which code has been received by this particular ListView
            Case $LVN_GETDISPINFO
                ConsoleWrite("LVN_GETDISPINFO" & @CRLF) ; It doesn't work!

            Case $LVN_ODCACHEHINT
                ConsoleWrite("LVN_ODCACHEHINT" & @CRLF) ; It doesn't work!

            Case $LVN_COLUMNCLICK
                ConsoleWrite("LVN_COLUMNCLICK" & @CRLF) ; It works!
        EndSwitch ; Message Code

    Case $hdlListView1
        Switch $intMessaggeCode ; Which code has been received by this particular ListView
            Case $NM_DBLCLK
                ConsoleWrite("NM_DBLCLK" & @CRLF) ; It doesn't work!
        EndSwitch ; Message Code
EndSwitch ; Window From

 

Notifications that do not work usually result from lack of understanding or bad code.


Post all your code and a test database and I'll take a look.

Edited by LarsJ
Link to comment
Share on other sites

Hey @LarsJ:)
Thanks for your reply.
Sorry if I ask always for Help, but this thing is stoping me by keep going with the work I have to do, and so, I always search for explanations! :)
By the way, let me reply you "statement by statement"...

Quote

And you have remembered to add the $LVS_OWNERDATA (virtual listview) style to the listview?

Yes, I did :)

16 minutes ago, LarsJ said:

Notifications that do not work are usually result from lack of understanding or bad code.

I just switched the two switches ( before it was ):

Switch $intMessageCode
    Case $LVN_ODCACHEHINT
        Switch $hdlWindowFrom
            Case $hdlListView
        
        EndSwitch
EndSwitch

And after it is:

Switch $hdlWindowFrom
    Case $hdlListView
        Switch $intMessageCode
            Case $LVN_ODCACHEHINT
        
        EndSwitch
EndSwitch

And this little change, it's the cause of the issue.
 

16 minutes ago, LarsJ said:

Notifications related to the virtual listview should be placed in top of the Switch statements. I'm sure you are clicking very fast. But not that fast. Put your click notifications in the bottom.

The sample script I've made to understand ListViews ( and VLV too ) has $LVN_ODCACHEHINT and $LVN_GETDISPINFO at the bottom of the Switch statement.

At the moment, I can't post anything ( neither a similiar script ).
I have a distorsion ( I should stay in bed ), and I'm making a big effort to write here.
Can you please explain this to me?
Thanks again :ILA2:

Best Regards.

Edited by FrancescoDiMuro

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

Link to comment
Share on other sites

Link to comment
Share on other sites

@LarsJ
Little Update: I found what were causing the Virtual ListView to not be created.
I'm digging a little bit more to understand how to "free" the cache now, since I think ( as a non-expert I am ), the cache has to be free after some work with it.
I want to thank you to poiting me to the right direction, and I'd like to let everyone knows, that your help made me happier, 'cause from your help, I ( almost, I miss few things ) understood how Virtual ListView can be created, and this is amazing, since, from now on, I can use them, and they're really powerful.
So, I said all these stuffs because I want to spur everyone that help people is amazing, and it gives back ( hopefully ),a good result, both phisycal and moral.
I hope you got this :)
Have a wonderful day.


Best Regards.

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
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
 Share

×
×
  • Create New...