Tuts 4 You

Flickering and delay problems...

Rate this topic

Recommended Posts

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.

Share on other sites

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...

...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.

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

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

....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

Share on other sites

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)

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)

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()

Event = #PB_Event_CloseWindow
EndIf

Until Event = #PB_Event_CloseWindow
EndIf

If uMsg = #WM_EXITSIZEMOVE

Width = WindowWidth(0, #PB_Window_InnerCoordinate) - 150
Height = WindowHeight(0, #PB_Window_InnerCoordinate) - 80

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

Share on other sites

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

Share on other sites

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

Declare MenuCallback(hWnd, uMsg, wParam, lParam)

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)

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()

Event = #PB_Event_CloseWindow
EndIf

Until Event = #PB_Event_CloseWindow
EndIf

If uMsg = #WM_SIZE

Width = WindowWidth(0, #PB_Window_InnerCoordinate) - 150
Height = WindowHeight(0, #PB_Window_InnerCoordinate) - 80

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.

Share on other sites

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.

Share on other sites

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.

• 1

Share on other sites

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 CreateSolidBrush,Gray
mov eax,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? greetz Share this post Link to post Share on other sites 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. • 1 Share this post Link to post Share on other sites 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 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

Share on other sites

Hi lcf

What if wrong to use a Edit control it works if only a problem with Paint and WM_ERASEBKGND

Share on other sites

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

Share on other sites

You can use this WM_ERASEBKGND in  a static control too

With TextOut is a other solution.

Edited by ragdog (see edit history)

Share on other sites

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

Share on other sites

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.