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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Save a form in a VCX to and independent SCX file

Status
Not open for further replies.

Rajesh Karunakaran

Programmer
Sep 29, 2016
549
MU
Dear Team,

thread184-1766324

I referred the above link but couldn't find a solution to the exact requirement.
Similar to the question in above thread, I have a VCX file and there is a class which is actually a form. This form is used to display a help list to users from which they can select a record. I want to save this as an independent form, ie an independent SCX file like ANYNAME.SCX. My requirement is to use this form as a normal form.

I tried to instantiate the class, after setting the VCX as current CLASSLIB, as in
Code:
o=createobject('findCustomer')
. I expected I can use the 'SaveAs' method of the class instance. But, as this form contains table references, I am getting issues.
I referred in the Class Browser also but couldn't find anything for this purpose.

Is there a way to do it?

Thank you,
Rajesh
 
As in the thread that you referenced, the question is: Why do you want to do this?

If you want your own private version of the class, which you don't want other team-members to use or modify, just make a copy of the class.

If you want to be able to lauch the class on a form by itself, just add the class to a form (in the form designer), make it fill the form, and then launch it with DO FORM.

If this doesn't help, please give some more information about what exactly you want to achieve.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Rajesh said:
as this form contains table references, I am getting issues.
Can you clarify, what you mean with that?

Of course you "inherit" dependencies from a vcx class, the scx will have all the code the vcx has and look for tables, etc. It will also depend on any other class involved, control classes etc. When you expect to get a standalone SCX/SCT form you could even put into another project without further components, then you expect SaveAs() to magically flatten whole class family hierarchies and summarize all code into the SCX. It would not only be a bad decision in regard of code reusabiliy, it is impossible to merge code that way.

Besides that, the intended way to get an SCX from a VCX class is to [tt]CREATE FORM yourform.scx As classname FROM classlibrary[/tt]. This works very much like creating a new class based on the form class, but instead of creating a class creates an SCX. All SCX elements will have no code in them, but the inherited behaviour, you also won't be able to delete form elements, as they belong to the parent class, etc. The only things in your (or the SCX) posession then are the things you add afterwards, just like with any class inheritance. The benefit is you get a form dataenvironment, if you like that (classes don't have that) and you can DO FORM.

But you can also run a form class, you simply need to do one more step after o= CreateObject("findCustomer"), you do o.Show().

Bye, Olaf.
 
Dear Mike,

If you ask me 'Why do I want this?', there is no specific/exact requirement. It just like, if I want to copy the functionalities of the form from a class library to an independent form for some other purposes. Just like a normal form which is not supposed to be as a class inside a class library.

I think there is a way to put a normal form into a class library as a class.
However, it seems the reverse is not possible, at least directly.

Thanks,
Rajesh
 
Well, one tool that you could consider is the Class Browser (which you already mentioned). It doesn't do exactly what you want, but it can help you identify the members (properties, methods, objects) and the method code of the class in question. You can then use that information to build your form. But it is not an automatic process. Ultimately, you must build the form by hand.

Keep in mind that a class is essentially different from a form. Since you are referring to a VCX, you are presumably dealing with a visual class. These classes are generally based on controls (text boxes, grids, whatever) that are placed on a form. They do not equate to the form itself. So it doesn't make a lot of sense to convert the class to a form.

The exception is if the class is itself based on a form. But in that case, rather than convert the class to a form, you can simply instantiate it as a form, using CREATEOBJECT().

You also talked about doing the reverse: saving a form as a class. You are right that that's possible. You open the form in the Form Designer and select Save As from the File menu. You can also save individual controls as classes in this way. But, as you have discovered, there is no equivalent function in the Class Designer.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I've just done a quick experiment that might be of some help.

1. In the command window, instantiate the class using CREATEOBJECT():
[tt]lox = CREATEOBJECT("ManagedForm")[/tt]
(You might need to SET CLASSLIB first.)

