Remove Window Flicker

Just starting out? Need help? Post your questions and find answers here.
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Remove Window Flicker

Post 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.
Last edited by JHPJHP on Tue Dec 23, 2014 9:34 am, edited 3 times in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Remove Window Flicker

Post 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
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Re: Remove Window Flicker

Post 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!
Last edited by JHPJHP on Tue Dec 23, 2014 9:24 am, edited 1 time in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Remove Window Flicker

Post 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
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Re: Remove Window Flicker

Post by JHPJHP »

I had the same idea, and tried Delay(100) - just made things worse. Thanks for taking a look.
Last edited by JHPJHP on Tue Dec 23, 2014 9:25 am, edited 1 time in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Remove Window Flicker

Post 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.
BERESHEIT
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Remove Window Flicker

Post 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
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Remove Window Flicker

Post by netmaestro »

That's a bit better than the original but it still wobbles here on moving. It is an improvement though.
BERESHEIT
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Re: Remove Window Flicker

Post 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,

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: Remove Window Flicker

Post 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)
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Remove Window Flicker

Post 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.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Remove Window Flicker

Post by IdeasVacuum »

IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Re: Remove Window Flicker

Post 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!!!
Last edited by JHPJHP on Tue Dec 23, 2014 9:30 am, edited 2 times in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: Remove Window Flicker

Post 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.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
JHPJHP
Addict
Addict
Posts: 2253
Joined: Sat Oct 09, 2010 3:47 am

Re: Remove Window Flicker

Post 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.
Last edited by JHPJHP on Tue Dec 23, 2014 9:30 am, edited 1 time in total.

If you're not investing in yourself, you're falling behind.

My PureBasic StuffFREE STUFF, Scripts & Programs.
My PureBasic Forum ➤ Questions, Requests & Comments.
Post Reply