We are switching gears to WinDev this week, and a fairly simple requirement. Having an Edit-In-Place table that some of the controls are disabled based on logic. I know it sounds pretty straight forward, but there are a few gotchas that can get in your way at times, so we will take a look at a few different scenarios and how I handled them.
First let me say that doing Edit-In-Place with WD is an absolute pleasure compared to those “other” languages. I use to avoid edit in place like the plague, now if it is fewer than 5 or so fields in a file, you have to make a strong case for why I would ever spend the time to do a form instead of doing Edit-In-Place! Especially with some of the advanced features like Memory Browsing tables and TableSave.
But enough with the rosey kudo, that not watch you expect for me! When you start needing to apply logic to your Edit-In-Place tables it can get a bit more challenging, so today we are going to look at a couple of different scenarios I have done in the past.
Let’s start with the simple stuff, in the below screen shot notice that the Send Ach Debit Transaction Checkbox is disabled if the payment type is ACH. This makes for a both a nice visual effect and also make it easier for the user to understand the relationship of the item.
The first question with WX is generally, where do I put my code. Well for this we put our code in the Displaying a row of Table, event. And you might expect the code to look something like this.
In fact the first time I tried it, that is exactly how I wrote it. However the challenge is that will disable the entire column not an individual row. Which can be handy if the user doesn’t have security rights to edit a particular field, but in that case you logic should be somewhere in the init code instead of firing on every row. With the code firing on every row, the column will switch from being enable or disabled based on the last row the table displayed.
It should be noted by the way, that Displaying a Row doesn’t mean what you may think. Displaying a row is the event fired when a row is first added to the table. Unless you do something to refresh that row, it isn’t fired again for that row, as you scroll up and down the table control. So if we were to scroll back up to the ACH entries the column would remain disabled.
So how do we tell it to disable a specific row? We address the row instead of the entire column. But again how? We much of the coding is similar to the coding for structured arrays. So to address a specific colum of a specfic row, the code is TableControl.ColumnName[Row#] . But how do you get the Row number? Well as is often the case with WX code, it depends.
If you have taken the normal defaults for setting up the table control it is quite easy. The table control itself contains the row number. So the code below is how we would code it.
Now as each row is displayed, the table control returns that row number, and our code works as expected. BTW notice, I didn’t have to include the TableName. in front of the column name, as long as you don’t have the same column name in two table controls on the save window, you can address the column name directly without having to prefix it with the TableName.
Remember I said this will only work if you have taken the defaults? What I was referring to is the “Stored item” on the content tab.
But things get interesting when you use something else for the stored item. And it seems that there are a lot of different conditions that may effect it. Unfortunately, I can’t find anything in the help that really maps it out either. So let’s take a look at a few different behaviors and the results.
The example we have been using is a File based browse and it is set to be loaded in memory, as you can see in the screen shot above.
If we changed the stored item to one of the other fields in the table, then TableControl or TableControl..Value returns the value of that item, instead of the Row Number. Often I will use this to return the primary key of the database table. To make it easier to see what is going on lets set it to PaymentType
Now I would expect, and my interpretation of Frenglish from the online help, we should be seeing “Check” or “ACH” as the value of the table control. But strangely enough in the display row code I still get the table row number instead. Placing this code in the Displaying a Row event
Gives us this trace. Which is definitely the Row Numbers, not the payment type.
And just to verify that stored item really is working. Placing the same code, on a button on the window. Indeed does return PaymentType as expected. As you can see in the last 2 lines of this trace.
But wait, just in case you are not confused enough already. Let’s look at my normal way of coding. Which means a table based on a class (or structured array). Generally when I code this way, I actually return the entire entry of the array as the stored item (in this case they call it stored variable). Like this.
On this type of table control, using TableControl or TableControl value always returns the value of the stored variable, even inside the Displaying a Row event. Again it is unclear to me from the online help if the File based table should behave differently in the Displaying a Row event, but even if it is a feature, its one that makes me nervous as I don’t like code that will return a completely different result based on where it is fired from. So lets look at a couple of different ways to handle this (and I use all of these depending on which way the wind is blowing that day)
First WX gives us a function that is perfect for this CurrentSubscript. That function returns the current row number for the current table. The only thing I don’t like about it is that instead of being able to pass the table name as a parameter as you can with all the other table functions, this one always references the “current table”. That could get messy if you have 2 table controls on the window and use the function in an event not specific for the table. But in our case we are using it in the Displaying a row event, so that will make our table the “current table” regardless. So we can use some code like this to get the job done.
Since one of the columns of the table control is the primary key we could use TableSeek to get the row number like so
The first parameter of TableSeek is the column to search, and the second column is the value to search for.
OK, well enough with that little detour. Back when we were talking about how to access a specific column of a specific row there was a little hint on yet another feature that could come in handy. What if you don’t want the user to be able to edit some rows at all, for instance they are system supplied defaults, etc. Simple enough, instead of referencing the column, we can just reference the row like so.
Which gives us this effect.
If you have users that complain about not being able to read the disabled rows, you could make them ReadOnlyNoSelection instead.
However its a trade off, because now there is no visual indicator that a row can’t be edited, they just are not able to select it.
And here is another little tip. You might think that we need to put some code in the combo box to enable or disable the check box when they chose Check or ACH during edit mode. But we don’t, because when the values of any of the columns are changed, the Displaying a Row event fires for that row, so our logic gets correctly fired there as well. This can be an important concept. Even if we change the value of a row from some other code, instead of the user doing it, the Display a Row Event will fire. For instance, we could but some code like this on a button, and see the checkbox being enabled and disabled automatically.
OK, so not the most useful code in the world, but the concept is a good one to understand, if you get into a situation where you have values being changed by external code, such as a background refresh process etc.
And before we wrap-up, how about a little bonus material? Not specific related to disabling fields, but a handy concept when dealing with Edit in Place. Let’s say the requirement is that the description has a default value, that is rarely changed, and is based on the payment type. Well we could put some code like this in the Selecting a Row of the combo box for payment type.
That code, checks to make sure the description is blank, because we do want to allow the user to change it if they want, and we don’t want to override anything they entered. But if it is blank, it sets the value base on the value of the combo box, and then presses the Tab key twice, Once to exit the combo, once to skip the description field. A very handy, and nice feature if your app involves a lot of data entry, making the users life a little easier will always be appreciated. And more importantly, give them less of an opportunity to mess up!
For another look at some tips and tricks for Edit in Place be sure to take a look at this article as well, WD Container Column (Table Control) used as a Lookup Button
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