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!

Copying ALL Objects with PEMS from One PageFrame1.page to another Page in the same PageFrame

Status
Not open for further replies.

stanlyn

Programmer
Sep 3, 2003
945
US
Hi,

I want to code and place objects only in page1 in the pageframe as this the base page. When the code is running and the user clicks the plus tab/page it creates a new tab/page in the pageframe based on all the stuff that makes up page1.

Now, I need to programatically copy ALL objects and page pems into the newly created page. Is there a way to automate the creation of all the code to create those objects and etc? I know I can create the objects by iterating the pages controls, but what about all the events and method code?

Any ideas?

Thanks,
Stanley
 
Make a subclass of the page as you want it. Then when you add a new page, you add the subclass instead.
 
If you copy all controls including all code and PEMs, which includes all binding, then why use a pageframe at all?
Controls you want to appear in all pages can be put on top of the page1, in the same position, but not in page1.

If you want the pages to contain more and more controls, why not use the visible property? You can show and hide controls, let the activate event of each page make the controls visible or invisible for that certain page, but let the controls not be in the pages, then they are only visible with a certain pagenumber, for example:

Code:
thisform.page1control1.visible = .t.
thisform.page2control1.visible = .f.
thisform.page3control1.visible = .f.

Code:
thisform.page1control1.visible = .t.
thisform.page2control1.visible = .t.
thisform.page3control1.visible = .f.

Code:
thisform.page1control1.visible = .t.
thisform.page2control1.visible = .t.
thisform.page3control1.visible = .t.

Notice: I didn't forget dots here, the controls are part of the form, not of the pageframe pages. Thheir visibility is controlled with the page tabs activate events, making them appear seemingly being on the activated page.
Seems cumbersome, but you could also centralize this into a form method called with pagenumber as parameter and have sections for pagenumber>0, pagenumber>1, pagenumber>2, etc or even for certain controls only visible on one page.

Of course you could do as Tore said, too, and have page classes inheriting from each other, one class per page, which you use and only add new controls, but doing so live at runtime is not really recommendable. You'd need to adjust pageframe.memeberclass and pageframe.memberclasslib before adding a page by incrementing pagecount.

Bye, Olaf.
 
Hi Olaf,

This is a continuation of the current thread "Get Name of Selected Page on PageFrame" where I create and delete pageframe.pages at will.

So when you mention "You'd need to adjust pageframe.memeberclass and pageframe.memberclasslib before adding a page by incrementing pagecount.", does that mean I'd need to hack (by opening them up as a table and edit) those classes right before creating the new page before getting Tore's solution to work?

Olaf said:
If you want the pages to contain more and more controls
No additional controls or code added to the newly created pages. They are to be exactly as page1. That is why in my original spec, I said that I will only edit and build page1 and when user clicks to add a new page, all of page1's code and controls are copied to the new page.

Also note that each page on the pageframe will be containing and controlling an entirely different session/instance from each other.

Olaf said:
doing so live at runtime is not really recommendable
Is there an issue with this? Explain why it is not recommended...

Thanks,
Stanley


 
Stanley said:
Quote (Olaf)
doing so live at runtime is not really recommendable

Is there an issue with this? Explain why it is not recommended...

I won't try to explain why it's not recommended, but what I can tell you is that it is extremely unusual.

You say you want to let the user (my emphasis) click to add a new page, with all the controls copied from Page 1. I find it difficult to envisage a scenario where you would want to do that. If the user is responsible for creating some new entity, a page frame is almost certainly not the best way to represent it.

If you absolutely have to do it this way, I suggest that you create a class, based on a container, that holds all the controls. Place the class on Page 1 at design time. Then, when you create a new page at run time, programmatically add the class to that page as well. But just because you can do it that way, it doesn't mean you should.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Perhaps he hopes it will visually represent a cardex or rolodex arrangement?
So perhaps he wants to add one page per record... there were packages like that
back in the old DOS days - was one called Delta?

I suspect it's a bad idea, if that is his idea, pageframes are graphically a bit flakey in my experience, I find
buttons 'move' a bit - certainly when accessed via RDP. If you had a pageframe with 100 or more pages I think it would
be very hard to manage.

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.
 
I repeat, make a subclass for your page. This is one of the reasons why subclasses were "invented". Then when you add a page, all you have to do is add one line of code in it's init: this.addObject('cntPage','YourPage')

