Jump to content

A couple of questions regarding bitmaps and GUI


NMS
 Share

Recommended Posts

FIrst of all, I apologize for the state of how it all looks as I had to remove thousands of lines to make a workable demo. It works, but it's not pretty. So if you see any inconsistencies just handwave it and they'll go away.

1. First issue is with Global $idPic = GUICtrlCreatePic('', 10, 45, 720, 405) on line 15.
It works well however I want to center the image in the control by using $SS_CENTERIMAGE. The moment I add that style and click on a different image the new one simply repaints on top of the old one. Refer to function Func1 for repainting. I could always resize the picture control and place it in the middle based on the bitmap passed but seems like the $SS_CENTERIMAGE is (should be) the perfect solution.

2. Next is the fact that I couldn't find a way to make images scrollable with a horizontal bar only in the list view. Basically one row and infinite columns is what I'd like. I tried formatting the list with with just 1 item and all the rest are subitems however the images are not displayed. Seems like the isssue is with the _GUICtrlListView_SetView($idListview, 0). Specifically the fact that 0 value refers to large icons and the list is then treated differently. I'm wondering if there are any workarounds or similar solutions.

3. It seems there's a memory leak in function Func1. RAM increases each time a new thumbnail is loaded without releasing the old one when next one is drawn.

Spoiler
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <StaticConstants.au3>
#include <File.au3>
#include <GuiImageList.au3>
#include <GDIPlus.au3>

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
_GDIPlus_Startup()

Global $PATH_TO_FOLDER_WITH_IMAGES = 'C:\Windows\Web\Wallpaper\Theme1\'

Global $hGUI1 = GUICreate('test', 1000, 660, -1, -1)
Global $idPic = GUICtrlCreatePic('', 10, 45, 720, 405) ;BitOR($SS_NOTIFY, $SS_CENTERIMAGE)
GUICtrlSetResizing(-1, BitOR($GUI_DOCKLEFT, $GUI_DOCKTOP, $GUI_DOCKWIDTH, $GUI_DOCKHEIGHT))
Global $idListview = GUICtrlCreateListView('',  10, 470, 980, 160, _
                                     BitOR($LVS_SINGLESEL, $LVS_SORTASCENDING, $LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_REPORT), _
                                     BitOR($LVS_EX_SNAPTOGRID, $LVS_EX_DOUBLEBUFFER, $LVS_EX_SUBITEMIMAGES))
GUICtrlSetBkColor(-1, $COLOR_WHITE)
_GUICtrlListView_SetView($idListview, 0)
_GUICtrlListView_SetIconSpacing($idListview, 119, 40)
_GUICtrlListView_SetTextColor($idListview, $COLOR_BLACK)
GUISetState(@SW_SHOW, $hGUI1)

Local $aArray = _FileListToArray($PATH_TO_FOLDER_WITH_IMAGES, '*', 1)

Local $hImage = _GUIImageList_Create(100, 100, 5, 1)
_GUICtrlListView_SetImageList($idListview, $hImage, 0)
Local $TempCount = 0
For $i = 1 To $aArray[0]
    If StringRegExp($aArray[$i], '(?i)\.(jpeg|jpg|png)', 0) Then
        Local $TempBitmap = Resize($PATH_TO_FOLDER_WITH_IMAGES & $aArray[$i], 100)
        _GUIImageList_Add($hImage, $TempBitmap)
        _WinAPI_DeleteObject($TempBitmap)
        _GUICtrlListView_AddItem($idListview, $aArray[$i], $TempCount)
        _GUICtrlListView_SetItemImage($idListview, $TempCount, $TempCount)
        $TempCount += 1
    EndIf
Next


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

Func Func1($TempValue)
    If $TempValue = -1 Then
        GUICtrlSendMsg($idPic, $STM_SETIMAGE, 0, 0)
        Return
    EndIf

    Local $TempImage = ''
    $TempImage = $PATH_TO_FOLDER_WITH_IMAGES & _GUICtrlListView_GetItemText($idListview, $TempValue)
    Local $TempBitmapImage = _GDIPlus_ImageLoadFromFile($TempImage)
    If Not @error Then
        GUICtrlSendMsg($idPic, $STM_SETIMAGE, 0, 0)
        ;Dimensions should not exceed 720 x 405
        Local $TempWidth = _GDIPlus_ImageGetWidth($TempBitmapImage)
        Local $TempHeight = _GDIPlus_ImageGetHeight($TempBitmapImage)
        Local $TempWidthNew = $TempWidth * 405 / $TempHeight
        Local $TempHeightNew = 405
        If $TempWidthNew > 720 Then
            $TempWidthNew = 720
            $TempHeightNew = $TempHeight * 720 / $TempWidth
        EndIf
        Local $TempBitmapResized = _GDIPlus_ImageResize($TempBitmapImage, $TempWidthNew, $TempHeightNew)
        Local $TempBitmapNew = _GDIPlus_BitmapCreateHBITMAPFromBitmap($TempBitmapResized)
        _WinAPI_DeleteObject(GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $TempBitmapNew))
        _WinAPI_DeleteObject($TempBitmapNew)
        _GDIPlus_ImageDispose($TempBitmapImage)
        _GDIPlus_BitmapDispose($TempBitmapResized)
    EndIf
