Moving code to a window superclass

I’m looking for some suggestions of harmonising some code. To explain I have a family of dialog boxes that have some common properties, for example:

The top variables panel is one of two choices, depending on the need for a single variable or a pair of variables. Next there can be a Filters panel. Finally, the lower Options panel can be any one of 4 or 5 different variants.

Each Variables panel is a container control, as is the Filters panel and the multiple Options panels.

There are then a series of windows that bring these containers together into the allowed combinations. All of these windows are subclasses of an ActionDialog base class to allow common properties and methods to apply to all of the sub-classes. All of this has worked a treat until I introduced a splitter control (of my own making). This sits between the variables panel and filters panel. It allows me to vary the space allocated to the Variables and Filters panel, as follows:

Now I have special code that allows the splitter to work along with the wider window context. Currently that code sits in each of my ActionDialog subclasses, because they are the only ones that contain the action panels. What I would like to do is have that code in the ActionDialog super class. In other words in 1 place rather than 8 time in all the sub-classes. The problem obviously is that the super-class is an empty subclass of DesktopWindow. Because of that I can’t reference container controls that only exist in child classes.

Obviously I could have the controls on the subclasses register their contents with the parent class. Which in turn would allows me to put some of the common code into the parent class. However, I cannot define event actions in the parent class, despite having a reference to the controls in the parent it does not allow me to have events on those references.

The best I can seem to do is Add methods to the super class and call those from each of the events in each of the sub-classes. Not quite as bullet proof as I would like, as it would be possible to forget to call the super-class method.

I’ve already defined class Interfaces for the ActionDialogs (as a container of panels) and Panels (a type of ContainerControl that supports the required methods for an ActionDialog).

Shouldn’t that code exist in a parent splitter class that each splitter inherits from?

It’s hard to explain. All the code for dragging the splitter is in the splitter class. It has limits on movement built in etc. when moved it generates “Moved” events which then trigger on the instance to allow that to adjust the other controls on the window. All of that is fine.

It is the code to move and resize the top and bottom panels. That is currently on the sub-classes and not the super-class.

For example each Variables and Filters panel has code to remember its new heights. It has code to adjust when the window is resized, etc. I would love to centralise that code, rather than duplicate it all over in each sub-class.

I’ve managed that for window events, because they can exist in the super-class. Control events can’t, because the panels don’t exist there, only references to them. The compiler / ide won’t let me add events to a property of a control class, as I can on a dragged and dropped instance of That same class.

A method in the window can raise an event on the window. A control on the window can call such a window method which would in turn raise an event. That approximates having control events on the window.

For now I have made methods on the parent class that perform the actual actions. Each of the events in the sub-classes calls these methods to do the dirty work.

@Tim_Hare That is pretty much what I am doing, without the need to raise the events up to the super-class. The issue remains that I have to define the events on each sub-class window and then enter the code to perform the super-class method. I can’t think of a way of automatically performing that. Not with interfaces or standard class configurations.

I am using the RaiseEvent from the panel classes to propagate up to the sub-class windows. For example the Filters panel (DesktopContainer) has a checkbox Use Filters. Changing that checkbox to on raises a GoLarge event, turning it off raises a GoSmall event. The issue is that this container is on 8 different window sub-classes. In each of those GoLarge and GoSmall events I now have to put code to call the FiltersGoLarge or FiltersGoSmall method of the super-class.

Are you not using a subclass of DesktopContainer? You can define the events there (in one place) and if needed propagate them forward if the containers on the window need to do something special.

My motto is, subclass every control you use and isolate common code and events in it. I very rarely use a raw Xojo control.

2 Likes

Yes, I’m using DesktopContainer subclasses. I am happy I can define events on them. The issue is that these events only fire on instances of the container class within the window they are placed on.

If I have more than one window that contains that subclass I have to implement its events on the that window by window basis. Even if I simply make them call a method defined in the window common super-class.

Not sure if I am missing something, because it should work if designed this way:

Yes, that clearly demonstrates the problem. To get the event to propagate upwards I have to put code in every SubClass of the window. This is more true of control events, rather than window events. as the superclass of the windows doesn’t actually have any controls on it.

You cannot create a true window and then create subclasses of that window. You can only sub-class a true window from an abstract subclass of Window or DesktopWindow.

Class ActionDialog Super DesktopWindow
// Can't have control events here.
Method ImplementationForGoLarge
Method ImplementationForGoSmall

Class DescriptiveDialog Super ActionDialog // This is a real window with controls
Control conVariablesY // an embedded container
   // Event triggers and I have to code the call to ActionDialog Methods

Class PairedTDialog Super ActionDialog // This is a real window with controls
Control conVariablesXY // an embedded container
   // Event triggers and I have to code the call to ActionDialog Methods

Class conVariables Super DesktopContainer // Abstract Container class
Define Event GoLarge
Define Event GoSmall

Class conVariablesY Super conVariables // A real container with controls
Control Raises GoLarge or GoSmall

Class conVariablesXY Super conVariables // A real container with controls
Control Raises GoLarge or GoSmall

Windows by code are a recurring topic here. Many times not ending with satisfying solutions.

No, the PairedTDialog, DescriptiveDialog etc are real windows produced using the IDE. They really exist. What is missing is the ability for an abstract DesktopWindow superclass to define the types of control its subclasses should contain.

For example ActionDialog always contains:

  • One subclass of conVariables (2 subclasses)
  • One subclass of conFilters (1 subclass)
  • One subclass of conOptions (7 subclasses)

That leads to 8 different windows in total. I have to remember to define each event on each window and then propagate those to the ActionDialog class. With 9 different events I have to hook up for each that is 72 events I have to hook up. Miss one and I have a problem.

I can have properties on ActionDialog to hold a references to each of the controls, however, I cannot create events handers on those referenced controls. If that was possible the events could simply propagate to the parent classes automatically.

Even if I had to define it in a different way, such as adding a control proxy of a given class to the abstract window, which could act as a repository for the events.