Consultancy and Programming
Advice, tips, techniques and downloads for Visual Foxpro developers.
This article applies to Visual Foxpro 6.0 and earlier. If you are using a later version, please refer to the note at the end of the article.
Most VFP applications are MDI (multiple document interface) in nature. That means that users can open several forms at the same time and jump from one to another at will. MDI applications usually have a Window menu, with options to cascade and tile the open windows and to select specific windows. VFP has most of that functionality built in. But there is no Cascade function. If you want to let your users cascade their forms, you have to write the code yourself.
What exactly do we mean by cascade? Essentially, it means that all the open forms will appear on the screen, each offset slightly to the right and below the one before. If you examine other MDI applications, you will observe a fairly consistent behavior.
Specifically, each window (form) is resized so that it occupies three quarters of the parent window. The first window is then moved to the top left corner of the parent. Subsequent window are placed on top of the previous one, offset down and to the right by an amount equal to the height of the title bar. If a given window does not fit within the boundaries of the parent, the sequence starts again from the top left corner of the parent.
The code at the end of this article implements this procedure. As it is generic, it does not know the names of the forms that it is working with. Instead, it uses _SCREEN to access the forms.
For those who havent worked with _SCREEN before, it is essentially a device which allows the main VFP window to be manipulated as if it was itself a form. You can use it to alter the main window's title, to assign an icon to the main window (see the FoxStuff article "Do your application icons always show up?"), to move the main window to a particular point on the screen, and, as in this case, to access the forms currently contained in the main window. It has around 70 properties and 20 methods, all of which are described in the VFP Help.
Our Cascade routine uses two properties of _SCREEN: the Forms property is an array (to be precise, a collection) of the currently open forms; and FormCount is the number of forms in this collection. Using these properties, the routine iterates through the open forms, changing their sizes and positions as it does so.
There are a couple of points to watch out for. The routine can only resize a form if its BorderStyle property is 3; other border styles are non-resizable. So we need to test the BorderStyle property each time round the loop. But before we do that, we must check that this property actually exists. That's because the Forms collection can also hold floating toolbars, and these do not have a border style. The Type() function is used to check that the property exists.
Even if the form is resizable, it might be subject to minimum and maximum sizes, as stipulated by its MinWidth, MinHeight, MaxWidth and MaxHeight properties. If any of these properties is greater than -1, it means that a corresponding limit is in force. Our routine tests for this before resizing each form.
After the form is resized, the routine moves it to its new position. The Sysmetric(9) function, called near the start of the code, determines the height of the title bar, this being the amount of the vertical and horizontal offset for each window.
To use the code, cut and paste it to your application. Add a Cascade prompt to your Window menu, and place a suitable call (e.g. DO Cascade) in its result field.
PROCEDURE Cascade LOCAL lnHorizOff, lnVertOff, lnNewWidth, lnNewHeight LOCAL lnNewLeft, lnNewTop, lnFmIdx lnHorizOff = Sysmetric(9) && horizontal offset lnVertOff = Sysmetric(9) && vertical offset lnNewWidth = 0.75 * _SCREEN.Width && new form width lnNewHeight = 0.75 * _SCREEN.Height && new form height lnNewLeft = 0 lnNewTop = 0 FOR lnFmIdx = 1 TO _SCREEN.FormCount WITH _SCREEN.Forms(lnFmIdx) IF Type(".BorderStyle")<>"U" ; AND .BorderStyle = 3 * form has a resizable border, adjust its dimensions * subject to its min/max height and width .Width = IIF(.MinWidth = ; -1,lnNewWidth,Max(lnNewWidth,.MinWidth)) .Width = IIF(.MaxWidth = ; -1,lnNewWidth,Min(lnNewWidth,.MaxWidth)) .Height = IIF(.MinHeight = ; -1,lnNewHeight,Max(lnNewHeight,.MinHeight)) .Height = IIF(.MaxHeight = ; -1,lnNewHeight,Min(lnnewHeight,.MaxHeight)) ENDIF * move the form to its new position IF (lnNewTop + .Height < _SCREEN.Height) ; AND (lnNewLeft + .Width < _SCREEN.Width) * the form will not overflow the main window, * so go ahead and move it .Move(lnNewLeft,lnNewTop) * calculate the position of the next form lnNewLeft = lnNewLeft + lnHorizOff lnNewTop = lnNewTop + lnVertOff ELSE * form does overflow, so go back to * top left corner .Move(0,0) lnNewLeft = lnHorizOffset lnNewTop = lnVertOffset ENDIF ENDWITH ENDFOR ENDPROC
Although the technique described in this article will work in VFP 7.0 and later, it is no longer necessary. VFP 7.0 introduced a native Cascade function on the Window menu. To implement Cascade in your own application, simply add a Cascade prompt to your Window menu and set its bar # to _mw1_cascade.
Mike Lewis Consultants Ltd. March 1998. Revised November 2001.
FoxStuff is maintained by Mike Lewis Consultants Ltd. as a service to the VFP community. Feel free to download and use any code or components, and to pass around copies of the articles (but please do not remove our copyright notices or disclaimers).
The information given on this site has been carefully checked and is believed to be correct, but no legal liability can be accepted for its use. Do not use code, components or techniques unless you are satisfied that they will work correctly in your applications.
© Copyright Mike Lewis Consultants Ltd.