Playing with splitters
The splitter is a control (here a shape) can divide a screen or form or container into two or many (more splitters) resizable parts.
it can be horizontal or vertical.
i used the sps splitter class (with light modifications) to make it in use with this top level form as demo.
the class is as a flat text in the end of the code below.can reverse to make it as (vcx+vct) and drop it on a form.
sps link:http://www.sweetpotatosoftware.com/spsblog/2005/08/13/SplitterClassForVisualFoxPro.aspx
there is 3 containers with some advanced complexity with some controls as treeview,listbox,grid,editbox,label,image....
the sps class is the best splitter i found in vfp namespace because its light and performent.
preferably use containers to split complex configuration controls.
in the demo there is 4 splitters (1 vertical and 3 horizontal).mousedown on the splitter to move the adjacent controls.this can split as well the form or screen into economic areas.
see the images below.
first image is downloaded from web to beautify an image control in container.can replace it with local image (name it as yimage.jpg) and cut the relative code at begin.
Click on code to select [then copy] -click outside to deselect
*1*
Publi m.yrep
m.yrep=Addbs(Justpath(Sys(16,1)))
Set Defa To (yrep)
*download the picture used in code.if dont have internet connect , replace by a local image named yimage.jpg
Declare Integer URLDownloadToFile In urlmon.Dll Integer pCaller, String szURL, String szFileName, Integer dwReserved, Integer lpfnCB
Declare Integer DeleteUrlCacheEntry In wininet String lpszUrlName
Local lcDownloadURL,lcDownloadLoc,lnResult
lcDownloadURL = "http://img.over-blog-kiwi.com/1/43/54/07/20160217/ob_d8f409_sam-2259-resized.JPG"
lcDownloadLoc = "yImage.jpg"
lnResult = DeleteUrlCacheEntry(lcDownloadURL)
lnResult = URLDownloadToFile(0, lcDownloadURL, lcDownloadLoc , 0,0)
If lnResult = 0
Wait Window "Download yimage.jpg Complete" nowait
*Else
*!* Messagebox("Download fails")
Endi
Publi yform
yform=Newobject("ysplitters")
yform.Show
Read Events
Retu
*
Define Class ysplitters As Form
Height = 570
Width = 881
ShowWindow = 2
ShowTips = .T.
AutoCenter = .T.
Caption = "Splitters Demo"
BackColor = Rgb(212,208,200)
Name = "Form1"
Add Object splitter1 As splitter With ;
Top = 54, ;
Left = 223, ;
Height = 521, ;
Width = 6, ;
Anchor = 7, ;
Name = "Splitter1"
Add Object ycont As ycont With ;
Anchor = 7, ;
Top = 48, ;
Left = 0, ;
Width = 224, ;
Height = 527, ;
Name = "ycont"
Add Object ycont1 As ycont1 With ;
Anchor = 15, ;
Top = 48, ;
Left = 232, ;
Width = 644, ;
Height = 527, ;
Name = "ycont1"
Add Object ycont0 As ycont0 With ;
Anchor = 10, ;
Top = 3, ;
Left = -1, ;
Width = 877, ;
Height = 36, ;
BorderWidth = 0, ;
BackColor = Rgb(0,0,0), ;
Name = "ycont0"
Add Object splitter2 As splitter With ;
Top = 36, ;
Left = 2, ;
Height = 11, ;
Width = 874, ;
Anchor = 10, ;
vertical = .F., ;
minimumsize = 29, ;
Name = "Splitter2"
Procedure filltree
Parameters m.path, m.nlevel, m.nCount
Local DirArr,i,nTotDir,lvl,pkey
m.path = Alltrim(m.path)
If Parameters()<2 Or Type("m.nlevel") #"N"
lvl = 0
Else
lvl = m.nlevel
Endif
If Parameters()<2 Or Type("m.nCount") #"N"
Cnt = 0
Else
Cnt = m.nCount
Endif
lvl = lvl + 1
Cnt = Cnt + 1
pkey = Lower(Substr(m.path,1,Rat("\",m.path,2)))+"_"
* Add items to treeview control
o = This.ycont.oleTreeview
If Cnt = 1
oNode = o.nodes.Add(,1,Lower(m.path)+"_",Lower(m.path),,)
oNode.Image = "world"
Else
oNode = o.nodes.Add(m.pkey,4,Lower(m.path)+"_",Strtran( Strtran(Lower(m.path),"c:\program files\microsoft visual foxpro 9\samples\solution\",""),"\",""),,)
oNode.Image="open"
Endif
Dimension DirArr[1,1]
nTotDir=Adir(DirArr,m.path+"*.","D")
Asort(DirArr)
For i = 1 To m.nTotDir
If DirArr[m.i,1] != '.' And Atc('D',DirArr[m.i,5])#0
This.filltree(m.path+DirArr[m.i,1]+'\', m.lvl, m.cnt)
Endif
Endfor
Endproc
Procedure Load
Close Data All
Sele company From Home(1)+"samples\data\customer" Into Cursor ycurs
Endproc
Procedure Destroy
Clea Events
Endproc
Enddefine
*
*-- EndDefine:ysplitters
Define Class ycont As Container
Anchor = 7
Top = 48
Left = 0
Width = 224
Height = 527
lexpanded=.F.
Name = "ycont"
Add Object splitter2 As splitter With ;
Top = 311, ;
Left = 8, ;
Height = 6, ;
Width = 206, ;
Anchor = 90, ;
vertical = .F., ;
minimumsize = 29, ;
Name = "Splitter2"
Add Object list1 As ListBox With ;
FontBold = .T., ;
FontName = "Segoe Script", ;
FontSize = 10, ;
Anchor = 80, ;
Height = 212, ;
ColumnLines = .T., ;
Left = 4, ;
MousePointer = 15, ;
Top = 324, ;
Width = 212, ;
ItemForeColor = Rgb(0,255,255), ;
ItemBackColor = Rgb(0,0,0), ;
ItemTips = .T., ;
Name = "List1"
Add Object oleTreeview As OleControl With ;
oleclass="MSComctlLib.TreeCtrl.2", ;
Top = 5, ;
Left = 7, ;
Height = 295, ;
Width = 209, ;
Anchor = 75, ;
Name = "oleTreeview"
Add Object oleimageslist As OleControl With ;
oleclass="MSComctlLib.ImageListCtrl.2" , ;
Top = 165, ;
Left = 183, ;
Height = 100, ;
Width = 100, ;
Name = "oleImageslist"
Procedure Init
If Fontmetric(1, 'MS Sans Serif', 8, '') # 13 Or ;
fontmetric(4, 'MS Sans Serif', 8, '') # 2 Or ;
fontmetric(6, 'MS Sans Serif', 8, '') # 5 Or ;
fontmetric(7, 'MS Sans Serif', 8, '') # 11
This.SetAll('fontname', 'Tahoma')
Else
This.SetAll('fontname','MS Sans Serif')
Endif
This.SetAll('fontsize',8)
********
Procedure Init
* Check to see if OCX installed and loaded.
If Type("THIS.oleTreeview") # "O" Or Isnull(This.oleTreeview)
Return .F.
Endif
* Check to see if OCX installed and loaded.
If Type("THIS.oleImagesList") # "O" Or Isnull(This.oleimageslist)
Return .F.
Endif
With This.oleimageslist
xpic1=Home(1)+"GRAPHICS\ICONS\WIN95\MYCOMP.ICO"
xpic2=Home(1)+"graphics\bitmaps\outline\closed.bmp"
xpic3=Home(1)+"GRAPHICS\BITMAPS\TLBR_W95\OPEN.BMP"
.ImageHeight = 16
.ImageWidth = 16
.usemaskcolor=.T.
.ListImages.Add(,"world",LoadPicture(m.xpic1))
.ListImages.Add(,"open",LoadPicture(m.xpic2))
.ListImages.Add(,"openo",LoadPicture(m.xpic3))
Endwith
This.oleTreeview.ImageList =This.oleimageslist.Object
Local cDir
cDir = Home(1)+"samples\solution\"
If Empty(m.cDir)
Return .F.
Endif
This.oleTreeview.nodes.Clear
Thisform.filltree(m.cDir)
********
*expand all nodes
If This.oleTreeview.nodes.Count > 0
* only do this if we have nodes in the treeview
For Each loNode In This.oleTreeview.nodes
If loNode.Children > 0
* only do this if this node has child nodes
loNode.Expanded = !This.lexpanded
Endif
Endfor
* set form's Expanded property to new value
This.lexpanded = !This.lexpanded
Endif
Endproc
Procedure list1.Init
With This
.ColumnCount = 1
.RowSourceType = 6
.RowSource = "ycurs.company"
Endwith
Endproc
Procedure oleTreeview.NodeClick
*** Événement de contrôle ActiveX ***
Lparameters Node
*repaint all nodes with icon "open"
i=1
For Each loNode In This.nodes
If i=1
loNode.Image="world"
Else
loNode.Image= "open"
Endi
i=i+1
Endfor
*change only icon node clicked only to "openo"
Node.Image="openo"
Endproc
Enddefine
*
*-- EndDefine: ycont
Define Class ycont1 As Container
Anchor = 15
Top = 48
Left = 232
Width = 644
Height = 527
Name = "ycont1"
Add Object grid1 As Grid With ;
Anchor=15, ;
Height = 247, ;
Left = 5, ;
Top = 5, ;
Width = 639, ;
Name = "Grid1"
Add Object splitter2 As splitter With ;
Top = 253, ;
Left = 3, ;
Height = 11, ;
Width = 641, ;
Anchor = 10, ;
vertical = .F., ;
minimumsize = 29, ;
Name = "Splitter2"
Add Object image1 As Image With ;
Anchor = 15, ;
Picture =m.yrep+ "yimage.jpg", ;
Stretch = 2, ;
Height = 268, ;
Left = 1, ;
Top = 260, ;
Width = 643, ;
Name = "Image1"
Procedure grid1.Init
Sele * From Home(1)+"samples\data\customer" Into Cursor ycurs
With This
.RecordSource="ycurs"
.DeleteMark=.F.
.GridLines=0
.Themes=.F.
.SetAll("backcolor",Rgb(212,208,200),"header")
.SetAll("forecolor",Rgb(255,0,0),"header")
.SetAll("fontbold",.T.,"header")
.SetAll("DynamicBackColor","IIF(MOD(RECNO( ), 2)=0, RGB(225,205,235) , RGB(208,215,212))", "Column")
Locate
.Refresh
Endwith
Enddefine
*
*-- EndDefine:ycont1
Define Class ycont0 As Container
Anchor = 10
Top = 3
Left = -1
Width = 877
Height = 36
BorderWidth = 0
BackColor = Rgb(0,0,0)
Name = "ycont0"
Add Object label1 As Label With ;
FontName = "Segoe Script", ;
FontSize = 22, ;
Anchor = 10, ;
Alignment = 2, ;
Caption = "This is a splitter demo", ;
Height = 37, ;
Left = 1, ;
Top = -4, ;
Width = 800, ;
ForeColor = Rgb(255,0,0), ;
BackColor =0, ;
Name = "Label1"
Add Object yhelp As Label With ;
FontName = "Arial", ;
FontSize = 20, ;
fontbold=.T.,;
mousepointer=15,;
Anchor = 10, ;
Alignment = 2, ;
Caption = "?", ;
autosize=.T.,;
Left = 820, ;
Top = 0, ;
ForeColor = Rgb(0,255,0), ;
BackColor =0, ;
Name = "yHelp"
Add Object edit1 As EditBox With ;
Anchor = 15, ;
Height = 200, ;
Left =119, ;
Top = 38, ;
Width = 639, ;
fontsize=12,;
backcolor=0,;
ForeColor = Rgb(255,255,255), ;
Name = "Edit1"
Procedure Init
TEXT to this.edit1.value noshow
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin vel risus eget lorem feugiat
fermentum nec a turpis. Phasellus purus sem, mollis ac posuere eget, ornare vel orci. Sed ac rutrum
nulla. Aenean ultrices eget lectus eu efficitur. In hac habitasse platea dictumst. Nulla in iaculis nisi.
Nullam et pulvinar tellus. Donec arcu dui, efficitur a odio non, porta congue dolor. Aenean viverra
auctor sagittis. Integer lobortis dignissim auctor. Proin et volutpat massa.
Cras vitae felis venenatis, egestas sem quis, sodales neque. Donec venenatis hendrerit odio, non
pellentesque metus scelerisque ac. Suspendisse aliquet rhoncus odio id viverra. Vestibulum feugiat
lectus a nisl pulvinar, in tempor metus eleifend. Nunc id odio quam. Praesent egestas lorem ut
sollicitudin consectetur. Vestibulum id bibendum est. Ut vel lacus sapien. Quisque eget molestie
sem. Integer eget purus eu orci molestie aliquam quis in ante. Integer a magna eget lectus finibus
porttitor. Donec fringilla sapien a quam aliquet, pellentesque blandit nisl placerat. Nam hendrerit
velit vel ex aliquam, eget convallis ante mollis.
ENDTEXT
This.edit1.Left=(This.Width-This.edit1.Width)/2
This.Refresh
Endproc
Procedure yhelp.Click
local m.myvar
text to m.myvar noshow
The splitter is a control can divide a screen or form or container into two or many resizable parts.
it can be horizontal or vertical.
i used the sps splitter class (with light modifications) to make it in use with this demo.
the class is as a flat text in the end of the code below.can reverse to make it as (vcx+vct)
sps link:http://www.sweetpotatosoftware.com/spsblog/2005/08/13/SplitterClassForVisualFoxPro.aspx
there is 3 containers with some advanced complexity with some controls as treeview,listbox,grid,editbox,label,image....
the sps class is the best splitter i found in vfp namespace because its light and performent.
preferably use containers to split complex configuration controls.
in the demo there is 4 splitters (1 vertical and 3 horizontal).mousedown on the splitter to move the adjacent
controls.this can split as well the form or screen into economic areas.
see the images below.
first image is downloaded from web to beautify an image control in container.
endtext
Messagebox(m.myvar,0+32+4096,"summary help")
endproc
Enddefine
*
*-- EndDefine: ycont0
*this class is from SPS website translated to flat text
Define Class splitter As Shape
Height = 182
Width = 8
MousePointer = 9
SpecialEffect = 0
Style = 0
BackColor=Rgb(192,192,192)
mousedownat = 0 && Tracks mouse and allows class to ignore moves caused by resizing form
vertical = .T. && Set to .F. for horizontal splitter
minimumsize = 40 && This is how small (in pixels) the panels can get when moving the splitter
Name = "splitter"
Procedure MouseLeave
Lparameters nButton, nShift, nXCoord, nYCoord
This.mousedownat = 0
Endproc
Procedure Move
Lparameters nLeft, nTop, nWidth, nHeight
*!* If you want to move the splitter during runtime and have it move the other controls
*!* then set mousedownat != 0 and call this move method of the splitter
*!* remember to set mousedownat back to 0 when you are done moving the splitter
Local loControl, llLockScreenWas, lnMovement, llIsSplitter, lcUniqueTag, lnMarginOfError, lnAnchorWas
If This.mousedownat == 0
DoDefault(m.nLeft, m.nTop, m.nWidth, m.nHeight)
Return
Endif
m.loControl = Null
*!* The following tag can be placed in controls you don't want moved as well
m.lcUniqueTag = "DoN't_MoVe_SpLiT" && Just something that is pretty well guaranteed to be unique
This.Tag = m.lcUniqueTag
m.llLockScreenWas = Thisform.LockScreen && JIC the screen was already locked
Thisform.LockScreen = .T.
m.lnMovementLeft = m.nLeft - This.Left
m.lnMovementTop = m.nTop - This.Top
For Each m.loControl In This.Parent.Controls
If m.loControl.Tag = lcUniqueTag && this splitter so just loop
Loop
Endif
If Pemstatus(m.loControl,"Anchor",5)
m.lnAnchorWas = m.loControl.Anchor
m.loControl.Anchor = 0
m.llIsSplitter = m.loControl.Class = "Splitter"
If This.vertical && Vertical Splitter
lnMarginOfError = Int(This.Width/2) && JIC the developer got the splitter a little too close
If m.loControl.Left <= This.Left && Control is to the left of splitter
If (m.loControl.Left + m.loControl.Width) <= (This.Left + lnMarginOfError) And !m.llIsSplitter
m.loControl.Width = Max(m.loControl.Width + m.lnMovementLeft, 0)
Endif
Else && Control is to the right of splitter
If !m.llIsSplitter
m.loControl.Width = Max(m.loControl.Width - m.lnMovementLeft, 0)
Endif
m.loControl.Left = m.loControl.Left + m.lnMovementLeft
Endif
Else && Horizontal Splitter
lnMarginOfError = Int(This.Top/2) && JIC the developer got the splitter a little too close
If m.loControl.Top <= This.Top && Control is above the splitter
If (m.loControl.Top + m.loControl.Height) <= (This.Top + lnMarginOfError) And !m.llIsSplitter
m.loControl.Height = Max(m.loControl.Height + m.lnMovementTop, 0)
Endif
Else && Control is below the splitter
If !m.llIsSplitter
m.loControl.Height = Max(m.loControl.Height - m.lnMovementTop, 0)
Endif
m.loControl.Top = m.loControl.Top + m.lnMovementTop
Endif
Endif
m.loControl.Anchor = m.lnAnchorWas
Endif
Next
m.lnAnchorWas = This.Anchor
This.Anchor = 0
DoDefault(m.nLeft, m.nTop, m.nWidth, m.nHeight) && Finally move the splitter
This.Anchor = m.lnAnchorWas
Thisform.LockScreen = m.llLockScreenWas
This.Tag = ""
Endproc
Procedure MouseMove
Lparameters nButton, nShift, nXCoord, nYCoord
Local lnMovement
If m.nButton = 1 And !(This.mousedownat == 0)
If This.vertical
If m.nXCoord != This.mousedownat
m.lnMovement = m.nXCoord - This.mousedownat
If Between(This.Left + m.lnMovement, This.minimumsize, This.Parent.Width - This.Width - This.minimumsize)
This.Move(This.Left + m.lnMovement, This.Top, This.Width, This.Height)
This.mousedownat = m.nXCoord
Endif
Endif
Else && Horizontal
If m.nYCoord != This.mousedownat
m.lnMovement = m.nYCoord - This.mousedownat
If Between(This.Top + m.lnMovement, This.minimumsize, This.Parent.Height - This.Height - This.minimumsize)
This.Move(This.Left, This.Top + m.lnMovement, This.Width, This.Height)
This.mousedownat = m.nYCoord
Endif
Endif
Endif
Endif
Endproc
Procedure MouseDown
Lparameters nButton, nShift, nXCoord, nYCoord
If This.vertical
This.mousedownat = nXCoord
Else
This.mousedownat = nYCoord
Endif
Endproc
Procedure Init
*IF !THIS.vertical
* THIS.MOUSEPOINTER = 7 && NS
*ENDIF
With This &&modified
If .vertical
.MouseIcon=Home(1)+"GRAPHICS\CURSORS\VE_SPLIT.CUR"
.MousePointer=99
Else
.MouseIcon=Home(1)+"GRAPHICS\CURSORS\HO_SPLIT.CUR"
.MousePointer=99
Endi
Endwith
Endproc
Procedure MouseUp
Lparameters nButton, nShift, nXCoord, nYCoord
This.mousedownat = 0
Endproc
Enddefine
*ENDDEFINE splitter
Important:All Codes above are tested on VFP9SP2 & windows 10 pro