2. Also in the command window, do this:
[tt]lox.SaveAs("NewForm")[/tt]

You will now have a SCX file named NewForm.SCX, containing all the members of the original class - which I think is what you want.

But of course this will only work if the class in question is a form class - for the reasons I mentioned above. In fact, there is no SaveAs method for non-form classes.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Rajesh said:
I think there is a way to put a normal form into a class library as a class.
However, it seems the reverse is not possible, at least directly.

I think that Olaf already gave you the exact and direct command to get a form from a class library. The issues you mentioned in the original post are related to the design of your classes, not to the possibility (or impossibility) to extract a form from a VCX.
 
Thanks, atlopes.

Maybe it got lost in the text, so let me put it into a code section:
Code:
CREATE FORM yourform.scx As classname FROM classlibrary

This way the form inherits from classname just like a subclassed class would. Well, see what I already wrote above.

Bye, Olaf.
 
Going back to the idea to "flatten a class hierarchy": You don't have that option itself, but there are several options other than subclassing.

Just note once again, an SCX is not really much easier to handle. You do [tt]oForm = CreateObject("formclass")[/tt] and [tt]oForm.Show()[/tt]. Put these two lines into a DoForm function and you can run your forms with one call, too. You just need to keep oForm alive for the form not to vanish after the oForm variable releases. So if you don't have a form handler, that's the time to create one. The main job of a form handler will be to manage and store form references, starting a form is just one job, knowing all running forms, and when asked to start a form deciding to do so or return a reference to the already running form is one of the advanced tasks, but surely keeping form references is a base task. And that's most easily done by storing them into a collection, which then is the only object needing to be kept alive. VFP oes exactly do that with it's _SCREEN.FORMS array/collection. It's a native thing that existed way before collection, so it's not based on some fox class, bu essentially it is a collection.

Back on the topic of trying to flatten class hierarchy into one file: As I don' know the findCustomer class, I can't tell you how hard or simple trying to flatten class hierarchy and get rid of it might be. If this form class is based on the native form and its controls also are native, there's nothing to flatten and loForm.SaveAs() would work, though it never gives you exactly the corresponding SCX, as init then already has run and you save properties etc in the state they are in the moment of saving:

Code:
o = CREATEOBJECT("form")
o.Caption="Test"
o.SaveAs("MyForm.scx")
MODIFY FORM MyForm.scx

You're in the form designer and that SCX form has the caption "Test".

So code depending on initial values by using the ResetToDefault() method could fail, but that's almost never a hard problem. You may get closest to the original when putting a SaveAs into the load event, but I'm not sure if that would work, no controls of the form are available at that moment, so you most likely end up with an empty form only containing all user-defined form methods.

One way to save the form as is would be making use of ASELOBJ() when having the form open in the class designer and then SaveAs that object. I won't show how to use that in detail, as that ends up the same as [tt]CREATE FORM AS findCustomer Of CustomerForms.vcx[/tt] does, so use that. Or use saveas, as it likely get's you close enough when init doesn't do much anyway.

But there is another simple way if you don't want to fiddle with the original class but have it as the starting point for your edits: Copy the class. As undesirable copies are in the sense of OOP code reuse, that'll give you the chance to vary from the parent class of the findCustomer form - maybe a general findSomething form class - and at the same time don't go back to the initial state of that parent class but start at the stage the findCustomer form is at. So actually a copy of a class also is an inheritance and subclassing, but it subclasses the parent class and copies over the current state of the class, which you copy.

And copying a VCX class is simple. Create a new empty VCX ideally named in a way it appears next to the class library containing the findCustomer form in the project manager. Now simply drag&drop the findCustomer class there. Now you see why I asked you to name the new VCX alphabetically close. You can also drag&drop across project boundaries into any class library of a separate project you have open in a second project manager. You can now rename the new VCX, nothing depends on its name yet, and you must rename your class copy, or you risk on CREATEOBJECT('findCustomer') starting your form copy instead of the original. That copy process, of course, creates the same dependencies on parent classes as the findCustomer form has rooted in the VCX of the findCustomer's parent class library anyway. After renaming th findCustomer form class, you might also drag&drop it back to its original VCX library to exist side by side to findCustomer.