If ALL the pages is this pageframe will be identical, you may even make this subclassed page the default page for the pageframe. I haven't tried this, so I don't know if it actually works, but I don't see any reason why it shouldn't. Doing this way, you must subclass the pageframe, and specify that every page will use your subclassed page. This will also mean that you avoid having one extra "level" of containership. In other words, you will can for instance address YourPageFrame.page1.YourFirstElement instead of YourPageFrame.page1.YourSubClassedPage.YourFirstElement.
 
Hi guys,

Mike said:
I find it difficult to envisage a scenario where you would want to do that

Ever heard of a multi-tab browser like chrome, firefox or ie? That is what I'm creating where each tab/page represents the users search results based on what the user searches for.

Mike said:
If the user is responsible for creating some new entity
They are NOT creating any new records or editing them, only searching and traversing the table with a next, prev, and ... buttons, and generating output like, email, fax, or print.

GriffMG said:
Perhaps he hopes it will visually represent a cardex or rolodex arrangement?
No, see note above to Mike.

GriffMG said:
If you had a pageframe with 100 or more pages I think it would be very hard to manage
Yes, I totally agree. That is why I'm limiting the page count to 8 pages (what can fit on a single line), much like a web browser with 8 tabs where the user's search queries can be completely unrelated.

GriffMG said:
In other words, you will can for instance address YourPageFrame.page1.YourFirstElement instead of YourPageFrame.page1.YourSubClassedPage.YourFirstElement.
I plan to reference each pages objects with a "this.parent" construct, as I will not be referencing other pages and their objects from within a page, the same way a browser works. Does anyone see a problem with this so far?

Thanks,
Stanley

 
Stanlyn,

first you know what my expectation or interpretation was, using pageframes to add more and more controls to each page and thereby letting the user go through steps (=tabs) of a workflow. Same page still doesn't make sense to me. And that the new page initially copied controls will be the same - as you said you copy them including all PEMS and code, they will be the same, not have a different controlsource, etc.

You repeated to say:
Stanlyn said:
All of page1's code and controls are copied to the new page.
Then why use pages at all?

You say
Stanlyn said:
each page on the pageframe will be containing and controlling an entirely different session/instance
Learn your terminology, one form can only have one session - data session - you can bind other tables. But then why first copy?

Supposed your controls on page1 have a grid bound to table1, you have the same grid bound to table1, if you want to bind it differently, then there is no need to copy current PEMs values, is there? You have a class and instanciate it with other controlsource.

If you want the same page bound to other data, then use a page class or as Mike suggested a container class. You don't copy whatever page1 has to a new page, that would need complicated code, it's more than just select all via CTRL+A and paste via CTRL+V. This isn't text, this is controls with any structure and substructure, are you mad? Are you feeling lucky? Is recursive code in your daily dose of programming you do? That's why I said it's not recommendable, even if you already have a page or container, if you would need to add controls for the next page you need to create new classes at runtime, that's not the base league of programming and even I would avoid it, as there are simpler ways - classes.

If you really want the same set of controls, but presumably bind different data, you can do that with one single page class you set in memberclass/memberclasslibrary and that's simple, as it even doesn't need changing the memberclass property. I actually don't like how MS added the memberclasses functionality, because the concept of using a container you put on an empty page is even enabling you to parameterize the init, but you can use that concept for all same pages, sure enough.

Stanlyn said:
Explain why it is not recommended...

First of all, this was referring to composing new page classes to add further controls (as it made no sense to me you want the exact same page). Are you even seeing how complicated this is, and how hard to maintain, can't you really think of a simpler solution?

If you want to reuse something, you create a class, if you really need no further things on further pages it's simply that, nothing more. You know how to put controls on a form, then you also know how to put controls on a form class or a page class or a container clas. It works exactly the same, the outmost object just isn't a form with its titlebar etc, but a page with its tab/caption or a container with just its border (you may set to width 0). So the solution stares at you.

In the situation as I understand it, you could now follow Tores or Makes advice. As Tore suggests: Design a page and let the pageframe create that automatically with any pagecount increment or as Mike suggests: Design a container and create that for new page with the advantage to be able to parameterize its init, eg with the alias of the main table/cursor this container should handle - your search result alias.

Always aim for a simple solution. Even jsut thinking "copy all objects" should ring alarm bells and let you put this thought away as "no". This is complicated in detail, because objects are not always simply flat with some simple vartype PEMs, they most often contain subobjects and copying objects means not just copying a reference, you need new instances of any page1 member, sub member, sub sub member, ..., you'd need to program recursively. Are you sure? Even I wouldn't do that, as there are much simpler routes.

Bye, Olaf.
 
Assume you have your form with pf1 and page1, VFP makes it easy for you to follow Mikes suggestion of using a container class.

