Jump to content

SQLite Virtual Listview, WM_DRAWITEM questions


Recommended Posts

Posted (edited)

Hello everyone!

I got a problem in making a SQL Virtual listview image tool,

The images are stored in binary and I need to read and display them in a virtual listview,

Listview style: $LVS_ OWNERDATA and $LVS_ OWNERDRAWFIXED, not Imagelist method

Data Array I got from $LVN_ODCACHEHINT(Virtual listview) is not match when I scrolled up or down listview ctrl, so WM_DRAWITEM report errors

My test script are in rar package below. Thank you very much!

 

@LarsJ

 

#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

;#AutoIt3Wrapper_UseX64=y

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

Opt( "MustDeclareVars", 1 )


Global Const $ODT_LISTVIEW = 102
Global Const $ODA_DRAWENTIRE = 0x1
Global Const $ODA_SELECT = 0x2
Global Const $ODA_FOCUS = 0x4
Global Const $ODS_SELECTED = 0x0001


Global $pTable, $iCols, $hLV, $array


  _SQLite_Startup()
  _SQLite_Open( "random_data.db" )

Global $iRows
Global $sSQL = "SELECT * FROM RandomData;"
  _SQLite_GetTableEx( -1, $sSQL, $pTable, $iRows, $iCols )
  $pTable += $iCols * ( @AutoItX64 ? 8 : 4 )

  GUICreate( "Virtual ListView", 1650, 800 )

Global $idLV = GUICtrlCreateListView( "", 10, 10, 1650-20, 800-20, $LVS_OWNERDATA+$LVS_OWNERDRAWFIXED, BitOR( $WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT ) )
  $hLV = GUICtrlGetHandle( $idLV ) ;                                Virtual listview                          Reduces flicker
  For $i = 0 To $iCols - 1
    _GUICtrlListView_AddColumn( $idLV, "Col" & $i, 160 )
  Next










GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")



  GUICtrlSendMsg( $idLV, $LVM_SETITEMCOUNT, $iRows, 0 )
  GUIRegisterMsg( $WM_NOTIFY, "WM_NOTIFY" )
  GUISetState( @SW_SHOW )
  
  HotKeySet("{F1}","RowsCount")

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

  $pTable -= $iCols * ( @AutoItX64 ? 8 : 4 )
  _SQLite_FreeTable( $pTable )
  _SQLite_Close()
  _SQLite_Shutdown()


Func RowsCount()
    ;ToolTip(UBound($array,1))  
    _ArrayDisplay($array)
