Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Defing a class with two visual controls 2

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
621
GB
Hope I am not trying to run before I can walk.

I would like to define a class (to be made available in my Form Controls Window) which would result in two controls being displayed on the form where they are placed. Perhaps a text box and a check box.

So, having placed this new control on the form, at run time I would like both the text box and the check box to appear on the form.

I have rather optimistically tried to do this by subclassing the text box, putting it into my baseclasses.vcx, and then opening the .vcx file and editing the methods memo field to create a Checkbox object and call its Init() method. How naive can I be - It does not work!

Has anyone successfully done this?

Thanks. Andrew
 
You can't add a checkbox to a textbox.

The VFP control classes can be broken down into two groups, containers and non-containers. Both checkboxes and textboxes are non-containers. Containers include grids, pageframes, and the Container and Control classes, which are both essentially "boxes" you can put controls in.

The way you combine multiple controls into a single class is by starting with one of the container classes and then adding all the controls you want. In your case, you probably should subclass the Container baseclass and then add the checkbox and textbox to it, position them as you want them to appear, and add whatever code you need.

Tamar
 
There's an easier route.

You should create one each of your label and textbox classes, then drop one of each on a form. Arrange them as you wish and set properties as you wish.

Then select both in controls in the form designer and choose "Save as Class" from the File menu. The result will be a container class containing both of the controls. You can then use this composite class on forms.

The mistake most people make in going this route is in using VFP's native base classes to create the composite. You should start with classes of your own making.
 
Just as a theoretical possibility, more to learn a few things on instanciation:

You can do as you initially planned and let a textbox add a checkbox, but you need to add the checkbox to the textbox's parent (this.parent) or to the formlevel (thisform)
There are Createobject() and Newobject() functions and Object.AddObject() and Object.NewObject() methods. The functions create objects as root object, a control is useless this way, as a control always has to be contained in something else. The difference between Create... and New... is the parameterisation, you can use new without first setting SET CLASSLIB or SET PROCEDURE to prg defined classes.

But even if you do the right This.Parent.Addobject() in the textbox you need to know all objects are created with visible = .F., even if that setting is .T. in the class definition.

So finally what youo could do is:
Code:
This.Parent.Addobject("MyCheckBox1","mycheckbox")
* position checkbox below textbox
This.Parent.MyCheckBox1.Left = This.Left
This.Parent.MyCheckBox1.Top = This.Top + This.Height + 2
This.Parent.MyCheckBox1.Visible = .T.

But still this is just theoretically, it has an essential disadvantage: You will not be able to visually design the form, you will not be able to override the methods of the checkbox in it's instance and so overall this is a bit like programming blindly. You'd alway need to leave some space below such a textbox for it to appear at runtime.

If you want to go with the Visual in Visual FoxPro, you do as Dan or Tamar suggest and create a container class as the main class, to which you add your textbox and checkbox. Dan's suggestion of creating that class from selected controls on a form is the easy way to do that, as you can start from an example you already have on a form, but it's also not awfully complicated to start with an empty container, especially if you don't already have a form example. Creating controls on a new form just to easier create the compound class from it is, well, a bit of a detour.

About the usage and addressing, which changes due to the additional container:
As you now put a container on your forms, which contains a textbox and combobox, your addressing changes: From the outside (eg in form.init) you address them via thisform.yourtextcheckcontainer.yourtextbox1 and thisform.yourtextcheckcontainer.yourcheckbox1 instead of thisform.yourtextbox1 and thisform.yourcheckbox1. But the controls themselves still adress themselves with THIS (eg you still can address THIS.Value in the valid event of the textbox). And you can address the textbox from the checkbox via This.Parent.yourtextbox1, this also doesn't differ, the parent now just is the container, not the form.

Of course the names "your..." depend on your naming, but you get the principles, hopefully.

Bye, Olaf.
 
That would be a nice feature ... were VFP able to use the visual designer to generate class code (like FPW's screen-to-mpr generation), and to read class source code and edit it in the visual designer, able to save as vcx or class code.

Wouldn't be too hard to implement. A simple source file parsing and conversion to/from a vcx file. Hmmm....

Best regards,
Rick C. Hodgin
 
Mike said:
But I'm not sure if there's a way to go in the other direction.

It would be nice if VFP could arrange everything in a project in a class, to allow visual refactoring, updating all code within (the way NetBeans does, for example).

Visual FreePro would allow that. :)

Best regards,
Rick C. Hodgin
 
>were VFP able to use the visual designer to generate class code

