Changing tab order of controls while running

Woinowski

Active Member
Licensed User
Longtime User
I know how to change the tab order of controls in the designer (send to back), but I have an application with some runtime generated controls.

Interestingly, the tab order is just the reverse of the generation order, which is slightly annoying (it would mean to use a For/Next Loop with STEP - 1 to get it all in the right order ;-)

Therefore it would be very nice to be able to manipulate the tab order differently. Is this possible?
 

Cableguy

Expert
Licensed User
Longtime User
You can use the lostfocus event to make the next control gain focus in the order you want...
 

Woinowski

Active Member
Licensed User
Longtime User
Nice idea ...

... although a little bit like shooting yourself in the foot :sign0162:
 

Cableguy

Expert
Licensed User
Longtime User
I don't really understand you'r comment...
You say it's a nice idea, but a bit like shooting yourself in the foot, why? it gets the job done...
Another way is to edit the spb file and invert the order of the control-creators code...
 

willisgt

Active Member
Licensed User
I'm having the same issue - a program which creates a great many controls dynamically, which really screws up the tab order. In my case, I always want the tab order to be the same, so I could potentially use Cableguy's idea of using the lostFocus event.

Woinowski, it sounds as though you want to be able to manipulate the tab order any way you want. I haven't tried this one yet (probably will this weekend), but it might work...

Put an ArrayList on your form. Every time you create a control dynamically, put the name of the control into the list. When you're finished creating controls, run through all of the items in the array list and do something like:

B4X:
sub form1_SetTabOrder
   For i = 0 to ArrayList1.Count - 1
      Control( ArrayList1.Item(i) ).BringToFront
   Next
end sub

You could alter the tab order by removing items from and inserting items into the array list; just be sure to call the subroutine again when you're done changing the contents of the list.

Like I say, I haven't tried this one yet.

Gary
 

Woinowski

Active Member
Licensed User
Longtime User
Why I think these solutions are strange

Simple: Setting Focus according to tab order is something that can be handled perfectly well by the Framework (CF) or the Operating System (Windows [Mobile]).

Also, it should be done this way.

Faking (overriding) a tab order by catching events is something only real programmers do. :sign0060: Have a look at this http://www.pbm.com/~lindahl/real.programmers.html

Probably you understand why I think this is shooting yourself into the foot. Hopefully, you haven't been offended by my answer.

PS: Feels also a little bit like back in the good old VIC 20 times. :cool:
 

agraham

Expert
Licensed User
Longtime User
http://www.pbm.com/~lindahl/real.programmers.html

PS: Feels also a little bit like back in the good old VIC 20 times. :cool:
Thanks for the link, I remember when that was published though I haven't seen it for years, nor the story of Mel. I have saved them to show and explain the to a younger generation! As you and I, apparently being of a certain age, know there is MORE than an element of truth in those tales of the early days.

PS: TRS80-Model 1's set me off. - My brother was into Commodore Pets. Those machines set off the Motorola approach vs the Intel approach schism that persists in some form to this very day.
 

willisgt

Active Member
Licensed User
A problem with my approach...

I finally got around to trying the solution I suggested (placing the names of the controls in an arrayList, running through the list, and using .bringToFront to set the tab order).

The form this is called from contains a control called 'arrayFormMedsTabOrder'.

Here's the relevant code:

B4X:
sub formMeds_Show

   ...

      arrayFormMedsTabOrder.Add( "formMedsHeader" )
      arrayFormMedsTabOrder.Add( "labelMedsNDC" )
      arrayFormMedsTabOrder.Add( "textMedsNDCLabeler" )
      arrayFormMedsTabOrder.Add( "labelMedsNDCSep" )
      arrayFormMedsTabOrder.Add( "textMedsNDCProduct" )
      arrayFormMedsTabOrder.Add( "labelMedsProduct" )
      arrayFormMedsTabOrder.Add( "textMedsProduct" )
      arrayFormMedsTabOrder.Add( "btnMedsSearch" )
      arrayFormMedsTabOrder.Add( "labelMedsGeneric" )
      arrayFormMedsTabOrder.Add( "textMedsGeneric" )
      arrayFormMedsTabOrder.Add( "btnMedsClear" )
      arrayFormMedsTabOrder.Add( "labelMedsDose" )
      arrayFormMedsTabOrder.Add( "textMedsDose" )
      arrayFormMedsTabOrder.Add( "labelMedsRoute" )
      arrayFormMedsTabOrder.Add( "comboMedsRoute" )
      arrayFormMedsTabOrder.Add( "labelMedsFrequency" )
      arrayFormMedsTabOrder.Add( "textMedsFrequency" )
      arrayFormMedsTabOrder.Add( "labelMedsDiagnosis" )
      arrayFormMedsTabOrder.Add( "textMedsDiagnosis" )
      arrayFormMedsTabOrder.Add( "btnMedsDXSearch" )
      arrayFormMedsTabOrder.Add( "btnMedsPrev" )
      arrayFormMedsTabOrder.Add( "btnMedsNext" )
      arrayFormMedsTabOrder.Add( "btnMedsMenu" )

      setFormTabOrder( "formMeds" )

   ...

end sub

and...

B4X:
Sub setFormTabOrder( pArray )

   ctl = "array" & pArray & "TabOrder"
   
   For x = 0 To Control( ctl, ArrayList ).Count - 1
      Control( Control( ctl, ArrayList ).Item( x ) ).BringToFront
   Next

End Sub

The code produces no errors, but does not produce the desired tab order. In one place, it jumps halfway through the list; in another, it tabs backwards (relative to what I expect). It works properly on about the last half of the list.

Anyone have any ideas?

:sign0163:

Gary