If that form is based on the native form, you don't have a direct parent class dependency in your copy, but then you still might have references to control classes on the form. You'll not strip off dependencies anyway and shouldn't want to strip them off, the whole purpose of classes is to reuse code and not redo everything from scratch.

A much more straightforward way of copying a form to some new project will be to copy all base VCX libraries from the old to the new project, meaning to reuse the same class hierarchy. That gives you a chance to not only edit this class but refactor the whole class hierarchy aka framework of the project without affecting the old project. All the parent class libraries are what you need to support a class copy you did with drag&drop, too, anyway, if you want to become independent on the old project. That way of copying the whole project structure into a new project home is possible, as references are stored in relative paths.

That problem is none, if your new form should belong to the same project, you shouldn't want to decouple from all that hierarchy within the same project, inheritance is good and it's all established and will work.

OK, at this point I think I established enough awareness of not being able to really flatten the class hierarchy of the form and all its content, yet aside from these possibilities, Steven Black has thought of a tool to extract all the essential parts as share utility. You find that on
This is not the way I would recommend to work, no matter if within the same project or a new project, as that collects all dependencies into one "big ball of gum" VCX, but it's a way to share a single class with someone without needing to copy a whole project libs just to not forget some dependency. It has its boundaries on dependencies not detectable when they come in by macro substitution or any code creating objects at runtime. And it still doesn't flatten the whole thing into one class, it just pulls together all parent and grandparent stuff in one VCX. And it keeps it at the VCX level. To be fair it is the best option for sharing code without needing to share a whole framework and so it deserves its name and is good for its purpose.

And after all that, of course, your normal way of acting in an OOP project is to inherit from findCustomer or its parent form class. I can't tell you which way you'll be better off. To summarize the options:

1. When you start at the parent class level and still want almost the same behavior and composition as the findCustomer form has made, you have to redo a lot.
2. If you, therefore, inherit from findCustomer itself you have all the work done, but now can't edit things inherited, only call them by DODEFAULT or overload by writing new code.
3. The copy, as the third option, gives you a parent class inheritance with all the things added and modified in the findCustomer form at your disposal to change, maybe the best compromise, still not an SCX.

4. To get a similar result as 1 in an SCX CREATE FORM with the class options and specify the parent class of findCustomer.
5. CREATE FORM with the class options specifying findCustomer and you have a findCustomerSCX which compares to 2.
6. Instantiate findCustomer and SaveAs you finally get an SCX comparing to 3 minus some fiddling with the effects the Load() and Init() had.

All these options won't remove control class dependencies and other parent class dependencies, though. It was never the intention of any OOP concept to enable that kind of refactoring.
And since the options4-6 are less known and even less often used, developers get the idea SCXes leave you with the most freedom o editing and modifying forms, yet they only give you as much freedom, as you normally base an SCX on a native empty form, so everything on it was created from scratch. It's not the best way to optimize your work time. The need to edit or even remove parts of a class-based form or subclass form is pointing out the parent class has specialized too early with something turning out to not be necessary for all child classes and your class hierarchy is too flat for that matter.

Besides the technical problems of a not so well thought of class hierarchy, you might also face the copyright problem of inheriting from a paid framework. It should never become a problem within a company having bought that framework to also use it in other projects, but it can become a problem in contract work where you're faced with not illegally reusing something for customer A in a customer B project based on no or another framework. Then you have a business problem on top of a technical one. I'll just scratch that, as you say "as this form contains table references, I am getting issues." That problem is most likely more of a code problem than an inheritance problem, as a form class has no data environment you could inherit or copy, you inherit/copy code the form uses certainly also for data access. To be able to change that using other tables the copy option is your best choice.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top