Jump to content
Tuts 4 You

Flickering and delay problems...


LCF-AT

Recommended Posts

Teddy Rogers
Posted

It wouldn't surprise me if InvalidateRect is compiled by default as I would suspect some of the PB gadgets use GDI functions at some point for drawing, e.g. canvas gadgets being one of the most prominent. I'd put the flickering issue in the topic you linked to down to the way PB handled drawing of gadgets back in it's earlier releases, there have been many improvements since 2008. I noticed they are using the PB function SmartWindowRefresh, I can't say I have ever needed to use that and will assume it's some sort of double buffering. The only flickering I have had problems with has always been on WinXP and often fixed by using WS_CLIPCHILDREN, as in my example when that OS is detected. Just be aware that some issues with GDI could be attributed to your graphic card and/or driver. Can you send me what you have done thus far and I'll see how it behaves here?

Ted.

Posted

Hi Ted,

WS_CLIPCHILDREN is good to reduce flickering but not only using this alone.Using this flag + both APIs at end of WM_SIZE is the best alternativ I could found till now.Anyway whether it make sense or not so just only the end results does count.On Internet you cant find any correctly working way how to handle it also not on MSDN so it seems to be secret or whatever.So for testing I did changed some of my apps using new flag & APIs and all look good so far and didnt seen any flickering anymore as I had before.Only two points bring a disadvantage.Manually resizing getting slower (can live with that issue) and Groupbox will not updated (cant use this control anymore but I can also live with that).So I made some pics....below the button in the GBox as it should shown...

2016-08-16_205005.png

...now below you see all smudge after moving window to left / right side and it keeps so till I move the mouse over it or minimize / max the window.

2016-08-16_205026.png

Below another one.This time with enabled WS_CLIPCHILDREN on main dialog.Right after starting it will shown so with any white color etc

2016-08-16_205144.png

Now if I move it then I get this to see...

2016-08-16_211127.png

....but is almost shown ok except on left / right side ends are some overlaps and above and below some black paints.So it looks totally bad BUT ONLY if I use a GBox.If I disable the GBox and set the flag to not visible then all is fine again.There must be any strange issue with that control.

All the trouble with controls resizing / flickering really sucks.Other things too of course on programing.

PS: Just make a test.Create a dialog with a button and a Groupbox and put button inside which also keep at same position if you move the window = with the window you know.If you did then check what happens if you move the window (larger smaller) and you should get same bad results without to use InvalidateRect API TRUE.Now on second try enable WS_CLIPCHILDREN on main dialog and try it too without InvalidateRect = also bad results.So what I mean is you should just try to get a button shown in a GBox 1A as it should shown if you resize the window with mouse and without to use InvalidateRect API at WM_SIZE etc.

PS2: If you want I can make some exe files with the diffrent flags / APIs for you to test etc.

greetz

Teddy Rogers
Posted

The joys of GDI! I would still try and avoid trying to force things to work by excluding regions and prompting updates unless you are actually drawing to a window.

If in doubt you can always resort to one safe option, guaranteed to work perfectly, WM_EXITSIZEMOVE...

Declare MenuCallback(hWnd, uMsg, wParam, lParam)

SetWindowCallback(@MenuCallback())

