Scroll bars in Table control have become disabled

RacingDog

Active Member
Licensed User
The program I am developing has a number of tables accessed via a Tab control. 4 or 5 days ago, the only one that needs the table's scroll bars was working fine. Since then I have added the rest of the code. Now the scroll bars are still there, but disabled. Given I have no direct access to the scroll bars via any method or property of a Table control, and in any case have no need to access them from the code, this is something of a mystery.

One of the recent additions is the tidy up code to disable the sundry table's events from doing anything whilst programatic changes to contents are being made. I first thought I may have messed that up, but a) I commented it out for that table and it made no difference, so I put it back; b) the table is otherwise working perfectly, I can scroll by selecting a cell and then using cursor keys and the data updating is working fine too.

So, it is literally just the scroll bars on this one table which are disabled, and I ain't touched those!

To find the table in the app, run it and just scroll the Tab bar once and select the Till tab. Then just look at the table with your eyes and it is obviously wrong. In the code the Table is called TillDetails.

As Paul Daniels says, you'll like this, but not a lot.

Any ideas chaps?
 

RacingDog

Active Member
Licensed User
Well I can try, but I would have called this trivially small compared to megabyte stuff people expected me to look at when I was working. I just got on with it, that is what I people expected of me.

A simple use of the search facility reveals that the table is accessed in only a few functions, hardly rocket science.

In any case, what do you want to know? I've already said I do nothing with the scroll bars because there is nothing anyone can do with them. What would you be looking for? Something you already know isn't there? Suppose it is the text size? Making things smaller would remove the problem.

Oh well, hang on, this me take a little while and there are other things to do tonight.
 

RacingDog

Active Member
Licensed User
OK try this, just hope I'm not too late for something else now, oh well.
 

Attachments

  • hacked.sbp
    10 KB · Views: 281

agraham

Expert
Licensed User
Longtime User
Well I can try, but I would have called this trivially small compared to megabyte stuff people expected me to look at when I was working. I just got on with it, that is what I people expected of me.
That is an incredibly arrogant statement, as though you think that this forum is obligated to find a solution for you and should just get on with it. If that is so trivially small compared with what you are used to you are obviously wonderfully talented and so should just get on and just fix it yourself without intervention by us lesser mortals.

I, and others, who provide support on this forum are doing so voluntarily and in our own time. I don't see why we should spend time wading through your code attempting to see what might be relevant to your problem when it is easier for you, who wrote that code, to strip it down to the essentials necessary to demonstrate the problem. It is an obvious courtesy to extend to those who might try to help. When I was running a team of over twenty programmers it is a practice that I would insist on before involving additional man-power to tackle a problem. It maximised efficiency and minimised the impact on others work.
 

agraham

Expert
Licensed User
Longtime User
I'm surprised that with all your experience of multi-megabyte stuff you couldn't work this out for yourself!

TillDetails.Enabled = False ' disables the ScrollBars

From the MSDN documentation of DataGrid which is what a Basic4ppc Table is based on.

"When a scrollable control is disabled, the scroll bars are also disabled. For example, a disabled multiline textbox is unable to scroll to display all the lines of text."

P.S. I found it by stripping back your hacked version even further till the problem went away. I've never used a Table in anger and didn't know that disabling it disabled any scrollbars.
 
Last edited:

klaus

