Jump to content

create simple double buffering with gdi+ ?


pixartist
 Share

Recommended Posts

$hWnd = WinGetHandle("mywindow")
_GDIPlus_Startup ()

$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    ;_WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.

this doesnt work :) the onpaint function triggers itself by repainting the window :)

Link to comment
Share on other sites

$hWnd = WinGetHandle("mywindow")
_GDIPlus_Startup ()

$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    ;_WinAPI_RedrawWindow($hGUI, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.

this doesnt work :( the onpaint function triggers itself by repainting the window :(

Here is a working template.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>

Global $GuiSizeX = 500, $GuiSizeY = 500

$hGui = GUICreate("GDIPlus Example", $GuiSizeX, $GuiSizeY)
GUISetState()

_GDIPlus_Startup()
;$hImage = _GDIPlus_ImageLoadFromFile(@WindowsDir & "\Web\Wallpaper\Autumn.jpg")
; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)

;End Double Buffer add-in 1 of 3

;Graphics here
_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
;$hBrush = _GDIPlus_BrushCreateSolid(0xFF0080FF)
;_GDIPlus_GraphicsFillEllipse($hGraphic, 3, 3, 50, 90, $hBrush)

;$hPen = _GDIPlus_PenCreate(0xFFFF0000, 2)
;_GDIPlus_GraphicsDrawLine($hGraphic, 0, $GuiSizeX, $GuiSizeY, 0, $hPen)



;End of graphics

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;End Double Buffer add-on 2 of 3

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
    ;_GDIPlus_BrushDispose($hBrush)
    ;_GDIPlus_PenDispose($hPen)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()         
            Exit            
    EndSwitch
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc ;==>MY_PAINT

And, this is an interesting way Smashly has done it.

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>

Opt("GUIOnEventMode", 1);0=disabled, 1=OnEvent mode enabled
Global Const $iPI = 3.1415926535897932384626433832795

Global $ApW = 600, $ApH = 400
Global $Button[1]

$hGui = GUICreate("GDIPlus Graphics on Picture Control - OnEvent Mode", $ApW + 40, $ApH + 40)
GUISetOnEvent(-3, "_Quit")
GUISetBkColor(0xff8080, $hGui)

$Pic = GUICtrlCreatePic("", 20, 20, $ApW, $ApH)
GUICtrlSetState(-1, $GUI_DISABLE)

$Button[0] = GUICtrlCreateButton("Exit", 5, 5, 100, 45)
GUICtrlSetOnEvent($Button[0], "_Quit")
GUICtrlSetBkColor(-1, 0xF000FF)
GUICtrlSetColor(-1, 0xBadB0B)

GUICtrlCreateLabel("$iH = $iWidth - $iW", 120, 75, 200, 20)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)

PicSetGraphics($Pic, $ApW, $ApH)


While 1
    Sleep(10)
WEnd

Func PicSetGraphics($cID, $iW, $iH)
    Local Const $STM_SETIMAGE = 0x0172
    Local Const $IMAGE_BITMAP = 0
    Local $hWnd, $hBitmap, $hImage, $hGraphic, $hBrush, $hBrush1, $hbmp, $aBmp
    $hWnd = GUICtrlGetHandle($cID)
    _GDIPlus_Startup()
    
    $hBitmap = _WinAPI_CreateSolidBitmap($hGui, 0xFFFF90, $iW, $iH)     
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)
    
    GUISetState(@SW_SHOW, $hGui)
    
;----->  All Graphics Here
    
    $hBrush = _GDIPlus_BrushCreateSolid(0xFF000090)
    _GDIPlus_GraphicsFillEllipse($hGraphic, 200, 20, 100, 150, $hBrush) 
    
; -----> End of all Graphics
    
    $hbmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    $aBmp = DllCall("user32.dll", "hwnd", "SendMessage", "hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hbmp)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME))
    
; Save Graphics on picture control
;_GDIPlus_ImageSaveToFile($hImage, @DesktopDir & "\TestWrite1.png")
;ShellExecute(@DesktopDir & "\TestWrite1.png")
    
    If $aBmp[0] <> 0 Then _WinAPI_DeleteObject($aBmp[0])
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BrushDispose($hBrush1)
    _GDIPlus_GraphicsDispose($hGraphic)
    _WinAPI_DeleteObject($hbmp)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_Shutdown()
EndFunc  ;==>PicSetGraphics

Func _Quit()
    Exit
EndFunc  ;==>_Quit
Edited by Malkey
Link to comment
Share on other sites

@Malkey: Maybe a little off topic, but, how do you could set an event to a graphic maded with GDI+ or the best method for you? Thanks.

In Smashly's example in post #2, the graphics are drawn on a pic control, one could "not disable" the pic control and use GUICtrlSetOnEvent($Pic, "_Pic"). But problems can arise with other controls when enabling a large pic control.

Thinking about it, I came up with an OnEvent example and posted to the thread at

http://www.autoitscript.com/forum/index.ph...st&p=647030

Edit: Also, monoceres used OnEvent mode in his Magic Wand script here

http://www.autoitscript.com/forum/index.ph...st&p=589516

Edited by Malkey
Link to comment
Share on other sites

In Smashly's example in post #2, the graphics are drawn on a pic control, one could "not disable" the pic control and use GUICtrlSetOnEvent($Pic, "_Pic"). But problems can arise with other controls when enabling a large pic control.

Thinking about it, I came up with an OnEvent example and posted to the thread at

http://www.autoitscript.com/forum/index.ph...st&p=647030

Edit: Also, monoceres used OnEvent mode in his Magic Wand script here

http://www.autoitscript.com/forum/index.ph...st&p=589516

I'm thinking about this way, too (Attaching to a control). Currently, I'm doing a script with knobs like an EQ, where the control needs a notify to be rotated. For this reason I'm thinking in GDI+ use.

I will try to apply your tips. Thanks, Malkey.

Link to comment
Share on other sites

Here is a working template.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>

Global $GuiSizeX = 500, $GuiSizeY = 500

$hGui = GUICreate("GDIPlus Example", $GuiSizeX, $GuiSizeY)
GUISetState()

_GDIPlus_Startup()
;$hImage = _GDIPlus_ImageLoadFromFile(@WindowsDir & "\Web\Wallpaper\Autumn.jpg")
; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)

