I have made picture viewer in VB which also shows all the pics present in a folder as thumbnails using image list and listbox. The problem is whenever the user clicks refresh it takes long time for the image to load. I want to some how make a cache like thing where i can store the image for faster access in the future.

Edited 5 Years Ago by battlex2010: n/a

I have made picture viewer in VB which also shows all the pics present in a folder as thumbnails using image list and listbox. The problem is whenever the user clicks refresh it takes long time for the image to load. I want to some how make a cache like thing where i can store the image for faster access in the future.

Simple Approach

Here is how I would approach the problem. Firstly, I will build a custom control to display the thumbnails of a given directory path. Then, I create a DirectoryPath property which I can tell my control to list all pictures in that directory in thumbnails.

Dim memDirectoryPath As String = ""
Dim memFile As New List(Of IO.FileInfo)
Dim memThumbnail As New List(Of Image)

Public Property DirectoryPath() As String
        Get
            Return memDirectoryPath
        End Get
        Set(ByVal value As String)
            memDirectoryPath = value
        End Set
End Property

Then I want to construct list of files and list of thumbnails in given directory whenever the directory is assigned.

Public Property DirectoryPath() As String
        Get
            Return memDirectoryPath
        End Get
        Set(ByVal value As String)
            memDirectoryPath = value

            '' Clear the old list of file and thumbnail
            memFile.Clear()
            memThumbnail.Clear()

            '' Construct list of file and its thumbnail
            For Each file As IO.FileInfo In (New IO.DirectoryInfo(value)).GetFiles()
                memFile.Add(file)
                memThumbnail.Add(Nothing)
            Next
        End Set
End Property

Notice that I add Nothing as a thumbnail which actually is not the thumbnail of the file. Assuming that the directory contains a thousand of images. Constructing a thousand of thumbnails is very expensive. I wouldn't want my program to become struck whenever I accidentally browse such directory. What I really want to do is loading only thumbnails that are necessary.

So the question laid on how to define "what is necessary". Lets say my whole screen could only display thumbnail in 10 columns and 5 rows which is 50 thumbnails per screen. So only 50 thumbnails get to display on the screen per time. Another 950 thumbnails will be hidden. Then, it is not necessary to load those 950 thumbnails.

Whenever, I scroll a row down then I will need to load another 10 new thumbnails. If I scroll a row up. I won't need to load any new thumbnails because it is already loaded.

'' Starting row.
    Dim memStartRow As Integer = 0
    '' Number of rows that can be display on the screen.
    Dim memMaxRowPerScreen As Integer
    '' Number of column that can be display on the screen.
    Dim memMaxColumnPerScreen As Integer

    Const THUMBNAIL_WIDTH As Integer = 120
    Const THUMBNAIL_HEIGHT As Integer = 80
    Const THUMBNAIL_PADDING As Integer = 5

    Private Sub Thumbnailer_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _
                                        Handles Me.Paint
        If memFile.Count = 0 Then
            '' No need to display anything if there is no picture
            Exit Sub
        End If

        Dim index As Integer = memStartRow * memMaxColumnPerScreen
        Dim x As Integer = THUMBNAIL_PADDING
        Dim y As Integer = THUMBNAIL_PADDING

        For i As Integer = memStartRow To memStartRow + memMaxRowPerScreen
            For j As Integer = 1 To memMaxColumnPerScreen
                If memThumbnail(index) Is Nothing Then
                    '' If it is not already loaded, load the thumbnail
                    Dim fullImage As Image = Image.FromFile(memFile(index).FullName)
                    memThumbnail(index) = fullImage.GetThumbnailImage( _
                                        THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, Nothing, New IntPtr)
                    fullImage.Dispose()
                End If

                e.Graphics.DrawImage(memThumbnail(index), x, y)
                x += THUMBNAIL_WIDTH + THUMBNAIL_PADDING

                index += 1
                If index >= memFile.Count Then
                    '' There is no more thumbnail.
                    Exit Sub
                End If
            Next

            x = THUMBNAIL_PADDING
            y += THUMBNAIL_HEIGHT + THUMBNAIL_PADDING
        Next
    End Sub

There are a few things that need to be done to make this control functional such as having scroll bar and thumbnail is select-able. Scroll bar can easily be implemented by changing the memStartRow value whenever the scroll bar value is changed.

Better Approach

There are better solution to the problem than the above solution which involve with thread. Whenever DirectoryPath property is changed, I will create a thread to slowly load all the thumbnails. Whenever each thumbnail is successfully loaded, I will check whether that thumbnail is currently displayed on the screen. If it is, then invalidate the control.

Edited 5 Years Ago by invisal: n/a

This question has already been answered. Start a new discussion instead.