EndFunc



Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
    #forceref $hWnd, $Msg, $wParam
    
    
    
    

    Local $tagDRAWITEMSTRUCT,  $cID, $itmID, $itmAction,  $hDC
    $tagDRAWITEMSTRUCT = DllStructCreate( _
   "uint cType;" & _
   "uint cID;" & _
   "uint itmID;" & _
   "uint itmAction;" & _
   "uint itmState;" & _
   "hwnd hItm;" & _
   "handle hDC;" & _
   "long itmRect[4];" & _
   "ulong_ptr itmData" _
   , $lParam)
   
    If DllStructGetData($tagDRAWITEMSTRUCT, "cType") <> $ODT_LISTVIEW Then Return $GUI_RUNDEFMSG
    $cID = DllStructGetData($tagDRAWITEMSTRUCT, "cID")
    $itmID = DllStructGetData($tagDRAWITEMSTRUCT, "itmID")
    $itmAction = DllStructGetData($tagDRAWITEMSTRUCT, "itmAction")
    
    $hDC = DllStructGetData($tagDRAWITEMSTRUCT, "hDC")
    
    Local $itmState = DllStructGetData($tagDRAWITEMSTRUCT, "itmState")
    ;Local $hItm = DllStructGetData($tagDRAWITEMSTRUCT, "hItm")
    Local $bSelected = BitAND($itmState, $ODS_SELECTED),$iBrushColor
    

    Switch $cID ; will look for ControlID, not window handle.
        Case $idLV
            Switch $itmAction
                Case $ODA_DRAWENTIRE
                    ;#cs
                    ; don't forget, this is BGR, not RGB
                    If $itmState = $bSelected Then ; item is not selected
                        $iBrushColor = 0xCCEECC
                    Else ; item is selected
                        $iBrushColor = 0xEEDDBB
                    EndIf
                    
                    Local $aBrush = DllCall("gdi32.dll", "hwnd", "CreateSolidBrush", "int", $iBrushColor)
                    Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush[0])
                    Local $iLeft = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1)
                    DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", $iLeft + 1, 1) ; rectangle coordinates for coloring
                    ;+1 is the left margin
                    _WinAPI_FillRect($hDC, DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), $aBrush[0])
                    _WinAPI_SelectObject($hDC, $aBrushOld)
                    _WinAPI_DeleteObject($aBrush[0])
                    ;#ce

                    
    

                    
                    ;For $i = 0 To _GUICtrlListView_GetColumnCount($hLV) - 1
                    For $i = 0 To UBound($array,2) - 1
                        ; 1. get subitem text:
                        Local $iSubItmText = $array[$itmID][$i];_GUICtrlListView_GetItemText($hLV, $itmID, $i)
                        ; 2. get subitem coordinates for drawing its respective text
                        Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hLV, $itmID, $i)
                        ; the function above accepts not only subitems (one-based index), but also main item (index=0)
                        ; 3. pass the coordinates to a DLL struct
                        Local $iSubItmRect = DllStructCreate("long[4]")
                        DllStructSetData($iSubItmRect, 1, $aSubItmRect[0] + 6, 1) ; +6 is left margin (X)
                        DllStructSetData($iSubItmRect, 1, $aSubItmRect[1] + (-2), 2) ; + (-2) is upper margin (Y)
                        DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3)
                        DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4)
                        DllCall("user32.dll", "int", "DrawTextW", "hwnd", $hDC, "wstr", $iSubItmText, "int", StringLen($iSubItmText), _
                            "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT  )
                        ;_WinAPI_DrawText ( $hDC, $iSubItmText, $iSubItmRect,  $DT_WORD_ELLIPSIS +$DT_LEFT  )

#cs
                        ; Load image
Local $hSource = _WinAPI_LoadImage(0, @ScriptDir & '\1.bmp', $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
Local $hDestDC = _WinAPI_CreateCompatibleDC($hDC)
Local $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, @DesktopWidth, @DesktopHeight)
Local $hDestSv = _WinAPI_SelectObject($hDestDC, $hBitmap)
        _WinAPI_DrawBitmap($hDC, 10,10, $hSource)
#ce
                    Next


            EndSwitch
    EndSwitch
    ;#ce
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_DRAWITEM




Func WM_NOTIFY( $hWnd, $iMsg, $wParam, $lParam )
  Static $iPtrSize = @AutoItX64 ? 8 : 4, $hDLL = DllOpen( "kernel32.dll" ), $aDisplay[100][$iCols], $iFrom, $iTo
  ;Static $tText = DllStructCreate( "wchar[4094]" ), $pText = DllStructGetPtr( $tText )
  ;Static $tagNMLVCACHEHINT = $tagNMHDR & ";int iFrom;int iTo"

  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_GETDISPINFOW
                    #cs
                    Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam )
                    If Not BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), 1 ) Then Return ; 1 = $LVIF_TEXT
                    Local $iItem = DllStructGetData( $tNMLVDISPINFO, "Item" ) - $iFrom
                    If $iItem < 0 Or $iItem > $iTo - $iFrom Then Return
                    Local $iSubItem = DllStructGetData($tNMLVDISPINFO,"SubItem")
                    Local $sItem = $aDisplay[$iItem][$iSubItem]
                    Local $l = StringLen( $sItem )
                    DllStructSetData( $tText, 1, $sItem )
                    DllStructSetData( $tNMLVDISPINFO, "Text", $pText )
                    DllStructSetData( $tNMLVDISPINFO, "TextMax", ( $l <= 4094 ? $l : 4094 ) )
                    Return
                    #ce
                    
                Case $LVN_ODCACHEHINT
                    ;Local $tNMLVCACHEHINT = DllStructCreate( $tagNMLVCACHEHINT, $lParam )
                    ;$iFrom = DllStructGetData( $tNMLVCACHEHINT, "iFrom" )
                    ;$iTo = DllStructGetData( $tNMLVCACHEHINT, "iTo" )
                    
                    $iFrom = _GUICtrlListView_GetTopIndex ( $idLV )
                    $iTo = $iFrom+39
                    If $iTo > $iRows-1 Then $iTo = $iRows-1
                    ;ToolTip($iFrom&" - "&$iTo)
                    Local $pFrom, $pStr, $iLen, $tWstr
                    For $i = $iFrom To $iTo
                        $pFrom = $pTable + $i * $iCols * $iPtrSize
                        For $j = 0 To $iCols - 1
                            $pStr = DllStructGetData( DllStructCreate( "ptr", $pFrom + $j * $iPtrSize ), 1 )
                            $iLen = DllCall( $hDLL, "int", "MultiByteToWideChar", "uint", 65001, "dword", 0, "ptr", $pStr, "int", -1, "ptr", 0, "int", 0 )[0]
                            $tWstr = DllStructCreate( "wchar[" & $iLen & "]" )
                            DllCall( $hDLL, "int", "MultiByteToWideChar", "uint", 65001, "dword", 0, "ptr", $pStr, "int", -1, "struct*", $tWstr, "int", $iLen )
                            $aDisplay[$i-$iFrom][$j] = DllStructGetData( $tWstr, 1 )
                        Next
                    Next
                    ;ToolTip(_GUICtrlListView_GetTopIndex ( $idLV )&" - "&_GUICtrlListView_GetNumberOfWorkAreas( $idLV )&" - "&$iFrom&" - "&$iTo)
                    

                    $array = $aDisplay
                    Return
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    #forceref $hWnd, $iMsg, $wParam
EndFunc