(I finally have a free weekend, so I'll have to spend some of it dusting off my TRS-80, Atari 2600, or maybe the Exidy Sorcerer... ) :)
 
Last edited:

willisgt

Active Member
Licensed User
I removed all the labels from the list. Changing the code to:

B4X:
      arrayFormMedsTabOrder.Add( "textMedsNDCLabeler" )
      arrayFormMedsTabOrder.Add( "textMedsNDCProduct" )
      arrayFormMedsTabOrder.Add( "textMedsProduct" )
      arrayFormMedsTabOrder.Add( "btnMedsSearch" )
      arrayFormMedsTabOrder.Add( "textMedsGeneric" )
      arrayFormMedsTabOrder.Add( "btnMedsClear" )
      arrayFormMedsTabOrder.Add( "textMedsDose" )
      arrayFormMedsTabOrder.Add( "comboMedsRoute" )
      arrayFormMedsTabOrder.Add( "textMedsFrequency" )
      arrayFormMedsTabOrder.Add( "textMedsDiagnosis" )
      arrayFormMedsTabOrder.Add( "textMedsDiagnosisDesc" )
      arrayFormMedsTabOrder.Add( "btnMedsDXSearch" )
      arrayFormMedsTabOrder.Add( "btnMedsPrev" )
      arrayFormMedsTabOrder.Add( "btnMedsNext" )
      arrayFormMedsTabOrder.Add( "btnMedsMenu" )

did not change the tab order. :sign0148:

The behavior is the same whether I'm just running the code (F5), or a compiled executable.

I've got to be missing something really simple here...

Gary
 

willisgt

Active Member
Licensed User
I've copied the relevant code into the attached example. It behaves exactly the same way as the larger application it was copied out of.

Thanks for taking the time to look at this...

Gary
 

david

Member
Licensed User
Actuallly, I don't think you are missing anything simple.

I have been doing work on a Wasp 3200 bar code device. I have to account for bar code input, key board input and sip input.

In addition, I have to move the user back and forth between fields on lost focus events where I encounter errors.

The primary spec. called for me to move the user around based upon hitting the enter key. That is relatively easy, but once you start adding error messages, on lost focus events and sometimes on key enter events, you start to get weird results.

The particularly application that gave me the most trouble has 29 fields laid out on one screen but on various panels that I expose or hide depending upon the runtime data entry.

I can get it to work perfectly when I create a windows executable, only to have it fail on the device side. Eventually, I used global error flags to keep track of where I was and how the application should respond.

My particular problems seem to be the result of timing that varies from the windows executable (where I do my initial testing) to the finished product on the device.

My conclusion is that it is entirely a Windows .Net problem. It has nothing to do with Basic4PPC (which I think is a wonderful development platform). My application ended working well, but with over 4,000 lines of code.

If you remember, Sun Micro Systems Java advertisements, "Write Once Run Anywhere" and if you ever tried to implement that on multiple platforms, you will know that the slogan was true only if you didn't care which window appeared first or how the various dialogs appeared. I think Microsoft is coming up against the same problem. They will never admit it. They will just leave developers to think they are missing "something really simple".

Good Luck.

Regards,

David
P.S. I really do love Basic4PPC. However, Erel still must work within the confines of .NET. Don't blame him or the product. Just bear in mind that Basic4PPC is years ahead of Microsoft's own Visual Studio products for hand held development.
 

willisgt

Active Member
Licensed User
David, I'm curious to know more about your approach to this problem. How exactly did you make use of globals to solve the problem?

In this case, the form is static and I can use .lostFocus to direct input to the next field. However, much of this application uses forms where the controls are generated dynamically. LostFocus gets a little dicey on those forms.

So, while I'm hoping to resolve the problem with the code I posted (as it would solve my problem in all cases), I'm looking for alternatives in case it can't be resolved.

This program gets released to our clients on Wednesday, whether the tab order is correct or not.

:sign0082:

Gary
 

agraham

Expert
Licensed User
Longtime User
I've played with this now and yes, the tab order doesn't get set properly at runtime. However in the help BringToFront is only documented as setting the Z-order, i.e. the visible layering and not the tab order. It seems to be an unwarranted assumption that because BringToFront and SendToBack seem to affect both Z-order and Tab-Order in the Designer then BringToFront at runtime will do both as well.

You probably know this, but in case others reading this are unaware of it, where the controls are created at design time you can get the tab order you want by selecting the controls by turn in the tab order you want and selecting SendToBack for each one. Whether this is by design, as it is not documented, or a welcome side effect I don't know.

Perhaps Erel will comment if he catches this post?
 

agraham

Expert
Licensed User
Longtime User
You could try playing with this library. No guarantees that it will always work. Only works in optimised compile mode - will warn otherwise.

B4X:
 TabOrder.New1(B4PObject(1),TabControlNames(),NumOfControls)

Invoke it as above passing an array of the controls in the required tab order together with how many of them are in the array. If you don't pass all the tabbable controls on a form then you may get odd results.

Version of your example enclosed that tabs properly. I've hacked the library into it - you will want to tidy it up.
 

willisgt

Active Member
Licensed User
Very cool - it does exactly what I need!

Naturally, this is something I ( and probably more than a few others ) would like to see incorporated into, say, ControlsEX.dll.

Thanks again for taking time to look at this!

Gary
 

Cableguy

Expert
Licensed User
Longtime User
All this can be very easely avoided if we can do 2 "simple" things:

1-Plan better our apps and the controls we wich to incorporate...and create/place them at runtime in the inverse order, we wich the tabs to be...
2-Edit or create an automated (app) editing tool to re-write the control creation lines in the .b4p file.

Still I set back and was hopping to see what Agrahams aproch would bring, results wise, and as I espected, only the z-order gets changed...
This is a very common confusion...z-orde=tab order? = FALSE...
So now, and using the words of david:
"In addition, I have to move the user back and forth between fields on lost focus events where I encounter errors."

Wich takes me to my first reply to this thread...
 

agraham

Expert
Licensed User
Longtime User
Still I set back and was hopping to see what Agrahams aproch would bring, results wise, and as I espected, only the z-order gets changed
Sorry Cableguy - I DO understand the differences between tab order and z-order as is clear from my post #15. It IS the tab order that my little library sets. In fact it sets the TabIndex property for each control given to it in the order in which they are placed in the array and obviously works for me and Gary. It needs a library as this property is not available in B4PPC. Why do you think it is setting the z-order?
 

Cableguy

Expert
Licensed User
Longtime User
I was not refering to your DLL, but to the array/bringtofront aproach...
Sorry if I was somewhat missunderstood...

Still, if the only need is to invert the tab-order, a simple "batch" app would fullfill the need, editing the spb file, and reversing the object creation order..
Your DLL is very usefull, and this feature is also handy if one set the control in an non-inverted tab order....
 
Top