One of the challenges of using Combo boxes on Table Controls is that they can’t be editable combo boxes, and the values allowed have to be the same for each row.
Well of course I needed to be able to entered values other than what was in the list, as well as have a different possible list for each row.
So I figured out how to “emulated” a combo box using a Container Column, a button, and a lookup screen. Read on to see how.
The requirements for this project was a tall order!
- An Edit in Place Table
- Results Column that is configurable as either a numeric value or a string
- Results Column should be an editable combo box.
- Regardless of type configured ND is always a valid value indicating No Results
- If Results is Numeric based allow configuration of the number of decimal positions
- If Results is Numeric based allow configuration for highlighting abnormal results
- If Results is Character based allow configuration of a valid list of selection and display as a combo
If you have ever worked with combo boxes in a table control then you know that almost everything on that list is not possible, since they can not be editable combo boxes or have different selection list for each row. So I had to figure out how to “emulate” a combo box using a very cool feature of WinDev Tables call a container control, a button and a lookup screen.
Let’s take a look at a few screen shots of the final product.
In this screen shot I have typed .55 into the numeric result
However when I tab off the field we will see that the result has changed to .6, that is because this particular test is configured to only allow 1 decimal position.
In this shot we see that the numeric result is colored red, that is because this particular test is configured to have an high alert at that level. This is also a warning level configuration that would turn it yellow instead of red.
Moving on to Text Example 1 we see that if I drop down the combo box the valid values are Value 1, Value 2, Value 3. I can either select on of these values, type on of the values in directly (for those data entry type folks that hate the mouse), or type ND to indicate no result.
If I type a value not on the list we see that it generates an error. Those of you that follow my open source project, should recognize that error as coming from my Balloon Tip class.
And if we look at the second Text Example we see that it has a different list of valid values, and the Example 1 would have been accepted for this test.
So now that we have seen it in action lets take a look at WinDev and see how it was accomplished.
The key feature that makes all of this possible is the ability to have a container column on a table control. Which is a column that can contain a set of controls. If you have not looked at container columns I urge you to try them out! There are all types of rich interfaces, that can be done via the container column. Container columns can even have a table control inside them, that’s right a table in a table! Sorry WebDev guys but this is a feature that hasn’t made it to WebDev this is a WinDev only feature.
For our purposes all we are going to put in the container is a button, that we have styled to look like a combo box.
Notice we made the column width just the width of the button.
So lets take a look at the code behind this button.
As usual it doesn’t take much WX code to accomplish quite a lot.
Line 1 and 2 get the current mouse position relative to the screen. Since this is on a click event that will be the exact pixel that was clicked on.
Line 4 uses a different format of the MouseXPos to get the mouse position relative to the current control. If you clicked on the 5 pixel to the right of the edge of the button then it will return 5. Subtracting this value from X gives use the left edge of the button.
Line 6 uses the width of the actual result column (the entry field) to subtract from X to give us the left edge of the entry field. So now we have the exact X position that we want the combo to be positioned at.
Line 8 is figuring out how far down on the button you clicked and moving the Y position to the bottom of the button.
And Line 10 is a 1 pixel adjustment I had to make to get things “just right”.
Line 11 is concatenating the X and Y positions onto the Lookup window name. This may be another WinDev feature you haven’t seen before. If you take a look at the online help you will see that you can specify the X and Y position of a window via the Open statement and if you try it for yourself, you will find that it sure would be nice if they have given us an example of that call. But no fear Uncle Pete to the rescue! The call is very tricky for 2 reasons, first if you try to type the command as Open(MyWindow,x,y) then X and Y are treated as parameters to pass, that is why I am using a string field to hold the window name and positions. The next little trick is to notice that for some reason (Frenglish?) they have switch the X and Y order and you pass the Y position first.
Line 12 makes the actual call and accepts the results. Notice I am actually passing the list of valid values to the window, the actual lookup window doesn’t have to have any logic to get the list of values, it just needs to display them and allow a selection.
Line 13 check to see if we got a result back or did the user press escape.
Line 14 sets our entry field to the value returned
And finally line 15 uses another handy WX trick to force the code in the exit event of the entry field to execute. This avoid me having to either duplicate the code here or move it into a local procedure to be called from both places. So now I know that even down the road when I make changes to the validation logic of the entry control, that will automagically apply to the lookup button as well.
So let’s take a look at the lookup window. There isn’t a lot of fancy code here, the key is really in setting all the properties correctly to get the correct look to emulate a combo box.
If we look at it at design time we will see that the window doesn’t have any frame, the table control is the exact same size as the window, and the buttons are actually off the window so that they are not displayed.
If we look at the GUI tab of the window description we will see that Resizable, store the size and position, and adapt the size are all turned off. If these were on the positioning logic we just looked at would not have an effect because the window would be repositioned based on where it was last displayed.
And on the Style tab we don’t want any title or status bar, or any of the system menus or icons. And we don’t want the window to have any type of a border.
For the table control we need to set a few style setting there as well so that we emulate a combo box.
First we don’t want the table to have a caption
And likewise we don’t want the columns to have captions either. So now our table is just a pure list of values, aka a combo box.
And a few properties for the buttons. Notice the Cancel button has the shortcut set to Esc. But also notice that the button is marked as visible. You might have expected it to be invisible since we don’t want it to be seen. However if we make the button invisible the hot key will no longer function, so instead we make it visible, set it off the screen and set the anchoring so that no matter how the screen is resized the button will never be on the screen.
The OK button is very similar except its hot key is the Enter Key.
Now that we have all of the properties set, lets take a look at the code.
That is the entire code of the window! As mentioned earlier the window accept a parameter that is a comma separated list of values to display.
So we declare an array of strings. If we look at the content table of the table control we will see that that is the content for our table.
We use the StringtoArray function to split the comma separated list into array entries.
Next we see how many options there are. If there are 10 or fewer we resize the screen so that only that many rows are displayed. This took a bit of experimenting to get right, but it turned out that each row used 19 pixels and I had to add 2 for what apparently is a slight top and bottom edge or something. If there are more than 10 options we size the window to 192, which will display 10 rows and cause the table to display a vertical scroll bar.
If the cancel button is pressed we return an empty string and if the OK button is pressed we return the selected value.
One line of code left, On Left button up, we force the OK button to be pressed. This is again to emulate a combo box. Normally clicking on a row just selects it, but in this case we want to actual complete the window. Initially I had this code on the On Left Button down, but the problem was that event fires before the normal WD row selection logic fires so I would not have the correct row in memory. Moving it to the up event gave the expected behavior.
And there you have it we are emulating a combo box, and not can have different values for each row of a table and it took a total 23 total lines of code to accomplish. Once again the power of the WX language never cease to amaze me!
Hopefully this article has inspired you to experiment with the container column, with the ability to have controls like tables and internal windows inside a container column the possibilities are endless. I hope to see some examples of how you all have solved project requirement with them in the future!
Be sure to go over to wxLive.us and watch the Uncle Pete’s corner webinar that is the companion to this article.
Uncle Pete’s Corner is webinar series on all things WX, to watch the recorded version of this webinar, many other WX related webinars or to watch future ones live go to wxLive.us