Post by Rod on Nov 29, 2022 13:29:05 GMT
Ok, this is from a recent discussion about why the ENTER key does not move you from one textbox to the next and why you don't get an event from a textbox.
The way a computer operator is trained on a typical Windows machine is to key TAB to move focus from textbox to textbox and subsequently the ENTER button allowing the operator to then press ENTER to complete the form. Operators like to keep their fingers on the keys, so this scheme allows them to complete a form without touching the mouse.
Now BASIC attracts a lot of recreational programmers who are untrained in the ways of Windows. They immediately complain that ENTER should complete a textbox and move on, but they never explain how ENTER should then be used to complete the form.
In this example ENTER or TAB will move you from textbox to textbox, Ctrl+ENTER will complete the form and you can click with the mouse as well. These dummy textboxes allow color change, highlighting with mouse or keys, copy, paste, delete, insert, backspace etc.
They do most things a textbox does but there are a couple of restrictions. Firstly fixed width font, secondly they don't coexist with other controls so best for purely textual input forms. I don't really like color input but it is often requested so its in too.
If nothing else this code will give you more respect for our humble native textbox.
The next step would be to show how to mask and verify the input character by character but I will wait and see if any interest is expressed.
Me? I stick to normal textboxes and play by the rules.
The way a computer operator is trained on a typical Windows machine is to key TAB to move focus from textbox to textbox and subsequently the ENTER button allowing the operator to then press ENTER to complete the form. Operators like to keep their fingers on the keys, so this scheme allows them to complete a form without touching the mouse.
Now BASIC attracts a lot of recreational programmers who are untrained in the ways of Windows. They immediately complain that ENTER should complete a textbox and move on, but they never explain how ENTER should then be used to complete the form.
In this example ENTER or TAB will move you from textbox to textbox, Ctrl+ENTER will complete the form and you can click with the mouse as well. These dummy textboxes allow color change, highlighting with mouse or keys, copy, paste, delete, insert, backspace etc.
They do most things a textbox does but there are a couple of restrictions. Firstly fixed width font, secondly they don't coexist with other controls so best for purely textual input forms. I don't really like color input but it is often requested so its in too.
If nothing else this code will give you more respect for our humble native textbox.
The next step would be to show how to mask and verify the input character by character but I will wait and see if any interest is expressed.
Me? I stick to normal textboxes and play by the rules.
nomainwin
global blink,blinktime,chrWidth,chrHeight,leftmargin,topmargin
global caretX,maxchr
global tb$,tb,text$
global highlight,copytext$,startChr,endChr
blink=0 'a flag 0/1 to say blinked or not
blinktime=0 'the time at which we will blink again
chrWidth=7 'the width in pixels the font needs to separate characters
chrHeight=15 'the height in pixels the font needs per line
leftmargin=chrWidth 'left hand margin
topmargin=chrHeight 'top margin, not used here
caretX=0 'the pixel position of the caret in the text
maxchr=80 'max characters allowed in each box
dim dtb$(3,3) 'dummy text box info, 1=text 2=backcolor 3=color
tb$="#1.tb1" 'handle variable pointing to currently selected graphicbox
tb=1 'the number of that graphicbox
WindowWidth = 300
WindowHeight = 400
UpperLeftX = (DisplayWidth-WindowWidth)/2
UpperLeftY = (DisplayHeight-WindowHeight)/2
'firstly we create a hidden graphicbox that will hold the focus
'and so receive all keystroke and mouse input
graphicbox #1.key, 0, 0, 0, 0
'now we set out our visible form with graphicboxes
'standing in for textboxes
statictext #1.st1,"This is text box 1",20,20,200,25
graphicbox #1.tb1, 20,45,200,25
statictext #1.st1,"This is text box 2",20,80,200,25
graphicbox #1.tb2, 20,105,200,25
statictext #1.st1,"This is text box 3",20,140,200,25
graphicbox #1.tb3, 20,165,200,25
'now create a graphicbox button, normal buttons will not work
'since the focus is always forced to the hidden graphicbox
graphicbox #1.bb4, 20,220,200,40
open "textbox demo" for window as #1
#1 "trapclose quit"
'set the graphicbox font, color and click handler
#1.tb1 "down ; font courier_new 9 ; when leftButtonDown htb"
#1.tb2 "down ; font courier_new 9 ; when leftButtonDown htb"
#1.tb3 "down ; font courier_new 9 ; when leftButtonDown htb"
#1.bb4 "down ; color black ; fill 192 255 255 ; font courier_new 9 ; when leftButtonDown submit"
#1.bb4 "backcolor 192 255 255 ; place 60 22 ;\Submit Form"
dtb$(1,1)="1234567890"
dtb$(1,2)="white"
dtb$(1,3)="black"
dtb$(2,1)="abcdefghij"
dtb$(2,2)="255 255 200"
dtb$(2,3)="black"
dtb$(3,1)="Oh my!"
dtb$(3,2)="255 200 255"
dtb$(3,3)="blue"
'set default text if desired
text$=dtb$(1,1)
tb$="#1.tb1"
tb=1
call display
text$=dtb$(2,1)
tb$="#1.tb2"
tb=2
call display
text$=dtb$(3,1)
tb$="#1.tb3"
tb=3
call display
'set text focus and cursor to first textbox
text$=dtb$(1,1)
caretX=len(text$)*chrWidth
tb$="#1.tb1"
tb=1
'now we repeatedly call blink, if 500ms has elapsed blink will toggle
'the cursor. It also forces focus back to the hidden textbox
'a scan within blink allows other events to be handled
[loop]
call blink
goto [loop]
'this sub captures all keyboard input via the hidden graphicbox
'keyboard input is one or two bytes long. Most are one byte and
'simply state the key pressed ABC etc If a control key is
'pressed we get two bytes the first byte indicates what control
'key is pressed Shift Ctrl etc.
sub fetchkey h$,k$
#1.key "when characterInput" 'Turn off Keyboard.
if len(k$)=1 then
k=asc(k$)
if k>=32 and k<=126 then
'we have a standard one byte character
'add/insert this character to text
if len(text$)<maxchr then
text$=left$(text$,caretX/chrWidth)+chr$(k)+right$(text$,len(text$)-caretX/chrWidth)
caretX=caretX+chrWidth
end if
else
'react to the few one byte command characters
select case k
case 3 'CTRL+C
if highlight then
copytext$=mid$(text$,startChr,endChr-startChr+1)
else
highlight=1
startChr=1
endChr=len(text$)
copytext$=text$
end if
case 10 'CTRL+Enter
call submit h$,0,0
case 22 'CTRL+V
if highlight then
'replace highlighted text
text$=left$(text$,startChr-1)+copytext$+right$(text$,len(text$)-endChr)
text$=left$(text$,maxchr)
highlight=0
else
'insert at cursor
text$=left$(text$,caretX/chrWidth)+copytext$+right$(text$,len(text$)-caretX/chrWidth)
text$=left$(text$,maxchr)
highlight=0
end if
call display
end select
end if
else
'we have a two byte command, use the rightmost value
'to react to command key pressed
k=asc(right$(k$,1))
c=asc(left$(k$,1))
select case k
case _VK_SHIFT
'do nothing
case _VK_RETURN
'tab/move to next tb or roll round
'you can catch last textbox enter here too
dtb$(tb,1)=text$
'eraze the cursor in the box we leave
call display
select case tb
case 1
tb=2
tb$="#1.tb2"
case 2
tb=3
tb$="#1.tb3"
case 3
tb=1
tb$="#1.tb1"
end select
text$=dtb$(tb,1)
caretX=chrWidth*len(text$)
case _VK_TAB
'tab/move to next tb or roll round
'you can catch last textbox enter here too
dtb$(tb,1)=text$
'eraze the cursor in the box we leave
call display
select case tb
case 1
tb=2
tb$="#1.tb2"
case 2
tb=3
tb$="#1.tb3"
case 3
tb=1
tb$="#1.tb1"
end select
text$=dtb$(tb,1)
caretX=chrWidth*len(text$)
case _VK_LEFT
if caretX=0 then
'do nothing
else
caretX=caretX-chrWidth
if c=4 then
if highlight=0 then
highlight=1
startChr=caretX/chrWidth+1
endChr=startChr
else
if endChr<startChr then t=startChr : startChr=endChr : endChr=t
select case
case caretX/chrWidth=startChr-2
startChr=startChr-1
case caretX/chrWidth=endChr-2
endChr=endChr-1
end select
end if
else
highlight=0
end if
end if
case _VK_RIGHT
if caretX>=len(text$)*chrWidth then
'do nothing
else
caretX=caretX+chrWidth
if c=4 then
if highlight=0 then
highlight=1
startChr=caretX/chrWidth
endChr=startChr
else
if endChr<startChr then t=startChr : startChr=endChr : endChr=t
select case
case caretX/chrWidth=startChr+1
startChr=startChr+1
case caretX/chrWidth=endChr+1
endChr=endChr+1
end select
end if
else
highlight=0
end if
end if
case _VK_UP
'do nothing
case _VK_DOWN
'do nothing
case _VK_PRIOR
'do nothing
case _VK_NEXT
'do nothing
case _VK_HOME
caretX=0
case _VK_BACK
'we need to delete any highlighted text or a single charcter to the
'left of the cursor
if caretX=0 then
'do nothing
else
if highlight then
text$=left$(text$,startChr-1)+right$(text$,len(text$)-endChr)
'move the caret left
caretX=(startChr-1)*chrWidth
else
text$=left$(text$,caretX/chrWidth-1)+right$(text$,len(text$)-caretX/chrWidth)
'move the caret left
caretX=caretX-chrWidth
end if
highlight=0
end if
case _VK_END
caretX=len(text$)*chrWidth
case _VK_DELETE
'we need to delete any highlighted text or a single character to the
'right of the cursor
if text$="" then
'do nothing
else
if highlight then
text$=left$(text$,startChr-1)+right$(text$,len(text$)-endChr)
'move the caret to end of text if necessary
If len(text$)*chrWidth < caretX then caretX=len(text$)*chrWidth
else
text$=left$(text$,caretX/chrWidth)+right$(text$,len(text$)-caretX/chrWidth-1)
'leave the caret where it was
end if
highlight=0
end if
end select
end if
call display
end sub
sub submit h$,x,y
'dtb$() contains the input
notice "Input actioned"
call quit h$
end sub
sub quit h$
close #1
end
end sub
'capture change of dummy textbox and set the handle variable pointing to it
sub htb h$,x,y
#1.key "when characterInput" 'Turn off Keyboard.
highlight=0
'capture old textbox text
dtb$(tb,1)=text$
'eraze the cursor and redisplay only text
call display
'set the new textbox handle, number and text
'we may select the current or a new textbox
tb$=h$
tb=val(right$(h$,1))
text$=dtb$(tb,1)
'set the cursor to the mouse position or end of text
caretX=int(x/chrWidth)*chrWidth-leftmargin
If len(text$)*chrWidth < caretX then caretX=len(text$)*chrWidth
'turn on mouse tracking
#tb$ "when leftButtonMove ttb"
#tb$ "when leftButtonUp stb"
call display
end sub
'track the mouse movement in the current dummy textbox, highlighting text
sub ttb h$,x,y
'if mouse moves set highlight flag and startChr
highlight=1
startChr=caretX/chrWidth+1
if startChr<1 then startChr=1
if startChr>len(text$) then startChr=len(text$)
xChr=int(x/chrWidth)*chrWidth-leftmargin
endChr=xChr/chrWidth
if endChr<1 then endChr=1
If endChr > len(text$) then endChr=len(text$)
'redisplay text to show highlight building
call display
end sub
'stop tracking and change mouse event for the current dummy textbox
sub stb h$,x,y
#tb$ "when leftButtonMove"
#tb$ "when leftButtonUp"
#tb$ "when leftButtonDown htb"
call display
end sub
'redisplay the contents of the current dummy textbox
sub display
if endChr<startChr then t=startChr : startChr=endChr : endChr=t
#tb$ "discard ; fill ";dtb$(tb,2);" ; backcolor ";dtb$(tb,2);" ; color ";dtb$(tb,3)
if highlight then
#tb$ "place ";leftmargin;" 15"
#tb$ "\";mid$(text$,1,startChr-1)
#tb$ "place ";leftmargin+(startChr-1)*chrWidth;" 15"
#tb$ "backcolor blue ; color white ;\";mid$(text$,startChr,endChr-startChr+1)
#tb$ "place ";leftmargin+endChr*chrWidth;" 15"
#tb$ "backcolor ";dtb$(tb,2);" ; color ";dtb$(tb,3);" ;\";mid$(text$,endChr+1,len(text$)-endChr);" ";
else
#tb$ "place ";chrWidth;" 15"
#tb$ "\";text$;" ";
end if
end sub
'blink the text cursor in the appropriate dummy textbox
'then reset the focus to the hidden graphicbox
sub blink
if time$("ms")>blinktime then
if blink=0 then
call display
#tb$ "color black ; place ";leftmargin+caretX;" 15 ; go 10"
blink=1
else
call display
#tb$ "color white ; place ";leftmargin+caretX;" 15 ; go 10 ; color black"
blink=0
end if
blinktime=time$("ms")+500
end if
#1.key "setfocus"
#1.key "when characterInput fetchkey"
scan
end sub