Variable as webpage

Right now I’ve got two parts to each routine. One for Windows, Apple, etc. and one for iPad. I’d like to reduce them to just one each. My windows, etc. webpage is “cc”. My iPad webpage is “ccIpad”. I’ve also declared a virtual webpage called “c”. Next is a container declared as create: cc.create.

When I say c = cc Xojo gives me the error Type “WebPage” has no member named “create”.

So, I’m confused. How do I declare c to be cc or ccIpad?

Am I following correctly that cc and ccipad inherit from c, and c inherits from WebPage?

If so then you need to define your interface in c. (I don’t mean an actual Xojo Interface, though that’s another way to go.) Define your methods in c even if some of them are empty place holders. Common behavior can exist in c; platform specific behavior can exist via overriding methods in cc and ccipad; and your variables can all be type c. A simple example and use of OOP inheritance.

[quote=197983:@John Scanlan]Right now I’ve got two parts to each routine. One for Windows, Apple, etc. and one for iPad. I’d like to reduce them to just one each. My windows, etc. webpage is “cc”. My iPad webpage is “ccIpad”. I’ve also declared a virtual webpage called “c”. Next is a container declared as create: cc.create.

When I say c = cc Xojo gives me the error Type “WebPage” has no member named “create”.

So, I’m confused. How do I declare c to be cc or ccIpad?[/quote]

Is create a method you have added to a module with extends ? Otherwise indeed there is no such method in Xojo AFAIK.

Why not simply do cc.show or ccIpad.show according to session.browser and/or Session.Header("User-Agent") in the Open event of Session ?

Create is a container.

When I do routines that reference data in create I need to have two versions of a command:

x = cc.create.calcArray(I,j) and x = ccIpad.create.calcArray(I,j)

this is what I’m trying get rid of by saying

if ipad then
c = ccIpad
else
c = cc
end if
x = c.create.calcArray(I,j)

This is where I’m getting the error. btw, c is declared as a webpage in session.

Part of the confusion is due to naming. “Create” sounds like a method name, not the name of a class or of a control placed on a page. Variable and class names like c and cc are also confusing. I’m not even sure if cc or ccIpad refer to variables or classes.

You said c is declared as a WebPage. WebPage knows nothing about methods, properties, or controls that exist in pages that are subclasses of WebPage. So c.create generates an error.

If I understand you correctly now…you can use WebPage.ControlWithName to find your container control named “create”. However, you will have to cast it to the correct type. ControlWithName returns a WebControl, and WebControl knows nothing about calcArray. So…

Dim objPage As WebPage = (whatever code gets your page)
Dim objControl As WebControl = objPage.ControlWithName("create")
If objControl IsA MyContainerWithCalcArray Then
    Dim objContainer As MyContainerWithCalcArray = MyContainerWithCalcArray(objControl)
    x = objContainer.calcArray(I,j)
Else
   (Do something else because the page does not have a create container.)
End If

“MyContainerWithCalcArray” would be replaced with whatever you named your WebContainer subclass which has the calcArray method.

This is one way to deal with this. There are better ways which make use of class inheritance and/or Interfaces. Another option would be to avoid having separate pages for different devices, and create a “responsive” layout via code.

Ok, tried that Daniel, didn’t work. Sorry ‘create’ is short for create gymnastics routine. cc is short for CircleCalc. There’s no issue of whether the controls, etc exist, they do.

cc and ccIpad are webpages.
create is a container embedded into cc or ccIpad.
c is a property in session declared as a webpage.
calcArray is a variable in session.

The key is that I want only one set of commands which can be used whether the platform is windows, etc or iPad.

‘responsive’ layout is likely beyond my pay-grade unless it’s fairly simple.

But the WebPage type doesn’t know about anything that exists in cc or ccIpad. Hence the error.

When you use the menu command Insert >> Container Control, what you are really doing is creating a subclass of WebContainer. Is “create” the name of the subclass (visible in the project navigator to the left)? Or the value of the Name property of an instance you have placed on a page (visible in the Inspector to the right when the container is selected in a layout)?

ControlWithName is searching the Name property of each control instance on the page. So if you have MyContainer and you drop it on a page, the IDE will automatically set the Name property to MyContainer1 (you can change it to anything). MyContainer1 would be an instance of type MyContainer. When calling ControlWithName you use MyContainer1 (or whatever name you set in the IDE Inspector while designing the page).

Now if you embed MyContainer at runtime using EmbedWithin, the Name property should actually be the same as the type. Just different behavior between the IDE layout editor and the EmbedWithin method.

If these two pages have more in common then just this one task you are ultimately going to want to implement a proper class hierarchy or set of Interfaces. Heck, I would likely use a common base class or Interface even for this one thing.

This is what Interfaces were made for.

Create a Class Interface with one Method: Create. Have both web pages implement that interface. Then change the declaration of c to your interface name. Your code will now work.

Tim, create is not a method, it’s a container. I know the name sucks, but it makes sense in my program. It’s the container in which you create a gymnastics routine.

I’ll just stick with cc to keep this simpler.

create is a property in the webpage cc declared as containerCreateRoutines. It is initialized by create = new containerCreateRoutines in cc.shown. When it needs to be dsiplayed, it’s done by cc.create.embedWithin(cc, 0, 78, cc.create.width, cc.height - 110) in session.

Daniel, CircleCalc is a complex program reviewing and organizing gymnastics routines. Many routines (program routines) will access data from create and numerous other containers, so I’ll use the solution over and over. That’s why I wished to do it at the webpage level. If I can only do it at the container level, that’s fine.