If OpenWindow(0, 0, 0, 500, 250, "Form1", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  WindowBounds(0, 500, 250, #PB_Ignore, #PB_Ignore)
  
  ; Create the listview, with some contents...
  
  ListIconGadget(1, 10, 10, 350, 170, "No.", 100, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
  AddGadgetColumn(1, 1, "Name", 100)
  AddGadgetColumn(1, 2, "Other", 100)
  
  For Num = 0 To 100
    AddGadgetItem(1, -1, "Test " + Str(Num) + #LF$ + "Test" + #LF$ + "Test")
  Next Num
  
  ; Create an exit button with a frame around it...
  
  FrameGadget(2, 380, 70, 100, 80, "Box")
  ButtonGadget(3, 390, 90, 80, 50, "Exit", #PB_Button_Toggle)

  ; Wait for a PB window event...
  
  Repeat
    Event = WaitWindowEvent()
    
    If GetGadgetState(3)
      Event = #PB_Event_CloseWindow
    EndIf

  Until Event = #PB_Event_CloseWindow
EndIf

Procedure MenuCallback(hWnd, uMsg, wParam, lParam)

  If uMsg = #WM_EXITSIZEMOVE

    Width = WindowWidth(0, #PB_Window_InnerCoordinate) - 150
    Height = WindowHeight(0, #PB_Window_InnerCoordinate) - 80
    
    ResizeGadget(1, #PB_Ignore, #PB_Ignore, Width, Height)
    ResizeGadget(2, Width + 30, Height - 100, #PB_Ignore, #PB_Ignore)
    ResizeGadget(3, Width + 40, Height - 80, #PB_Ignore, #PB_Ignore)

  EndIf
  
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Ted.

LCF-Test.exe

Posted

Hi Ted,

thanks again for your new testfile and infos.Ok so in your file nothing get moved inside the window till I release the button whats a little disadvantage so I would also like to see everything on resizing you know.So does it mean you cant also handle that issue with the Groupbox too?

So the other strange thing I dont check is if I try only to update the Groupbox / Exit button using InvalidateRect + handle of GB / Exit & rect then nothing happens on these controls and they keep still smudged. but if I use InvalidateRect once for all controls then it will updated.So if this would work then I would only use IR API for the handles of controls which make problem and smudge but it seems that I cant do this for GB alone.

greetz

 

Teddy Rogers
Posted

This code works perfectly fine for me resizing across multiple screens without any flickering; WinXP, Win7 and Win10...

Declare MenuCallback(hWnd, uMsg, wParam, lParam)

If OpenWindow(0, 0, 0, 500, 250, "Form1", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  WindowBounds(0, 500, 250, #PB_Ignore, #PB_Ignore)
  
  ; Create the listview, with some contents...
  
  ListIconGadget(1, 10, 10, 350, 170, "No.", 100, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect)
  AddGadgetColumn(1, 1, "Name", 100)
  AddGadgetColumn(1, 2, "Other", 100)
  
  For Num = 0 To 100
    AddGadgetItem(1, -1, "Test " + Str(Num) + #LF$ + "Test" + #LF$ + "Test")
  Next Num
  
  ; Create an exit button with a frame around it...
  
  FrameGadget(2, 380, 70, 100, 80, "Box")
  ButtonGadget(3, 390, 90, 80, 50, "Exit", #PB_Button_Toggle)
  
  SetWindowCallback(@MenuCallback())
  
  ; Wait for a PB window event...
  
  Repeat
    Event = WaitWindowEvent()
    
    If GetGadgetState(3)
      Event = #PB_Event_CloseWindow
    EndIf

  Until Event = #PB_Event_CloseWindow
EndIf

Procedure MenuCallback(hWnd, uMsg, wParam, lParam)
  
  If uMsg = #WM_SIZE
    
    Width = WindowWidth(0, #PB_Window_InnerCoordinate) - 150
    Height = WindowHeight(0, #PB_Window_InnerCoordinate) - 80
    
    ResizeGadget(1, #PB_Ignore, #PB_Ignore, Width, Height)
    ResizeGadget(2, Width + 30, Height - 100, #PB_Ignore, #PB_Ignore)
    ResizeGadget(3, Width + 40, Height - 80, #PB_Ignore, #PB_Ignore)
    
    RedrawWindow_(GadgetID(2), #Null, #Null, #RDW_INTERNALPAINT | #RDW_UPDATENOW)
    RedrawWindow_(GadgetID(3), #Null, #Null, #RDW_INTERNALPAINT | #RDW_UPDATENOW)

  EndIf

  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Ted.

LCF-Test.exe

Posted

Hi again,

found another flickering problem on static controls.Example,so I made a downloader what does show infos about download on static controls like size / speed etc and these controls flicker too.I am just using SetWindowText API or WM_SETTEXT.Problem seems to be that the controls getting updated to fast but if I add a sleep API with 50 ms then its ok but then the download is also slower if I just set sleep into DL code part.Also have test edit control but this is flicker free.Strange again.I made a test file with a counter where you can see it.Dont wanna change my statics to disabled edits now.

Static_vs_Edit.exe

Teddy Rogers
Posted

The first control flickers in your example because it is a static control. Simple fix would be to use an edit control, like the second control box you are using. If you really wanted to stick with static controls set the style to SS_SIMPLE, the only downside to this is you will lose centering plus some other things I've forgotten about. If you want to keep centering the best thing would be to draw text directly to the control either using TextOut or ExtTextOut, I'd suggest the latter as it is easier to fill/clear the area before writing again otherwise it starts writing on top of each previous write. I'd stick to setting Sleep to around 1ms in your thread...

Ted.

  • Like 1
Posted

Hi Ted,

thanks for the info.So I have test it with SS_SIMPLE and its bad that I cant center the text.

Also tried it with TextOut but I get flickering too and the thread does hang after a while....below the code loop.

    invoke GetDlgItem,hWnd_main,1002
    mov esi,eax
    invoke GetDC,eax
    mov DC, eax   
    invoke  GetClientRect,esi,addr rect
    invoke CreateSolidBrush,Gray
    mov eax,CC
    invoke FillRect,DC,addr rect,CC
    invoke DeleteObject,CC
    invoke SetBkMode,DC,TRANSPARENT
    invoke SetTextColor,DC,Red
    invoke SelectObject,DC,hFont    
    invoke wsprintf,addr BUFFER,chr$("%08d"),edi
    invoke lstrlen,addr BUFFER   
    invoke TextOut,DC,0,0,addr BUFFER,eax
    invoke ReleaseDC,esi,DC

Do you see the problem?

Static_vs_Edit2.exe

greetz

Teddy Rogers
Posted

You only need to use FillRect once simply to clear the control at the start or if the size of the text is smaller than previous text output. You probably only need to setup brush, pen and colour once and leave the main loop of the process simply for displaying the text. You may need to display the text on WM_PAINT to help reduce any flickering and handle WM_ERASEBACKGND. I've quickly knocked up an example here, I still prefer using ExtTextOut...

Declare Counter1(void)
Declare Counter2(void)
Declare Counter3(void)

If OpenWindow(0, 0, 0, 260, 100, "Form1", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)

  ButtonGadget(1, 170, 10, 80, 80, "Start/Stop", #PB_Button_Toggle)
  
  TextGadget(2, 10, 10, 150, 20, "SetWindowText", #SS_SUNKEN | #SS_CENTER)
  TextGadget(3, 10, 40, 150, 20, "TextOut", #SS_SUNKEN | #SS_SIMPLE)
  TextGadget(4, 10, 70, 150, 20, "ExtTextOut", #SS_SUNKEN | #SS_SIMPLE)
  
  If LoadFont(0, "Arial", 9)
    SetGadgetFont(2, FontID(0))
  EndIf
  
  Repeat
    Event = WaitWindowEvent()
    
    Select Event
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1

            If GetGadgetState(1)
              CreateThread(@Counter1(), #Null)
              CreateThread(@Counter2(), #Null)
              CreateThread(@Counter3(), #Null)
            EndIf
            
        EndSelect

    EndSelect
  
  Until Event = #PB_Event_CloseWindow
EndIf

Procedure Counter1(void)
  Static Total, hdc, hFont, r.RECT

  Repeat
    Total = Total + 100

    ; Display the output text...
    
    SetWindowText_(GadgetID(2), Str(Total))
    
    Sleep_(1)
    
  Until GetGadgetState(1) = #False
  
EndProcedure

Procedure Counter2(void)
  Static Total, hdc, hFont, r.RECT
  
  ; Get the rectangular dimensions of the control...
  
  GetClientRect_(GadgetID(3), @r.RECT)
  
  ; Get control HDC and set text to be aligned as centered to it...
  
  hdc = GetDC_(GadgetID(3))
  SetTextAlign_(hdc, #TA_CENTER)
  
  ; Get the background colour and then set the stock DC brush colour as background...

  SetBkColor_(hdc, GetSysColor_(#COLOR_BTNFACE))
  
  fObject = GetStockObject_(#DC_BRUSH)
  SetDCBrushColor_(hdc, GetSysColor_(#COLOR_BTNFACE))  
  
  ; Clear the background in the control...
  
  FillRect_(hdc, r.RECT, fObject)
  
  ; Create a font for use in the control...
  
  hFont = CreateFont_(15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial")
  SelectObject_(hdc, hFont)

  Repeat
    Total = Total + 100
    
    ; Display the output text...

    TextOut_(hdc, r\right/2, r\top, Str(Total), Len(Str(Total)))

    Sleep_(1)
    
  Until GetGadgetState(1) = #False
  
  DeleteObject_(hFont)
  ReleaseDC_(GadgetID(3), hdc)
  
EndProcedure

Procedure Counter3(void)
  Static Total, hdc, hFont, r.RECT
  
  ; Get the rectangular dimensions of the control...
  
  GetClientRect_(GadgetID(4), @r.RECT)
  
  ; Get control HDC and set text to be aligned as centered to it...
  
  hdc = GetDC_(GadgetID(4))
  SetTextAlign_(hdc, #TA_CENTER)
  
  ; Set the background colour...
  
  SetBkColor_(hdc, GetSysColor_(#COLOR_BTNFACE))
  
  ; Create a font for use in the control...
  
  hFont = CreateFont_(15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial")
  SelectObject_(hdc, hFont)
  
  Repeat
    Total = Total + 100
    
    ; Display the output text...
    
    ExtTextOut_(hdc, r\right/2, r\top, #ETO_OPAQUE, r.RECT, Str(Total), Len(Str(Total)), #Null)
    
    Sleep_(1)
    
  Until GetGadgetState(1) = #False
  
  DeleteObject_(hFont)
  ReleaseDC_(GadgetID(4), hdc)
  
EndProcedure

Ted.

LCF-Test.exe

  • Like 1
Posted

Hi Ted,

thanks again.So I see the problem was FillRect API = flickering.But I see I can also use it without using FillRect API.

A:    
    
    .if STOP == 0h
    inc edi
    invoke GetDlgItem,hWnd_main,1002
    mov esi,eax
    invoke GetDC,eax
    mov DC, eax 
    invoke  GetClientRect,esi,addr rect
    invoke GetSysColor,COLOR_BTNFACE
    mov CC, eax
    invoke SetBkColor,DC,CC
    invoke SetTextColor,DC,Red
    invoke SelectObject,DC,hFont    
    invoke wsprintf,addr BUFFER,chr$("%08d"),edi
    invoke lstrlen,addr BUFFER   
    invoke TextOut,DC,5,0,addr BUFFER,eax
    invoke ReleaseDC,esi,DC    
    jmp AS
    .endif

So in your example file I also see a problem for the TextOut & ExTextOut versions.Just run the counter then stop and now just minimize the window and call it back and now you see both counters was deleted and you see the TextOut & ExTextOut inside of both controls and only the first one keeps.Seems to be a problem of these TextOut APIs so I have too in my examples.

greetz

Posted

Hi raggy,

so the problem isnt the edit control its static control in that case.The last example of Ted using static control with TextOut API is working to get no flickering on it but the content in the static controls are gone if you minimize the window or move it out if desktop a little so thats the only disadvantage.

greetz

Posted (edited)

You can use this WM_ERASEBKGND in  a static control too

Read this paper or google "Static control flicker WM_ERASEBKGND" ;)

With TextOut is a other solution.

 

"Many Roads Lead to Rome"

Edited by ragdog
Posted

I have test it already with WM_ERASEBKGND but it dosent work.Just create a normal static control and let run a counter inside in loop and send the text via WM_SETTEXT like I did first and test it.Now you see its flickering.Now you can add WM_ERASEBKGND etc and you see it has no effect against the static control flickering.Just test it.Shouldnt take much time to create such a test project for you or?Give it try and you will see it.

greetz

Teddy Rogers
Posted

Are calling BeginPaint and EndPaint?

BeginPaint_(GadgetID(1), ps.PAINTSTRUCT)
ExtTextOut_(hdc, r\right/2, r\top, #ETO_OPAQUE, r.RECT, Str(Total), Len(Str(Total)), #Null)
EndPaint_(GadgetID(1), ps.PAINTSTRUCT)   

Ted.

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
×
×
  • Create New...