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!

Event Control Philosophy

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
Hi All,
I recently discovered that there was an oddity with one of my controls (dropdown/combobox). When an item is selected, the Click event then updates values of some other controls based on what was selected (in this case, if you pick a "country" in the drop-down list, it will automatically set the value of "Region, Country Code (Mobile), Country Code (Non-Mobile), and Country Abbreviation". This all works great, but I realized since it's a combobox, if I type the value (it auto populates as you type), and then I just tab into the next field, the "Click" doesn't happen. So if I then click on the field it updates.
I realized I could put This.Click into the LostFocus event, and that worked.
So my question is... is this really the "right" way to go about it? Should LostFocus make a call to Click, or should Click make a call to LostFocus, or should they both make a call to some function elsewhere.. Just trying to figure out what the development "norm" is for this?
Or is there some other better way all together?
Thanks


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Neither. You should never let one event call another. As a general rue, in Click you shouldn't have more than one line, which calls another method. Then you can call this method from both Lostfocus and Click.
 
Hi Tore,
So is that Method something you create and add to the specific object? Or should it be form level? Or a non-visual class... this is the kind of "best practice" I'm trying to get to.


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Right. In my base classes for all objects that have a click method, I have created a custom onClick method. So all my base class click methods have one line, this.onClick(). I have done the same for some other events. Like both ProgrammaticChange and InteractiveChange calls a custom AnyChange method.

I know that both Doug Hennig and Tamar Granor wrote some good articles about recommendations for changes you should apply in your own baseclasses.

This is one of these articles:
Unfortunately I am not able to find the other articles... :-(
 
Tore has covered that well, just to stress out, the common method is ideally in the same control and not on form level or external event class. The need for that would only be there for the trivial technical reason you use a native class you can't extend when it's already on the form and you have not subclassed it so you also can't write that into the class itself. But that means being lazy out of a technical reason, you just should have subclassed the control earlier and while it's very often recommended to at least have a first level subclassing of every native class people don't do so.

That's not where it ends, because while you can extend such a first level inheritance with all the details you need in the one or other form, you could end up with a control class, that implements way too many specialties each only necessary in the one or other form but not all forms. So it pays to give it some thought of what class hierarchy of controls you need, which feature is generally useful and which would instead ask for a subclass and not a general behavior for all such controls.

If your click code influences other controls, eg picking a country in a country ComboBox should set a list of regions of another ComboBox or even an image control showing a country map that already asks for a mediator pattern implementation or a class composed from these two Comboboxes or a Combo and an Image so the behavior is encapsulated. The ideal base class for that is a container (or YourContainer subclassed from the container) and the reference to the other (sibling) control would be by this.parent.othercontrol instead of thisform.othercontrol and work in general, no matter if you put this on the form level, on a page of a pageframe, in a container or even into a grid column.

More so, if several similar aspects of a form changing triggered by choices made in single controls, that may best be governed by a central instance, a mediator. But the mediator pattern is not just a container or the form having its controls, a mediator would have methods to let components register as handlers or subscribers of events. I would only go for this complexity when there is more you would need to put into a single class of a control than makes sense to put into a control like class, eg if all form elements have such dependencies. In your sample the combination of two lists where the second one is a detail list filtered by the major choice that asks for a control composed of the two lists.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I agree with the others. Rather than the Click calling the LostFocus, or the LostFocus calling the Click, they should each call a new method: one that performs the specific function you are interested in.

I like to think of event-handlers such as Click and LostFocus as being a link between the user interface and the underlying functionality. Their job is to receive an event and then to call on a more specialised function to handle the event.

I'm not sure I agree completely with the statement that "in Click you shouldn't have more than one line". That might be a bit too restrictive, although the general principle is a good one.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Tore. Most of what I read in Doug's article related to properties I remember hearing at DevCon in '95 and '96, so have implemented a lot of those, but the AnyChange() is a cool idea. I wind up having a lot of code in the Refresh() event, which I've always felt like probably needed to be somewhere else as well, as I end up calling those updates a lot.
Will make the AnyChange addition, and update the Click and LostFocus events with some other localized function as well then. Will see how that works out going forward.


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Thanks guys, I'm getting the feel for it now. I have implemented the AnyChange method in both my Textbox and Combobox classes for now.

@Olaf, while I returned to VFP about three years ago now (as you know), going all the way back to around 2002 when I started leveraging VFP as VFP (and not just a "better FoxPro 2.6", one of the first things I did was subclass every single native control, and those classes are still what I'm using today. I bought a VFP training course on CDs (I can't remember the name of it now unfortunately), but it was extensive I think it had 9 CDs and books to match, and I spent a couple weeks going through all of them, that became my "foundation" in the language. When I "reemerged" 3 years ago I couldn't find those disks anymore or the books, must have gotten jettisoned in one of my many moves, or I'd have gone through them again. I think they were based on VFP6 by then actually. Then a lot change between 6 and 9, and I only barely touched 8 before "leaving" the development world. So there is a lot of cool stuff, and a lot of confusing things as well that were espoused at the DevCon's that now are considered "bad practice". So I'm left with kind of a messy understanding of some of it, partly from being forgetful in what I once knew, and partly for "missing out" on a lot of what evolved in that 15 year space in between. But the sub-classing is one thing I have always relied on, and I think I've done reasonably well in most instances. It's kind of fun and exciting to learn more about the OOP aspects, going beyond the properties and methods parts of OOD, and finding some of the nuances like goApp and how useful that's been.

I see the wisdom of creating Methods to call from events. I've heard (and read) that mentioned many times but it didn't really "click" to me until today. (I was always thinking you had to use methods already part of the class... wasn't thinking about adding my own so much). I've added a few before but they've usually had specific purposes, and not just a centralization for other activities.




Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
MS or any programming language vendor could add a few methods you might use, but it depends on the specific case, you also don't get a bunch of suggested function names doing nothing before you don't provide code.

Every existing event has a base behavior and even the structure of methods often is not only foreseen as "for you". Programming always is about adding your own structure and so Doug's paper also only is one way of doing things.

A last good discussion about OOP design was in I'll point out two things Tom Borgman said there in his post from Wednesday, August 22, 2018 7:57 PM referencing the three numbered questions Alieneko had:

Tom Borgmann said:
1. Add the method to your form. Forms are the only VFP-Class where you can add new properties and methods at design time without creating a subclass first.
Well, that's a) the lazy solution and b) only a local solution to this form

But as I said here and as Tom says in point 3:
Tom Borgmann said:
...some time in the future you'll have a main textbox class with so many functionalities that would better be placed in special subclasses.

His conclusion to sometimes solve the problem with a form method and using the form as an event handler that way is better than always adding behavior to the one subclass you made. It's a good step you did subclass the native classes, but it's not sufficient, as you not always will have the need to call the same routine from LostFocus and Click.

The conclusion should not be to use the form as it's technically the only simple and fast solution but to create a hierarchy of subclasses of the controls for specific cases. And in this case you better not just create a specific ComboBox, your situation rather asks for a control or container based class, which has both the lists of countries and their regions.

In this case, the mix of thoughts you need to have is about encapsulating everything, which belongs together into one class. In the case discussed in the MSDN thread, the need was to have an indicator for unsaved changes and that is much more common, in that case, you could define a data modification form that in the very general case would need to care for that topic of detecting and saving changes. Indeed it's not really a form job, it's located in the middle tier, but you have to make your way from each single control to that layer and it's one strategy to let each single control have a reference to the business data access layer implemented as some container or first escalate this to the form level which talks to the data access components.

VFPs direct data binding of controls to DBFs always makes you think 2 tier only, but once you use (remote) views or cursor adapters or data access business objects the layer to which controlsource binds isn't the database backend directly, its the cursor you fetched from the DB an which is then saved to the DB after biz rule checks from the layer of the data access components.

You don't get along well if you only make one subclass of everything, true OOP will have a hierarchy of classes. So you cannot rest on your laurels because you did that, what was suggested, always think in the most central concerns of OOP, encapsulation, reusability but also simplicity, not having one god class, one culmination point of everything only needed sometimes in some cases.

The more layers you have the harder it is to extend something, the more it branches the less you keep together things and VFP has no inheritance from multiple parents, that makes it hard to later create something merging classes from two branches. That's a balancing act. A composition from two or more base classes or in this case controls is one way to get to that type of inheritance.

This case is still quite simple you don't put together two different types of combo boxes from different branches, you simply put together two of your subclassed ComboBox into a container so they are combined in one class and can reference each other via their common container parent without any complex mechanism like a mediator to which one registers as parent level responsible for countries and the other as child level for regions. It's simpler, it's hardwired, but even when you would expect a country to have a hierarchy level between the whole country and region, then you could extend that class easily with another ComboBox. Eg in Germany we have the country and states and regions would perhaps best compare to what we call "circle", so there are three levels.

The essence is, you do add more than just the one subclass, just life is more complex your OOP hierarchy should reflect that. You can delay some class design for later refactoring as long as you only have a use for something once, then you start with a form level method. But you have to keep in mind this form level method exists for the two controls which are in fact one unit or should be one unit. If you always o for form methods you'd lose that coupling. If you always put all things into one class hierarchy level you're burdening everything with something you only need in some cases.

You can have a set of additional methods making general sense, a set of properties as Doug Hennig proposes, but in the end the meat of the whole structuring is neither common methods and properties or PEM in general, but the way you structure your hierarchy and are not lazy to define some new controls and compositions reusable in several places.

For example, the next generalization thought about a region picker with country/region list could be about that type of hierarchy. You come across that in many places, You have formula/recipe, order/order details, house/room, etc. you could use a control with two lists of which the choice in one filters the other as a very generic drill-down control.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hi Olaf,
Understood majority of your points here, and most of it is clear. Many of what you mention as well I am doing also, though the idea of a "container" with multiple variations of a control is a little lost on me. I have a "baseclass" VCX which has all the form controls subclassed, and where a big majority of my run-of-the-mill functionality for a control on a form comes from. But I also have some very specialized controls, usually kept in another VCX, like navigation, ribbon. One very specialized control I have is a container with an image and a text control in it, which act as a "Flag" on a map, and keep a tally of the number of locations within that. That map is a subclass on a tabbed pageframe that allows looking at different world views (like world wide, then regions like Europe, Asia, Middle East, Oceana, North America, etc). So I think this is the kind of thing you mean about this kind of specialized subclassing, rather than trying to make my pageframe subclass do everything.
I have added methods to both forms and controls. I agree (intuitively) I have never liked adding too many methods or properties to an object, especially when I know it has a limited use. In a few cases, I have dynamically added the property at runtime instead of making it permanent for the object.
As you may have guessed that's coupled with this Country/Region/City which also utilizes "Suburb" to identify locations. Those are then plotted on the map. To prevent "overcrowding" we introduced suburb so if the only piece of information we have about a location is it's country, it will still show a flag on that location. For areas like Tokyo, even on a fairly large scale map, we have a lot of locations so Yokohama, Kawasaki, Tokyo all will show up on the "Tokyo" flag object because their "suburb" is Tokyo, and the lowest level wins. This isn't done through "classes" as much as it's manage through the data table. (All data driven, so as we add locations, we don't have to re-code).
But I sense this isn't the "OOP" way, and what you're describing is. I'm just curious how that could effect our result.


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top