Object-containing canvas with controls of multiple classes

I have adapted an object container canvas sample application to my needs. I want to be able to drag, scale, click on, etc…different kinds of objects. Objects will be of many different classes, but all subclasses of Canvas. Each will know how to draw itself into the containing canvas, and accept mouse events.

The problem I have, is how to declare these contained controls at the container level. I imagined it would be Variant. I might have ObjectAControl and ObjectBControl… and assign one or the other to the Variant. That part works. But when I go to call the methods of the Variant …that doesn’t seem to work.

If for instance each of my object types were subclasses of the same super class (that was subclassed from Canvas)…could I then declare each object as the superclass, then call whatever superclass methods were available?

I’m sure this is easy but I am a newbie and don’t know the correct syntax, trial-and-error is frustrating, and I don’t know what to search for in the documentation.

If the objects are to be drawn on a Canvas, then those objects do not need to be Canvases themselves. They can just be classes that the main Canvas draws onto itself.

Xojo includes a couple examples of this technique:

  • Examples/CanvasDrawDrag
  • Examples/ObjectsInCanvas

If you want to have different classes to handle different things, you can make them all be subclasses of a common parent or you could have an interface that they all implement.

You might also find the Retro Gaming webinar (and its companion project) helpful as it also does this sort of thing to draw the game objects.

Thanks Paul for your reply.

The ObjectsInCanvas project was my starting point.

I didn’t realize I didn’t need the objects to be canvases, though it is kind of handy to be able to drop one on a regular container for testing. I have a Draw method which I call from the Paint event (Draw g,0,0), so it can draw into its own canvas, or the container’s canvas by calling Draw with the container’s Graphics object and the desired X,Y position.

I tried using a common interface, that didn’t seem to work, or I didn’t do it right.

I’ll have a look at that project

There was an excellent project in xDev which does exactly that. Do you subscribe to xDev? If not then I could send it to you.

No Markus, don’t know about xDev. Presumably a publication. That would be great.

Check the private conversation :wink:

That is a great project for learning about graphics and so on.

I’m thinking part of my problem is that I am trying to do the same with controls rather than classes.

For instance, I just had a go at creating a control that would be a super class for a variety of other controls. That control (call it MySuperCtl) had ContainerControl as its super class.

Then I made another control (call it MySubCtl), which had formerly had ContainerControl as its super class, and tried changing the super class to MySuperCtl. Here is the error that occurred:

“The project item mySubCtl cannot inherit from a Window”

Seems like there are limitations on controls that do not apply to classes, and that the limitations do not necessarily follow the normal logic of Xojo.

Which one?

If you are talking about SimpleDraw then doing it with Controls is like trying to put round pegs into square holes. You can do it with a really big hammer and a lot of force but it isn’t a good fit.

Controls are end products of classes. They have certain purposes. A PushButton is there to be pushed. A canvas is there to be painted on. A ContainerControl is there to … well … contain controls, aka a group of controls that you want to reuse in that arrangement.

Classes are blueprints. You can make them do whatever you want them to do. You can customize them for the purpose you have in mind.

Read up on the Graphics class and Object2D.

Object2D will allow you to handle rotation and all sorts.

I’ve abandoned the ContainerControl and now trying the same idea with Canvas as the superclass for my superclass. It seems to work though its odd that the Paint event does not get called on my superclass. I need to call Super.Draw from the subclass. Also not sure if there is an efficient way to use the Canvas for containing other controls, because there is no on-screen editor for the Canvas.

FYI, ContainerControls are more akin to Window than Control and have the same limitations as a Window. You cannot subclass UI, only logic. Once you put a control on a ContainerControl, you can no longer subclass it. Same with Window.

Basically the idea would be that you have a number of objects that you want to draw, and for the canvas to have a list of objects.

Note that those objects are not canvases or anything, they are their own class that you define. Like “Triangle”, “Crescent”, “Car”, “Horse”, etc. (whatever it is you want to draw)

Each object knows how to draw itself.

If you want to draw an object on the canvas then you add it to the list.

In the canvas paint event you paint all the objects on that list by calling their draw method.

OK I’ve got it. I’ve got a three-tiered hierarchy. At the top is SpaceCtl which takes care of all spatial information, including real world dimensions and position, screen coordinates, scale factor, rotation, etc. Then I’ve got a ContainedObjectCtl which is subclassed from a SpaceCtl.

I turned the ObjectContainerCanvas into ContainerCtl which deals exclusively with ContainedObjectCtl. I can now drag around, zoom, pan…all that.

Then subclassed ContainedObjectCtl to get an application-specific control. It overrides Draw, and adds application-specific features, mouse handling within its bounds and so on. I don’t see any reason why I should not be able to have multiple application-specific controls subclassing ContainedObjectCtl.

Thank you for help in sorting this out.

May I suggest a renaming?

Don’t use “control” when you mean “class”. It introduces subtle confusions which become bigger confusions when you revisit code 6 months later …