[Module] DeFlicker - easily deflicker resizeable Windows

Share your advanced PureBasic knowledge/code with the community.
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

[Module] DeFlicker - easily deflicker resizeable Windows

Post by PureLust »

Hi there,

any PB Programmer on Windows might have noticed, that a resizeable GUI will flicker like hell while resizing the Window.

DeFlicker provides you with an easy way to suppress this flicker by just adding two simple lines of code:
---------------------------------------------------------------------------------------------------------------------------------------------------------
1. In your Gadget-Resize Routine, just call 'DeFlicker_StartResize(Window#)' before your first ResizeGadget()
2. If you finished the resizing, just call 'DeFlicker_EndResize()' after your last ResizeGadget()
... Done !!!

So, that's all you have to add to your Code: (Ok, ... if we also count the XInclude-Line, you need 3 additional Lines of Code:) :wink:

Code: Select all

XInclude "Modul_DeFlicker.pbi"
...
...
DeFlicker_StartResize(Window#)
... (Your Routine where you resize your Gadgets)
DeFlicker_EndResize()
...
DeFlicker has already been testet by several users it seems to work fine on XP, Win7, Win8.1 & Win10.

[EDIT 31.01.2020] Changed DeFlicker functions to use Macros and CompilerIF to make sure DeFlicker is only active on Windows. So you can include DeFlicker even in your crossplatform code without any need to change your code for OSX or Linux

You will find some Information about additional Functions within the Sourcecode in german language.
But because these additional functions are only needed if you have to finetune the deflickering, you may not need them at all.
Nevertheless ... if you would like to know more about these finetuning-functions and do not understand the german description, leave me a comment.

The Code does include a stress-test demo with 124 resizable Gadgets.
At the top left in the demo, you can enable or disable the 2 included 'DeFlicker'-commands with a CheckBox.
So you can easily see the difference with 'DeFlicker' and without 'DeFlicker'.

'DeFlicker' is Windows-Only, but as far as I know, Linux and OS-X do not have this flicker-problem at all.

Code: Select all

;	Modul: DeFlicker
;	----------------------------
;	Bei größenveränderlichen Fenstern tritt häufig (vor allem bei älteren, langsameren PCs) ein störendes
;	Flimmern auf, wenn das Fenster und die darin befindlichen Gadgets resized werden.
;	Durch DeFlicker kann man dieses Flimmern nun auf einfache Weise unterbinden.

;	Anwendung:
;	---------------------
;	Die 'standard' Anwendung ist denkbar einfach:
;	In der Routine, in der das Resizing der Gadgets vorgenommen wird, muss vor dem ersten ResizeGadget()
;	die DeFlicker-Funktion 'StartResize(Window)' aufgerufen werden (mit Angabe der entspechenden Fensternummer).
;	Wenn alle Gadgets resized wurden, muss noch EndResize() aufgerufen werden, wodurch das Fenster und die Gadgets
;	(weitestgehend) flimmerfrei neu gezeichnet wird.

;	Hinweis:
;	---------------------
;	Manchmal muss - um ein optimales Ergebnis zu erhalten - noch bei eingen Gadgets ein wenig Feintuning betrieben werden.
;	Wenn z.B. transparente Images verwendet werden, so sollte DeFlicker für diese Images ggfl. abgeschaltet werden um
;	keine unschönen Nebeneffekte durch nicht gelöschte Grafikreste zu erhalten (siehe 'SetGadgetDeFlicker()' oder
;	'SetGadgetTypeDeFlicker()' weiter unten).
;
;	Hierzu kann man das DeFlickern auf 4 Arten sowohl generell für eine GadgetTyp als auf für einzelne Gadgets justieren:
;	-	#DeFlicker_Full		-	der gesamte Bereich eines Gadgets wird entflimmert (sinnvoll bei allen 'normalen' rechteckigen Gadgets)
;	-	#DeFlicker_NO			-	der Bereich des Gadgets wird nicht entflimmert (sinnvoll bei allen Arten von Container- Gadgets, die weitere Gadgets enthalten)
;	-	#DeFlicker_Top16/20	-	hier werden nur die oberen 16/20 Pixel des Gadgets entflimmert (z.B. nützlich für PanelGadgets die nur in der Höhe verändert werden)
;     (oder auch Werte)			(statt der Konstanten #DeFlicker_Top16/20 kann auch die Anzahl der Pixel als Parameter übergeben
;										 werden (also z.B. '16' oder '20'. Erlaubt sind hierbei Werte von 3-999 Pixel)
;	-	#DeFlicker_Region		-	Bei #DeFlicker_Region kann ein spezieller Bereich definiert werden, der entflimmert werden soll.
;										Dies ist z.B. zum Optimieren des Tab-Bereichs bei PanelGadgets sinnvoll.

;	Zur Verfügung stehende Funktionen:
;	----------------------------------------
;	-	DeFlicker_StartResize(Window)											-	verhindert von nun an, dass das Fenster neu gezeichnet wird (s.o.)
;	-	DeFlicker_EndResize(RefreshWindow=#True)							-	erlaubt wieder das Neuzeichnen des Fensters und zeichnet den Inhalt neu (s.o.)
;																							(Hinweis: EndResize() ruft automatisch 'RefreshWindow(Window)' auf um den Fensterinhalt
;																							 neu zu zeichnen. Dies kann durch den optionalen Parameter (RefreshWindow=#False)
;																							 unterbunden werden. RefreshWindow() kann dann bei Bedarf separat aufgerufen werden.
;	-	DeFlicker_RefreshWindow(Window)										-	zeichnet den Fensterinhalt möglichst flimmerfrei neu (s.o.)


;	-	DeFlicker_SetGadgetTypeDeFlicker(GadgetType, RefreshType)	-	setzt die standard DeFlicker-Art für einen bestimmten GadgetType
;																							(#DeFlicker_Region ist hierbei nicht möglich)
;	-	DeFlicker_GetGadgetTypeDeFlicker(GadgetType)						-	gibt die aktuell eingestellte DeFlicker-Art für einen GadgetType zurück


;	-	DeFlicker_SetGadgetDeFlicker(Gadget, RefreshType [, xPos, yPos, Width, Height])
;																						-	setzt die DeFlicker-Art für ein ganz bestimmtes Gadget
;																							Bei #DeFlicker_Region muss noch der Bereich definiert werden
;	-	DeFlicker_GetGadgetDeFlicker(Gadget)								-	gibt die aktuell eingestellte DeFlicker-Art für dieses Gadget zurück


;   Anwendungsbeispiel:
;   ---------------------------------------------------------------------------------------------------------------------------
;   Am Ende dieses Codes (nach der Definition des Moduls: DeFlicker) findet Ihr ein kleines Hardcore-Beispiel mit 124 Gadgets

Macro DeFlicker_StartResize(Window)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::StartResize(Window)
	CompilerEndIf
EndMacro

Macro DeFlicker_EndResize(RefreshWindow=#True)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::EndResize(RefreshWindow)
	CompilerEndIf
EndMacro

Macro DeFlicker_RefreshWindow(Window)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::RefreshWindow(Window)
	CompilerEndIf
EndMacro

Macro SetGadgetTypeDeFlicker(GadgetType, RefreshType)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::SetGadgetTypeDeFlicker(GadgetType, RefreshType)
	CompilerEndIf
EndMacro

Macro GetGadgetTypeDeFlicker(GadgetType)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::GetGadgetTypeDeFlicker(GadgetType)
	CompilerElse
		0
	CompilerEndIf
EndMacro

Macro SetGadgetDeFlicker(Gadget, RefreshType, xPos=#PB_Ignore, yPos=#PB_Ignore, Width=#PB_Ignore, Height=#PB_Ignore)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::SetGadgetDeFlicker(Gadget, RefreshType, xPos, yPos, Width, Height)
	CompilerEndIf
EndMacro

Macro GetGadgetDeFlicker(Gadget)
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		DeFlicker::GetGadgetDeFlicker(Gadget)
	CompilerEndIf
EndMacro


#DeFlicker_NO			= 1
#DeFlicker_Region		= 2
#DeFlicker_Top16		= 16
#DeFlicker_Top20		= 20
#DeFlicker_Full		= 1000

CompilerIf #PB_Compiler_OS = #PB_OS_Windows
	
	DeclareModule      DeFlicker
		
		Declare   StartResize(Window)
		Declare   RefreshWindow(Window)
		Declare   EndResize(RefreshWindow=#True)
		
		Declare   GetGadgetTypeDeFlicker(GadgetType)
		Declare   SetGadgetTypeDeFlicker(GadgetType, RefreshType)
		
		Declare   GetGadgetDeFlicker(Gadget)
		Declare   SetGadgetDeFlicker(Gadget, RefreshType, xPos=#PB_Ignore, yPos=#PB_Ignore, Width=#PB_Ignore, Height=#PB_Ignore)
		
	EndDeclareModule
	Module   DeFlicker
		
		EnableExplicit
		
		#DeFlicker_NO			= 1
		#DeFlicker_Region		= 2
		#DeFlicker_Top16		= 16
		#DeFlicker_Top20		= 20
		#DeFlicker_Full		= 1000
		
		Structure   GadgetDetails_Struct
			GadgetID.i
			GadgetNumber.i
			GadgetType.i
			left.l
			top.l
			right.l
			bottom.l
		EndStructure
		Structure   UserDefined_DeFlickerType_Struct
			GadgetNumber.i
			DeFlicker_Type.l
			xPos.w
			yPos.w
			Width.w
			Height.w
		EndStructure
		
		#MaxGadgetTypes = 40
		Global   Dim GadgetType_Default.l(#MaxGadgetTypes)
		Global   NewList   CallBackGadgetList.GadgetDetails_Struct()
		Global   NewList   UserDefined_DeFlickerType.UserDefined_DeFlickerType_Struct()
		Global   LastResizedWindow
		Global 	DeflickerLevel
		Define   n
		
		For n = 0 To #MaxGadgetTypes
			GadgetType_Default(n) = #DeFlicker_Full								; Standard für alle Gadgets ist erst einmal 'Full'-Deflicker
		Next
		
		GadgetType_Default(#PB_GadgetType_Frame)		= #DeFlicker_Top16	; Jetzt werden einige Ausnamen voreingestellt
		GadgetType_Default(#PB_GadgetType_Container)	= #DeFlicker_NO
		GadgetType_Default(#PB_GadgetType_Splitter)	= #DeFlicker_NO
		GadgetType_Default(#PB_GadgetType_Panel)		= #DeFlicker_Full
		
		Procedure   GetGadgetList_Callback(hwnd,*WinPos.POINT)				; interne Routine - CallBack zum Ermitteln der Gadgets-Liste
			
			; CallBack zur Erstellung einer LinkedListe mit Details zu allen Gadgets in einem Window
			
			Protected   ActPBGadget, GadgetPos.RECT
			
			ActPBGadget = GetProp_(hwnd, "PB_ID")												; Gadget# des PB-Gadgets
			
			If IsGadget(ActPBGadget) And GadgetID(ActPBGadget) = hwnd					; Checken ob die ermittelte Gadget# aus ok ist
				If AddElement(CallBackGadgetList())
					CallBackGadgetList()\GadgetID			= hwnd
					CallBackGadgetList()\GadgetNumber	= ActPBGadget
					CallBackGadgetList()\GadgetType		= GadgetType(ActPBGadget)
					GetWindowRect_(hwnd, @GadgetPos)															; Desktop-Position des Gadgets ermitteln
					CallBackGadgetList()\left				= GadgetPos\left		- *WinPos\x			; Gadgetposition auf Position im Fenster umrechnen
					CallBackGadgetList()\top				= GadgetPos\top		- *WinPos\y			;       ''
					CallBackGadgetList()\right				= GadgetPos\right		- *WinPos\x			;       ''
					CallBackGadgetList()\bottom			= GadgetPos\bottom	- *WinPos\y			;       ''
				EndIf
			EndIf
			
			ProcedureReturn #True
			
		EndProcedure
		Procedure   GetGadgetList(Window, List GadgetList.GadgetDetails_Struct())   ; interne Routine zum Erstellen einer Liste mit allen Gadgets
			
			; Ermittelt Details aller PB-Gadgets in einem Fenster und gibt diese in einer LinkedList zurück
			
			Protected   WinPos.POINT
			
			If IsWindow(Window)
				WinPos\x = WindowX(Window, #PB_Window_InnerCoordinate)	; Window-Position ermitteln, dami diese an den CallBack übergeben werden kann
				WinPos\y = WindowY(Window, #PB_Window_InnerCoordinate)
				
				ClearList(CallBackGadgetList())														; LinkedList des CallBacks löschen
				EnumChildWindows_(WindowID(Window),@GetGadgetList_Callback(),@WinPos)	; Alle Gadgets ermitteln und per CallBack auswerten
				CopyList(CallBackGadgetList(), GadgetList())										; Die vom CallBack erstellte LinkedListe auf die eigentliche Liste kopieren
			Else
				Debug "Window Nr."+Str(Window)+" konnte nicht gefunden werden."
			EndIf
			
			ProcedureReturn   ListSize(GadgetList())
			
		EndProcedure
		
		Procedure   StartResize(Window)
			If IsWindow(Window)
				If DeflickerLevel = 0
					SendMessage_(WindowID(Window),#WM_SETREDRAW,#False,0)
					LastResizedWindow = Window
				EndIf
				;    		DeflickerLevel + 1
			Else
				Debug "Window Nr."+Str(Window)+" nicht gefunden."
			EndIf
		EndProcedure
		Procedure   RefreshWindow(Window)
			
			If IsWindow(Window)
				
				Protected   ps.PAINTSTRUCT
				Protected   Validate.RECT
				Protected   NewList GadgetList.GadgetDetails_Struct()
				Protected   hWnd.i = WindowID(Window)
				Protected   WinRect.rect
				Protected   ActDeFlickerType
				Protected   ClearEventLoop = #True
				
				GetGadgetList(Window, GadgetList())
				
				GetClientRect_(hWnd, @WinRect)
				InvalidateRect_(hWnd,WinRect,1)
				
				ForEach GadgetList()
					
					If GadgetList()\GadgetType = #PB_GadgetType_Panel
						ClearEventLoop = #True
					EndIf
					
					ActDeFlickerType   = GadgetType_Default(GadgetList()\GadgetType)
					
					ForEach UserDefined_DeFlickerType()
						If UserDefined_DeFlickerType()\GadgetNumber = GadgetList()\GadgetNumber
							ActDeFlickerType = UserDefined_DeFlickerType()\DeFlicker_Type
							Break
						EndIf
					Next
					
					Select ActDeFlickerType
							
						Case   #DeFlicker_Full            ;   Gadget-Bereich wird komplett 'DeFlickered'
							
							ValidateRect_(hWnd, @GadgetList()\left)
							
						Case   #DeFlicker_Region
							
							Validate\left		= GadgetList()\left	+ UserDefined_DeFlickerType()\xPos
							Validate\top		= GadgetList()\top	+ UserDefined_DeFlickerType()\yPos
							Validate\right		= GadgetList()\left	+ UserDefined_DeFlickerType()\Width
							Validate\bottom	= GadgetList()\top	+ UserDefined_DeFlickerType()\Height
							
						Case   #DeFlicker_Region+1 To #DeFlicker_Full-1      ;  Nur oberen Teil des Gadgets 'DeFlickern'
							
							Validate\left		= GadgetList()\left + 8
							Validate\top		= GadgetList()\top
							Validate\right		= GadgetList()\right - 8
							Validate\bottom	= GadgetList()\top + ActDeFlickerType - 1
							
							If GadgetList()\GadgetType = #PB_GadgetType_Frame
								If StartDrawing(WindowOutput(Window))
									DrawingFont(GetGadgetFont(GadgetList()\GadgetNumber))
									Validate\right		= GadgetList()\left + 8 + TextWidth(GetGadgetText(GadgetList()\GadgetNumber))
									Validate\bottom	= GadgetList()\top + TextHeight(GetGadgetText(GadgetList()\GadgetNumber))
									If Validate\right > GadgetList()\right : Validate\right = GadgetList()\right : EndIf
									StopDrawing()
								EndIf
							EndIf
							ValidateRect_(hWnd, @Validate)
						Default
							
							; No DeFlicker at all
							
					EndSelect
					
				Next
				
				BeginPaint_(hWnd, ps.PAINTSTRUCT)
				EndPaint_(hWnd, ps.PAINTSTRUCT)
				RedrawWindow_(hWnd,#Null,#Null,#RDW_INVALIDATE);
				
				CompilerIf #PB_Compiler_Debugger         ; need this Trick to get special Gadgets refreshed (like PanelGadget)
					DisableDebugger
					If ClearEventLoop
						While WindowEvent() : Wend
					EndIf
					EnableDebugger
				CompilerElse
					If ClearEventLoop
						While WindowEvent() : Wend
					EndIf
				CompilerEndIf
				
			Else
				Debug "Window Nr."+Str(Window)+" nicht gefunden."
			EndIf
		EndProcedure
		Procedure   EndResize(RefreshWindow=#True)
			;    	If DeflickerLevel > 0 : DeflickerLevel - 1 : EndIf
			If DeflickerLevel = 0
				SendMessage_(WindowID(LastResizedWindow),#WM_SETREDRAW,#True,0)
				If RefreshWindow : RefreshWindow(LastResizedWindow): EndIf
			EndIf
		EndProcedure
		
		Procedure   GetGadgetTypeDeFlicker(GadgetType)
			If GadgetType >= 0 And GadgetType <= #MaxGadgetTypes
				ProcedureReturn GadgetType_Default(GadgetType)
			EndIf
		EndProcedure
		Procedure   SetGadgetTypeDeFlicker(GadgetType, RefreshType)
			If GadgetType >= 0 And GadgetType <= #MaxGadgetTypes And RefreshType >= #DeFlicker_NO And RefreshType <= #DeFlicker_Full And RefreshType <> #DeFlicker_Region
				GadgetType_Default(GadgetType) = RefreshType
				ProcedureReturn #True
			EndIf
		EndProcedure
		
		Procedure   GetGadgetDeFlicker(Gadget)
			ForEach UserDefined_DeFlickerType()
				If UserDefined_DeFlickerType()\GadgetNumber = Gadget
					ProcedureReturn UserDefined_DeFlickerType()\DeFlicker_Type
				EndIf
			Next
		EndProcedure
		Procedure   SetGadgetDeFlicker(Gadget, RefreshType, xPos=#PB_Ignore, yPos=#PB_Ignore, Width=#PB_Ignore, Height=#PB_Ignore)
			
			If IsGadget(Gadget) And RefreshType >= #DeFlicker_NO And RefreshType <= #DeFlicker_Full
				
				Repeat
					ForEach UserDefined_DeFlickerType()
						If UserDefined_DeFlickerType()\GadgetNumber = Gadget
							Break 2
						EndIf
					Next
					
					AddElement(UserDefined_DeFlickerType())
				Until #True
				
				With UserDefined_DeFlickerType()
					\GadgetNumber		= Gadget
					\DeFlicker_Type	= RefreshType
					If RefreshType	= #DeFlicker_Region
						\xPos				= xPos
						\yPos				= yPos
						\Width			= Width
						\Height			= Height
					EndIf
				EndWith
				
			EndIf
			
		EndProcedure
		
	EndModule
CompilerEndIf


; ========================================================================================
; ====                        Sample-Code with 124 Gadgets                            ====
; ========================================================================================


CompilerIf #PB_Compiler_IsMainFile
   
   EnableExplicit

   #winMain = 0
   Global   DeFlicker_enabled = #True
   Global   xCount = 8, yCount = 14
   Define   n
   
   Procedure   ResizeGadgets()      ; Dies ist die BindEvent-Routine zum resizen der Gadgets
      
      Protected   x,y, ActX, ActY, ActWidth.f, ActHeight.f
      Protected   ActWinWidth = WindowWidth(#winMain), ActWinHeight = WindowHeight(#winMain)
      
      ; =============================  just call StartResize() before you resize  ============================
      
      If DeFlicker_enabled
         DeFlicker_StartResize(#winMain)
      EndIf
      
      ; ======================================================================================================
      
         
      ; Resize Button-Area
      
      ActX = 8
      ActY = 28
      ActWidth = (ActWinWidth - ActX - 300 - (xCount-1) * 5) / xCount
      ActHeight = (ActWinHeight - ActY - 13 - (yCount-1) * 5) / yCount
      
      For x = 0 To xCount - 1
         For y = 0 To yCount - 1
            ResizeGadget(30 + x + y*xCount, ActX + x * (ActWidth + 5), ActY + y * (ActHeight + 5), ActWidth, ActHeight)
         Next
      Next
      
      ResizeGadget(1, ActWinWidth - 290, 10, 280, ActWinHeight/2 - 15)
      ResizeGadget(20,ActWinWidth - 270, 35, 250, 19)
      ResizeGadget(21,ActWinWidth - 270, 55, 250, 19)
      ResizeGadget(22,ActWinWidth - 270, 75, 250, 19)
      ResizeGadget(23,ActWinWidth - 275, 98, 250, ActWinHeight/2 - 143)
      ResizeGadget(24,ActWinWidth - 275, ActWinHeight/2 - 38, 250, 25)
      
      ResizeGadget(2, ActWinWidth - 290, ActWinHeight/2 + 5, 280, ActWinHeight/2 - 15)
      ResizeGadget(10,10,10,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2)
      ResizeGadget(11,(GadgetWidth(2)-6)/2+5,10,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2)
      ResizeGadget(12,10,(GadgetHeight(2)-50)/2 + 20,(GadgetWidth(2)-36)/2, (GadgetHeight(2)-50)/2-10)
      ResizeGadget(13,(GadgetWidth(2)-6)/2+5,(GadgetHeight(2)-50)/2 + 20,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2-10)
      
      ; =============  just call EndResize() when you are finished with the Gadget resizing  =================
      
      If DeFlicker_enabled
         DeFlicker_EndResize()
      EndIf
      
      ; ======================================================================================================
      
   EndProcedure
   
   Procedure   CheckBox_EnableDeFlicker()
      If IsGadget(0)
         DeFlicker_enabled = GetGadgetState(0)
      EndIf
   EndProcedure
   
   OpenWindow(#winMain,0,0,800,600,"DeFlicker Hardcore-Sample", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
   WindowBounds(#winMain, 520, 360, #PB_Default, #PB_Default)
   
   BindEvent(#PB_Event_SizeWindow, @ResizeGadgets())
   
   CheckBoxGadget(0,10,5, 150, 20, "enable DeFlicker")      ; CheckBox um 
   SetGadgetState(0, DeFlicker_enabled)
   BindGadgetEvent(0, @CheckBox_EnableDeFlicker())
   
   FrameGadget(1, 10,10,10,10," iFrame ")
   OptionGadget(20,10,10,10,10,"I use PB on Windows")
   OptionGadget(21,10,10,10,10,"I use PB on Linux")
   OptionGadget(22,10,10,10,10,"I use PB on MacOS")
   EditorGadget(23,10,10,10,10, #PB_Editor_WordWrap)
   ComboBoxGadget(24,10,10,10,10)
   
   PanelGadget(2, 10,10,10,10)
   AddGadgetItem(2, -1, "Panel 1")
   ButtonGadget(10, 10,10,80,80,"do")
   ButtonGadget(11, 100,10,80,80,"re")
   ButtonGadget(12, 10,100,80,80,"mi")
   ButtonGadget(13, 100,100,80,80,"fa")
   AddGadgetItem(2, -1, "Panel 2")
   AddGadgetItem(2, -1, "Panel 3")
   CloseGadgetList()
   
   For n = 30 To 29 + xCount * yCount
   	ButtonGadget(n,10,10,10,10,"Btn:"+Str(n-29))
   Next
   
   ResizeGadgets()
   
   While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
   
CompilerEndIf
If it's of some use for you or if you locate some problems, just leave a message. :wink:
Last edited by PureLust on Sat Feb 01, 2020 12:57 am, edited 2 times in total.
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Jagermeister
Enthusiast
Enthusiast
Posts: 136
Joined: Thu Nov 15, 2012 11:38 pm
Location: Los Angeles

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Jagermeister »

Verrry nice! Interestingly, the only flicker I get is when decreasing horizontally or vertically over PB's Procedure Browser pane. :? Even more curious is the flicker is more intense with DeFlicker on. :shock: None of this happens with any other pane.

Win 7 Ultimate, PB 5.42 LTS x64
HanPBF
Enthusiast
Enthusiast
Posts: 562
Joined: Fri Feb 19, 2010 3:42 am

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by HanPBF »

You should enable the checkbox as default.

This is great!!!!!!!

Thanks a lot!!!
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by PureLust »

HanPBF wrote:This is great!!!!!!!
Thanks a lot!!!
You are welcome. :wink:
Jagermeister wrote:..., the only flicker I get is when decreasing horizontally or vertically over PB's Procedure Browser pane. :?
What do you mean with "PB's Procedure Browser pane"? There is no Browser-Gadget in my example. Do you mean the Window, created by PB, titled "DeFlicker Hardcore-Sample"?
Jagermeister wrote:Even more curious is the flicker is more intense with DeFlicker on. :shock:
Do you mean, it flickers more, if you check the Checkbox "enable DeFlicker" in the top-left? :shock:

Thanks and greets,
PL.
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Dude »

This is working great for me, PureLust. Thank you! :)

A quick question: do these constants need to be defined twice in the code?

Can I keep the ones inside the module instead, and remove the outside ones?

Code: Select all

#DeFlicker_NO         = 1
#DeFlicker_Region      = 2
#DeFlicker_Top16      = 16
#DeFlicker_Top20      = 20
#DeFlicker_Full      = 1000
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Kwai chang caine »

A little bit late "May 30, 2016" :oops:
But thanks to DUDE, i have see this splendid code, missed before :oops:
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by PureLust »

Dude wrote:A quick question: do these constants need to be defined twice in the code?

Can I keep the ones inside the module instead, and remove the outside ones?[/code]
Hi Dude, ... the outside ones are just for easy access, if you do not use 'UseModule'.

E.g.: Without 'UseModule' you usually need to write:
- DeFlicker::GadgetType_Default(#PB_GadgetType_Splitter) = DeFlicker::#DeFlicker_NO

Because of the outside defined constants, you can save the 'DeFlicker::'-prefix for the Constants:
- DeFlicker::GadgetType_Default(#PB_GadgetType_Splitter) = #DeFlicker_NO

So .. DeFlicker does non need the Outside constants ... it's just to save some code.

But ... you only need these constants if you are not happy with DeFlickers Result with Default-Settings and want want to tweak DeFlickers output.
So, in most cases you may not use/need them at all and can get rid of the outside once anyway. ;)

Kwai chang caine wrote:Thanks for sharing 8)
You are welcome. :mrgreen:
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
said
Enthusiast
Enthusiast
Posts: 342
Joined: Thu Apr 14, 2011 6:07 pm

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by said »

Nice :D
Many thanks for sharing :D
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Dude »

Jagermeister wrote:more curious is the flicker is more intense with DeFlicker on. :shock:
I noticed today I don't need DeFlicker if I use SmartWindowRefresh(win,#True) and actioning the #WM_SIZING and #WM_WINDOWPOSCHANGED messages in a callback like so:

Code: Select all

If Message=#WM_SIZING or Message=#WM_WINDOWPOSCHANGED
  UpdateWindow_(WindowID(win))
EndIf
Doing this has removed all flicker in my specific situation.
Last edited by Dude on Sat Jan 27, 2018 8:33 am, edited 3 times in total.
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by PureLust »

Dude wrote:Adding this simple #WM_SIZING check has removed all flicker in my specific situation.
Hi Dude, ... I've just tested your Version and it works excellent !!! Image

But whow ... I was never aware, how much SmartWindowRefresh slows down the resizing-process of a Window. :shock:

In the following test-code (it's just a conversion of the DeFlicker-Example-Window to your Version) you can enable and disable SmartWindowRefresh with the checkbox top-left.

Any idea, what SmartWindowRefresh does, that could cause such a dramatic performance dropdown?

Code: Select all

EnableExplicit

#winMain = 0
Global   xCount = 8, yCount = 14
Define   n

Procedure   ResizeGadgets()      ; Dies ist die BindEvent-Routine zum resizen der Gadgets
	
	Protected   x,y, ActX, ActY, ActWidth.f, ActHeight.f
	Protected   ActWinWidth = WindowWidth(#winMain), ActWinHeight = WindowHeight(#winMain)
	
	; Resize Button-Area
	
	ActX = 8
	ActY = 28
	ActWidth = (ActWinWidth - ActX - 300 - (xCount-1) * 5) / xCount
	ActHeight = (ActWinHeight - ActY - 13 - (yCount-1) * 5) / yCount
	
	For x = 0 To xCount - 1
		For y = 0 To yCount - 1
			ResizeGadget(30 + x + y*xCount, ActX + x * (ActWidth + 5), ActY + y * (ActHeight + 5), ActWidth, ActHeight)
		Next
	Next
	
	ResizeGadget(1, ActWinWidth - 290, 10, 280, ActWinHeight/2 - 15)
	ResizeGadget(20,ActWinWidth - 270, 35, 250, 19)
	ResizeGadget(21,ActWinWidth - 270, 55, 250, 19)
	ResizeGadget(22,ActWinWidth - 270, 75, 250, 19)
	ResizeGadget(23,ActWinWidth - 275, 98, 250, ActWinHeight/2 - 143)
	ResizeGadget(24,ActWinWidth - 275, ActWinHeight/2 - 38, 250, 25)
	
	ResizeGadget(2, ActWinWidth - 290, ActWinHeight/2 + 5, 280, ActWinHeight/2 - 15)
	ResizeGadget(10,10,10,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2)
	ResizeGadget(11,(GadgetWidth(2)-6)/2+5,10,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2)
	ResizeGadget(12,10,(GadgetHeight(2)-50)/2 + 20,(GadgetWidth(2)-36)/2, (GadgetHeight(2)-50)/2-10)
	ResizeGadget(13,(GadgetWidth(2)-6)/2+5,(GadgetHeight(2)-50)/2 + 20,(GadgetWidth(2)-6)/2-15, (GadgetHeight(2)-50)/2-10)
	
EndProcedure

Procedure MyWindowCallback(WindowID, Message, wParam, lParam)
	Protected	Result = #PB_ProcessPureBasicEvents
	
	If Message=#WM_SIZING
		UpdateWindow_(WindowID)
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure   CheckBox_EnableSmartWindowRefresh()
	If IsGadget(0)
		SmartWindowRefresh(#winMain, GetGadgetState(0))
	EndIf
EndProcedure

OpenWindow(#winMain,0,0,800,600,"DeFlicker Hardcore-Sample", #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered)
WindowBounds(#winMain, 520, 360, #PB_Default, #PB_Default)
SmartWindowRefresh(#winMain,#True)

BindEvent(#PB_Event_SizeWindow, @ResizeGadgets())

CheckBoxGadget(0,10,5, 150, 20, "enable SmartWindowRefresh")      ; CheckBox um 
SetGadgetState(0, #True)
BindGadgetEvent(0, @CheckBox_EnableSmartWindowRefresh())

FrameGadget(1, 10,10,10,10," iFrame ")
OptionGadget(20,10,10,10,10,"I use PB on Windows")
OptionGadget(21,10,10,10,10,"I use PB on Linux")
OptionGadget(22,10,10,10,10,"I use PB on MacOS")
EditorGadget(23,10,10,10,10, #PB_Editor_WordWrap)
ComboBoxGadget(24,10,10,10,10)

PanelGadget(2, 10,10,10,10)
AddGadgetItem(2, -1, "Panel 1")
ButtonGadget(10, 10,10,80,80,"do")
ButtonGadget(11, 100,10,80,80,"re")
ButtonGadget(12, 10,100,80,80,"mi")
ButtonGadget(13, 100,100,80,80,"fa")
AddGadgetItem(2, -1, "Panel 2")
AddGadgetItem(2, -1, "Panel 3")
CloseGadgetList()

For n = 30 To 29 + xCount * yCount
	ButtonGadget(n,10,10,10,10,"Btn:"+Str(n-29))
Next

SetWindowCallback(@MyWindowCallback())    

ResizeGadgets()

While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
Ohh, ... btw: Image HAPPY NEW YEAR TO ALL OF YOU !!! :mrgreen:
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
Fred
Administrator
Administrator
Posts: 16616
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Fred »

SmartWindowRefresh bascially create a clip region out of all sibling control, and apply it to the WM_ERASEBACKGROUND message, so the erase doesn't overwrite the controls with a solid color. So the more control you have in your root window, the worste it will perfom.
PureLust
Enthusiast
Enthusiast
Posts: 477
Joined: Mon Apr 16, 2007 3:57 am
Location: Germany, NRW

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by PureLust »

Fred wrote:SmartWindowRefresh bascially create a clip region out of all sibling control, and apply it to the WM_ERASEBACKGROUND message, so the erase doesn't overwrite the controls with a solid color. So the more control you have in your root window, the worste it will perfom.
Hi Fred, thanks for clarifying.
So, in theory it does the same as my Deflicker-Routine.
But instead of using Clip-Regions, I just use InvalidateRect() and ValidateRect() to exclude all controls, which seems to be much faster.

Maybe it's worth to try this method on SmartWindowRefresh and include Dudes 'UpdateWindow_(WindowID(win))' to get a fast and perfect Result?
[Dynamic-Dialogs] - create complex GUIs the easy way
[DeFlicker] - easily deflicker your resizeable Windows
[WinFX] - Window Effects (incl. 'click-through' Window)
HanPBF
Enthusiast
Enthusiast
Posts: 562
Joined: Fri Feb 19, 2010 3:42 am

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by HanPBF »

Thanks for all Your work!

But: hopefully PB team does not put so much time anymore in Win32 technology.
It's 2018... :wink:

(At Xojo site they work also around that annoying flicker problem; at the moment, this IDE is not usable for windows UI projects...)

O.k., maybe I am wrong. Is Win32 still used across PB community for UI? Not only little helper tools; for big projects?


Happy New Year 2018!!!!
Fred
Administrator
Administrator
Posts: 16616
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by Fred »

What's the alternative to win32 ?

@PureLust, I will give it a try.
HanPBF
Enthusiast
Enthusiast
Posts: 562
Joined: Fri Feb 19, 2010 3:42 am

Re: [Module] DeFlicker - easily deflicker resizeable Windows

Post by HanPBF »

http://www.cplusplus.com/forum/lounge/140601/

Unfortunately no true alternative...

Styling win32 is a mess.
So, combining canvasgadget with other gadgets seems indeed best solution at the moment.

Only better would be an embeddable WebKit or other HTML engine with true PureBasic interaction.
Post Reply