;End Double Buffer add-in 1 of 3

;Graphics here
_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
;$hBrush = _GDIPlus_BrushCreateSolid(0xFF0080FF)
;_GDIPlus_GraphicsFillEllipse($hGraphic, 3, 3, 50, 90, $hBrush)

;$hPen = _GDIPlus_PenCreate(0xFFFF0000, 2)
;_GDIPlus_GraphicsDrawLine($hGraphic, 0, $GuiSizeX, $GuiSizeY, 0, $hPen)



;End of graphics

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;End Double Buffer add-on 2 of 3

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
;_GDIPlus_BrushDispose($hBrush)
;_GDIPlus_PenDispose($hPen)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()         
            Exit            
    EndSwitch
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
; Check, if the GUI with the Graphic should be repainted
; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc;==>MY_PAINT
the problem is, did you try out the first example? it lags like HELL when redrawn... Edited by pixartist
Link to comment
Share on other sites

the problem is, did you try out the first example? it lags like HELL when redrawn...

If you can live without the re-painting of the GUI after restoring from a minimized state, removing the invalidate command from the MY_PAINT() function does reduce the lag.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>

Global $GuiSizeX = 500, $GuiSizeY = 500

$hGui = GUICreate("GDIPlus Example", $GuiSizeX, $GuiSizeY)
GUISetState()

_GDIPlus_Startup()
;$hImage = _GDIPlus_ImageLoadFromFile(@WindowsDir & "\Web\Wallpaper\Autumn.jpg")
; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)

;End Double Buffer add-in 1 of 3

;Graphics here
_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
;$hBrush = _GDIPlus_BrushCreateSolid(0xFF0080FF)
;_GDIPlus_GraphicsFillEllipse($hGraphic, 3, 3, 50, 90, $hBrush)

$hPen = _GDIPlus_PenCreate(0xFFFF0000, 2)
_GDIPlus_GraphicsDrawLine($hGraphic, 0, $GuiSizeX, $GuiSizeY, 0, $hPen)


;End of graphics

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.

_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
_WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
;End Double Buffer add-on 2 of 3

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
        ;_GDIPlus_BrushDispose($hBrush)
            _GDIPlus_PenDispose($hPen)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()
            Exit
    EndSwitch
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;_WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_FRAME, $RDW_UPDATENOW );, $RDW_ALLCHILDREN));

    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

Another way to repaint or refresh the graphics at approximately 33 frame per sec is using _Timer_SetTimer().

I think there was a better way already posted somewhere on these forums.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <Timers.au3>
Global $GuiSizeX = 500, $GuiSizeY = 500

$hGui = GUICreate("GDIPlus Example", $GuiSizeX, $GuiSizeY)
GUISetState()

_GDIPlus_Startup()
;$hImage = _GDIPlus_ImageLoadFromFile(@WindowsDir & "\Web\Wallpaper\Autumn.jpg")

; Create Double Buffer
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer

;Graphics here
_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
;$hBrush = _GDIPlus_BrushCreateSolid(0xFF0080FF)
;_GDIPlus_GraphicsFillEllipse($hGraphic, 3, 3, 50, 90, $hBrush)

$hPen = _GDIPlus_PenCreate(0xFFFF0000, 2)
_GDIPlus_GraphicsDrawLine($hGraphic, 0, $GuiSizeX, $GuiSizeY, 0, $hPen)

;End of graphics

_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)

$iTimer = _Timer_SetTimer($hGui, 30, "MY_PAINT"); create timer

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
        ;_GDIPlus_BrushDispose($hBrush)
            _GDIPlus_PenDispose($hPen)
            _Timer_KillTimer($hGui, $iTimer)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()

            Exit
    EndSwitch
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
EndFunc  ;==>MY_PAINT
Link to comment
Share on other sites

how to paint on an Pic object with gdi+ then ? is that even possible ?

If you look at the second example Post #2, I mentioned it is an interesting way Smashly has done it.

That comment expanded is:-

The script has the GDI+ graphics on a Pic control () . Following the picture control down the script we have

Created here $Pic = GUICtrlCreatePic("", 20, 20, $ApW, $ApH)

The pic control ID is transferred to the PicSetGraphics($cID, $iW, $iH) function here PicSetGraphics($Pic, $ApW, $ApH)

Within the PicSetGraphics() function the pic control ID, $Pic, is called $cID.

The handle of the pic control is created here $hWnd = GUICtrlGetHandle($cID)

The re-painting or refreshing of the graphics on the pic control on the GUI is done here

$aBmp = DllCall("user32.dll", "hwnd", "SendMessage", "hwnd", $hWnd, "int", $STM_SETIMAGE, "int", $IMAGE_BITMAP, "int", $hbmp)

using $hWnd, which is the handle of the pic control.

I still think this is interesting because I can not yet imagine the possibilities that this method makes available for the use of GDI+ graphics on a GUI.

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...