Say you have a menu item and a button that do the same task. Why is it bad practice to put the code for the task into one control's action event and then make a call to that event from the other control? Delphi allows this as does vb6 but realbasic doesn't and says you should put the code into a method that is then called by both the menu and the button
相关问题
- Is there a Delphi 5 component that can handle .png
- Is there a way to install Delphi 2010 on Windows 2
- Is TWebBrowser dependant on IE version?
- iOS objective-c object: When to use release and wh
- DBGrid - How to set an individual background color
相关文章
- Best way to implement MVVM bindings (View <-> V
- Python relative import with more than two dots
- Windows EventLog: How fast are operations with it?
- How to force Delphi compiler to display all hints
- Coloring cell background on firemonkey stringgrid
- Bind a char to an enum type
- Reading (with Filesystem.FileGet) VB6 record file
- HelpInsight documentation in Delphi 2007
It's a question of how your program is organized. In the scenario you've described, the menu item's behavior will be defined in terms of the button's:
Any of those three implementations will work, but why should the menu item be so dependent on the button? What's so special about the button that it should define the menu item? If a new UI design did away with buttons, what would happen to the menu? A better way is to factor out the event handler's actions so it's independent of the controls it's attached to. There are a few ways to do that:
One is to get rid of the
MenuItem1Click
method altogether and assign theButton1Click
method to theMenuItem1.OnClick
event property. It's confusing to have methods named for buttons assigned to menu items' events, so you'll want to rename the event handler, but that's OK, because unlike VB, Delphi's method names do not define what events they handle. You can assign any method to any event handler as long as the signatures match. Both components'OnClick
events are of typeTNotifyEvent
, so they can share a single implementation. Name methods for what they do, not what they belong to.Another way is to move the button's event-handler code into a separate method, and then call that method from both components' event handlers:
This way, the code that really does stuff isn't tied directly to either component, and that gives you the freedom to change those controls more easily, such as by renaming them, or replacing them with different controls. Separating the code from the component leads us to the third way:
The
TAction
component, introduced in Delphi 4, is designed especially for the situation you've described, where there are multiple UI paths to the same command. (Other languages and development environments provide similar concepts; it's not unique to Delphi.) Put your event-handling code in theTAction
'sOnExecute
event handler, and then assign that action to theAction
property of both the button and the menu item.Want to add another UI element that acts like the button? No problem. Add it, set its
Action
property, and you're finished. No need to write more code to make the new control look and act like the old one. You've already written that code once.TAction
goes beyond just event handlers. It lets you ensure that your UI controls have uniform property settings, including captions, hints, visibility, enabledness, and icons. When a command isn't valid at the time, set the action'sEnabled
property accordingly, and any linked controls will automatically get disabled. No need to worry about a command being disabled through the tool bar, but still enabled through the menu, for example. You can even use the action'sOnUpdate
event so that the action can update itself based on current conditions, instead of you needing to know whenever something happens that might require you to set theEnabled
property right away.It is neater obviously. But ease of use and productivity is of course also always important.
In Delphi I generally refrain from it in serious apps, but I call eventhandlers in small stuff. If small stuff somehow morphes into something bigger, I clean it up, and usually at the same time increase logic-UI separation.
I do know though that it won't matter in Lazarus/Delphi. Other languages might have more special behaviour attached to eventhandlers.
This is an extension answer, as promised. In 2000 we have started to write an application using Delphi. This was one EXE and few DLL’s containing logic. This was movie industry, so there was customers DLL, booking DLL, box office DLL and billing DLL. When user wanted to do billing, he opened appropriate form, selected customer from a list, then OnSelectItem logic loaded customers theaters to next combo box, then after selecting theater next OnSelectItem event filled third combo box with information about the movies, that has not been billed yet. Last part of the process was pushing the button “Do Invoice”. Everything was done as an event procedures.
Then someone decided we should have extensive keyboard support. We have added calling event handlers from another even handlers.. The workflow of event handlers begun to complicate.
After two years someone decided to implement another feature – so that user working with customer data in another module (customers module) should be presented with a button titled “Invoice this customer”. This button should fire the invoice form and present it in such a state, like it was user who have been manually selecting all the data (the user was to be able to look at, make some adjustments, and press magic “Do Invoice” button). Since customer data was one DLL and billing was another, it was EXE that was passing messages. So the obvious idea was that customer data developer will have single routine with single ID as a parameter, and that all this logic will be inside billing module.
Imagine what happened. Since ALL logic was inside event handlers, we spent huge amount of time, trying actually not implement logic, but trying to mimic user activity – like choosing items, suspending Application.MessageBox inside event handlers using GLOBAL variables, and so one. Imagine – if we had even simple logic procedures called inside event handlers, we would have been able to introduce DoShowMessageBoxInsideProc Boolean variable to the procedure signature. Such a procedure could have been called with true parameter if called from event handler, and with FALSE parameters when called from external place.
So this is what have taught me not to put logic directly inside GUI event handlers, with a possible exception of small projects.