Expert
Licensed User
Longtime User
I had also a look at this problem and found a 'strange' behaviour with the table control.
Changing a cell value when the Table is disabled, the scrollbars remain disabled even when the table is enabled again.
With this code the Table.ScrollBars remain disabled.
B4X:
[FONT=Courier New][SIZE=2][COLOR=#0000ff][FONT=Courier New][SIZE=2][COLOR=#0000ff][FONT=Courier New][SIZE=2][COLOR=#0000ff]Sub [/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][FONT=Courier New][SIZE=2]btnTest_Click[/SIZE][/FONT]
[SIZE=2][FONT=Courier New] Table1.Enabled=[/FONT][/SIZE][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800080][FONT=Courier New][SIZE=2][COLOR=#800080][FONT=Courier New][SIZE=2][COLOR=#800080]False[/COLOR][/SIZE][/FONT]
[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][FONT=Courier New][SIZE=2] Table1.Cell([/SIZE][/FONT][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000][FONT=Courier New][SIZE=2][COLOR=#800000][FONT=Courier New][SIZE=2][COLOR=#800000]"Test2"[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][FONT=Courier New][SIZE=2],[/SIZE][/FONT][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800080][FONT=Courier New][SIZE=2][COLOR=#800080][FONT=Courier New][SIZE=2][COLOR=#800080]1[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2][FONT=Courier New][SIZE=2])=[/SIZE][/FONT][/SIZE][/FONT][FONT=Courier New][SIZE=2][COLOR=#800000][FONT=Courier New][SIZE=2][COLOR=#800000][FONT=Courier New][SIZE=2][COLOR=#800000]"12"[/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT][/COLOR][/SIZE][/FONT]
[FONT=Courier New][SIZE=2][SIZE=2] Table1.Enabled=[/SIZE][/SIZE][/FONT][SIZE=2][COLOR=#800080][SIZE=2][COLOR=#800080][SIZE=2][FONT=Courier New][COLOR=#800080]True[/COLOR][/FONT][/SIZE]
[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2][COLOR=#0000ff][SIZE=2][COLOR=#0000ff][SIZE=2][FONT=Courier New][COLOR=#0000ff]End Sub[/COLOR][/FONT][/SIZE]
[/COLOR][/SIZE][/COLOR][/SIZE]
The Table can be enabled but NOT the ScrollBars.

Commenting out Table1.Cell("Test2",1)="12" it works.

Attached a sample program to show it.

Best regards.
 

Attachments

  • TestTableScrollbars.sbp
    1.1 KB · Views: 283

agraham

Expert
Licensed User
Longtime User
Playing further it seems the scrollbars return on the next assignment to a cell after setting Enable True again.

It looks like a bug in DataGrid. I've poked around in the DataGrid and DataTable CLR code but I can't see anything obviously amiss. However It's all a bit complicated as DataGrid is quite a clever (complicated!) multi-component control that can bind to data sources and do all sorts of ADO stuff.
 

RacingDog

Active Member
Licensed User
Ah, amid the hot air, somebody saw the point.

The code does not need to be understood, but simply used to trigger an underlying problem namely the Table and it's Scrollbars get out of step. These should never be in different enable/disabled states if the user has no access to the scroll bars. If they are different then the implementation of the control is wrong and needs looking at. That I presumed was obvious from my first post, I said look at the control with your eyes.

Of course I know that using the disable turns everything off, now who is being unecessarily insulting? That was never the problem being reported and the off hand, "oh the user is always wrong" presumption did not go down well. Did you not read the words to the effect that the control was otherwise behaving correctly? It was a rather important phrase to take on board. I was not reporting that the the Table was disabled, so the catty remark that presumed that I was reporting such was totally wide of the target.

The discrepency between the control and its subsidiary control was what was being reported. I'm afraid I got a bit cross at the assumption I was reporting a user error and the request to "please pointlessly strip down the code to reveal something that isn't there". It isn't there because it is in the control.

So sorry about getting angry, I had other things to attend to as I said, and it was already late in the evening, and to me it was blatantly obvious, just by looking at the screen that the problem was in the control, so I really rather thought it would be as blindingly obvious to everybody. Clearly not.

So let's all calm down and look at the real problem, a control which gets into an inconsistent internal state, which is clearly something I cannot look at because I don't have either the sources or the ide used to build the control, that is why I was reporting it.
 

RacingDog

Active Member
Licensed User
OOer, hang on, if this is a new observation, does that mean most people don't normally protect their event handlers from unwanted recursions and user interference? So for the benefit of those who wonder what on earth I was playing at in this code...... Those who already know, please ignore.

There are two reasons for my code making heavy use of the Enable property.

First, Windows has lots of other things running, whether as tasks or threads. This means that even the swiftest of event handlers can be slugged by other software such that the user has time to interact. This means the state to which you are responding can be changed mid way through handling it. That is unstable. It won't happen often, but it can happen and give you one of those, "but it usually works" seriously hard to find bugs.

Second, disabling a control doesn't stop it producing messages (events in IDE speak) in response to programmatic changes hence you can get unwanted calls to your event handlers, which can similarly destroy the state you are in the middle of handling. It also can cause recursion. If those recursions are unwanted then at best you are slowing down your software, at worst it can fail to terminate and hang and/or crash your software. Now you can use your own flag to control this, but if you already know that you will be using the Enable property because of the first point, then you can shave a resource requirement and use that as the controling flag. This program of mine would misbehave without those checks. I know 'cos I forgot some of them to start with and hence saw it happen. Doh! I really should have known better. That's what happens when you become rusty due to not programming for a few years. It's grim reading health that stopped me, so don't depress yourselves by asking, not that I mind though.

Sometimes you can dispense with the checks, or at least limit where events are allowed, and make use of the internally produced events, but it is always best to keep the user out when tinkering with that which he can see.

OK. Those who skipped this can wake up again now. :)
 

agraham

Expert
Licensed User
Longtime User
It's not necessary to disable the Table. Lots of other people have used it for several years without finding the need to do so. Basic4ppc is a single threaded .NET process. All code runs on the GUI thread and the message loop is only re-entered when the code terminates so there is no possibility of re-entrancy.

There are only two occasions when re-entrancy to a Basic4ppc event Sub can occur. Firstly if the Sub calls DoEvents which in turn calls the message loop to process outstanding messages, and secondly if the event Sub raises a MsgBox as the message box pumps the message loop to get its GUI events. Timers cannot cause re-entrancy as they are run on the GUI thread in response to messages received on the message loop. I know of no other thing that can cause re-entrancy in normal Basic4ppc code and I know quite a lot about Basic4ppc internals and re-entrancy as my Threading library will work in both the interpreted IDE as well as when compiled.
 

RacingDog

Active Member
Licensed User
I wasn't just thinking of recursion by re-entry. It can happen mutually too (via two event handlers). But if anything recurs that is a worst case. You can still get unwanted events. That is more common and just as much a nuisance.

Take my full source. Put breakpoints on the first code lines (if statements) of Sales_SelectionChanged and SalesCell_ValueChanged. Now run. Select the Sales tab. You will now hit the first breakpoint. Press F10. It takes you back to a line in Tabs_SelectionChanged. The line above is the culprit a call to SelectCell. I only want user selections to cause any processing, so it is essental to trap this.

F5. Click the button This. You now hit the second breakpoint. F5 till it runs again.. Select the top left cell. F5. Spin the spinner up 1. F5. Now select the empty cell in the middle of the top line. 1st bp. F5 and we are where? Second bp. F10. The lines above show that the assignment to Value is the culprit. Again processing is not required at this time, only when the user does it.

So, two jumps from Event Handler to Event Handler. In other words a message being generated and handled whilst a first message is being handled. Given what you just said about B4PPC, that implies a DoEvents inside these controls? Yes/no/maybe?

I tried taking out the first breakpoint to see if selecting a cell under Start on a lower row did anything. Sure enough, I ended up at the second bp. So I wasn't being mislead by the fact of using the debugger which might have been a cause of the program being stopped and therefore eligible for message processing.

Whatever, without going through the whole proggy, just trust me when I say for all cases in this program, programatic changes are not required to cause processing, only those made by the user are to be processed. That wasn't happening, I had to force it to happen.

But remember, the real use of disable is to stop user interaction during slow processing. You have to see my old laptop when my flakey wireless connection is playing up. You could play a game of speed chess sometimes! Other systems are nowhere near as bad, but they still have their moments. The use of disable as a flag is just piggy-backed on top of that. Two birds with one stone and all that.

Incedently, some of the program complexity was caused by only having a ValueChange event for the up/down control. It would have been simpler with the SpinUp/SpinDown events seen in other environments as there are differing types of end conditions to cater for.
 

agraham

Expert
Licensed User
Longtime User
So, two jumps from Event Handler to Event Handler. In other words a message being generated and handled whilst a first message is being handled. Given what you just said about B4PPC, that implies a DoEvents inside these controls? Yes/no/maybe?
No. Not all events are necessarily triggered by a call from the message loop. One message being processed can cause another call directly to other Windows Procedures, most commonly by a native code SendMessage API call within the message processing code, which in turn raises a Basic4ppc event. But all the code is being run sequentially on the main GUI thread of the application without interruption (apparently! as obviously the system is time slicing all the time but a single process is unaware of this - and let's not get into the threading tricks the .NET Garbage Collector does to ensure safe checkpointing of CLR code so it can reclaim unused memory, it's very interesting, nay fascinating, but a bit arcane).
 

RacingDog

Active Member
Licensed User
Well, yeah, SendMessage was always the standard way of blowing the basic loop model.

Basically, however it is done underneath, the Events model user sees events which give the appearance of being interruptable by other events because no direct call is made by the user, regardless of whether the lower system sees it as not being an interrupt.

***************

Just to give an insight, this app is to be used on a small preserved railway with just two stations. I've been doing the same thing on the laptop using a separate app for the price setting part in Delphi and the rest in an Excel spreadsheet which had lots of controls, but could also be used as the Ticket Returns form, by hiding everything and printing the basic layout. The app went to meetings, the sheet to the ticket office.

Then I transfered the app to the mobile pc by rewriting in B4PPC as this was more convenient for me to take to meetings (less to carry; longer battery life). And there it should have rested. But now I can't lift things for any distance, so I want to do it all on the mobile pc or a phone, I can always write out ticket forms manually later from the collected data. Less convenient but needs must.

Some of the non-standard requirements that other B4PPC users won't have is for example, tickets are numbered with 4 digits, so you have to handle the day the numbers wrap around. Also, to allow corrections of mistakes in tickets sold, the spin down not only has to stop when you get down to your starting number (ie 1 sale) but also has to go blank for 0 sales, otherwise it gets seriously confusing having meaningless numbers displayed. And of course depending on where you've got to in day and the initial options, some things have to be selectable on the tables some of the time but not others. Other items are never input but are calculated despite appearing on the same table as input items. The displays would fragment (visually) too much were this not so.

So that's what all the "ess aitch one tee" in the app is about and why it is not entirely as other apps. But the individual little bits are all trivial, there's no complex computing, the complexity lies in controlling what the user can do and what he sees, which needs being accurate, complexity is really the wrong word.

Hope that helps.

*************

But anyway, we are (ok I am) off topic. The basic problem is this inconsistency inside the table control. I don't know from where I'm sitting whether that is how it is wrapped by B4PPC or an effect of .net. I've not seen this problem with grids not living with .net, but that may not prove much.
 

RacingDog

Active Member
Licensed User
OK, I know when I'm beat. Even if that gets reported to MS, it will be ages before we see a fix, so I've changed the code. Access to critical events is now controlled by a global boolean and I only use Enable where it absolutely has to be used.
 

klaus

Expert
Licensed User
Longtime User
As agraham reported in post #8, when a cell is accessed after the enabling the table scrollbars are enabled.
So you could use this workaround to make your code running as you expected.​
B4X:
   TillDetails.Enabled = True
   TillDetails.Cell ( ValueStr, 0 ) = TillDetails.Cell ( ValueStr, 0 )

Best regards.
 

RacingDog

Active Member
Licensed User
Hah, I could yes, but it reminds me of the time I deliberately put a NOP instruction into an assembly code module with a comment do not remove. I didn't say why as I figured anyone who was dumb enough to ignore the warning deserved the extremely obscure multi-task timing bug it fudged around. One of those is enough for one lifetime :D
 
Top