A number of other languages have a splitter control of some sort, why not Visual FoxPro? To be fair, I have seen some splitter classes floating around from time to time, but I thought I’d try my hand at it. I was convinced it couldn’t be too difficult, and Visual FoxPro didn’t disappoint me. Below is a download link for the class library that I placed my splitter class in (based on shape) and an example form showing how the class is used (I’ve taken a screen shot of it so you can see what it looks like). Now, if you want to try the splitter class out before you go to the trouble of downloading it, I’ve also created a cut-n-paste/execute example that you’ll find directly beneath the screen shot. This splitter control is designed to work with Visual FoxPro 9.0. If you are using a previous version then you will need to modify/delete a few things.
Download Splitter.vcx and Form Example (8 KB approx.)
*!* Cut-N-Paste the code below into a prg file and execute it to see and try out a working example of the splitter class
PUBLIC oform1
oform1=NEWOBJECT(“form1”)
oform1.Show
RETURN
************************************
DEFINE CLASS form1 AS form
************************************
DoCreate = .T.
Caption = “Splitter Example”
Name = “Form1”
MDIForm = .T.
Autocenter = .T.
ADD OBJECT text1 AS textbox WITH ;
Anchor = 11, ;
Height = 29, ;
Left = 0, ;
Top = 0, ;
Width = 375, ;
Name = “Text1”
ADD OBJECT edit1 AS editbox WITH ;
Anchor = 7, ;
Height = 217, ;
Left = 0, ;
Top = 33, ;
Width = 184, ;
Name = “Edit1”
ADD OBJECT edit2 AS editbox WITH ;
Anchor = 15, ;
Height = 217, ;
Left = 188, ;
Top = 33, ;
Width = 187, ;
Name = “Edit2”
ADD OBJECT splitter1 AS splitter WITH ;
Top = 32, ;
Left = 183, ;
Height = 219, ;
Width = 6, ;
Anchor = 7, ;
Name = “Splitter1”
ADD OBJECT splitter2 AS splitter WITH ;
Top = 28, ;
Left = 0, ;
Height = 6, ;
Width = 376, ;
Anchor = 10, ;
vertical = .F., ;
minimumsize = 29, ;
Name = “Splitter2”
PROCEDURE Init
This.text1.Value = “Visual FoxPro Rocks!”
This.Edit1.Value = “Visual FoxPro is an extremely versatile development tool. ” + ;
“Not only does it allow a developer to create great datacentric applications, ” + ;
“it also allows the developer to extend the actual language with new classes, ” + ;
“code libraries, and hooks. If you’re an avid Visual FoxPro developer like myself ” + ;
“then good for you. And, if you’re not, then I encourage you to give Visual FoxPro ” + ;
“a try. You won’t regret it”
This.Edit2.Value = “This is an example of a splitter class for use in Visual FoxPro 9.0 forms. ” + ;
“It is pure Visual FoxPro, so there aren’t any additional ActiveX or DLL dependencies ” + ;
“to worry about when distributing your application. To see it in action move the ” + ;
“horizontal and vertical splitters around on this form. Also, by resizing the form you ” + ;
“can see that it handles the new Visual FoxPro 9.0 Anchors property with aplomb.”
ENDPROC
ENDDEFINE
************************************
DEFINE CLASS splitter AS shape
************************************
Height = 182
Width = 8
MousePointer = 9
SpecialEffect = 0
Style = 0
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
ENDPROC
PROCEDURE MouseUp
LPARAMETERS nButton, nShift, nXCoord, nYCoord
This.mousedownat = 0
ENDPROC
ENDDEFINE
Hello, I’m trying to use your work.
I’m not an experienced programmer so probably I’ll do a lot of error.
I had some problem using it and I discovered that for a reason I don’t understand
in the mouse move event there is code that ask THIS.PARENT.CONTROLS and try to do
something with every control : ok, I can (and in fact I did) write DoN’t_MoVe_SpLiT
in the tag property of every other control of the form to evitate this, but this force me
to write something in the tag property that probably I can’t use for any other stuff.
My newbie question is : how can I place a container with some control and your splitter in it and force the splitter to exclude every control out of the container without touch the tag property ?
Thank’s in advance
Bert
P.S.
Sorry for my bad english