Advice on applying OOP to GUI design (long)

Similar things have been covered in the past, but I would like to kick the hornet’s nest again, just to see if anything may have changed in the past several years…

Here’s the (design) situation:

I need to group several sets of controls inside separate container controls in my main application window. In my situation, these containers will be displayed along one side of the application window and can be scrolled up and down so the user can gain access to each of them. Here is an example based on an the previous version of this application:

Each of these “containers” would be based on a standard “container” which, ideally, would have a set of common interface elements (e.g. the disclosure arrow to hide/show the contents, a “reset” button, and optionally a checkbox to activate/deactivate the child controls). For context:

Here is the place where I need advice:

In the old application, I was able to build this “Control Group” container object and place multiple instances of it on my window, programmatically spacing and scrolling them as needed. Because they were based on a standard ContainerControl, the sizes could vary, and the container could react to and raise events (e.g. changing its own size when the user used the disclosure triangle (DidResize), or raising an event when the user clicked the “reset” icon (DidReset)). The issue was that all the embedded controls within each and every “Control Group” (popup menus, sliders, etc.) belonged to the main window. The main window ended up with hundreds of controls, and their associate code on it.

In the new version of this application, I want to move the majority of the UI elements to individual containers, exposing the properties and events of each to the main window as needed. The problem is that a container control can not be subclassed from another container control (e.g. cntVideoDeviceOptions would be a subclass of the more generic “cntControlGroup”), inheriting it’s UI and behaviors. My current idea is to place a “Control Group” container (with the disclosure/check/reset UI) onto a second blank container control would then be placed on the main application window. All the unique UI controls would be children of this “master” container, which would serve to pass properties and events to the main application window. Unfortunately the “control group” events (DidResize, DidCheck, DidReset, etc.) could only be passed back to the main window if they were duplicated in each of the “master” containers, at which point I might as well just make entirely new container object for each of the groups.

How can I get around this? Essentially I want to create a new reusable UI object (a control group) that I can add to my main window at design time and then place custom UI controls on top of it.

Advice?

Cheers.

-bill k

You can subclass a ContainerControl (or Window) by inserting a new Class and changing its super to ContainerControl (or Window). I haven’t tried but you should be able to dynamically create controls at that point.

I’m not sure that’s the best solution for your needs, but perhaps can give you another vector from which to attack the problem?

I initially thought of that Kem (i.e. creating a new container control “cntExposure” and setting it’s Super to the more generic “cntControlGroup”), but the compiler complains with the error:

The project item cntExposure can not inherit from a window (cntControlGroup).

That seems like it would be the easiest way to go about this, but it doesn’t look like it will work…

You can subclass as much as you want, however many levels deep, until you put controls on it. Then you can no longer subclass. Ie., you can subclass logic - methods and properties - but not layout. So create a blank container subclass and pre-do the business logic, then add the controls at the leaf node of subclasses and put instances of that container on your window.

Tim, I’m not really following what you’re saying. Here’s a specific example, this is the goal:

Screen Shot 2020-08-04 at 8.24.33 PM

My initial idea was that the “template” container control (cntControlGroup) would contain the common UI and “business logic”, and the “document” container (cntExposure) would contain all the controls unique to this instance. The cntExposure instance would include an instance of the cntControlGroup container that fills cntExposure and would be locked to all four sides. What we get is the “blended” container shown above. This would be added to the main window as “grpExposure”.

You’re saying that the template (cntControlGroup) can’t contain any controls on it, and I can certainly create a container like that, but looking at the example above, where would those controls reside? I can put them on cntExposure, but then what would the global “IsChecked” property of cntControlGroup look like? It would have to “check” a UI element on it’s own parent control? That doesn’t make sense to me.

In a sense I’m trying to create a custom library control that acts like a container, and that I can create multiple instances of in the IDE. One possibility would be to create a custom Xojo plugin with this functionality, but I’m guessing that there’s an easier solution.

cntExposure would BE a cntControlGroup. Ie., it’s super is cntControlGroup, so it inherits the logic, properties and events of cntControlGroup. It wouldn’t contain a cntControlGroup, it would be one.

I get that part Tim, but if a container control can’t be subclassed from anything with any sort of UI, where would these go?

Part of the whole exercise is to make it so that it’s easy to change the look and behavior of the underlying container control. Those elements (the disclosure triangle, group title, reset, check and location labels) all have to be somewhere.

It’s sounding like the way to do this is to add multiple cntControlGroup containers to the main window, and then each unique control container (cntHistogram, cntExposure, etc.) would be placed into each of them.

Sorry, that look way too much back and forth to come up with a super simple solution.

Make a container for those common controls. This project demonstrates the basic design: https://gofile.io/d/tKvQty

Thanks for the example Thom. I’ll have a look.

Just wanted to put an end to this thread and let people know how I finally decided to resolved my issue. I took a look at Thom’s suggestion, and although it worked perfectly well, there were a few things that I wanted to incorporate that couldn’t easily be done using his model, so I went back to my previous approach of a “container within a container” solution. This gives the flexibility of having all the visual and common UI code in multiple instances of one “parent” container control, with the individual UI as separate containers, therefore not needing to put all those controls onto the main window.

The “parent” container handles user clicks on the various controls along the “title bar”, raising various events that are handled in the main window (e.g. moving all the other control groups around when one is opened or closed). The nice thing is that all the visual stuff (borders, background patterns, etc.) can be easily updated as needed. The application is a long way from finished, but here’s how it’s starting to come together:

It requires a bit of object organization in the main window code, each “group” has two objects to keep track of (i.e. grpExposure - the parent, and cntExposure - the child), but so far I haven’t run into any drawbacks. It would be great if container objects like this that have some UI elements could be subclassed, but this seems to be a workaround. #ChangeMyMind

if you really mean 1 parent and 1 child.
you could also drop the parent cc (this small row at top) into each “child” container control.
then you have only a single control in the window for each group.
cou can add a Base Class with Super to ContainerControl and use this Base Class at this single (current child) CC.
this base class have some benefit if you will store them in one list with one type.
but you can then also cast it back into individual cc.