I seem to be using the ListBox a lot. I don’t like the idea of having to refer to columns by referencing their order (with an integer). This means every time I add, a new column or just change their column order, I have to update all references in my code. Which gets tedious. I’d like to reference columns by column name. Is there any simple way of doing this? Or do I need to write a new Method?
I gather the best way to do this is by subclassing the Listbox, which would allow me to add custom methods. But I’m not sure where to begin.
Create constants representing the columns. You’re now using names in your code (i.e. kFirstNameCol, kLastNameCol) and when the order changes you change indexes in one place. It’s also probably the most efficient method since you’re not string matching to identify a column.
Even if you created a subclass of ListBox which accepted names for every argument that currently expects an integer column index, you would still want to use constants for those names for a number of reasons: compiler checking; auto complete; and I don’t know if the Xojo compiler optimizes out duplicate strings. So you don’t gain much by using names directly.
For “one off” ListBoxes I would store the constants in the parent window. For a ListBox that might be used in more than one location I would subclass ListBox and make the constants (along with other ListBox behavior) part of the subclass. That way all of the ListBox behavior gets “dropped” in a window any time I need it.
If you do want to search for strings, and assuming you’re using heading for the columns, you could do it without subclassing. You could put something like this in a module:
Public Function lb_col_by_name(extends lb as listbox, search as string) as integer
dim i, c as integer
c = lb.ColumnCount
for i = 0 to c -1
if lb.heading(i) = search then
exit for i
I’ve got one application where I support the user changing the order of the columns, and the column header can be localized. I found the easiest way for me to keep track was to put a column ID in the ListBox.ColumnTag for each column.
Right now I’m referencing cells with code like this. Where LastIndex is part of a For/Next loop, and 4 is the 4th column in.
dataList.Cell(dataList.LastIndex,4) = something
So in this example, 4 is the constant. And yes, I understand this is the most efficient way to access these cells.
But my Listbox is synced to a database, so at a minimum there would be the load ListBox (from the db) and the save (to the db) routines that would need to be updated as changes occured. But then… as my app develops there could be even more varied column instances, cascading my maintenance chores further, for each minor revision.
At this point, I’m willing to sacrifice some run time efficiency for the sake of easy maintenance. Column counts would never be more than a dozen, so I think doing a search for each read or update, as Scott’s code indicates, would be the answer I’m looking for. And I’m sure I can modify his little routine to reference cells using parameters like this: (“Heading Name”, row).
Though I am intrigued by his use of the extends keyword. Would this be part of common SubClass definitions, only used outside of an actual SubClass?
And if by chance my headings were getting too long, as Ed suggested, I could use the column tags to reference the columns by tag name (or id) rather than using the entire (potentially long) column name.
I’ll work on this and post my code when complete. Thanks guys!!
[quote=422917:@paul townsend]Right now I’m referencing cells with code like this. Where LastIndex is part of a For/Next loop, and 4 is the 4th column in.
dataList.Cell(dataList.LastIndex,4) = something
So in this example, 4 is the constant. [/quote]
4 is not a constant, it’s a literal. Use actual constants. Here’s a screenshot of what I mean:
Now your code is: dataList.Cell(dataList.LastIndex, kLastNameCol)
You can reference kLastNameCol in a thousand places. If the column index changes, you just change the value of the constant kLastNameCol, and every code point that uses kLastNameCol works.
If you use Scott’s code with literal strings then you will have the same problem as soon as a heading name changes. If you’re lucky the string will be unique so you can find/replace. But if you’re not it’s as bad as hand editing literal integers. (And in a big project you won’t be lucky.) Even with Scott’s code you would want to use constants, but if you’re using constants you might as well use the integer indexes.
Edward Palmer’s suggestion is the way to go when the end user can modify column arrangement.
@Daniel: Thanks for taking the time to explanation this to me. I’ve never really used Constants much before. But in this context, I have a new appreciation for how useful they can be. And in this situation, save maintenance time, which is exactly what I’m trying to do. I still have a lot to learn.
Thank you. Unfortunately it has been a long time since I’ve updated wcc or that site. The controls still work and I still answer tech support emails…I just need to follow the plan I originally laid out and get some updates out there. (Other life changes and issues interfered with my work on wcc.)
The Xojo community is a great one. It’s one of the many advantages of Xojo. No language is perfect for every project or task. That said, Xojo is my favorite cross platform tool and my favorite Rapid Application Development (RAD) tool, and the Xojo community one of the best out there. With the future web framework it may also become my favorite web app tool. Some of the styling limitations hold it back from that at the moment. But when it’s appropriate for a project it is so much nicer than ASP.NET or PHP.
Remember not everyone who “helps out” on the forum are “Pre-Release Testers”, or own an “Enterprise” or “Pro” edition of Xojo, but all the means is that “we” don’t have the $$$ to invest in tools that “we” don’t need, and/or don’t have the resources to be a “Tester”… that however doesn’t diminsh any contributions we make