First, like Mike says, the Class Browsers Viewcode Toolbutton does exactly that, the inverse can be found in the fox wikis by Tom Rettig, but may not work in any case.

I like to visually design things, that's more intuitive and productive for me. I don't like to go the Xaml route in defining GUI descriptive, even if there would be a good visual editor (Visual Studio is bad at that, Expression Blend is better), but you can only expect them to create verbose Xaml code, this makes Desktop GUI designer go towards the HTML world in also being markup code. I'd rather like to see the inverse trend, but it doesn't look like that.

Developers seem to love markup code, at least when they started that way and got used to it. But isn't it really ineffective to design frontends by writing markup? The markup get's wrong much too easy, is verbose and soon enough unmaintainable, unless using visual designers generating that markup. But that typically has the disadvantage of a verbose result being less effective in it's rendering. Even nowadays I experience weird results in HTML or CSS just by having one space too much or too less at the wrong place. This is an annoyance, which can't be fixed without moving away from markup. But this leads away from the main topic, so I'll stop with that rant here ;).

With the class code this is not the case and there is of course an advantage of seeing and editing all code of a class in one editor at once, you can overview the whole class. But in VFP as it is, the disadvantage to not be able to drag such a class definition of a control onto a form overweighs that advantage, so you better not design visual classes as prg classes.

You shouldn't have much code in visual controls or forms anyway, it should call into the business tier of your application. If you do so, the ineffective way of the visual class designer to only show one method at a time is not a big disadvantage. It actually supports such a programming style and leads you into doing that. And business logix can be defined in prg classes, I prefer containers here, too, but that's a matter of taste.

That all has nothing to do with you, Rick, I don't know your plans for the visual designer of your Visual FreePro and putting class code into one file is easily possible and would have an advantage. Of course also for sharing in FAQs here, but there are many possibilities to freely host binary files, may it be by the public portion of a dropbox or github, codeplex....

You could actually also create a vcx class and still edit all class code in one editor window: Just open the vcx/scx as a table and edit in the Code memo, there you have all methods of one object in one editbox. But don't forget to COMPILE after hacking in there.

Bye, Olaf.
 
Olaf said:
With the class code this is not the case and there is of course an advantage of seeing and editing all code of a class in one editor at once, you can overview the whole class. But in VFP as it is, the disadvantage to not be able to drag such a class definition of a control onto a form overweighs that advantage, so you better not design visual classes as prg classes.

The idea would be that no matter where the definitions are, they can be edited in code or visually, yet they appear in the project as separate entities able to be clicked on and sought out (in raw source code or through a designer). The ability to switch between would also be native as everything registered to a class, for example, would have to go both ways. So no matter where changes were made, everything registered to that class would see the immediate changes -- be they in source code, or through the designer.

Olaf said:
You shouldn't have much code in visual controls or forms anyway, it should call into the business tier of your application. If you do so, the ineffective way of the visual class designer to only show one method at a time is not a big disadvantage. It actually supports such a programming style and leads you into doing that. And business logix can be defined in prg classes, I prefer containers here, too, but that's a matter of taste.

Depends on the application. For large applications it's a necessity. For smaller ones, it's an unnecessary complexity. For middle-sized apps ... it's about what code do you want to most reuse.

Olaf said:
That all has nothing to do with you, Rick, I don't know your plans for the visual designer of your Visual FreePro and putting class code into one file is easily possible and would have an advantage. Of course also for sharing in FAQs here, but there are many possibilities to freely host binary files, may it be by the public portion of a dropbox or github, codeplex....

The idea is that the code can be defined anywhere. VFrP would parse the entirety of the project's source code and identify definition blocks. They would appear in a new project manager which has a better layout with filtering and the ability to edit some properties directly from there (change a field name or size without bringing up the designer). Lots of simplified UI abilities.

Olaf said:
You could actually also create a vcx class and still edit all class code in one editor window: Just open the vcx/scx as a table and edit in the Code memo, there you have all methods of one object in one editbox. But don't forget to COMPILE after hacking in there.

I don't particularly like the idea of the VCX. It has uses for being a container object that's edited visually. But in VFrP, everything would be able to be edited visually regardless of whether it's in source code or non-source-code form. So, it would be better to leave everything permanently in source code form, that way it's always able to be shared, copied, etc.

The GUI of the project manager would allow drag-and-drop applications to put objects into the visual designer. This would be a mere extension of the presentation manager for forms rendering anyway.

Best regards,
Rick C. Hodgin
 
Thank you all. This is just the information I need. I have been able to create a control (in fact a pseudo-combobox).