Guys, while I think I’m pretty good at programming (I’ve done things I’ve been told can’t be done) I’m still an amateur (attorney / engineer / coach / judge) . . .

thanks for all your help guys

The problem is not so much your competence, as your description. If several people trying their best cannot understand it, it seems you may want to reformulate. Please forgive me, I maybe too limited, but read your first post several times and still, it makes no sense.

I’m hoping the last one made more sense.

Here’s another thought, again with an Interface (you want to create a contract with your objects so that different kinds of objects will all act in the same way). Create an interface with a method

Function CalcArray(I as integer, j as integer) as integer

In each webpage, implement it as

return create.CalcArray(I,j)

Declare c as your interface type and you’re golden. Add additional methods to the contract (the Class Interface) and feel free to implement them however is appropriate in each webpage. You’re caught up in the fact that the implementation is almost exactly the same for create.CalcArray, but it doesn’t have to be. All you need to say is, these 2 webpages, as different as they are, both can give me certain data (from where I do not care) and can also respond to certain instructions. That’s the beauty of a class interface. From the outside, the objects respond the same, but their internal implementations can be vastly different.

OK, I think we’re getting some where. (In fairness to you John, there’s ample room for confusion when the same word can mean different things. Example: a container named “create” could refer to a subclass name, a variable name, a property name, or the value in the WebContainer.Name property.)

I’m pretty sure ControlWithName(“containerCreateRoutines”) would work because when you create a new instance the Name property will be the same as the class/type name. That said, this is not the solution I would use based on the following:

As Tim points out you can use one or more Interfaces. The advantage is that anything can implement an Interface and respond appropriately. The disadvantage is that you can still end up with some code duplication.

You can also create a parent class which implements common methods, and have your pages inherit from that class. Done properly you can eliminate duplicate code. But everything must inherit from the parent class.

You can also mix the two: code to an Interface and use the Interface when declaring variable and property types, but implement using parent classes where appropriate.

is there a good class hierarchy or set of Interfaces example?

Ok, looking at my project again, I’ve realized that the webpage (either ‘cc’ or ‘ccIpad’) is tiny; only three controls. So simply creating a webpage called ‘c’ that can be formatted depending on the platform is simple.

The user interface is built by containers. Let’s look at a better named container: About (contains the program info and the login button). I have a container called ‘containerAbout’ and another one called ‘containerIpadAbout’ for Ipad.

The webpage ‘cc’ contains a property ‘a’ declared as containerAbout and ‘ccIpad’ has a property ‘a’ declared as containerIpadAbout.

I’m curious about a couple of options (don’t think they’ll work, but what the hell): Can I create a property on the fly, so I can declare a as the container needed? Can I change the type of a property? Can I create another property that will inherit a type (a as something = a_ipad or a as something = a_desktop)?

None of your options will work. The problem is not with the property any way.

You have containerAbout and containerIpadAbout. Pretend each container has a fancy logo animation you want to be able to perform via a method call. How do you arrange this so that you do not have to type test, typecast, and branch your code?

With Interfaces:

  • Create a new interface iAboutContainer.

  • Add a method to iAboutContainer called AnimateLogo.

  • Add the interface to both containerAbout and containerIpadAbout.

  • Add the animation code to containerAbout.AnimateLogo and containerIpadAbout.AnimateLogo.

  • Your property should now be declared as iAboutContainer.

  • You can store EITHER type in the property. When you want to trigger the animation, just call cc.a.AnimateLogo.

Note: your property type is now an iAboutContainer, NOT a WebContainer. It may be holding a value that is both an iAboutContainer and a WebContainer, but the compiler does not know this from the property type. So you cannot call standard WebContainer stuff without first performing a typecast.

With a base class:

  • Create a new class baseAboutContainer.

  • Set its Super to WebContainer.

  • Add a method AnimateLogo. Leave it blank.

  • Set the super of containerAbout and containerIpadAbout to baseAboutContainer.

  • Add AnimateLogo methods to both and enter the animation code.

  • Your property should now be declared as baseAboutContainer.

  • You can store EITHER type in the property. When you want to trigger the animation, just call cc.a.AnimateLogo.

Note: in this case your property type, baseAboutContainer, inherits everything in WebContainer. So you can call AnimateLogo and all the WebContainer methods. So you can do something like:
cc.a.AnimateLogo
cc.a.ScrollTo(500,500)

Can I read username.text using x = cc.a.username.text?

That’s really most of what I need to do, is get data from the windows.

btw, the program is at http://sc1473a.dfw1.1701hosting.com/cgi-bin/rio/rio.cgi

No. Nor should you. Define an API that your window implements and your other code calls. Code outside of cc should know nothing about a, let alone a.username. It might call a method cc.username that returns a string. It shouldn’t know or care where that name comes from.

I agree with solid interfaces, BUT…I don’t think it has to be at the level of a window/page. I think it’s valid for a container to be something you obtain from a window/page and work with directly. There are cases where the window/page is an empty frame and the containers do all the work. This sounds like one of them.

I definitely agree that code outside of the container should know nothing about the controls within. So at the very least you want a common GetUserName or UserName method that returns the string value your code expects.

Tim . . . are you saying I shouldn’t have programming in session methods that reads data from webpage containers?

Damn . . . the real frustration here is that I’ve got the iPad layouts that are different from the layouts for other platforms because I need to deal with fat coach fingers (gymnasts mangle their hands) instead or mouse pointers so the controls on the iPad need to be much bigger than on the other platforms.

The test username for http://sc1473a.dfw1.1701hosting.com/cgi-bin/rio/rio.cgi is Denver and the password is us14.