![]() |
![]() |
|
![]() |
ObjectPAL® List Tricks © 2001 Kasey Chang Introduction In Paradox®, you place a drop-down list by creating a field on the form, then change the type of the field to a drop-down list. It's nearly the same as a regular "list", though those are rarely used nowadays. I refer to both of them as an "OPAL List". The OPAL list is actually a compound object. It's a list object inside a field object. The two objects need to be manipulated separately. Populating a list or selecting a value in the list via OPAL does not set the field's value. Usually, it is best to name both the field and the list object ASAP. What I usually do is I name the field with prefix "f". For example, if the field is a list of customer codes, I call the field fCustomerCode. The list inside would then be lstCustomerCode. The quickest way to populate the list would be to use the datasource property of the list. However, that way is rather limiting, as you can only specify one field. So what do you do if you want a fancier-looking list? You have to populate the list yourself. Let's first go over the list properties. The .list properties A list is a very straight-forward object. You can define the size (or count). You can then access one of the items at a time by changing the selection property. Let's say we're trying to populate the list fCustomerCode.lstCustomerCode with the contents of a tcursor, let's call that tcCustomerCode. It's connected to a table Customer, which contains two fields: CustomerCode, and CustomerName. .list.count is pretty obvious: it's the number of items in the list you plan to use. Keep in mind that the maximum number of UI items is 2500, and you shouldn't ever come close to needing that many. If you do, something's wrong with your user interface. Usually, you set the count with a tcursor's nrecords() function, like this: fCustomerCode.lstCustomerCode.list.count= tcCustomerCode.nrecords().list.selection is the current item, counting from 1. It also controls the highlight. Keep in mind though that this only affects the list, not the field that contains the list. .list.value is the value of the current item (as specified by .list.selection). You can both read from it and set it. Usually you use this in a scan loop with the tcursor: scan tcCustomerCode: fCustomerCode.lstCustomerCode.list.selection=tcCustomerCode.recno() fCustomerCode.lstCustomerCode.list.value=tcCustomerCode.CustomerCode endscanYou can simplify the code somewhat by declaring a uiobject to attach to the list like this (assuming tcCustomerCode is already open): var uio uiobject endvar uio.attach(fCustomerCode.lstCustomerCode) uio.list.count=tcCustomerCode.nrecords() scan tcCustomerCode: uio.list.selection=tcCustomerCode.recno() uio.list.value=tcCustomerCode.CustomerCode endscanThis populates the list and leaves the highlight on the last item. So if you want the first item to be highlighted, you'll have to jump back by specifying .list.selection=1 after the loop has concluded. Do as I say, not as I do Sometimes, you want to show one thing while you need something else in the actual field. In the "Customer Code" example above, it's not that user friendly to show the Code when you can show the entire customer name. However, the database just wants the code. In that case, you need to provide some "translation code". You'll also need to use an undefined field as you can't connect this type of field straight to the table. Unless the list is constantly refreshed (i.e. it changes frequently and by multiple users), you probably will not want to keep a tcursor open just to do the translation, but you can definitely do that. Just do a locate or qlocate with the tcursor and lookup the other value. Still, it's more efficient if you do not need to keep the table open. You can stuff both values (in this example, the name and the code) into the list, then try to "separate" them with some sort of parsing algorithm. For example, say John Public Company is a customer, and their code is JPC. We can populate the list with "John Public Company (JPC)", and pull only the content inside the parentheses using match() when the list value is returned. If you just want to show "John Public Company", but still get JPC, then it's best to use an array doing your lookup. You can use either a regular array or a dynarray. With regular array, use the .list.selection as the index. With dynarray, you'll use the actual content as the index. You'll need a field actually connected to the table, but invisible. The actual interface is done via an undefined field with all this code. As this field updates (changevalue) it sets the value in the invisible field, and vice versa. Forcing Field Commit Another problem some OPAL beginners have with a list is the value is not committed immediately upon selection. Instead, the value is only committed when you leave the field (i.e. tab to another field). The changevalue method code you got works fine, just not at the right time. So how do you force a commit? In a drop-down list (and radio button, and checkbox), the newvalue method is triggered upon selecting a choice, but the value is not committed yet. You can intercept this event by checking in the newvalue method for eventinfo.reason()=EditValue. What you need to do then is force the commit of the new value. ;newvalue method dodefault if eventinfo.reason()=EditValue then ;we found it self.action(EditCommitField) endifEditCommitField is a predefined OPAL actionEvent that tells the field to commit the value already selected. This will kick off the changevalue method immediately upon selecting a new choice. As explained before, this also works for checkboxes and radio buttons. A few tips on List Flexibility Remember, a field can have a different value from its list. If you just initialize the list, the field would still have no value. I find it convenient to write a custom method to initialize the list (usually I just call it initList) on the field. Why at field level? Because it's also useful to set the existing field value. In the open method of the list I can call initList. This way, I can force an update of the list whenever I need to without duplicating code. You'll probably want InitList to accept a tcursor as a parameter. I also find it convenient to use a custom method to read the value from the list. This makes it easier to implement the show-A-use-B lists and in general is a good habit to get into. That way you know exactly how you got the value. The list can be set to specific fonts and font sizes. If you need some things to line up properly set a monospaced font like Courier New. You can empty a list by setting the .list.count to 0. It's best to do delayScreenUpdates(yes) while you populate the list so you don't see the list pop in and out. Remember to set it back to no! In Conclusion Lists are an indispensable part of the user interface, and they offer a lot of power with the right customization. Hope these tips help you applying lists to your projects. Discussion of this article |
![]() 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. ![]() |
![]() |
|