Subclassing the form titlebar & other stuffs

Published on by Yousfi Benameur

The form (with its titlebar) is made in my knowledge with APis (createwindow for ex.) and its difficult to traverse its titlebar , add controls or  make changes (even with gdiplus class as shown in a solution windowsevents form sample)  because there is Apis callbacks to redraw it instantaneously as init.(I see on the web someones making buttons or even gradients on the native window form titlebar with C++ & C# ! Its not yet the case in VFP)

The simplest way to do that is to subclass the title bar by a vfp control as container and embed in it what vfp controls  we want.
this is the method described in the sample i ship below.
This makes a some skin to  the native vfp form
see some screenshots in the section below.

 

The top level form used in the project have a subclassed titlebar made with a container.
the native titlebar is cut with the form property
form.titlebar=0
can embed in this container any vfp objects (textbox,editbox,image, spinner,label,container... .)
must resize the container in the resize form method.

-the standard menu (left icon or image) is not standard colored (see with editing the ymenu.mnx)

-the second menu (top level form) is positionned at line3 to be under the titlebar with this code line (you can position it as you want) :

DEFINE MENU (m.cMenuName) IN (m.oFormRef.Name) BAR at line 3.
the menu mpr generated is saved as a prg sdiform.prg otherwise the menu is always above the titlebar.in the form init execute :[do sdiform.prg with this,.t.] instead an mpr.
this trick necessits only the mpr as prg file (no menu embed).
The form is limited when resizing with the minWidth & minHeight properties.

Can customize the background titlebar (random or set as an image in "image folder"), the caption(property form.ycaption.Forecolor) and the form picture.....
can add fontname,fontsize...but its not the goal here.I just focus on how to do that operation
Can set the transparency between opacity=100-255 (values <100 are very transparent).A
normal good opacity  value is 210 (set initially on the form).
.This can set a kind of form glass with your desktop as background..

When setting transparency change the color with some units(+-) to see the change on form.
Can make a hole on form playing with the key  (#Define LWA_COLORKEY 1)  instead alpha channel(#Define LWA_ALPHA 2) or both the 2 constants.
Can clear this hole by setting new transparency to 255
Of course the form is movable by the titlebar
A hole with tranpsarency 0 can make the desktop icons clickable(hrere opacity>100 then no problem).
I added a menu on the top level form (showWindow=2 only) for demo.(coded in  sdiform.prg)
Click on the left icon or on the image to fire thecontextuel menu(you can extend it in the visual menu on project)
Download the entire proj , test it and generate an exe with your vfp9 version.
i added a large quantity of small pictures in the "image"  folder (can filter or change).

 

*remarks
-can add many items to menu as your taste
-can make small images in the  controlbox container (minimize,max and close)

 

Some screenshots made on running application
Some screenshots made on running application
Some screenshots made on running application
Some screenshots made on running application
Some screenshots made on running application
Some screenshots made on running application
Some screenshots made on running application

Some screenshots made on running application

Click on code to select [then copy] -click outside to deselect

                        
*2*created on 11 of  january 2017 (user question on UT)
*--yposition_any_window.prg
*--	starting with Listing child windows for the Windows desktop-Nesw2News
*--adapted to search a specific window done with its title caption .
*--browse the result with informations on hwnd,window dimensions,title window,visibility,class (as option)
*--suppose 1 single instance of window with mycaption title.(it takes the first window)
*--window caption is localized (microsoft windows)...must put the exact localized title to search.change
*--titles below (for french locale)
*--the setwindoxPos API can position any window given by its handlecan set left,top,width & height

*begin code
_Screen.WindowState=1

Local mycaption
*mycaption="Sans titre - Paint"
*run/n mspaint

*myCaption="Sans titre - Bloc-notes"
*run/n notepad

mycaption="Explorateur de fichiers"  &&warning loclized (here french---in english: files explorer... must be exact title.
Run/N explorer.Exe

Inke(3)  &&wait to make window appear for positionning it

#Define GW_HWNDLAST 1
#Define GW_HWNDNEXT 2
#Define GW_CHILD 5

Do Declare

Create Cursor csResult (HWnd N(12), isvisible N(1),;
	leftpos I, toppos I, rightpos I, botpos I, wincap C(100), classname C(64))
Local hDesktop, hFirstChild, hLastChild, rc, cWinCap, cWinClass,;
	nVisible, nLeft, nTop, nRight, nBottom
hDesktop = GetDesktopWindow()
hFirstChild = GetWindow(hDesktop, GW_CHILD)
hLastChild = GetWindow(hFirstChild, GW_HWNDLAST)
hCurrent = hFirstChild

Do While .T.
	cWinCap = GetWinText(hCurrent)
	cWinClass= GetClsName(hCurrent)
	nVisible = IsWindowVisible(hCurrent)

	rc = Repli(Chr(0),16)
	= GetWindowRect(hCurrent, @rc)
	nLeft = buf2dword(Substr(rc, 1,4))
	nTop = buf2dword(Substr(rc, 5,4))
	nRight = buf2dword(Substr(rc, 9,4))
	nBottom = buf2dword(Substr(rc, 13,4))
	***********test searched window here
	If Allt(Lower(mycaption)) == Allt(Lower(cWinCap))
		Insert Into csResult Values (hCurrent, nVisible,;
			nLeft, nTop, nRight, nBottom, cWinCap, cWinClass)
	Endi

	If hCurrent = hLastChild
		Exit
	Endif
	hCurrent = GetWindow(hCurrent, GW_HWNDNEXT)
Enddo
Locate
*BROWSE NORMAL   NOWAIT    && for isvisible=1
If Reccount()=0
	Messagebox("Window ["+mycaption+" ] not found...cancelling",16+4096,"error",1500)
	Return .F.
Endi
lnHandle=HWnd

If HWnd=0
	Messagebox("fails! no window on desktop....cancelling!",16+4096,"error",1500)
	Return .F.
Endi

*position window here-this is tests for 6 positions
Local xleft,xtop,xwidth,xheight    &&as you want
m.xwidth=500
m.xheight=200
SetWindowPos(m.lnHandle,0, 0,0,m.xwidth+100,m.xheight-50,64)
Inke(1)
SetWindowPos(m.lnHandle,0, 100,0,m.xwidth,m.xheight+100,64)
Inke(1)
SetWindowPos(m.lnHandle,0, 100,300,m.xwidth-50,m.xheight,64)
Inke(1)
SetWindowPos(m.lnHandle,0,400,50,m.xwidth,m.xheight+40,64)
Inke(1)
SetWindowPos(m.lnHandle,0, 50,500,m.xwidth+100,m.xheight+100,64)
Inke(1)
*centered on screen
m.xwidth=xwidth+200
m.xheight=m.xheight+200
SetWindowPos(m.lnHandle,0,(Sysmetric(1)-xwidth)/2,(Sysmetric(2)-xheight)/2,m.xwidth,m.xheight,64)  

Retu


Function GetClsName(hWindow)
	Local nBufsize, cBuffer
	cBuffer = Repli(Chr(0), 250)
	nBufsize = GetClassName(hWindow, @cBuffer, Len(cBuffer))
	Return Substr(cBuffer, 1, nBufsize)


Function GetWinText(hWindow)
	* returns window title bar text -- Win9*/Me/XP/2000
	Local cBuffer, nResult
	cBuffer = Space(250)
	nResult = GetWindowText(hWindow, @cBuffer, Len(cBuffer))
	Return Substr(cBuffer, 1, nResult)
endfunc

Function buf2dword(lcBuffer)
	Return Asc(Substr(lcBuffer, 1,1)) + ;
		BitLShift(Asc(Substr(lcBuffer, 2,1)),  8) +;
		BitLShift(Asc(Substr(lcBuffer, 3,1)), 16) +;
		BitLShift(Asc(Substr(lcBuffer, 4,1)), 24)
endfunc

Procedure Declare
	Declare Integer GetDesktopWindow In user32
	Declare Integer GetWindow In user32 Integer HWnd, Integer wFlag
	Declare Integer GetWindowRect In user32 Integer HWnd, String @lpRect
	Declare Integer IsWindowVisible In user32 Integer HWnd

	Declare Integer GetWindowText In user32;
		INTEGER HWnd, String @lpString, Integer cch

	Declare Integer GetClassName In user32;
		INTEGER HWnd, String lpClassName, Integer nMaxCount

	Declare Integer SetWindowPos In user32;
		INTEGER HWnd, Integer hWndInsertAfter,;
		INTEGER x, Integer Y, Integer cx, Integer cy,;
		INTEGER wFlags
 endproc		
		
*endcode
*can use findwindow to get the window but i prefer this code(for another uses).



To be informed of the latest articles, subscribe:
Comment on this post