It is made up of a text box for the user to enter a customer account or a search string, and a grid which is made visible if the account or search string does not uniquely specify a customer (or product, or supplier or nominal account . . .). Also a label to display the product description, customer name &c.

To make the control reusable it has 4 properties (at present) :

zfile The Alias of the table to be searched
zIndex The Tag(!) on which the table is to be searched
zKeyname,zDescname The names of the fields to be displayed in the grid.​

A few questions:

What is the best way of letting the developer (admittedly just myself, but I might forget) know that these properties need to be set up to make the control work? Traditionally I have tried to document or remember my work, but is there a way of making a reminder available when the control is on the form?

I have created the class as a container and it works fine. Is there a way of specifying a property in the class definition that I do not want a line border to the container? Or do I just do this in the classes Init() method?

The methods I have written in this code include a fair few bits of code such as :

lField = .zFile + "." + .zDescname
.cbdesc.caption = &lField

Is this acceptable? I have a vague folk memory that the use of macros is discouraged.

Finally, my grid has two columns whose control sources are fields in the table being browed. When the user enters a search key "#CITY" to say that he wants the character string CITY to appear somewhere in the description, I confess that, since it only knows the Alias of the table being searched, I say :

lFilter = '"' + lSearch + '"' + " $ " + .zFile +".mnem"
SET FILTER TO &lFilter​

It all works, but I am aware that many people think filters are undesirable. So I am happy to hear of a better alternative.

Grateful for all your time. And I will consider your notes, Olaf, for which thank-you. Andrew

 
Andrew said:
What is the best way of letting the developer (admittedly just myself, but I might forget) know that these properties need to be set up to make the control work? Traditionally I have tried to document or remember my work, but is there a way of making a reminder available when the control is on the form?

Interesting question. Off the top of my head, if I had to do this, I would add a zSetup property set to .f. and test it in the class's init event to see if the user set it to .t. manually, which would be an indication the user did set up this control properly.

The code would be something like:
Code:
* Verify we're setup
IF NOT this.zSetup
    MessageBox("This control" + chr(13) + ;
        "    " + this.Parent.Name + "." + this.Name + chr(13) + ;
        "has not been setup." + chr(13) + ;
        "-----" + chr(13) + ;
        "Please set zSetup to .t. when completed.")
ENDIF

Best regards,
Rick C. Hodgin
 
Andrew said:
I have created the class as a container and it works fine. Is there a way of specifying a property in the class definition that I do not want a line border to the container? Or do I just do this in the classes Init() method?

BorderWidth, set it to 0.

Is this acceptable? I have a vague folk memory that the use of macros is discouraged.

In the case where there may be spaces, put it in parenthesis. In the case of field names, table aliases, etc., where no spaces can exist, you're good. Some people discourage this. I've never had a single issue with it, except that I believe it's slower than using EXEC().

I also use filters regularly. They are fast enough and appropriate in most cases. Experimentation will be your guide.

Best regards,
Rick C. Hodgin
 
@Ricj,

if you plan to implement classes that way as code files you can edit either as text or visually, that would be an advantage and doing it that way you could even stop supporting VCXes, as long as there is a migration tool. And the viewcode.prg is already one, actually, but you may also want to change how such a code file is structured.

@Andrew:
Code:
lField = .zFile + "." + .zDescname
 .cbdesc.caption = &lField

> Is this acceptable?
In short: Yes.

This will be done once in the init, right? Doesn't matter much, if doing eval or this. It will not make much difference even in forms with many such controls. What will cost most time is opening data files and reading them. Macro substitution is compilation of a single command line, while eval is executing the eval function, but in any case it's in memmory operations.

As far as I read this, you store the caption of the label in some field of some alias. It's ok to determine the value of it in that general way. You will not have spaces in there, even if the file name has spaces, the alias would have underscores at these places, alias names and field names don't allow spaces in vfp.

As already outlined, evaluate() would be sufficient here, unlike macro substitution it just won't allow execution of commands, but commands don't return a value, as it is needed here. So personally I'd use .cbdesc.caption = Evaluate(m.lField)

You may also define a caption_assing method and check the type of the value set. And if it's not a string, set the caption to a default value, for example the empty string, to avoid errors by wrong setup.

In that regard Rick's idea to add a zSetup property with default .f. you need to manually set .t. to signal you're finished with the setup of nonoptional properties is an elegant way of a general reminder. You can add the other properties to the favorites and add a description on how to set these, then you'd also have a general location of these nonoptional and other important values as favorites in that tab.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top