Open your form, activate page1, drill down to activate page1, select all controls of it and then save them as a container via menu "File", menu item "Save As Class":

saveasclass_nhdsni.png


Or you open up the class designer to create a page class and in this context can simply use cut&paste of the controls from the form.pf1.page1 to the page in the secondary class designer. By the way: Yes, you can modify several forms or classes side by side for such refactorings.

Bye, Olaf.
 
OK,

First of all, I have subclassed all the native controls before and added custom functionally to them... (long time ago and found it more trouble keeping them current with old and current projects, so I quit them), and lets not get into pros and cons of that. I have never made use of the classing stuff that we are discussing here, so please bear with me...

Now I created a subclass of a pageframe named MultiTab_PF. I also selected some objects and saved them as a class. Now when I try to change either the MemberClass or MemberClassLibrary, it says it will change a bunch of stuff and I click OK. I next select the vcx and container and get this message... "The specified member class does not exist or is of wrong type."

What goes into those 2 pageframe properties, and when are they assigned, (at design time or programmaticly)?
Now what???

I also subclassed a page with controls on it, and using that changed all the pages in the pageframe. I startup the pageframe with the standard page count of 2. The 2nd page only has a plus sign (+) as its caption and a name of p9. I do not see a way to have a single custom page (for adding new pages) using this approach.

How do I get a copy of the classed containered controls onto pageX when adding them via code on the (+/add page)?

I intend to handle the different data sessions from the same table by using "select fields from table where xxxx into cursor curDataX'). Where X equals the originally assigned page number. Each session must be data independent regarding filters, sorts and selection.

Picture0004_c9virz.png

Thanks,
Stanley
 
Now I created a subclass of a pageframe named MultiTab_PF. I also selected some objects and saved them as a class. Now when I try to change either the MemberClass or MemberClassLibrary, it says it will change a bunch of stuff and I click OK. I next select the vcx and container and get this message... "The specified member class does not exist or is of wrong type."

It's not the pageframe you should be subclassing. It's the page. The MemberClass property should point to a page class. You should be setting that property at design time (along with MembmerClassLibrary). Then, at run time, you only need to increase the pageframe's PageCount property to get your new page.

