View Full Version : Problems Using TAB Key And Focussing On Text Boxes
gungadout
21-10-2010, 08:38
Hi Folks,
I'm still having strife with the TAB key.
I think I need to control its function manually.
I am unsure how to detect a Tab key press and an Enter key press. Clues, please?
Also, I am successfully detecting %EN_KILLFOCUS and %EN_SETFOCUS when moving between text boxes. I display a message in a label field (used as a message area to the operator) as each event is detected. I'm finding that when I click on a new text box, I get different responses at different times:
- when the window first appears, only one click is required to set focus on a text box (flashing vertical line);
- on any subsequent text box (as I am testing now) the first click does nothing; a second click is required to shift focus; the second click can be some seconds after the first; (it is not a double click);
- if I click on a button, then on a text box, focus is obtained on the first click; two clicks are needed on the next box;
- if I give focus to something else, say Windows Explorer, then give focus back to the thinBasic window, only one click is needed on the first text box clicked to get focus; subsequent text boxes need the two clicks again;
- if I click anywhere in the thinBasic window, then on a text box, focus is obtained immediately.
However, once focus is obtained in a particular text box (and the text entry vertical line is flashing), I need to click in the box another time before typing is accepted. During that limbo time, the cursor remains as an arrow, no matter where in the window it is. Once the required extra click is made, whether or not text is actually entered, a single click is all that is required to transfer focus to a new text box. A subsequent click is required for actual data entry, but.
I don't think that is normal behaviour. I must be doing something wrong. Is my display of messages in a label, relating to %EN_KILLFOCUS and %EN_SETFOCUS, causing the problem? If so, how can I overcome it? I will definitely need to display messages for the operator at times, related to those events.
All suggestions welcome.
Thanks,
Peter H.
Petr Schreiber
21-10-2010, 08:53
Hi Peter,
does your problem occur in this example as well? Are you using version 1.8.6.0:
#minVersion 1.8.6.0
Uses "UI"
' -- ID numbers of controls
Begin ControlID
%lLabel
%lLabel2
%tbTextbox
%tbTextbox2
%bClose
End ControlID
' -- Create dialog here
Function TBMain()
Local hDlg As DWord
Dialog New 0, "Message test",-1,-1, 160, 120, _
%WS_POPUP Or %WS_VISIBLE Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX To hDlg
' -- Place controls here
Control Add Label, hDlg, %lLabel, "", 5, 5, 150, 14, %SS_CENTER Or %SS_CENTERIMAGE Or %WS_BORDER
Control Add Textbox, hDlg, %tbTextbox, "", 5, 20, 150, 14, Call tbTextboxCallback
Control Add Label, hDlg, %lLabel2, "", 5, 35, 150, 14, %SS_CENTER Or %SS_CENTERIMAGE Or %WS_BORDER
Control Add Textbox, hDlg, %tbTextbox2, "", 5, 50, 150, 14, Call tbTextboxCallback2
Control Add Button, hDlg, %bClose, "Click to close", 5, 100, 150, 14, Call cbCloseCallback
Dialog Show Modal hDlg, Call cbDialog
End Function
' -- Callback for dialog
CallBack Function cbDialog()
' -- Test for messages
Select Case CBMSG
Case %WM_INITDIALOG
' -- Put code to be executed after dialog creation here
Case %WM_COMMAND
' -- You can handle controls here
'SELECT CASE CBCTL
'
' CASE ...
' IF CBCTLMSG = ... THEN
'
' END IF
'
'END SELECT
Case %WM_CLOSE
' -- Put code to be executed before dialog end here
End Select
End Function
' -- Callback for close button
CallBack Function cbCloseCallback()
If CBMSG = %WM_COMMAND Then
If CBCTLMSG = %BN_CLICKED Then
' -- Closes the dialog
Dialog End CBHNDL
End If
End If
End Function
CallBack Function tbTextboxCallback()
If CBMSG = %WM_COMMAND Then
Dim idControl As Long = %lLabel
Select Case CBCTLMSG
Case %EN_CHANGE
Control Set Text CBHNDL, idControl, "%EN_CHANGE"
Case %EN_ERRSPACE
Control Set Text CBHNDL, idControl, "%EN_ERRSPACE"
Case %EN_HSCROLL
Control Set Text CBHNDL, idControl, "%EN_HSCROLL"
Case %EN_KILLFOCUS
Control Set Text CBHNDL, idControl, "%EN_KILLFOCUS"
Case %EN_MAXTEXT
Control Set Text CBHNDL, idControl, "%EN_MAXTEXT"
Case %EN_SETFOCUS
Control Set Text CBHNDL, idControl, "%EN_SETFOCUS"
Case %EN_UPDATE
Control Set Text CBHNDL, idControl, "%EN_UPDATE"
Case %EN_VSCROLL
Control Set Text CBHNDL, idControl, "%EN_VSCROLL"
End Select
End If
End Function
CallBack Function tbTextboxCallback2()
If CBMSG = %WM_COMMAND Then
Dim idControl As Long = %lLabel2
Select Case CBCTLMSG
Case %EN_CHANGE
Control Set Text CBHNDL, idControl, "%EN_CHANGE"
Case %EN_ERRSPACE
Control Set Text CBHNDL, idControl, "%EN_ERRSPACE"
Case %EN_HSCROLL
Control Set Text CBHNDL, idControl, "%EN_HSCROLL"
Case %EN_KILLFOCUS
Control Set Text CBHNDL, idControl, "%EN_KILLFOCUS"
Case %EN_MAXTEXT
Control Set Text CBHNDL, idControl, "%EN_MAXTEXT"
Case %EN_SETFOCUS
Control Set Text CBHNDL, idControl, "%EN_SETFOCUS"
Case %EN_UPDATE
Control Set Text CBHNDL, idControl, "%EN_UPDATE"
Case %EN_VSCROLL
Control Set Text CBHNDL, idControl, "%EN_VSCROLL"
End Select
End If
End Function
Thanks,
Petr
gungadout
26-10-2010, 08:04
Hi Petr,
Thanks for your continued help.
Sorry for the delay in replying. My attention had to be on other things for a while, and I wanted to do more testing.
I am using version 1.8.0.0. I commented out the line "#MINVERSION 1.8.6.0" because of that.
Your example worked perfectly even in 1.8.0.0.
I kept playing around, and the tabs now work as they should.
I have three considerations to deal with now.
Firstly, I have set the text boxes to send notifications when focus is gained or lost. My problem is, that I have a Exit button on the screen. When it is clicked, the screen should drop everything and disappear (the menu screen should reappearwith no further ado). Naturally and correctly, when I click on the Exit button, the %EN_KILLFOCUS response for the current text box is triggered first. The normal processing associated with the %EN_KILLFOCUS needs to be bypassed, if the Exit button has been pressed. Is there any way, when in the logic for the %EN_KILLFOCUS response, that I can detect that the %EN_KILLFOCUS was triggered by a click on the particular button?
Secondly, I often wish to treat Enter key presses as though they were Tab presses. I think I saw an example of how to do that in my early days, but I cannot track it down. Would you please point me in the right direction.
Thirdly, some logic which used to work has stopped working, and I'm not sure why. It is associated with a Dialog End.
Selected code follows.
.
.
.
'---- hdlgCurrentScreen is the current screen number.
'---- when we get here, a selection has been made from the menu and verified as runnable.
'---- The screen with all its controls, has been defined.
'
Win_Show(hDlgMenu, %SW_HIDE)
'
'---- the menu goes away as it should
'
Dialog Show Modal hDlgCurrentScreen, Call cbDialogScreen
'
'---- the screen displays as expected. this is where the tabs are now working, etc.
'---- however, now, the menu is not redisplayed as it used to be. everything just disappears. the menu screen never '---- comes back, and in the Windows Task Manager, the thinBasic session has disappeared.
'---- neither of the MsgBoxes below appear, either. they were added afer the trouble started as debugging aids.
'
MsgBox(0,"CreateScreenDisplay - Back from Dialog Show Modal - hDlgCurrentScreen = " + hDlgCurrentScreen)
Win_Show(hDlgMenu, %SW_SHOW)
MsgBox(0,"CreateScreenDisplay - Back from Dialog Show Modal - hDlgCurrentScreen = " + hDlgCurrentScreen)
.
.
.
CallBack Function cbDialogScreen()
Select Case Callback_Message ' Callback_Message = CBMSG
Case %WM_COMMAND ' PEH this checks if it is an ordinary command, like a button press.
ScreenFieldNumber = Callback_Control
ThisControlNo = Callback_Control
ScreenFieldMessage = CBCTLMSG ' CBCTLMSG = Callback_Control_Message
.
.
.
'---- some variables used below are evaluated here
.
.
.
If FieldType = "B" Then ' was a button clicked?
Select Case ButtonText
Case "Exit"
Control Set Text hDlgCurrentScreen, lblStatusLine, "Exit Button Pressed = " + ButtonResponse + " " + CurrentScreenNumber
Sleep 2000
'---- the Control Set Text above shows that the Exit button was detected.
SendResult = TCP_Send(TCPFreeFile, "@(BR@\EX&BR)@" + $CR) ' this used to be below the Dialog End. ' 'moved as a test after things went strange.
Dialog End hDlgCurrentScreen
Case "File"
SendResult = TCP_Send(TCPFreeFile, "@(BR@\FI@BR)@" + $CR)
Case "Delete"
SendResult = TCP_Send(TCPFreeFile, "@(BR@\FD@BR)@" + $CR)
Case Else
Control Set Text hDlgCurrentScreen, lblStatusLine, "Button Clicked = " + ButtonNo + " " + ButtonText + " " + ButtonResponse
Sleep 2000
SendResult = TCP_Send(TCPFreeFile, "@(BR@" + ButtonResponse + "@BR)@" + $CR)
'---- the Control Set Text above shows that a click on a general button is detected properly, too.
.
.
.
End Select
End If
.
.
.
'---- %EN_SETFOCUS and %EN_KILLFOCUS are successfully handled here.
.
.
.
Case %WM_CLOSE
SendResult = TCP_Send(TCPFreeFile, "\EX" + $CR)
Dialog End hDlgCurrentScreen
'---- this now fails too, in the same way as the Exit button.
'---- the Exit button (above) and %WM_CLOSE fail even if they are the first thing clicked on.
End Select
End Function
Everything was going well in this regard up until now. Is there anything obvious that stands out?
Thanks in advance,
Peter H.
Petr Schreiber
26-10-2010, 09:04
Hi Peter,
all the messages flowing to controls are fired by Windows, so it is quite complex to completely ignore them.
The kill focus message for textbox is fired before we even register any message for the button being clicked.
So going over this would be about predicting the future :)
If something occurs in your app once textbox looses focus, maybe it will need to be done differentely, no other solution occurs to me.
Regarding TAB key - again, Windows eats this key, as it is used to jump between the controls. Regarding ENTER, we are more lucky.
It is enough to create button, where the control ID will be pre-defined %IDOK, and it should be clicked every time you hit enter.
There is nothing strange in your code, but maybe some parts are mysterious a bit. For example, how do you detect the FieldType?
I also do not see much of message filtering - for buttons for example BN_CLICKED. It seems you react to any message, but I might be wrong.
Petr
gungadout
26-10-2010, 11:21
Thanks for the tips, Petr.
I may have to stop using the %EN_KILLFOCUS response, and keep a record of each control number as it receives focus (by detecting %EN_SETFOCUS). I will then know the number of the control losing focus when a button is clicked. I can bypass the associated "lost focus" processing if the button is the Exit button, and manually invoke it otherwise.
I will try %IDOK.
Re FieldType. As screen construction parameters are sent from the database, I keep delimited arrays of field-related (control-related) information. FieldType data (T = text box, B = button, L = label, etc.) is kept in one of those arrays. I originally had 30 predefined possible text boxes, 10 possible buttons, etc., allowing up to 30 text boxes etc. to be defined on any given screen. However, I changed from predefined control numbers to flexible arrays in case the discontinuous ranges (less than 30 text boxes actually used, less than 10 buttons actually used, etc.) were contributing to the Tab problem I was experiencing.
I excluded all that array handling code from what I posted because I did not want to overwhelm you with extraneous stuff. The Control Set Text displays show that I am doing the right thing. Remember the Locate and CustomParseSet$ functions you coded for me? I have found them invaluable.
You are correct about my not using message filtering in a more standard way. There is probably madness in my method, and that would be due at least in part to my inexperience with message handling. My philosophy so far (right or wrong) has been to check for %WM_COMMAND and then to check if the control is a button or a text box (grids etc. to come later). Depending on the type of control, I then test for those message types that are of interest.
The sudden non-return to the menu screen still has me stymied. I'll just have to keep playing until it goes away.
Thanks again for all your help.
Regards,
Peter H.
gungadout
27-10-2010, 07:59
Hi Petr,
FYI.
I have done a lot of experimenting.
This is the only combination that works.
Select Case ButtonText
Case "Exit"
SendResult = TCP_Send(TCPFreeFile, "@(BR@\EX&BR)@" + $CR) '**** add @(BR@ etc ****
' Dialog End hDlgCurrentScreen
' Exit Function
' ScreenExitFlag = 1
Control Set Text hDlgCurrentScreen, lblStatusLine, "Exit Button Pressed = " + ButtonResponse + " " + CurrentScreenNumber + " " + Format$(ScreenExitFlag)
Sleep 2000
' exit function
Dialog End hDlgCurrentScreen
.
.
.
Case %WM_CLOSE
' -- Add here some de-initialization if needed
SendResult = TCP_Send(TCPFreeFile, "\EX" + $CR)
' Dialog End hDlgCurrentScreen
' ScreenExitFlag = 1
Exit Function
End Select
If ScreenExitFlag = 1 Then
Exit Function
' Dialog End hDlgCurrentScreen
End If
Notes.
1. Setting "ScreenExitFlag = 1" in "Case %WM_CLOSE" and commenting "Exit Function" out, also works, but is logically the same as the working example.
2. Setting "ScreenExitFlag = 1" in 'Case "Exit"' and commenting "Dialog End hDlgCurrentScreen" out, does not work, neither with "Exit Function" nor with "Dialog End hDlgCurrentScreen" active in the "If ScreenExitFlag = 1 Then" test. It seems that the value of "ScreenExitFlag = 1" is lost, even though it is not evaluated anywhere else after that.
3. In "Case %WM_CLOSE", activating "Dialog End hDlgCurrentScreen" and commenting "Exit Function" out, causes the "Dialog End hDlgCurrentScreen" in 'Case "Exit"' to fail (as well as "Case %WM_CLOSE"). Reversing that change results in the "Dialog End hDlgCurrentScreen" in 'Case "Exit"' working again.
4. In 'Case "Exit"', activating "exit function" and commenting "Dialog End hDlgCurrentScreen" out, causes failure.
5. By failure, I mean the whole thinBasic session simply disappears. The return to the menu screen is bypassed.
6. I know that the presence and positioning of the "If ScreenExitFlag = 1 Then" test is probably not good practice. It was put there for testing purposes only, but it may be instructive considering note 2.
7. My lack of knowledge makes me wonder why "Dialog End hDlgCurrentScreen" is required in one case, and "Exit Function" is required in the other. Commenting the "Control Set Text" and "Sleep" statements out, makes no difference.
No worries. It is working. That will do me. This was just information for you, in case it held some significance.
Regards,
Peter H.
Petr Schreiber
28-10-2010, 14:37
Hi Peter,
thanks for the info. I am not yet sure what could be the cause of sometimes mysterious behavior.
Any further details would help.
Petr