< Day Day Up > |
The point of object-oriented programming is that what you do to a class is inherited by classes derived from it, and reflected in objects based on it. You can begin to reap the benefits of object orientation in two minutes by subclassing the base form controls, and then using your subclassed controls on your forms. For example, let's say you create a label control of your own and use it on all of your forms. Shortly thereafter, your client decides to change the font with which labels are displayed on the screen. Instead of changing the FontName property of every label on every label on every screen, you change it in your label class, and the change instantly appears everywhere in your application. That's a powerful visual example of what inheritance can do for you. Subclassing the FoxPro Screen ControlsTo subclass the FoxPro screen controls, change to your project directory by typing CD ProjectDirectory and type the code shown in Listing 8.3. After each one pops up a designer, close the designer to save the class. Listing 8.3. Code to Type in the Command Window to Create a Class Library Containing Subclasses of All of the FoxPro ControlsCREATE CLASS MyLabel OF FormControls AS Label CREATE CLASS MyText OF FormControls AS TextBox CREATE CLASS MyEdit OF FormControls AS EditBox CREATE CLASS MyButton OF FormControls AS CommandButton CREATE CLASS MyGroup OF FormControls AS CommandGroup CREATE CLASS MyRadio OF FormControls AS OptionGroup CREATE CLASS MyCheck OF FormControls AS CheckBox CREATE CLASS MyCombo OF FormControls AS ComboBox CREATE CLASS MyList OF FormControls AS ListBox CREATE CLASS MySpin OF FormControls AS Spinner CREATE CLASS MyGrid OF FormControls AS Grid CREATE CLASS MyImage OF FormControls AS Image CREATE CLASS MyTimer OF FormControls AS Timer CREATE CLASS MyFrame OF FormControls AS PageFrame CREATE CLASS MyLine OF FormControls AS Line CREATE CLASS MyShape OF FormControls AS Shape CREATE CLASS MyPanel OF FormControls AS Container CREATE CLASS MyLink OF FormControls AS HyperLink There are probably a few properties that you'll want to change before using them. For example, change the Enabled property of MyText , MyEdit , MyCheck , MyCombo , MyRadio , and MySpin to .F. . This allows us to display a form with data that users can't edit until they click on the Edit button. I also go into the Click event of the MyButton class and enter this: MessageBox ( "Not yet coded", 64, _VFP.Caption, 1000 ) This produces a message that reminds the programmer (that's me) that something isn't done. Using Your Subclassed FoxPro ControlsOpen a form, and then use View, Toolbars from the menu to display the Form Controls toolbar if it isn't already visible. Click on the View Class (the three little books) icon and click on Add (which is very unintuitive, but which actually means "add a new class library to this list") and select FormControls.VCX from the resulting dialog. Voil , you've got classes! If you use these instead of FoxPro's base classes, you're ready to reap the benefits of OOP with just two minutes' work. But the best way to begin using your new subclassed controls in FoxPro is to select Tools, Options, Field Mapping, and then enter the name of a control and the FormControls.vcx class library for each of the data types you're likely to use in your tables. After you've done this (be sure to click Apply for each selection), you can open the Data Environment of a form, add a table or cursor, click on the word Fields at the top of the cursor icon and drag and drop it on the screen, and you're instantly using your controls, both a label and the appropriate control based on the data type. It's the biggest bang for the buck in FoxPro. If you want to do something to your controls, say enable or disable them, you can use FOR EACH Ctrl in THISFORM.CONTROLS...ENDFOR to iterate through them. Earlier, we saw how that's done. But usually a little more is required. For example, I often start with all input controls disabled, enable them when the user selects Add or Edit, and then disable them again when they click Save or Cancel. To do this, I add a form class property called EditableFields , and populate with the names of the controls that should be enabled or disabled, as shown in Listing 8.4. Listing 8.4. Providing a List of Editable Field Classes in Visual FoxProDEFINE CLASS MyBaseForm AS Form ... EditableFields = [MyTextMyEditMyCheckMyComboMyRadioMySpin] You can also create your form class in the Class Designer, use the Class, Add Property menu selection to add the property, and then open the Properties sheet for the class and type in the "EditableFields = " string shown in Listing 8.4. Then, you can enable them in the form class method called EnableFields as shown in Listing 8.5. Listing 8.5. The EnableFields Form Class MethodPARAMETERS OnOff FOR EACH Ctrl in THISFORM.Controls IF UPPER(Ctrl.Class) $ UPPER(THISFORM.EditableFields) Ctrl.Enabled = OnOff ENDIF ENDFOR To use this method, include the line THISFORM.EnableFields(.T.) in your cmdAdd and cmdEdit Click event code, and include the line THISFORM.EnableFields(.F.) in your cmdSave and cmdCancel Click event code. Better still, add these lines in the form's Save and Cancel methods that are called by the Edit, Add, Save, and Cancel buttons ' Click event code. Subclassing the Screen Controls in Visual Basic .NETSubclassing the form controls in Visual Basic .NET is as easy as pie, although not as easy as in FoxPro. Visual Basic doesn't have Visual Class Libraries (VCX files). Instead, you build a class file and declare each of the class names you want to use, following each Public Class statement with an Inherits statement that specifies the base class. It's almost too easy. However, to compensate for that, adding behavior to a class is harder and less obvious. Let's say you want to create a half- dozen input classes and change the text box background color when it has the focus. In FoxPro you just drag the controls onto the Class Designer, set some properties in the Properties sheet, and then double-click and override the GotFocus and LostFocus events. In Visual Basic .NET, you can't set properties visually in a class designer; you have to add a New method (a "constructor", like FoxPro's Init() method), and then add property assignments in the New method after calling the MyBase.New() method. Then, if there are base class events where you want to do something, you have to write an "event handler" and add a Handles clause to tie it to the original event. Note that the equivalents of GotFocus and LostFocus are called Enter and Leave respectively in .NET. The code shown in Listing 8.6 goes in the Class1 file that is created automatically when you select File, New, Project from the IDE menu and select Class as the project type. Name the project MyFormControls and change the name of Class1.vb to MyControls.vb . TIP You'll have to add references to System.Windows.Forms and to System.Drawing to the class library project, and also add the two Imports statements at the top of the class listing. Listing 8.6. Subclassing the Base Form Control Classes in Visual Basic .NETImports System.Windows.Forms Imports System.Drawing Public Class MyText Inherits TextBox Public Sub New() MyBase.New() Text = "" Enabled = False End Sub Public Sub EnterHandler( ) ByVal o As Object, _ ByVal e As EventArgs) _ Handles MyBase.Enter BackColor = BackColor.Blue ForeColor = ForeColor.White End Sub Public Sub LeaveHandler( _ ByVal o As Object, _ ByVal e As EventArgs) _ Handles MyBase.Leave BackColor = BackColor.White ForeColor = ForeColor.Black End Sub End Class Public Class MyCombo Inherits ComboBox Public Sub New() MyBase.New() Text = "" Enabled = False End Sub Public Sub EnterHandler( _ ByVal o As Object, _ ByVal e As EventArgs) _ Handles MyBase.Enter BackColor = BackColor.Blue ForeColor = ForeColor.White End Sub Public Sub LeaveHandler( _ ByVal o As Object, _ ByVal e As EventArgs) _ Handles MyBase.Leave BackColor = BackColor.White ForeColor = ForeColor.Black End Sub End Class Public Class MyCheck Inherits CheckBox Public Sub New() MyBase.New() Enabled = False End Sub End Class Public Class MyLabel Inherits Label Public Sub New() MyBase.New() Text = "Lbl" End Sub End Class Public Class MyRightAlignedLabel Inherits MyLabel Public Sub New() MyBase.New() TextAlign = ContentAlignment.MiddleRight End Sub End Class Public Class MyRadio Inherits RadioButton Public Sub New() MyBase.New() Enabled = False End Sub End Class Using Your Subclassed .NET ControlsTo use these controls, click on the User Controls toolbox heading, and then right-click and select Add/Remove Items. When the dialog appears, use Browse to find and click on [VSProjDir] \MyFormControls\bin\MyFormControls.DLL . All of the controls you just created will appear in your User Controls toolbox. You use them, rather than the base control classes, on your forms. Now, just as in FoxPro, if you change the FontName in the subclassed MyLabel class, it changes in all of your forms. Enabling/Disabling the Controls on a FormIn Listing 8.7, you have an Input procedure that can be called both from here and from click events such as Add and Edit . I look for any control whose name is in the form's list of input fields, and apply the Enabled = True/False logic only to those controls. Listing 8.7. Enabling and Disabling All Form Input Controls in Visual Basic .NETDim UserControls As String = "MYTEXTMYCOMBOMYRADIOMYSPINMYCHECK" Private Sub cmdEnableDisable_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cmdEnableDisable.Click Inputs(Button1.Text = "Enable") Button1.Text = IIf(Button1.Text = "Enable", "Disable", "Enable") End Sub Public Sub Inputs(ByVal OnOff As Boolean) Dim CtrlType As String Dim LastPeriod As Integer Dim Ctrl As Control For Each Ctrl In Controls LastPeriod = Ctrl.GetType.ToString.ToUpper.LastIndexOf(".") + 1 CtrlType = Ctrl.GetType.ToString.ToUpper.Substring(LastPeriod) If UserControls.IndexOf(CtrlType) > 0 Then Ctrl.Enabled = OnOff Next End Sub I use the fact that the name of a control's base class is located after the last period in the GetType return value. I convert both search and target to uppercase before looking for the control's base class name in the User Controls string. The initial "" character is not optional, by the way; otherwise , MYTEXT is found at location zero (thanks, Bill). The parameter ( Button1.Text = "Enable" ) uses a shorthand method of coding that sets the value of the Input() call's single parameter to True if the text property of the button is the string "Enable" , and to False if it says "Disable" (or anything else, for that matter). The last line changes the caption of the button itself. |
< Day Day Up > |