But if you are still having problems with that, I suggest you revert to my earlier suggestion: place all the controls in a container class, and programmatically add an instance of that class to the new page at runtime (using the page's AddObject method.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike has explained how to set MemberClass/Memberclasslibrary. The concept is not only implemented for Pageframes, also for grids, thus this isn't named more specific to only allow page classes, but members of a pageframe are pages, nothing else qualifies. The container idea is on a totally different page (pun intended), it's a totally different alternative solution, should you not like the memberclass idea.

In regard of the empty page with + tab. Yes, the memberclass appraoch will already let page2 be such a page WITH controls, but why bother. The moment the user activates the + page you only need to change its caption as it already is a page waiting for data to display and you only need to set its data bindings. The next page you create can be like this one, already having the controls to display the next search result, but with caption +, As the + page never is seen, it doesn't need to be empty. If you think about this as waste of memoery, think about how much RAM todays computers have, but not too long. This concern would be totally unnecessary.

If you want a last page to always remain empty, rather use the container idea. Each page then can have no container, or the container, even different containers are possible. You may also use pageframe.addobject to add your page class and can simply specify the pageclass to use as parameter, not setting memberclass and memberclasslibrary at all. Likewise the objects you can add have to be rooted in the native page class, but could then easily be a class differing per page, if you extend the search capability of your form to produce different types of search results needing different UI designs.

Stanlyn said:
I intend to handle the different data sessions from the same table by using "select fields from table where xxxx into cursor curDataX'). Where X equals the originally assigned page number. Each session must be data independent regarding filters, sorts and selection.
Get your terminology correct. What you create with a query is a cursor and it is created in an empty workarea with an alias - the name of the workarea - in the same session as source data is coming from, never in a different session.

There is nothing to fix in the query and your design to name the results with a suffix count, you just have to name things correctly, or your talking about problems always will not produce the right outcome for you, this is talking past each other.

A separate session means a whole new set of workareas, when you query in one session your result will be in the same session, always, there is no crossing of sessions, that's why they are allowing the same form (SCX or class) to run multiple times each having a private datasession, without the need for changing code to handle individual alias names. So - just by the way - showing the different results in a set of forms with each private datasession would allow you to always create the same cursor name (in form init, for example) and have identical bindings, yet another sort order and record pointer, as you have with a separate workarea, too. You could also put all these forms into one place with tabs by docking them, docking tabs will by default appear at the bottom, but this set of forms would surely be separate from the search form with the inpuit controls of filter criteria data, so you might stick with your pageframe.

Anyway, the main instrument is a class you can reuse. The subclassed controls are just the basis of such compositions as containers or pages, which on the next level can be combined with each other. OOP does only start with subclassed base controls, this is not the end of it. Anytime you want any composition of two or more things you already have and add further code to combine these "things" and let them interact with each other, you do this as a new class. For example it makes total sense to have a container with your first level subclassed label and any other of your first level subclassed controls (yourtextbox, youreditbox, yourcombobox, etc) to have all the basic controls with a labels, like the checkbox control has natively, the container base class for all these label+subclass control combinations could have setting label.caption to the caption text in the current user language, for example, so you only write that code once in the "anycontrolwithlabel" container class only containing the label itself.

On a later level you put together containers or pages or base class forms with these controls rather than base or your first level subclasses. So controls appearing on an end user form are likely neither native base controls nor you first level subclass but part of third, fourth or fifth level classes. You also don't cook with neutrons and protons and electrons, but with higher level ingredients. Microsoft just provided the atoms.

To show a valid hierarchy:

[pre]
textbox (VFP base control)
|
+-anytextbox (first inheritance level)

label
|
+-anylabel (first inheritance level)

textbox (VFP base control)
|
+-anytextbox (first inheritance level)

editboxbox (VFP base control)
|
+-anyeditbox (first inheritance level)

container
|
+--anycontainer (first inheritance level)
|
+--labelledcontrolcontainer (second inheritance level)
| (with anylabel control inside and space for any other control, init code to internationalize the anylabel.caption)
|
+--labelledtextbox (third inheritance level)
| (inherits anylabel and adds anytextbox)
|
+--labellededitbox (third inheritance level)
| (inherits anylabel and adds anyeditbox)
|
+---...
.
.

page (VFP base control)
|
+--anypage (first inheritance level)
|
+--searchresultpage (second inheritance level)
with labelledtextbox1,2,3, labellededitox1,2,3, etc or named with their purpose rather, or field name of data they bind.
[/pre]

That doesn't mean it's a rule to only only add one further control/sub object per inheritance level, but the higher the inheritance level, the more specialized the lower the inheritance level, the lower the usefulness as a member class on the final class levels and end user forms. Once you have labelledcontrols classes you will neither put native controls on a form you design, nor the first level "any"control classes, unless you really just want a basic control without a label. But even then you may set the visible of the label .f. or the caption to empty string to get there, because features needed throughout any form and control are not implemented on the any level.

The first "any" level is merely there to put in code/behaviour you need in any and whatever specialization. There are very few things, that belong there, but certainly workarounds of bugs, behaviour you want differnt from VFFP native behaviour or such things. So the first level mainly has the purpose you can add code and properties all further inheritance levels inherit and only is necessary, because you can't change the VFP native controls, your changes can only start at your first inheritance level. Prefixing this level with "any" makes clear changes on this level really affect any further level down the inheritance chain.

I hope this will give you a better idea of how to continue from having the first level subclasses. Any level of inheritance should address one major topic and you start combining higherr level classes only, otherwise you lose the ability to affect the compositions in the base levels. It would make no sense at all to base a datefrom/to control with two date textboxes using native textboxes, you compose this from ayntextboxes at least, maybe even two labelledtextboxes containers to be able to afffect this complex control via changing the base classes. One main thing the labelledcontainer with the anylabel inside it eneables you to do, for example, is have one and only one single place to define font and fontsize for any label in your forms. This is, where the strength of OOP shows later. It's a cumbersome and tedious thing to prepare all these levels before you start implementing your final goals, but it's worth it.

Bye, Olaf.
 
Last not least, here's why the base idea "Copying ALL Objects with PEMS" is a bad idea:

What you access when addressing an object is an instance of a class, even if you only program procedural style, forms are classes, controls are classes and run instanciated as objects. Any object addressed by it's name merely is an address to a memory section holding all info and code about that class, both VFP code you write in subclasses and C runtime code for the native base behaviour and PEMS.

If you set loGrdResultCopy = Thisform.grdResult, you don't get a copy of the grid, you just store the reference to the memory section holding the grid into a variable, which now also points to it. The only thing you can do is clone objects, and that's always only halfway covering any situation you might have with the current object state, if you really would want to clone it 1:1. Objects are not stateless and in their lifetime could have caused things anywhere in data or filesystem, you don't copy in the same similar manner, as if you initially had two same objects. For example if you clone a logger object, you obviously don't clone the log it has already written, if you in contrast initially have two logger objects, they write two logs.

I understand that type of copy is not your base intention, but in terms of how you should go about this with the recommended solutions, every page you create will be a blueprint of the original instead of a blueprint of the blueprint. There is no wearing off in digital copies you now will answer. Well, that's not the difficulty, the difficulty is creating a "photocopier", code that could copy any page1 composition to a further page. This is the insane idea about your concept, as there already is a very basic idea of classes for having an original you can start or create as many times as you need.

"But the designer creates such copies all the time with ease.", you say. Well, yes and no, at design time you have no objects with any history, you're at a frozen point in time, the designer just needs to copy the plan of things to become alive later. And last not least, isn't it much simpler to create one new object than a whol lotta objects? And in the similar situation you want to start a form twice, what do you program? Do you program code copying the already running form? No you simply write or even just call the same DO FORM command.

Bye, Olaf.
 
Hi Olaf,

Thanks for your continued support and VFP teachings. I've learned a lot from you... I've worked thru my problem using your logic and now have it working. I ended using the container model as Mike suggested. Currently it works as expected if I use a this.parent.parent methodology. I need a better way to reference objects starting from the form level instead of the current way of starting at the object level and working backwards.

But does that really matter? Is there any issues of using something like this.parent.parent.parent.parent.cmdDoIt.click(). If I use this parent.parent way, I will have to refactor all controls as the old way was referencing objects from the form's perspective, which is the way I perfer, not to mention all the work needed to refactor them to work from the object's perspective.

Any ideas, comments, pros or cons ?

By the way, thanks Olaf for your explicit detail on your comments... (its a lot to chew on)

Thanks again,
Stanley

 
Stanley,

There is nothing at all wrong with using [tt]this.parent.parent.....[/tt] notation. I do it all the time. It can be a bit tedious if you have a deeply nested container, and you have to take care to get the right number of parents (which is less of a problem with Intellisense). But those aren't serious issues.

The alternative is to start at the form level ([tt]THISFORM.TopLevelContainter.....[/tt]). This is neater, but has the disadvantage that the low-level objects need to know the name of the top-level container, which makes the whole thing less generic.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
What's better depends on how and where you reuse it. If you want to address a button on the form level, eg thisform.cmdDoIt.Click(), then certain this form of addressing works most easy from anywhere, but if you use a button on the same page as your container This.Parent.Parent.cmdDoIt.Click() is easier to maintain. You could think about moving the button to be part of the containerr instead of separate, and then reduce it to This.Parent.cmdDoIt.Click()

There's a whole different story about addressing controls, though. You should rather never need to do so. Controls are just a visualisation of functionality, be it buttons triggering a certain functionality or controls displaying and enabling to edit data. The main things are functionality and data, they have their home in methods and tables, so controls shoudln't addreess other controls, controls should address data and functionality. And so you put code into form mehtods and in the cmdDoIt.Click you call thisform.Doit(), which you then can also call from within a control in the page of a pageframe, or even the page in a a pageframe of a pageframe. In my code I seldom need this kind of parent relative addressing, even if there is a checkbox, which state has to automatically switch depending on the state of other checkboxes. This depency is about the state, which is data, it's not about the state of checkboxes, the state of checkboxes just refelct data staates, so all I need to concentrate on is changing data, not knowing where it is displayed. The forms and each control on it knows what it ahs to display and maintain and what functionality to cause, the data and functionality have to be centralised, the controls are spread as visually necessary, but they don't need to bind to each other, they all address centralised data and functions.

As you also have tables saving all the single values of your data in their fields and their relations via foreign keys pointing to related data, you can also centralise all functionaliy into form methods, where they can be triggered from many places, even if you think at first you only need a certain click functionality only in one place and one button.

If you need functionality on each page, the new container you have is a good place for that, too. Not every functionality needs to exist on the form. Indeed a more advanced concept is to put this into yet another container you can add on several forms needing that functionality. That could also be handled with inheritance of form families, but the separation into several containers for the UI and the functionality needed have the plus of being able to combine as necessary, eg have different UI on the same functionality or other functionality on the same UI, when it's universal and general enough, like a results list could be a UI for very many and different results.

If you have such dependency of a single outside button it's a sign the button is placed wrongly or the functionality. Besides the component idea of combinable UI and functionality containers you have to think about the indepedence of each single module, if you have dependency to outside things you have strongly coupled the maintainence of two classes, made things immovable. Any control should in the firs place only need to knwo about itself. Any functioanlisty should have hands on all data it needs to process either as it's inner properties or data, but it should not read somecontrol.value, for example, which would be the other wrong thing to do similar to calling some buttons click.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top