EndFunc

Func Resize($TempFile, $TempWidthOld)
    Local $TempBitmap1, $TempBitmap2, $TempGraphic, $TempImage, $TempWidth, $TempHeight, $TempSize, $TempBitmapReturn
    $TempBitmap1 = _WinAPI_CreateBitmap($TempWidthOld, $TempWidthOld, 1, 32)
    $TempBitmap2 = _GDIPlus_BitmapCreateFromHBITMAP($TempBitmap1)
    $TempGraphic = _GDIPlus_ImageGetGraphicsContext($TempBitmap2)
    _WinAPI_DeleteObject($TempBitmap1)
    _GDIPlus_GraphicsClear($TempGraphic, BitOR(0xFF000000, $COLOR_WHITE))
    $TempImage = _GDIPlus_ImageLoadFromFile($TempFile)
    $TempWidth = _GDIPlus_ImageGetWidth($TempImage)
    $TempHeight = _GDIPlus_ImageGetHeight($TempImage)
    $TempSize = Func2($TempWidth, $TempHeight, $TempWidthOld)
    _GDIPlus_GraphicsDrawImageRect($TempGraphic, $TempImage, $TempSize[0], $TempSize[1], $TempSize[2], $TempSize[3])
    _GDIPlus_ImageDispose($TempImage)
    _GDIPlus_GraphicsDispose($TempGraphic)
    $TempBitmapReturn = _GDIPlus_BitmapCreateHBITMAPFromBitmap($TempBitmap2)
    _GDIPlus_BitmapDispose($TempBitmap2)
    Return $TempBitmapReturn
EndFunc

Func Func2($TempWidth, $TempHeight, $TempWidthOld)
    Local $TempReturn[4]
    If $TempWidth <= $TempWidthOld And $TempHeight <= $TempWidthOld Then
        $TempReturn[2] = $TempWidth
        $TempReturn[3] = $TempHeight
        $TempReturn[0] = ($TempWidthOld - $TempReturn[2]) / 2
        $TempReturn[1] = ($TempWidthOld - $TempReturn[3]) / 2
    ElseIf $TempWidth > $TempHeight Then
        $TempReturn[2] = $TempWidthOld
        $TempReturn[3] = $TempHeight / ($TempWidth / $TempWidthOld)
        $TempReturn[0] = 0
        $TempReturn[1] = ($TempWidthOld - $TempReturn[3]) / 2
    ElseIf $TempWidth < $TempHeight Then
        $TempReturn[2] = $TempWidth / ($TempHeight / $TempWidthOld)
        $TempReturn[3] = $TempWidthOld
        $TempReturn[0] = ($TempWidthOld - $TempReturn[2]) / 2
        $TempReturn[1] = 0
    ElseIf $TempWidth = $TempHeight Then
        $TempReturn[2] = $TempWidthOld
        $TempReturn[3] = $TempWidthOld
        $TempReturn[0] = 0
        $TempReturn[1] = 0
    EndIf
    Return $TempReturn
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local $hWndFrom, $iCode, $tNMHDR, $hWndListView1, $hWndListView2
    $hWndListView2 = GUICtrlGetHandle($idListview)
    $tNMHDR = DllStructCreate('hwnd hWndFrom;int_ptr IDFrom;int Code', $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
    $iCode = DllStructGetData($tNMHDR, 'Code')
    Switch $hWndFrom
        Case $hWndListView2
            Switch $iCode
                Case $NM_CLICK
                    Local $TempIndex = _GUICtrlListView_GetNextItem($hWndListView2)
                    Func1($TempIndex)
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc

 

Any help is much appreciated. Been stuck on couple of these for a few days now.

Link to comment
Share on other sites

Maybe consider deliberate repositioning, based on window and image widths and using On Event for window resize detection for your first issue.

Make sure brain is in gear before opening mouth!
Remember, what is not said, can be just as important as what is said.

Spoiler

What is the Secret Key? Life is like a Donut

If I put effort into communication, I expect you to read properly & fully, or just not comment.
Ignoring those who try to divert conversation with irrelevancies.
If I'm intent on insulting you or being rude, I will be obvious, not ambiguous about it.
I'm only big and bad, to those who have an over-active imagination.

I may have the Artistic Liesense ;) to disagree with you. TheSaint's Toolbox (be advised many downloads are not working due to ISP screwup with my storage)

userbar.png

Link to comment
Share on other sites

On 7/18/2023 at 2:34 PM, TheSaint said:

Maybe consider deliberate repositioning, based on window and image widths and using On Event for window resize detection for your first issue.

A solution I considered.

On 7/21/2023 at 1:41 PM, Zedna said:

Sorry for not helping, just want to say it's (simple) nice example using Listview for images preview ...

I've seen it somewhere before tbh, not my idea. Don't remember where.

 

Anyway, I can find workarounds for the first 2 however I'm not sure what to do with the third one.

According to this article https://learn.microsoft.com/en-us/windows/win32/controls/stm-setimage the leak needs to be cleaned manually however it doesn't work. There's no error, _WinAPI_DeleteObject() should do the trick but it doesn't...

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...