Func _SQLite_GetTableEx( $hDB, $sSQL, ByRef $pTable, ByRef $iRows, ByRef $iCols )
  If __SQLite_hChk($hDB, 2) Then Return SetError(@error, 0, $SQLITE_MISUSE)
  Local $tSQL8 = __SQLite_StringToUtf8Struct($sSQL)
  If @error Then Return SetError(3, @error, 0)
  Local $avRval = DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_get_table", _
    "ptr", $hDB, _       ; An open database
    "struct*", $tSQL8, _ ; SQL to be executed
    "ptr*", 0, _         ; Results of the query
    "int*", 0, _         ; Number of result rows
    "int*", 0, _         ; Number of result columns
    "long*", 0)          ; Error msg written here
  If @error Then Return SetError(1, @error, $SQLITE_MISUSE) ; DllCall error
  $pTable = $avRval[3]
  $iRows = $avRval[4]
  $iCols = $avRval[5]
EndFunc

Func _SQLite_FreeTable( $pTable )
  DllCall($__g_hDll_SQLite, "int:cdecl", "sqlite3_free_table", "ptr", $pTable)
  If @error Then Return SetError(1, @error, $SQLITE_MISUSE) ; DllCall error
EndFunc

 

 

SQL - Virtual listview custom draw.rar

Edited by powerofos
Link to post
Share on other sites

You cannot combine virtual listview functionality (LVS_OWNERDATA) with owner drawn listview functionality (LVS_OWNERDRAWFIXED) the way you want to.

If you want to use an owner drawn listview, the only purpose of setting the LVS_OWNERDATA style (virtual listview) is to prevent data from being stored directly in the listview structures to avoid issues as described in this post. However, LVN_ODCACHEHINT notifications can in no way be combined with WM_DRAWITEM messages. It simply will not work. These are two completely different techniques that cannot be combined.

If you want to use a virtual listview and at the same time extract data from the SQLite database with the sqlite3_get_table() function that stores output in a C-array, then there is absolutely no point in using LVN_ODCACHEHINT to store data in another memory cache. The C-array is already a memory cache, and no more caching is needed.

If the purpose of your code is to display images in a listview where the images are stored as binary data in a SQLite database, then I would suggest that you first start by figuring out how to display just a single image from the database in a owner drawn listview. And once you have figured that out, you can figure out how to handle many images.

Link to post
Share on other sites
Posted (edited)

Hi Larsj,

Thank you for your reply!

Through your explanation,  I don't think I have the ability to deal with this problem, so I changed to another way.
Instead of reading data directly from the database, I read the data to the array first, and then use the drawitem message to draw it down,include the image.

The following rar package is an example that I modified from yours,  can you help me improve it or give me any suggestion?

Thank you!

@Larsj

Preview.thumb.png.a0f0b8ffe4ba5f5069dcd917097ee110.png

 

Image Virtual Listview(WM_DrawItem).rar

Edited by powerofos
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...