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 :twisted:

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.