![]() |
![]() |
|
![]() |
Subject: FAQ:PdoxWin:Preventing Paradox Events:2001.05.25 Version 1.0 (2001.05.25) Written by Bertil Isberg (CTech) edited by Paradox FAQ Team ==================== 0. Introduction ==================== This FAQ addresses a common request: "how do I stop Paradoxcontinuing to operate as a result of an event, if I don't want it to ?". The reason for wanting to trap this situation is most commonly: a. prevention of bad user input b. the result of finding inconsistent data This FAQ is appropriate to users of all versions of Paradox for Windows ------------------------------- 0.1 Legal Info and Disclaimers ------------------------------- Paradox is a trademark of Corel. Borland Database Engine (BDE) is a trademark of Inprise. The information provided in this FAQ is provided "as is" and is not warranted in any way. The information provided in this FAQ is not endorsed or authorized by Corel or Inprise in any shape, form, or manner. The editors claim NO responsibility for ANY illegal activity regarding this file, or as a result of someone reading this file. You may distribute this file, as long as the copies are complete, unaltered, and are in electronic form only. ------------- 0.2 Feedback ------------- Please send feedback in a Corel Paradox newsgroup or the news:comp.databases.Paradox newsgroup to any of the FAQ Team mentioned in the "FAQ: FAQ FAQ" document. Please preface the subject of your post with the string "PDXWIN FAQ" to alert Team members to the function of the message. Please specify the FAQ name and section number the comment applies to, if any. ============================== 1. General Information ============================== Almost everything you do in a Paradox form ends up in an action event being called. For example: Press the Tab key to move to next field active.action(fieldForward) Press Ctrl+Del keys active.action(dataDeleteRecord) Leave a record where a field has been changed active.action(dataUnlockRecord) Toggle the Edit button active.action(dataToggleEdit) active.action(dataEndEdit) Start editing a record by pressing F9 active.action(dataBeginEdit) When you want to take care of the user's interaction with your form, an object's action() event is the place to let your code interfere with Paradox' normal behaviour. ============================== 2. Example 1 ============================== If you want to prevent accidental deletions of records, the action event at form level should look like method action(var eventInfo ActionEvent) if eventInfo.isPreFilter() then ;// This code executes for each object on the form else ;// This code executes only for the form switch case eventInfo.id()=DataDeleteRecord : if msgQuestion("Verify Delete!", "Do you want to delete the current record?") = "Yes" then doDefault else eventInfo.setErrorCode(UserError) endif endSwitch endIf endMethod This code takes care of all different possibilities involved in deleting a record; Ctrl+Del keys, a custom Delete button, and the Paradox menuchoice Record | Delete. The more you get used to Paradox, the more you will use action-constants instead RunTime Library methods. In a pushButton(), you'll write the line: active.action(dataUnlockRecord) and in the action() event you'll take care of actions that should happen: method action(var eventInfo ActionEvent) if eventInfo.id()=DataUnlockRecord then if not lgDoMyTestsFirst() then eventInfo.setErrorCode(userError) return endif endif endMethod This way, the call to your custom method lgDoMyTestFirst() will execute whenever a record is to be unlocked. No matter how the unlock is triggered. There are two fundamentals to consider when sending actions a) they prefer to have an object to work on b) they shouldn't be disabled As seen above, I have used eventInfo.setErrorCode(UserError) to prevent the behaviour instead of disableDefault. ============================== 3. Referring to Objects ============================== When you want to send an action or trigger the same event with RTL methods (action(dataDeleteRecord) or DeleteRecord()) you must decide which object it should be sent to. During interactive work, all actions are sent to the active object. Mostly it's very natural, it is what you expect. Sometimes it can be confusing, especially if the active object is an undefined field not bound to a table. As unbound fields know nothing of DataDeleteRecord, the action will bubble up through the containership and reach the form. The form will take care of the action and apply it to the master table of the form, whatever that happens to be. For the following examples you could use Customer and Orders tables from the Paradox Sample directory. Take a copy of each of the two tables, so you won't destroy the contents of the original tables. ============================== 4. Example 2 ============================== Create a form with two tables, Customer and Orders, and do not link the tables in the data model. Pick Customer table first, so it will be the table shown in the upper left corner of the data model. In Design layout, check Style: Tabular. As the tables are unlinked, you will only get one table frame in your form. To get the second one, you have to use the Table tool on the Toolbar. When you have placed a second table frame in your form, right click it and choose Define tabe from the popup menu, and then select the Orders table. Run the form. Move to Customer and press Ctrl+Del and a record in Customer will be deleted. Move to Orders and press Ctrl+Del, a record in Orders will be deleted. Add a button to your form with one line of code: deleteRecord(). Move to Orders. Press the button and watch what happens. A record in Customer is deleted. When no object is specified, the action is sent to the form and the form will handle this with the Master table of the form as object for the action. The Master table is usually the one in the upper left corner of the data model; in the case of un-linked tables it is usually the first one added to the data model. Lesson 1: if you want an action to apply to the currently, active object, use active.deleteRecord() or active.action(dataDeleteRecord). Always use an object. It's better that you do it explicitly, rather than letting Paradox handle this automatically. Every action should be directed to a particular object. ============================== 5. DisableDefault ============================== The Paradox manuals mentions three statements to handle the default behaviour: doDefault: executes the default behaviour. Execution of the default behaviour of the object takes place immediately. After that, the code resumes immediately after the diDefault statement. Note that the default behaviour does NOT happen again after the endMethod is reached. disableDefault: to inhibit the default behaviour enableDefault: a programmer's help, as it allows you to first disableDefault as a standard and then enableDefault for some cases. This description has fooled a lot of ObjectPAL programmers. You should NOT use disableDefault to prevent the default behaviour. The way to do this is to set an error and thus invoke the Paradox errorhandling ------------------------------ 5.1. DisableDefault Example ------------------------------ Let's look at this more closely: You can use the form designed above for the following example: Add some lines in your form's action event, so it looks like: if eventInfo.isPreFilter() then ;// This code executes for each object on the form else ;// This code executes only for the form switch case eventInfo.id()=DataDeleteRecord : disableDefault endSwitch endIf endMethod In a pushButton method of a button, enter the code method pushButton(var eventInfo Event) if not active.action(dataDeleteRecord) then msgInfo("Record not deleted", "") else msgInfo("Record deleted","") endif endMethod Run the form, enter Edit mode and press the button. With disableDefault, you tell Paradox: Do not execute the default behaviour, because my code has taken care of this. So Paradox assumes the default behaviour is done and behaves accordingly. Now replace disableDefault in the form's action() event with eventInfo.setErrorCode(UserError) and repeat the steps above. Paradox behaves as expected. Lesson 2: An action event should not be disabled, but prevented with an errorCode. ============================== 6. A chain of events ============================== Some of the user interactions will trigger not only one action, but many. When a record is changed and you press the Edit button to end edit, for instance, the toggleEdit will turn into an unlockrecord and an endEdit. When actions are disabled, this chain of events will not get the correct information. eventInfo.setErrorCode(UserError) will stop the chain of events, disableDefault will not. disableDefault should be used for two things only: a) when you have replaced the default behaviour completely and you want Paradox to continue as if everything is Ok. E g when you translate a keypress in keyPhysical() event to something else. b) When you want to prevent bubbling. In most other situations, you should set an error instead of disableDefault. ------------------------------ 6.1. After-effects Example ------------------------------ Let's take a look at the effect of disableDefault in a changeValue() event. disableDefault: resets the old value and allows the cursor to move to next field eventInfo.setErrorCode(UserError): keeps the new value and prevents you from leaving the field. You can test this in the Ship Via field in Orders table. Write the following lines in the changeValue() event. method changeValue(var eventInfo ValueEvent) if eventInfo.newValue()="UPA" then disableDefault ; eventInfo.setErrorCode(UserError) endif endMethod Change the value to UPA in a record and Tab out of the field. As you'll see, you the new value will not be entered, but you can move off the field. Make a comment out of disableDefault, and let eventInfo.setErrorCode(UserError) execute by removing the semicolon. When disableDefault is used, the event chain will continue to execute as if everything is Ok, and canDepart() is allowed. eventInfo.setErrorCode(userError) will block the rest of events due to Paradox builtin errorhandling. ============================== 7. Internal and external builtin methods (events) ============================== As this article has been a comment to a part of the Paradox manuals, where basics of the event model is described, there is one more thing to be said. Built-in methods are classified into three categories, internal, external and special events. The last group contains only the pushButton(), changeValue(), and newValue() events. The manual states that internal events do not bubble, and reading carefully you will find that disableDefault should not be used to prevent the default behaviour for internal events, e g don't use disableDefault in an open() event. I recall having a hard time to understand why mouseEnter() and mouseExit() belonged to the category internal events and why Status() was an External event. The explanation is: The names of the categories, Internal and External, are just names. The classification is based upon the following: a. Events that do not bubble are called internal b. Events that may bubble are called external. That's why mouseEnter() and mouseExit() are internal events. They do not bubble. Status() may bubble. As you see, there is nothing to understand, only to accept. ============================== 8. Conclusion ============================== One of the most misused statements in the ObjectPAL language is disableDefault. With the examples shown, you have got an explanation why you should avoid it and use eventInfo.setErrorcode() when you want to prevent the default behaviour of a Paradox event (builtin method). You have always been shown the effects of not deciding the object which an action should be applied to. The recommendation is to always specify objects when actions and RunTimeLibrary methods are called. ============================== 9. Lessons ============================== Lesson 1: if you want an action to apply to the currently, active object, use active.deleteRecord() or active.action(dataDeleteRecord). Always use an object. It's better that you do it explicitly, rather than letting Paradox handle this automatically. Every action should be directed to a particular object. Lesson 2: An action event should not be disabled, but prevented with an errorCode. Paradox Community Newsgroups |
![]() Feedback | Paradox Day | Who Uses Paradox | I Use Paradox | Downloads ![]() |
|
![]() The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation. Paradox is a registered trademark of Corel Corporation. ![]() |
|
![]() Modified: 15 May 2003 Terms of Use / Legal Disclaimer ![]() |
![]() Copyright © 2001- 2003 Paradox Community. All rights reserved. Company and product names are trademarks or registered trademarks of their respective companies. Authors hold the copyrights to their own works. Please contact the author of any article for details. ![]() |
![]() |
|