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