Author : | Dan Howard (sproket@total.net) |
History: | 1.0 December 12, 1998 |
Initial Release | |
Additional Programmers: | |
Peter Rorlick | |
Gary White | |
Bowen Moursund | |
Jim Sare | |
Ken Mayer | |
Richard Sandieson |
dForm.cfm | Custom base form class |
treeview.wfm | A form for modifying a dTreeView control |
treeview.pop | An overridden popup for the dTreeView |
dControls.htm | This file |
fontget.cc | A font getter class |
ini.cc | A very slightly modified version Bowen Moursund's Ini class |
ini2.cc | An extended Ini class with a few additional behaviors |
aspin.cc | A new array spin box |
colorget.cc | A color getter class |
fDialog.cc | A set of file dialog related classes |
dControls.cc | The base set of custom controls |
treedrop.cc | A sort of combobox/treeview hybrid control |
dContainers.wfm | Sample form showing the containers in this library |
dControls.wfm | Sample form showing the dControls in this library |
dTreeView.wfm | Sample form showing the dTreeView in action |
fDialog.wfm | Sample form showing file dialog classes |
TreeDrop.wfm | Sample form showing TreeDropper in action |
It took me quite a bit longer to finish this than I had expected. As
I was working I kept coming up with new things to add. There are several
things which I have not included because I just thought of them in the
last day or so. I'll play around with them and update this library when
they are tested.
* I added a Repaint Method based on Jim Sare's repaint routines. Simply call form.Repaint() to force the form to redraw itself. Surprisingly fast.
* The form's onGotFocus event is used to attach a reference of the form to _app.ActiveForm. Very useful for debugging from the command window and for MDI apps. Not really my idea. I don't know who thought of it first but it's very useful.
* Sub classing from this form gives you a new Init method. Thanks to Peter Rorlick for the idea. If you define an Init with any control on this form, it will fire "before" the form opens. Much better than using the form's or the control's OnOpen which can cause unneeded screen flicker. As far as any sub classed form is concerned, Init is a replacement for both Open and ReadModal. There are plenty of examples of it's use in this library.
* The method Iterate is available. This I found to be a very useful method. It's purpose is to iterate through all controls on a form (including controls in containers and notebooks) and fire a code block on each. DForm uses this to handle the Init methods:
Class::Iterate({|o|; iif(type("o.Init") # "U", o.Init(),false) })This looks at every control and - if there is an Init method - it fires it. This is very powerful and "this" will be passed correctly. You can also specify a starting object if you want to simply iterate through - lets say - a notepad object. You could use:
form.Iterate({|o|; msgbox(o.name) } ,form.NotePad1)I liked this method so much I included it in the dTreeView object as well. This idea could also be used in a custom array, rowset, string or any other type of object that uses loops.
Most of the visual code was inspired by the work of Peter Rorlick. He's got a flair for making forms look great. Thanks Pete.
If a control is not listed here it's because there are no additional behaviors for them except for those noted here.
All of the standard controls have the following additional methods.
this.SetValue("MyFieldProperty",10)The second parameter is the initial value you want to assign to the field. Fields used in this manner are quite powerful and flexible. You can assign things to fields that could not be stored in a table - like arrays or even other objects.
Try this at the command window.
f = New Field() f.Value := {"one","two","three"} ?f.Type ---> ArrayNifty!
Fields as properties can be used as accessors for more complex objects.
Since fields have beforeGetValue, canChange, onChange and onGotValue,
you can control what goes in and what comes out of your objects. You can
even fire events when the property changes! There are several examples
of this in this library as well as a more detailed explanation of their
use elsewhere in this document.
e.g.. ? this.MyFieldProperty.ValueI include it for consistency with the Set/Get concept.
e.g.. To expand all treeitems:
this.Iterate({|o|;o.Expanded := true})* The dTreeView has a Fill method. You pass an array and the dTreeView will be filled with treeitems of the same structure. Ken Mayer wrote a similar FillFromArray method in his treeview from then dUFLP. I came up with the idea independently but when I heard of Ken's version I sneaked a peak at his code and improved mine as a result. Thanks Ken.
* Save/Restore have been added. The save method will create a file with a .TV extention and write all of the information in the treeview to it. The file name will be a long name consisting of the form classname + container names + dTreeView name. The TV file is styled after an INI file and is editable with NotePad. It's not the most elegant code I've ever written but it works. Apparently this will be implemented in the next in-line anyway.
* OnRightMouseDown has been added to implement a new popup for this
object. I added an "Edit Tree" option which calls another form allowing
you to further customize the treeview. I've not used the treeview for interactive
purposes but I've seen some posts from users on the newsgroups who have
done so. This adds a little more user interaction to the stock treeview.
This is using an interesting technique. Instead of bothering with the
form's popup property I simply create a custom popup and programmatically
open it with the popup's Open method. Gary White was the first person I've
seen use this technique so I'm crediting him for it. This is an excellent
idea as you can use this to easily add popups to virtually any control.
There are a couple of issues you should be aware of. Popup positions seem
to only accept the "char" metric. Also there's a bug with the enabled property.
The menu items are always enabled no matter what the setting is. :(
* I replaced the very oddly named "disablePopup" property with the slightly more normal name "popupEnable". It's more consistant with the editor object's popup property name.
* It's subclassed from the DataModRef object so it can be placed on the component pallet. Makes an excellent place holder for generic non visual code that you want to associate with a form. I've only begun to explore the potential of this technique.
* This contains the FullName, SetValue and GetValue methods described
at the top of this section.
PLUSES
* You can datalink your custom field properties to controls.
MINUSES
* They will become more strictly typed. The Length property will be
respected and they will be automatically padded. (debatable minus)
* Trying to code with datalinks is much more confusing. It's harder to see how/where/why field events are firing.
* It definitely adds a good chunk of overhead to what should be a simple
process.
Consider the ColorGetter object: The ColorGetter's purpose is to allow the user to get a color. They can type in a color name in the entryfield and the pushbutton will change to that color or they can click on the pushbutton and select a color which will update both the pushbutton and the entryfield. To use this control without the setter property would mean that you would have to override both the entryfield's OnChange and the pushbutton's OnClick in your forms. With the setter property you only have to deal with one event: Setter_OnChange.
Using the setter also let's you assign to the entire container. Run the DContainers.WFM form and type this in the command window:
_app.ActiveForm.ColorGetter1.Setter.Value := "Red"
OR
_app.ActiveForm.ColorGetter1.Setter.Value := "0x0000FF"
Gotchas:
_app.ActiveForm.ArraySpinbox1.Setter.Value := 2 ?_app.ActiveForm.ArraySpinbox1.Setter.Value --> "Two"Property morphing in action!
form.PushButton1.OldTop = form.PushButton1.Topthen later I would reverse it. I never liked doing this because it creates all kinds of extra properties. I always worried that someone else using this technique could cause a conflicts with my objects. So what I do now is create a custom property called SavedSettings as a collection object.
Class MyEntryField(f) of entryfield(f) this.SavedSetings = New Object() endclassThen I simply add to the object things that I want to save for later. A collection is simply an object used to store stuff into. Like a bag - you throw stuff into it and then take out the things as you need them. I'm working on a true collection object which I'll include in the next release. This technique makes your objects more encapsulated than using the "Old" way.
I'll leave that to you to experiment with. If you get this idea working
send it to me and I'll include it in the next release of this library.
This is the basic logic of creating popups.
function onRightMouseDown(flags, col, row) if type("form.MyPopup") = "U" set procedure to My.POP additive form.MyPopUp = New MyPopip(form,"MyPop") // Works only with the CHAR metric form.MyPopup.top = this.Top + row + 1.3 form.MyPopup.left = this.Left + col + 11.3 form.MyPopup.Open() endif return
I write everything using Char metrics. If you use another metric you'll
probably have some problems with object positioning etc. Would it be nice
to have a built in converter? Anyone want to write one?
The author accepts no responsibility for the use or consequences of the use of this software.