How to clear GetDC

Just starting out? Need help? Post your questions and find answers here.
AZJIO
Addict
Addict
Posts: 2141
Joined: Sun May 14, 2017 1:48 am

How to clear GetDC

Post by AZJIO »

Check how the code works. Next, on line 80, change flgTest = 1 and check again.
In the first option, I return the system color, but if I have a picture as a background, then I need a transparent color. I can duplicate another layer, but if the picture is large, I spend 2 MB on each layer.
I want to just erase the time frame and draw it somewhere else. There is an option to make the frames not intersecting. But then it is necessary to specially make large intervals between the buttons.

Code: Select all

EnableExplicit

#Window=0
#Menu = 0
Global BorderW = 5
Global hGUI
Global hDC, MemDC, hOldBMP
Global x, y, w, h
Global btnactive=0
Global lastactive=0
Global flgMemDC=1
Global d
Global hMenu, mNext, mPrev, mRight, mLeft, mEnter

Procedure WinCallback(hWnd, uMsg, WParam, LParam)
	Protected hBrush, MemBMP, Rect.RECT, p = 0, delta = 5
	If uMsg = #WM_PAINT
		If flgMemDC
			flgMemDC = 0
			
			MemBMP = CreateCompatibleBitmap_(hDC, w + BorderW*2 + delta, h + BorderW*2 + delta)
			hOldBMP = SelectObject_(MemDC, MemBMP)
			hBrush = CreateSolidBrush_($ff8800)
			SelectObject_(MemDC, hBrush)
			
			Rect\left = 0
			Rect\right = BorderW
			Rect\top = 0
			Rect\bottom = h + BorderW*2 + delta
			FillRect_(MemDC, Rect, hBrush) ; fill in the rectangle of the window in memory
			
			Rect\left = 0
			Rect\right = w + BorderW*2 + delta
			Rect\top = 0
			Rect\bottom = BorderW
			FillRect_(MemDC, Rect, hBrush) ; fill in the rectangle of the window in memory
			
			DeleteObject_(hBrush)
			
			hBrush = GetSysColorBrush_(#COLOR_MENU)
			SelectObject_(MemDC, hBrush)
			
			Rect\left = BorderW
			Rect\right = BorderW*2
			Rect\top = BorderW
			Rect\bottom = h + BorderW*2 + delta
			FillRect_(MemDC, Rect, hBrush) ; fill in the rectangle of the window in memory
			
			Rect\left = BorderW
			Rect\right = w + BorderW*2 + delta
			Rect\top = BorderW
			Rect\bottom = BorderW*2
			FillRect_(MemDC, Rect, hBrush) ; fill in the rectangle of the window in memory
			
			DeleteObject_(MemBMP)
		EndIf
		BitBlt_(hDC, x - BorderW, y - BorderW, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020) ; верх
		BitBlt_(hDC, x - BorderW, y + h, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020)	   ; низ
		BitBlt_(hDC, x - BorderW, y, BorderW, h, MemDC, p, p, $00CC0020)					   ; слева
		BitBlt_(hDC, x + w, y, BorderW, h, MemDC, p, p, $00CC0020)							   ; справа
	EndIf
	
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure Erase(last)
	Protected x, y, w, h, p = BorderW
	Protected rc.RECT
	lastactive = last
	
	x = GadgetX(last)
	y = GadgetY(last)
	w = GadgetWidth(last)
	h = GadgetHeight(last)
	rc\left = x - BorderW
	rc\right = x + w + BorderW
	rc\top = y - BorderW
	rc\bottom = y + h + BorderW
	
	Protected flgTest = 0
	If flgTest
		InvalidateRect_(hGUI, @rc, #True)
	; 	SendMessage_(hGUI,#WM_ERASEBKGND,0,0) 
	Else
		BitBlt_(hDC, x - BorderW, y - BorderW, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020) ; верх
		BitBlt_(hDC, x - BorderW, y + h, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020)	   ; низ
		BitBlt_(hDC, x - BorderW, y, BorderW, h, MemDC, p, p, $00CC0020)					   ; слева
		BitBlt_(hDC, x + w, y, BorderW, h, MemDC, p, p, $00CC0020)							   ; справа
	EndIf
EndProcedure

Procedure MoveFrame(d)
	Protected p = 0
	x = GadgetX(d)
	y = GadgetY(d)
	w = GadgetWidth(d)
	h = GadgetHeight(d)
	BitBlt_(hDC, x - BorderW, y - BorderW, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020) ; верх
	BitBlt_(hDC, x - BorderW, y + h, w + BorderW*2, BorderW, MemDC, p, p, $00CC0020)	   ; низ
	BitBlt_(hDC, x - BorderW, y, BorderW, h, MemDC, p, p, $00CC0020)					   ; слева
	BitBlt_(hDC, x + w, y, BorderW, h, MemDC, p, p, $00CC0020)							   ; справа
EndProcedure

Procedure SetActiveButton(btnactive, direction)
	While Not IsGadget(btnactive)
		If btnactive > d Or btnactive < 0
			ProcedureReturn
		EndIf
		btnactive + direction
	Wend
	
	SetActiveGadget(btnactive)
	MoveFrame(btnactive)
EndProcedure


hGUI = OpenWindow(#Window, 0, 0, 230, 120, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(0, 10, 10, 100, 25, "# 0")
ButtonGadget(1, 10, 40, 100, 25, "# 1")
ButtonGadget(2, 10, 70, 100, 25, "# 2")
ButtonGadget(3, 120, 10, 100, 25, "# 3")
ButtonGadget(4, 120, 40, 100, 25, "# 4")
ButtonGadget(5, 120, 70, 100, 25, "# 5")
d = 5

hMenu = CreatePopupMenu(#Menu)

mNext = 0
mPrev = 1
mEnter = 2
mRight = 3
mLeft = 4
If hMenu
	MenuItem(mNext, "Next" + #TAB$ + "->")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Down, mNext)
	MenuItem(mPrev, "Prev" + #TAB$ + "<-")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Up, mPrev)
	MenuItem(mEnter, "Enter" + #TAB$ + "Enter")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Return, mEnter)
	MenuItem(mPrev, "Left" + #TAB$ + "<-")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Left, mLeft)
	MenuItem(mNext, "Right" + #TAB$ + "->")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Right, mRight)
EndIf



hDC = GetDC_(hGUI)
MemDC = CreateCompatibleDC_(hDC)

x = GadgetX(0)
y = GadgetY(0)
w = GadgetWidth(0)
h = GadgetHeight(0)
SetActiveButton(btnactive, -1)

SetWindowCallback(@WinCallback())

Define Event, EvGadget, EvType, EvMenu
Define Quit

Repeat
	Event = WaitWindowEvent()
	EvGadget = EventGadget()
	EvType = EventType()
	EvMenu = EventMenu()
	
	Select Event
		Case #PB_Event_CloseWindow
			Quit = 1
			
		Case #PB_Event_RightClick
			DisplayPopupMenu(#Menu, WindowID(#Window))	
			
		Case #PB_Event_Menu            
			Select EvMenu  ; To see which menu has been selected
					
				Case 0 ; mNext
					btnactive = GetActiveGadget() ;tab + shift tab effect
					Erase(btnactive)
					btnactive=btnactive+1
					If btnactive>5
						btnactive=0
					EndIf
					SetActiveButton(btnactive, 1)
					
				Case 1 ; mPrev 
					btnactive = GetActiveGadget() ;tab + shift tab effect
					Erase(btnactive)
					btnactive=btnactive-1
					If btnactive<0
						btnactive=5
					EndIf
					SetActiveButton(btnactive, -1)
					
				Case 2	;mEnter
					btnactive = GetActiveGadget() ;tab + shift tab effect
					PostEvent(#PB_Event_Gadget, #Window, btnactive)      
					
				Case 3 ; mRight
					btnactive = GetActiveGadget()
					Erase(btnactive)
					btnactive + 3 ; rows
					If btnactive > 5
						btnactive = 5
					EndIf
					SetActiveButton(btnactive, 1)
					
				Case 4 ; mLeft
					btnactive = GetActiveGadget()
					Erase(btnactive)
					btnactive - 3 ; rows
					If btnactive < 0
						btnactive = 0
					EndIf
					SetActiveButton(btnactive, -1)  
			EndSelect
			
		Case #PB_Event_Gadget
			Select EvGadget
				Case 0
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 0 Clicked"
					EndSelect
					
				Case 1
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 1 Clicked"
					EndSelect
					
				Case 2
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 2 Clicked"
					EndSelect
			EndSelect
			
	EndSelect
Until Quit = 1

ReleaseDC_(hGUI, hDC)
SelectObject_(MemDC, hOldBMP)
DeleteDC_(MemDC)
CloseWindow(#Window)
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: How to clear GetDC

Post by chi »

Replace InvalidateRect with RedrawWindow.... The RDW_ERASENOW flag ensures that WM_ERASEBKGND is called before the function returns.

Code: Select all

RedrawWindow_(hGUI, rc, 0, #RDW_ERASE|#RDW_INVALIDATE|#RDW_ERASENOW)
Et cetera is my worst enemy
AZJIO
Addict
Addict
Posts: 2141
Joined: Sun May 14, 2017 1:48 am

Re: How to clear GetDC

Post by AZJIO »

chi wrote: Wed Jan 12, 2022 6:56 pm RedrawWindow
Thanks!

I have optimized the code

Code: Select all

EnableExplicit

Structure Rect2
	x.l
	y.l
	w.l
	h.l
EndStructure

#Window=0
#Menu = 0
Global BorderW = 5
Global hGUI
Global hDC, MemDC, hOldBMP
Global btnactive=0, lastactive=0
Global d
Global hMenu, mNext, mPrev, mRight, mLeft, mEnter
Global rsAcBtn.Rect2, rsOldBtn.Rect2
Global FWidth = 230, FHeight = 120
Global BorderColor = $FF8800

Procedure CreateBMP()
	Protected hBrush, MemBMP, Rect.RECT
	MemBMP = CreateCompatibleBitmap_(hDC, FWidth, FHeight)
	hOldBMP = SelectObject_(MemDC, MemBMP)
	hBrush = CreateSolidBrush_(BorderColor)
	SelectObject_(MemDC, hBrush)
	With Rect
		\left = 0
		\right = FWidth
		\top = 0
		\bottom = FHeight
	EndWith
	FillRect_(MemDC, Rect, hBrush)
	DeleteObject_(hBrush)
	DeleteObject_(MemBMP)
EndProcedure

Procedure Erase()
	Protected rc.RECT
	If BorderW
		CopyStructure(@rsAcBtn, @rsOldBtn.Rect2, Rect2)
		With rsOldBtn
			rc\left = \x - BorderW
			rc\right = \x + \w + BorderW
			rc\top = \y - BorderW
			rc\bottom = \y + \h + BorderW
		EndWith
		; 		RedrawWindow очищая старый регион провоцирует перерисовку и рисует кнопку функцией WinCallback
		RedrawWindow_(hGUI, rc, 0, #RDW_ERASE|#RDW_INVALIDATE|#RDW_ERASENOW)
	EndIf
EndProcedure

Procedure SetActiveButton(btnactive, direction)
	While Not IsGadget(btnactive)
		If btnactive > d Or btnactive < 0
			ProcedureReturn
		EndIf
		btnactive + direction
	Wend
	
	SetActiveGadget(btnactive)
	; 	Можно было бы вычислить координаты и размеры как при создании кнопок
	If BorderW
		With rsAcBtn
			\x = GadgetX(btnactive)
			\y = GadgetY(btnactive)
			\w = GadgetWidth(btnactive)
			\h = GadgetHeight(btnactive)
		EndWith
	EndIf
EndProcedure



Procedure WinCallback(hWnd, uMsg, WParam, LParam)
	If uMsg = #WM_PAINT
		With rsAcBtn
			BitBlt_(hDC, \x - BorderW, \y - BorderW, \w + BorderW*2, BorderW, MemDC, 0, 0, #SRCCOPY) ; верх
			BitBlt_(hDC, \x - BorderW, \y + \h, \w + BorderW*2, BorderW, MemDC, 0, 0, #SRCCOPY)		 ; низ
			BitBlt_(hDC, \x - BorderW, \y, BorderW, \h, MemDC, 0, 0, #SRCCOPY)						 ; слева
			BitBlt_(hDC, \x + \w, \y, BorderW, \h, MemDC, 0, 0, #SRCCOPY)							 ; справа
		EndWith
	EndIf
	ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure


hGUI = OpenWindow(#Window, 0, 0, FWidth, FHeight, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
ButtonGadget(0, 10, 10, 100, 25, "# 0")
ButtonGadget(1, 10, 40, 100, 25, "# 1")
ButtonGadget(2, 10, 70, 100, 25, "# 2")
ButtonGadget(3, 120, 10, 100, 25, "# 3")
ButtonGadget(4, 120, 40, 100, 25, "# 4")
ButtonGadget(5, 120, 70, 100, 25, "# 5")
d = 5
SetActiveButton(btnactive, -1)

hMenu = CreatePopupMenu(#Menu)

mNext = 0
mPrev = 1
mEnter = 2
mRight = 3
mLeft = 4
If hMenu
	MenuItem(mNext, "Next" + #TAB$ + "->")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Down, mNext)
	MenuItem(mPrev, "Prev" + #TAB$ + "<-")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Up, mPrev)
	MenuItem(mEnter, "Enter" + #TAB$ + "Enter")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Return, mEnter)
	MenuItem(mPrev, "Left" + #TAB$ + "<-")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Left, mLeft)
	MenuItem(mNext, "Right" + #TAB$ + "->")
	AddKeyboardShortcut(#Window, #PB_Shortcut_Right, mRight)
EndIf




; 	Если рамка равна 0, то не задействуем движок рисования рамки
If BorderW
	With rsAcBtn
		\x = GadgetX(0)
		\y = GadgetY(0)
		\w = GadgetWidth(0)
		\h = GadgetHeight(0)
	EndWith
	CopyStructure(@rsAcBtn, @rsOldBtn.Rect2, Rect2)
	
	hDC = GetDC_(hGUI)
	MemDC = CreateCompatibleDC_(hDC)
	CreateBMP()
	SetWindowCallback(@WinCallback())
EndIf

Define Event, EvGadget, EvType, EvMenu
Define Quit

Repeat
	Event = WaitWindowEvent()
	EvGadget = EventGadget()
	EvType = EventType()
	EvMenu = EventMenu()
	
	Select Event
		Case #PB_Event_CloseWindow
			Quit = 1
			
		Case #PB_Event_RightClick
			DisplayPopupMenu(#Menu, WindowID(#Window))	
			
		Case #PB_Event_Menu            
			Select EvMenu  ; To see which menu has been selected
					
				Case 0 ; mNext
					btnactive = GetActiveGadget() ;tab + shift tab effect
					Erase()
					btnactive=btnactive+1
					If btnactive>5
						btnactive=0
					EndIf
					SetActiveButton(btnactive, 1)
					
				Case 1 ; mPrev 
					btnactive = GetActiveGadget() ;tab + shift tab effect
					Erase()
					btnactive=btnactive-1
					If btnactive<0
						btnactive=5
					EndIf
					SetActiveButton(btnactive, -1)
					
				Case 2	;mEnter
					btnactive = GetActiveGadget() ;tab + shift tab effect
					PostEvent(#PB_Event_Gadget, #Window, btnactive)      
					
				Case 3 ; mRight
					btnactive = GetActiveGadget()
					Erase()
					btnactive + 3 ; rows
					If btnactive > 5
						btnactive = 5
					EndIf
					SetActiveButton(btnactive, 1)
					
				Case 4 ; mLeft
					btnactive = GetActiveGadget()
					Erase()
					btnactive - 3 ; rows
					If btnactive < 0
						btnactive = 0
					EndIf
					SetActiveButton(btnactive, -1)  
			EndSelect
			
		Case #PB_Event_Gadget
			Select EvGadget
				Case 0
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 0 Clicked"
					EndSelect
					
				Case 1
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 1 Clicked"
					EndSelect
					
				Case 2
					Select EvType               
						Case #PB_EventType_LeftClick
							Debug "Button 2 Clicked"
					EndSelect
			EndSelect
			
	EndSelect
Until Quit = 1

ReleaseDC_(hGUI, hDC)
SelectObject_(MemDC, hOldBMP)
DeleteDC_(MemDC)
CloseWindow(#Window)
Post Reply