Page 1 of 2
Remove Window Flicker
Posted: Tue Jun 05, 2012 9:32 pm
by JHPJHP
Hi,
I wrote a Magnify window, but the quality wasn't as clear for some of the resized images I was using it for, so I decided to go at it another way...
I load a fullsize version of the image into memory, and when the "magnify" window passes over the resized smaller version of the image - I "GrabImage" from the fullsize version, but the image flickers on #WM_MOVE.
The following:
Code: Select all
SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
works for the most part to resolve the flicker, but causes other adverse affects which I would rather avoid.
Code: Select all
Macro HIWORD(long)
(long >> 16) & $FFFF
EndMacro
Macro LOWORD(long)
long & $FFFF
EndMacro
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_MOVE
xpos = LOWORD(lParam)
ypos = HIWORD(lParam)
newImage = GrabImage(1, #PB_Any, xpos, ypos, 200, 200)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "Magnify", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
; SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
; SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
ImageGadget(0, 0, 0, 200, 200, #Null)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #TRUE)
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
...
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If #WM_LBUTTONDOWN : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Select EventType()
Case #PB_EventType_LeftDoubleClick
CloseWindow(0)
FreeImage(1)
End
EndSelect
EndSelect
ForEver
Any insite to resolve the flicker would be much appreciated.
Re: Remove Window Flicker
Posted: Tue Jun 05, 2012 10:22 pm
by IdeasVacuum
Hi JHPJHP, I can't see what it is we should do to replicate the flicker problem. The code snippet as-is does not run, suspect there is something missing anyway? If I butcher the code just to "make it work", all I see is the magnify window, which can be dragged around but it's opaque and doesn't show an image (and that's surely because I'm a lousy butcher lol):
Code: Select all
UsePNGImageDecoder()
gImageID.i = 0
Macro HIWORD(long)
(long >> 16) & $FFFF
EndMacro
Macro LOWORD(long)
long & $FFFF
EndMacro
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_MOVE
xpos = LOWORD(lParam)
ypos = HIWORD(lParam)
newImage = GrabImage(gImageID, #PB_Any, xpos, ypos, 200, 200)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "Magnify", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
SetLayeredWindowAttributes_(WindowID(0),0,196,#LWA_ALPHA) ;Transparency
gImageID = LoadImage(0, "C:\Program Files\PureBasic461\Examples\Sources\Data\Geebee2.ico")
SendMessage_(WindowID(0), #WM_SETICON, 0, gImageID)
ImageGadget(0, 0, 0, 200, 200, #Null)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #True)
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
OpenWindowMagnify()
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If #WM_LBUTTONDOWN : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Select EventType()
Case #PB_EventType_LeftDoubleClick
FreeImage(gImageID)
CloseWindow(0)
End
EndSelect
EndSelect
ForEver
Re: Remove Window Flicker
Posted: Tue Jun 05, 2012 10:38 pm
by JHPJHP
Hey IdeasVacuum,
Just put any jpeg image to C:\test.jpg...
NB*: Left mouse button down to drag the window (it's less of a flicker and more of a shake)... Double-click to close.
Code: Select all
Macro HIWORD(long)
(long >> 16) & $FFFF
EndMacro
Macro LOWORD(long)
long & $FFFF
EndMacro
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_MOVE
xpos = LOWORD(lParam)
ypos = HIWORD(lParam)
newImage = GrabImage(1, #PB_Any, xpos, ypos, 200, 200)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "Magnify", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
; SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
; SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
ImageGadget(0, 0, 0, 200, 200, #Null)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #TRUE)
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
UseJPEGImageDecoder()
LoadImage(1, "C:\test.jpg")
OpenWindowMagnify()
newImage = GrabImage(1, #PB_Any, WindowX(0), WindowY(0), 200, 200)
If newImage
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If #WM_LBUTTONDOWN : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Select EventType()
Case #PB_EventType_LeftDoubleClick
CloseWindow(0)
FreeImage(1)
End
EndSelect
EndSelect
ForEver
Cheers!
Re: Remove Window Flicker
Posted: Tue Jun 05, 2012 11:13 pm
by IdeasVacuum
OK, the original image does need to be bigger than, erm, a small image.
I see the effect - sort of a wobble rather than a flicker. Tried using a delay (WaitWindowEvent), which strangely had no effect.
This is the sort of thing that netmaestro is very good at, so hopefully he will take a look at the post.
test.jpg 682x512:
test.jpg
Re: Remove Window Flicker
Posted: Tue Jun 05, 2012 11:17 pm
by JHPJHP
I had the same idea, and tried Delay(100) - just made things worse. Thanks for taking a look.
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 12:16 am
by netmaestro
I can get it quite a bit better but not perfect yet. If I can improve on what I have I'll post some code. In the meantime, note that this code:
Code: Select all
Case #PB_Event_Gadget
If #WM_LBUTTONDOWN : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
doesn't quite do what you want it to. #WM_LBUTTONDOWN is a non-zero constant and so the If will always succeed. What's happening is that on any gadget event at all the SendMessage_() is executing. But this isn't affecting performance, just worth noting.
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 12:29 am
by breeze4me
try this.
Code: Select all
Macro HIWORD(long)
(((long) >> 16) & $FFFF)
EndMacro
Macro LOWORD(long)
((long) & $FFFF)
EndMacro
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_MOVING
*r.RECT = lParam
xpos = *r\left
ypos = *r\top
newImage = GrabImage(1, #PB_Any, xpos+200, ypos+200, 200, 200)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
Case #WM_EXITSIZEMOVE
ypos = WindowY(0)
If ypos < 0
ResizeWindow(0, #PB_Ignore, #PB_Ignore, 200, 200)
newImage = GrabImage(1, #PB_Any, WindowX(0)+200, ypos+200, 200, 200)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndIf
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "Magnify", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
; SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
; SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
ImageGadget(0, 0, 0, 200, 200, #Null)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #True)
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
UseJPEGImageDecoder()
LoadImage(2, "c:\test.jpg")
OpenWindowMagnify()
If CreateImage(1, ImageWidth(2) + 200, ImageHeight(2) + 200)
StartDrawing(ImageOutput(1))
DrawImage(ImageID(2), 200, 200)
StopDrawing()
EndIf
FreeImage(2)
newImage = GrabImage(1, #PB_Any, WindowX(0)+200, WindowY(0)+200, 200, 200)
If newImage
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If #WM_LBUTTONDOWN : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Select EventType()
Case #PB_EventType_LeftDoubleClick
CloseWindow(0)
FreeImage(1)
End
EndSelect
EndSelect
ForEver
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 12:33 am
by netmaestro
That's a bit better than the original but it still wobbles here on moving. It is an improvement though.
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 2:43 am
by JHPJHP
breeze4me, thanks for the efforts, but netmaestro is correct - there is still a wobble, it's even more prevalent with the images I'm using.
With my original code though it's almost completely gone if the following is added after the OpenWindow function:
Code: Select all
SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
But if a window is opened below the Magnify window - Layering allows it to bleed through.
netmaestro, thanks for pointing out the irrelevent code - I switched #LBUTTONDOWN to:
Code: Select all
If GetKeyState_(#VK_LBUTTON) : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Not a perfect replacement, but instead of all the Gadget events being hit only lbuttondown & lbuttonup are affected; I will write a MouseHook later, after I figure out why theres a wobble...
Thanks again guys,
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 7:09 am
by breeze4me
It looks like an internal drawing issue of Windows.
Code: Select all
Global quit
Procedure DrawImg(x, y)
If StartDrawing(WindowOutput(0))
newImage = GrabImage(1, #PB_Any, x + 200, y + 200, 200, 200)
If newImage
DrawImage(ImageID(newImage), 0, 0)
SetGadgetState(0, ImageID(newImage))
FreeImage(newImage)
EndIf
StopDrawing()
EndIf
;RedrawWindow_(WindowID(0), 0, 0, #RDW_ERASE|#RDW_INVALIDATE|#RDW_ERASENOW|#RDW_UPDATENOW|#RDW_NOCHILDREN) ;wobble terribly.
;RedrawWindow_(WindowID(0), 0, 0, #RDW_NOERASE|#RDW_INVALIDATE|#RDW_UPDATENOW|#RDW_NOCHILDREN)
;RedrawWindow_(WindowID(0), 0, 0, #RDW_INVALIDATE|#RDW_UPDATENOW|#RDW_NOCHILDREN)
;RedrawWindow_(WindowID(0), 0, 0, #RDW_NOERASE|#RDW_VALIDATE|#RDW_NOINTERNALPAINT|#RDW_NOCHILDREN)
;RedrawWindow_(WindowID(0), 0, 0, #RDW_NOERASE|#RDW_VALIDATE|#RDW_NOCHILDREN) ;less wobbling.
EndProcedure
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_PAINT
DrawImg(WindowX(0), WindowY(0))
Case #WM_MOVING
*r.RECT = lParam
xpos = *r\left
ypos = *r\top
DrawImg(xpos, ypos)
Case #WM_EXITSIZEMOVE
ypos = WindowY(0)
If ypos < 0
ResizeWindow(0, #PB_Ignore, #PB_Ignore, 200, 200)
DrawImg(WindowX(0), WindowY(0))
EndIf
Case #WM_LBUTTONDOWN
SendMessage_(hWnd, #WM_NCLBUTTONDOWN, #HTCAPTION, #Null)
Case #WM_LBUTTONDBLCLK
quit = 1
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "Magnify", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
;SetWindowLongPtr_(WindowID(0), #GWL_EXSTYLE, #WS_EX_LAYERED)
;SetLayeredWindowAttributes_(WindowID(0), 0, #Null, #LWA_COLORKEY)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #True)
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
OpenWindow(1, 700, 0, 200, 200, "", #PB_Window_BorderLess)
ImageGadget(0, 0, 0, 200, 200, 0)
UseJPEGImageDecoder()
LoadImage(2, "c:\test.jpg")
OpenWindowMagnify()
If CreateImage(1, ImageWidth(2) + 200, ImageHeight(2) + 200)
StartDrawing(ImageOutput(1))
DrawImage(ImageID(2), 200, 200)
StopDrawing()
EndIf
FreeImage(2)
Repeat
event = WaitWindowEvent()
Until quit = 1 Or event = #PB_Event_CloseWindow
CloseWindow(0)
FreeImage(1)
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 2:51 pm
by IdeasVacuum
Code: Select all
Repeat
iEvent = WaitWindowEvent(1)
Select iEvent
Case #PB_Event_Gadget: SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null)
Case #WM_LBUTTONDBLCLK
CloseWindow(0)
FreeImage(1)
End
EndSelect
ForEver
Add another Select condition if you have more than one gadget on the real app.
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 3:00 pm
by IdeasVacuum
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 4:32 pm
by JHPJHP
breeze4me thanks for the scripts - and the work you put into them (I learn something new every day)... Oh, and I like how you took the #WM_LBUTTONDOWN and #WM_LBUTTONDBCLICK from the WaitWindowEvent Loop to the CallBack procedure - I'll be using that in the future
If it's "an internal drawing issue of Windows", then this approach may not be a viable solution. Messing with your DrawImg function, and inter-changing the SendMessage (#WM_MOVE), the wobble is till there with the moving image - whether it's Drawn or the gadget is set; the stationary one is perfect.
Code: Select all
Procedure DrawImg(xpos, ypos)
If StartDrawing(WindowOutput(0))
newImage = GrabImage(1, #PB_Any, xpos, ypos, 200, 200)
If newImage
DrawImage(ImageID(newImage), 0, 0)
SetGadgetState(1, ImageID(newImage))
FreeImage(newImage)
EndIf
StopDrawing()
EndIf
EndProcedure
Procedure MoveWindow(hWnd, uMsg, wParam, lParam)
Result = #PB_ProcessPureBasicEvents
Select uMsg
Case #WM_MOVE
DrawImg(WindowX(0), WindowY(0))
EndSelect
ProcedureReturn Result
EndProcedure
Procedure OpenWindowMagnify()
If OpenWindow(0, 0, 0, 200, 200, "", #PB_Window_ScreenCentered|#PB_Window_BorderLess)
ImageGadget(0, 0, 0, 200, 200, #Null)
StickyWindow(0, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(0), Region, #TRUE)
If OpenWindow(1, 700, 0, 200, 200, "", #PB_Window_BorderLess)
ImageGadget(1, 0, 0, 200, 200, #Null)
StickyWindow(1, 1)
Region = CreateEllipticRgn_(0, 0, 200, 200)
SetWindowRgn_(WindowID(1), Region, #TRUE)
EndIf
DeleteObject_(Region)
SetWindowCallback(@MoveWindow())
EndIf
EndProcedure
UseJPEGImageDecoder()
LoadImage(1, "C:\test.jpg")
OpenWindowMagnify()
DrawImg(WindowX(0), WindowY(0))
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
If GetKeyState_(#VK_LBUTTON) : SendMessage_(WindowID(0), #WM_NCLBUTTONDOWN, #HTCAPTION, #Null) : EndIf
Select EventType()
Case #PB_EventType_LeftDoubleClick
CloseWindow(0)
FreeImage(1)
Break
EndSelect
EndSelect
ForEver
IdeasVacuum - Thanks for the link, I'm just starting to read it now - hopefully it will bear some fruit.
Probably doesn't need to be said, but I will anyway: This is one awesome community!!!
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 4:59 pm
by IdeasVacuum
.....The strange thing is, the wobble appears to be a time delay. If it's not caused by too many Window re-paints, then maybe GrabImage() is the guilty party. I'm wondering if, on loading the main image, the code could divide the image into a 'grid of regions' and each region stored as a separate image - then the magnifier, according to location, would display the appropriate pre-defined region image. A compromise though.
Re: Remove Window Flicker
Posted: Wed Jun 06, 2012 7:01 pm
by JHPJHP
Hey IdeasVacuum,
Concerning the link you attached, I loaded PureBasic 4.51 onto an XP SP3 box, same result - the wobble remains.
Also tried using CopyImage after the GrabImage so that only a "Grid" portion of the image was being used by the SetGadgetState function - same result.