ImageList in ListView zu langsam

  • Hi,

    ich möchte eine ListView mit Bildern aus einem Ordner machen. Dazu habe ich schon ein Script im Internet gefunden, das genau das tut. Mein Problem ist aber, dass das Bilder-zur-ImageList-hinzufügen eine ganze Weile braucht, besonders wenn man ein paar mehr Bilder hat.

    Daher meine Frage: Wie kann ich den Vorgang beschleunigen?

    Leider kenne ich mich nicht wirklich mit GDI+ oder ImageLists aus. Meine Ideen bisher wären: Irgendwie die _GUIImageList_AddImage() optimieren, nicht gleich alle Bilder laden, sondern nur die, die gerade in der ListView angezeigt werden (habe ich aber überhaupt keine Ahnung wie), ImageList irgendwie als Datei cachen und dann davon laden (?).

    [autoit]


    #Include <GDIPlus.au3>
    #Include <GUIImageList.au3>
    #Include <GUIListView.au3>

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    $hForm = GUICreate('MyGUI', 400, 400)
    $hListView = GUICtrlCreateListView('', 10, 10, 380, 380)
    _GUICtrlListView_AddColumn($hListView, 'Items', 200)
    $hImageList = _GUIImageList_Create(121, 91, 5, 1)
    _GUICtrlListView_SetImageList($hListView, $hImageList, 1)

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    GUISetState()
    For $i = 1 To 100 ;<<<<<<<<<<<<<< Hier Anzahl ändern
    _GUIImageList_AddImage($hImageList, -1, "IRGENDEIN ORDNER MIT BILDERN" & $i & ".jpg") ;<<<<<<<<<<<<<<<<<< Hier Ordner einfügen
    _GUICtrlListView_AddItem($hListView, $i, $i - 1)
    Next

    [/autoit][autoit][/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Do
    Until GUIGetMsg() = -3

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    Func _GUIImageList_AddImage($hWnd, $iIndex, $sFile)
    Local $W, $H, $hGraphic, $hPic, $hImage, $hIcon

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    _GDIPlus_Startup()
    $hPic = _GDIPlus_ImageLoadFromFile($sFile)
    $W = 121
    $H = 91

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    $hImage = DllCall($ghGDIPDll, 'int', 'GdipGetImageThumbnail', 'ptr', $hPic, 'int', $W, 'int', $H, 'ptr*', 0, 'ptr', 0, 'ptr', 0)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage[4])
    _GDIPlus_GraphicsClear($hGraphic, 0)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hPic, 0, 0, $W, $H)
    $hIcon = DllCall($ghGDIPDll, 'int', 'GdipCreateHICONFromBitmap', 'ptr', $hImage[4], 'ptr*', 0)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_ImageDispose($hImage[4])
    _GDIPlus_ImageDispose($hPic)
    _GDIPlus_Shutdown()
    If Not $hIcon[2] Then
    Return -1
    EndIf
    $iIndex = _GUIImageList_ReplaceIcon($hWnd, $iIndex, $hIcon[2])
    _WinAPI_DestroyIcon($hIcon[2])
    Return $iIndex
    EndFunc ;==>_GUIImageList_AddImage

    [/autoit]

    Edit (3 Jahre später):
    Für den Fall, dass jemand diesen Beitrag findet und das gleiche Problem hat, hier meine momentane Lösung:
    Zunächst einmal hatte ich alle Bilder auch als ICO gespeichert, was das ganze schon mal deutlich beschleunigt hat. Irgendwann war es mir aber trotzdem noch zu langsam, sodass ich jetzt die Icons erst lade, wenn sie in der ListView angezeigt werden. Zunächst habe ich eine ImageList erstellt, in der jedes Icon eine weiße Fläche ist. Mit _GUICtrlListView_GetTopIndex() und _GUICtrlListView_GetCounterPage() bekommt man raus, welche Items zu sehen sind. Ist dies der Fall, ersetze ich das weiße Bild in der ImageList mit dem richtigen Icon _GUIImageList_ReplaceIcon().

    Rechtschreibfehler sind Spezialeffekte meiner Tastatur.

    2 Mal editiert, zuletzt von owi dowi spinn (18. Juni 2017 um 17:54)

    • Offizieller Beitrag

    Du könntest von allen Images erstmal die kleinen Icons generieren lassen und diese abspeichern.
    Das würde dann einmalig länger dauern, aber das anschließende einlesen geht sehr schnell.
    Hier mal meine Variante:

    Spoiler anzeigen
    [autoit]


    #include <File.au3>
    #include <FileConstants.au3>
    #include <GDIPlus.au3>
    #include <GuiImageList.au3>
    #include <GuiListView.au3>
    #include <WinAPI.au3>
    #include <WinAPIGdi.au3>
    #include <WinAPIRes.au3>
    #include <WinAPISys.au3>

    [/autoit] [autoit][/autoit] [autoit]

    $hForm = GUICreate('MyGUI', 400, 400)
    $hListView = GUICtrlCreateListView('', 10, 10, 380, 380)
    _GUICtrlListView_AddColumn($hListView, 'Items', 200)
    $hImageList = _GUIImageList_Create(120, 90, 5, 1)
    _GUICtrlListView_SetImageList($hListView, $hImageList, 1)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    $sDir = 'c:\Users\Oscar\Downloads\img\' ; <- Pfad anpassen!
    $aSize = _GUIImageList_GetIconSize($hImageList)

    [/autoit] [autoit][/autoit] [autoit]

    ToolTip('Bitte warten!')
    $iTimer = TimerInit()
    _ImageFilesToIcons($sDir, '*.jpg', $aSize[0], $aSize[1]) ; <- mit dieser Funktion werden die Icons erstellt
    ToolTip('')
    MsgBox(0, 'Icons erstellt', 'Benötigte Zeit (s): ' & Round(TimerDiff($iTimer) / 1000, 3))

    [/autoit] [autoit][/autoit] [autoit]

    $aFiles = _FileListToArray($sDir, '*.ico', $FLTA_FILES, False) ; <- alle Icondateien in das Array holen
    $hIcon = 0
    For $i = 1 To $aFiles[0]
    $hIcon = _WinAPI_LoadIconWithScaleDown(0, $sDir & $aFiles[$i], $aSize[0], $aSize[1]) ; Icon laden
    _GUIImageList_ReplaceIcon($hImageList, -1, $hIcon) ; in die ImageList einfügen
    _WinAPI_DestroyIcon($hIcon) ; Icon zerstören und Speicher freigeben
    _GUICtrlListView_AddItem($hListView, $aFiles[$i], $i - 1) ; ListView-Eintrag hinzufügen
    Next

    [/autoit] [autoit][/autoit] [autoit]

    Do
    Until GUIGetMsg() = -3

    [/autoit] [autoit][/autoit] [autoit]

    Func _ImageFilesToIcons($sFilePath, $sFilter = '*', $iWidth = 32, $iHeight = 32)
    Local $aFiles = _FileListToArray($sFilePath, $sFilter, $FLTA_FILES, True)
    If @error Then Return SetError(1, 0, 0)
    Local $hPic, $hBitmap, $hIcon
    _GDIPlus_Startup()
    For $i = 1 To $aFiles[0]
    $hPic = _GDIPlus_ImageLoadFromFile($aFiles[$i])
    If Not @error Then
    $hBitmap = _GDIPlus_ImageResize($hPic, $iWidth, $iHeight)
    $hIcon = _GDIPlus_HICONCreateFromBitmap($hBitmap)
    _GDIPlus_ImageDispose($hPic)
    _GDIPlus_BitmapDispose($hBitmap)
    _WinAPI_SaveHICONToFile(StringRegExpReplace($aFiles[$i], '(.+\.).+', '$1') & 'ico', $hIcon)
    _WinAPI_DestroyIcon($hIcon)
    Else
    ConsoleWrite('!> "' & $aFiles[$i] & '" konnte nicht geladen werden!' & @CR)
    EndIf
    Next
    _GDIPlus_Shutdown()
    EndFunc ;==>_ImageFilesToIcons

    [/autoit]