Formatting Numeric Input

Code snippets illustrating how LBB can be used
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Formatting Numeric Input

Post by RNBW »

One thing that I see coming up time after time in BASIC forums is restricting the input of numbers to -.1-9 and also formatting the numbers in a text box.

The following code demonstrates the above and also copying text between textboxes and totalling the numbers in textboxes to a single textbox.

I hope it's of use. It does not work in Liberty Basic.

Code: Select all

' THIS CODE UTILISES A FUNCTION NumberOnly$() written by  Bob Bromley  -  May 5, 2004
' WHICH I HAVE MODIFIED, BECAUSE I ONLY WANT TO ENSURE NUMERIC ENTRY.
' BOB BROMLEY ALSO PRODUCED CODE THAT UTILISES TRIM$ AND USING TO PRODUCE FORMATTED
' NUMERICAL OUTPUT.
' Thank you Bob for the code you produced.

' The code checks numeric entry for each textbox and then produces it, formatted to
' 2 decimal places in the textbox immediately below.  A NOTICE will pop up if a non-
' numeric character is entered and the COMPUTE button pressed.
' The numbers are then listed in a texteditor.
' The COMPUTE button can be pressed after each entry or after all boxes have been
' completed. The downside of the latter, is that the ERROR NOTICE will pop up but 
' won't say which box is incorrect.


NOMAINWIN

' SET UP WINDOW SIZE AND POSITION
WindowWidth = 600 : WindowHeight = 630
UpperLeftX = int((DisplayWidth  - WindowWidth)  / 2)
UpperLeftY = int((DisplayHeight - WindowHeight) / 2)

' SET UP THE CONTROLS
STATICTEXT #m.stat4, "Enter numbers into first four boxes of top row", 35, 0, 400, 20
STATICTEXT #m.stat1, "Unformatted Numbers:  Enter number", 35, 15, 290, 20
STATICTEXT #m.stat3, "TOTAL", 355, 15, 75,20
TEXTBOX    #m.txt11, 35,  40, 75, 20
TEXTBOX    #m.txt12, 110, 40, 75, 20
TEXTBOX    #m.txt13, 185, 40, 75, 20
TEXTBOX    #m.txt14, 260, 40, 75, 20
TEXTBOX    #m.txt15, 335, 40, 75, 20

STATICTEXT #m.stat2, "Formatted Numbers: The numeric results are", 35,  70, 290, 20
TEXTBOX    #m.txt21, 35, 90, 75, 20
TEXTBOX    #m.txt22, 110, 90, 75, 20
TEXTBOX    #m.txt23, 185, 90, 75, 20
TEXTBOX    #m.txt24, 260, 90, 75, 20
TEXTBOX    #m.txt25, 335, 90, 75, 20


STATICTEXT #m.stat5, "Summary Results", 35, 220, 150, 20
TEXTEDITOR #m.Ted1,  35, 250, 300, 150

BUTTON     #m.btn1,  "Reset",   [ResetAll], UL,  60, 160,  60, 25
BUTTON     #m.btn2,  "Compute", [Compute],  UL, 172, 160,  60, 25


'Open a window for showing the controls and
'entering data
OPEN "Filtered Numeric Input" FOR WINDOW_NF AS #m
#m "trapclose [Quit]"
' I'm not sure of the benefit of the next two lines, because if numbers
' are entered in these boxes they will be overridden by the figures entered
' in the top row, formatted and displayed in the second row and the totals
' calculated and similarly displayed.
'#m.txt15, "!disable"
'#m.txt21, "!disable": #m.txt22, "!disable": #m.txt23, "!disable": #m.txt24, "!disable": #m.txt25, "!disable": 

GOTO [ResetStart]

[Compute]   ' Format the entered numbers and calculate total

'This routine doesn't quite work. It prints out the results
'correctly in the texteditor, but then prints out a series
'of 0.00 before entering the total.
FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";1;col
      #h1$ "!contents? amt$"
      h2$ = "#m.txt";2;col
      amt = CheckDecPoints(amt$)  ' Check for one decimal point
      amt = NumberOnly(amt$)      ' Make the conversion
      '#h1$, 
      num(row,col) = amt
      
      #h2$, (USING("############.##", num(1,col)))       ' Put the result in the lower textbox
      #m.Ted1, (USING("############.##", num(row,col))) 
   NEXT  
NEXT


total = num(1,1) + num(1,2) + num(1,3) + num(1,4)
amt = total
#m.txt15, amt
#m.txt25, (USING("############.##",amt))
#m.Ted1, (USING("############.##", amt))

WAIT

[ResetAll]  ' Blank the textboxes
FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";row;col
      h2$ = "#m.txt";row;col
      #h1$, ""
      #h2$, ""
   NEXT col 
NEXT row

#m.Ted1, "!CLS"

[ResetStart]                ' Blank both the textboxes
FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";row;col
      h2$ = "#m.txt";row;col
      a$ = STR$(0)
      #h1$, "!CLS"
      #h2$, "!CLS"
   NEXT col   
NEXT row

#m.Ted1, "!CLS"

WAIT

[Quit]
CLOSE #m
END

'----------------------------------------------------------------------------------------
'              FUNCTIONS
'----------------------------------------------------------------------------------------

FUNCTION NumberOnly(in$)                            ' Here is the meat of it!
[Start]
FOR i = 1 TO LEN(in$)
    t$ = MID$(in$, i, 1)
    [DoItAgain]
    SELECT CASE
                ' Do nothing if t$ is a numeral or a decimal point
        CASE ASC(t$) = 46 OR (ASC(t$) > 46) AND (ASC(t$) < 58)
                ' A minus sign is ok, as long as it preceeds the numbers
        CASE ASC(t$) = 45 AND i = 1
                
        CASE ELSE
            ' Error!!  Only valid numbers 0-9, - , and . can be entered
            NOTICE "ERROR!!!  Please enter a valid number (0-9  -  . )"
            'GOTO [Start]
            'GOTO [DoItAgain]
    END SELECT
NEXT
NumberOnly = VAL(in$)
END FUNCTION  


    ' We must allow decimal points, but more than 1 will give us an incorrect return.
    ' So the first thing to do is count them, and stop here if there is more than 1.
    ' Use this for severe error-checking.
FUNCTION CheckDecPoints(amt$)
t = 0
FOR i = 1 TO LEN(amt$)
    t$ = MID$(amt$, i, 1) : IF t$ = "." THEN t = t + 1
    IF t > 1 THEN NOTICE "Only 1 decimal point is allowed in the number! " : WAIT
NEXT
END FUNCTION 
It is a bit longwinded, but I found this as I was looking through code. I'll post a shorter method in due course.
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Re: Formatting Numeric Input

Post by RNBW »

Here's another example of formatted numeric input.

Code: Select all

'Filtered numeric input with "." and "-".

nomainwin
WindowWidth = 250 : WindowHeight = 130
statictext #isNum.1, "Enter a number", 30, 15, 80, 40
textbox #isNum.tb, 120, 12, 48, 25
button #isNum.test, "Test", [Test], UL, 55, 65, 40, 25
button #isNum.exit, "Exit", [exit], UL, 125,65, 40, 25
open "Check for numeric entry" for dialog as #isNum
print #isNum, "trapclose [exitCheck]"


[tb.inputloop] 'wait here for input event
wait


[Test] 'Perform action for the button named 'Test'
print #isNum.tb, "!contents?"
input #isNum.tb, num$
valid = IsNumeric(num$)

print num$

if valid > 0 then
print #isNum.tb,num$
notice "Valid numeric input. Thanks."
else
notice "Not a valid numeric!"
print #isNum.tb, ""
end if

print #isNum.tb, "!setfocus"
wait


[exitCheck]
confirm "Are you sure you want to exit?";checkExit$
if checkExit$ = "no" or checkExit$ = "N" then wait


[exit] 'Perform action for the button named 'exit'
close #isNum
end


'----------------------------------
' THIS FUNCTION IS THE ENGINE ROOM
'----------------------------------
function IsNumeric(s$)
IsNumeric = 1 'initialize to 1
'value will be set to 0 if non-numeric
'character is found

for i = 1 to len(s$)

'This line reads through each character
n$ = mid$(s$,i,1)
'This line checks if the character is a number, "." or "-".
'It also checks if character is "/" (asc(n$=47)
if (asc(n$)>57) or (asc(n$)<45) or (asc(n$) = 47)then
'If not numeric then IsNumeric = 0
IsNumeric = 0
end if

next i

if len(s$) = 0 then IsNumeric = 0
End Function
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Re: Formatting Numeric Input

Post by RNBW »

This is a bit more advanced than the previous examples. The program sets up a grid into which you can enter numbers ( - . 0 to 9 ). It carries out a check as you enter each individual character. If it's a valid number it accepts it. If it's not valid, you will see the character very briefly before it's deleted. Press tab to move to next cell to right and Shift+Tab to move to cell to left.

The grid is based on code provided by Richard Russell. It is NOT compatible with Liberty Basic because it can't cope with maphandle.

Code: Select all

    
    NoMainWin        
    Row = 10: Col =9
    Dim TB$(Row, Col)
    WindowWidth = 1000
    WindowHeight = 400
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    bWidth = 100: bHt = 30  'width & height of textboxes

    TextboxColor$ = "white"
    print: print
    For i = 1 to Row
       For j = 1 to Col  
           Stylebits #main.tb, _ES_RIGHT, _WS_BORDER, 0, 0
           'TextBox #main.tb, (bWidth+20)*j - 100, (bHt+10)*i - 15, bWidth, bHt+1 (RR's code)
           TextBox #main.tb, (bWidth)*j -100+20, (bHt)*i - 15, bWidth+1, bHt+1
           'TB$(i,j) = "#main.tb" + str$(i) + str$(j)
           TB$(i,j) = "#main.tb"; "_r";i;"c";j           
           'print TB$(i,j)   ' prints out handles on main win if you REM nomainwin
           maphandle #main.tb, TB$(i,j)
       Next
    Next

    Open "untitled" For Window As #main
    #main, "Font Arial 11"
    #main "TrapClose Quit"

While Hwnd(#main)
    Scan
    For i = 1 To Row
       For j = 1 to Col                    
         Call checkInput TB$(i,j)         
       Next j 
    Next i
    CallDLL #kernel32, "Sleep", 300   As long, _
                                ret As void
    
Wend


'---------------------------------------------------------------
' Check the characters entered.
'---------------------------------------------------------------
' It does not check for more than one occurence of "."
' or that "." is not the last character.
'---------------------------------------------------------------
Sub checkInput controlName$
    #controlName$ "!contents? txt$"
    initLen = Len(txt$)
    txt$ = num$(txt$)
    If Len(txt$) < initLen Then
        #controlName$ txt$
        handle = Hwnd(#controlName$)
        pos = Len(txt$)
        CallDLL #user32, "SendMessageA", handle As long, _
                                         _EM_SETSEL As long, _
                                         pos        As long, _
                                         pos        As long, _
                                         result     As void
    End If
End Sub

'------------------------
' Close down the program
'------------------------
Sub Quit handle$
    Close #handle$
    End
End Sub

'-------------------------------------------------------------
' function to replace remchar$() LB4.5 function
' This should make this compatible with earlier version of LB
' Code by GaRPMorE in Re: textbox input - numbers only
' in LB Forum Reply #6 on: Apr 22nd, 2016, 7:23pm »
'-------------------------------------------------------------
function num$(d$)
    for i=1 to len(d$)
        a=asc(mid$(d$,i,1))
        if a = 45 and i = 1 or a = 46 or a>47 and a<58 then num$=num$+chr$(a)
    next
end function 
As it stands it doesn't do anything useful, but maybe someone can make use of it. If so please let us know how you have used it.
guest
Site Admin
Posts: 192
Joined: Tue Apr 03, 2018 1:34 pm

Re: Formatting Numeric Input

Post by guest »

RNBW wrote: Thu Apr 12, 2018 8:59 amI hope it's of use. It does not work in Liberty Basic.
As far as I can see, the only reason it doesn't work in LB 4 is because you are sending an illegal command (CLS) to a textbox:

Code: Select all

FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";row;col
      h2$ = "#m.txt";row;col
      a$ = STR$(0)
      #h1$, "!CLS"
      #h2$, "!CLS"
   NEXT col   
NEXT row
Indeed this whole block of code appears to be superfluous, because it is immediately preceded by code which does the same thing legally:

Code: Select all

FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";row;col
      h2$ = "#m.txt";row;col
      #h1$, ""
      #h2$, ""
   NEXT col
NEXT row
I would suggest that, unless you know that your code can't work because it relies on an LBB extension, you test it in LB 4 as well because its syntax checking is often better (I have explained before why LBB's error checking is poor). Code that does not work in Liberty Basic purely because of an avoidable error is unfortunate.

Richard.
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Re: Formatting Numeric Input

Post by RNBW »

Drat it Richard! Of course you are absolutely correct in all respects. I have corrected the code below and can confirm that it IS compatible with LB4.

Code: Select all

' CODE BASED ON A ROUTINE BY BOB BROMLEY IN ONE OF THE LB NEWSLETTERS,
' WHICH I HAVE MODIFIED, BECAUSE I ONLY WANT TO ENSURE NUMERIC ENTRY.
' BOB BROMLEY ALSO PRODUCED CODE THAT UTILISES TRIM$ AND USING TO PRODUCE FORMATTED
' NUMERICAL OUTPUT.
' Thank you Bob for the code you produced.

' The code checks numeric entry for each textbox and then produces it, formatted to
' 2 decimal places in the textbox immediately below.  A NOTICE will pop up if a non-
' numeric character is entered and the COMPUTE button pressed.
' The numbers are then listed in a texteditor.
' The COMPUTE button can be pressed after each entry or after all boxes have been
' completed. The downside of the latter, is that the ERROR NOTICE will pop up but
' won't say which box is incorrect.


NOMAINWIN

' SET UP WINDOW SIZE AND POSITION
WindowWidth = 600 : WindowHeight = 630
UpperLeftX = int((DisplayWidth  - WindowWidth)  / 2)
UpperLeftY = int((DisplayHeight - WindowHeight) / 2)

' SET UP THE CONTROLS
STATICTEXT #m.stat4, "Enter numbers into first four boxes of top row", 35, 0, 400, 20
STATICTEXT #m.stat1, "Unformatted Numbers:  Enter number", 35, 15, 290, 20
STATICTEXT #m.stat3, "TOTAL", 355, 15, 75,20
TEXTBOX    #m.txt11, 35,  40, 75, 20
TEXTBOX    #m.txt12, 110, 40, 75, 20
TEXTBOX    #m.txt13, 185, 40, 75, 20
TEXTBOX    #m.txt14, 260, 40, 75, 20
TEXTBOX    #m.txt15, 335, 40, 75, 20

STATICTEXT #m.stat2, "Formatted Numbers: The numeric results are", 35,  70, 290, 20
TEXTBOX    #m.txt21, 35, 90, 75, 20
TEXTBOX    #m.txt22, 110, 90, 75, 20
TEXTBOX    #m.txt23, 185, 90, 75, 20
TEXTBOX    #m.txt24, 260, 90, 75, 20
TEXTBOX    #m.txt25, 335, 90, 75, 20


STATICTEXT #m.stat5, "Summary Results", 35, 220, 150, 20
TEXTEDITOR #m.Ted1,  35, 250, 300, 150

BUTTON     #m.btn1,  "Reset",   [ResetAll], UL,  60, 160,  60, 25
BUTTON     #m.btn2,  "Compute", [Compute],  UL, 172, 160,  60, 25


'Open a window for showing the controls and
'entering data
OPEN "Filtered Numeric Input" FOR WINDOW_NF AS #m
#m "trapclose [Quit]"
GOTO [ResetAll]

[Compute]   ' Format the entered numbers and calculate total

FOR row = 1 TO 2
   FOR col = 1 TO 4
      h1$ = "#m.txt";1;col
      #h1$ "!contents? amt$"
      h2$ = "#m.txt";2;col
      amt = CheckDecPoints(amt$)  ' Check for one decimal point
      amt = NumberOnly(amt$)      ' Make the conversion
      '#h1$,
      num(row,col) = amt

      #h2$, (USING("############.##", num(1,col)))       ' Put the result in the lower textbox
      #m.Ted1, (USING("############.##", num(row,col)))
   NEXT
NEXT


total = num(1,1) + num(1,2) + num(1,3) + num(1,4)
amt = total
#m.txt15, amt
#m.txt25, (USING("############.##",amt))
#m.Ted1, (USING("############.##", amt))

WAIT

[ResetAll]  ' Blank the textboxes
FOR row = 1 TO 2
   FOR col = 1 TO 5
      h1$ = "#m.txt";row;col
      h2$ = "#m.txt";row;col
      #h1$, ""
      #h2$, ""
   NEXT col
NEXT row

#m.Ted1, "!CLS"

WAIT

[Quit]
CLOSE #m
END

'----------------------------------------------------------------------------------------
'              FUNCTIONS
'----------------------------------------------------------------------------------------

FUNCTION NumberOnly(in$)                            ' Here is the meat of it!
[Start]
FOR i = 1 TO LEN(in$)
    t$ = MID$(in$, i, 1)
    [DoItAgain]
    SELECT CASE
                ' Do nothing if t$ is a numeral or a decimal point
        CASE ASC(t$) = 46 OR (ASC(t$) > 46) AND (ASC(t$) < 58)
                ' A minus sign is ok, as long as it preceeds the numbers
        CASE ASC(t$) = 45 AND i = 1

        CASE ELSE
            ' Error!!  Only valid numbers 0-9, - , and . can be entered
            NOTICE "ERROR!!!  Please enter a valid number (0-9  -  . )"
            'GOTO [Start]
            'GOTO [DoItAgain]
    END SELECT
NEXT
NumberOnly = VAL(in$)
END FUNCTION

    ' We must allow decimal points, but more than 1 will give us an incorrect return.
    ' So the first thing to do is count them, and stop here if there is more than 1.
    ' Use this for severe error-checking.
FUNCTION CheckDecPoints(amt$)
t = 0
FOR i = 1 TO LEN(amt$)
    t$ = MID$(amt$, i, 1) : IF t$ = "." THEN t = t + 1
    IF t > 1 THEN NOTICE "Only 1 decimal point is allowed in the number! " : WAIT
NEXT
END FUNCTION
tsh73
Posts: 44
Joined: Fri Apr 06, 2018 7:58 pm

Re: Formatting Numeric Input

Post by tsh73 »

Hello RNBW
I would say your code shows that could be done - and it's a good thing
But it really could be worked on to be used.

Taking last code:
* it checks numbers twice. Why it uses FOR by row?
* 2e3 barks as invalid, but then converts to 2000 as should be
* 2a3 barks as invalid but converts to 2 (as VAL() works)
* 2.3.4 barks over several dots and stops checking, skipping all other numbers and totalling.
Why two dots so bad and other extra character not so bad
(number converts with VAL as it could, and testing proceeds to next number) ?

Uh-oh
running it with LB
having "1.2.3" as a number breaks program - it catches error first time, after that pressing buttons ends with
Runtime error: invalid branch label: [...]
(and I have to kill it because trapclose doesn't work either)

Debugging a program is a sport of it's own ;)

If you need a function to check if number is valid, I could point to old JB contest
Is a valid number function()
(link probably disappear after April 15)
I think you can pick some function from there. Or take test suite to check your function with.
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Re: Formatting Numeric Input

Post by RNBW »

tsh73
Thanks for your response. As you say, the code is a bit clumsy and was just some that I have picked up along the way.

Personally, what I am more interested in is the numeric input code in the grid example ( RNBW » Thu Apr 12, 2018 6:18 pm ), in which a check is made for a valid input as each character is entered. What I have in mind for this will not require to check for exponential number input, but will require to check for double "." which it doesn't at the moment. However, I've just found some code that I think will do this, but it was late last night and my eyes were hardly open and the brain had shut up!

Thank you very much for the link to the code in the JB Conforums. I have taken a copy of the item, because I'm not likely to be able to check it out properly until next week, by which time the JB Conforums will probably have gone. A very quick look showed that a more detailed look will be beneficial.
guest
Site Admin
Posts: 192
Joined: Tue Apr 03, 2018 1:34 pm

Re: Formatting Numeric Input

Post by guest »

tsh73 wrote: Thu Apr 12, 2018 9:23 pm(link probably disappear after April 15)
I'm out of touch with what the JB and LB folks are intending to do with the old forums. What's the plan for the Just BASIC forum? Is it going to be made available for browsing and searching, in a similar way to the old LBB and BBC BASIC forums? I am aware of concerns in certain quarters about the Copyright implications, but as I've already explained I'm personally not too worried so long as contributors are given the opportunity to request that their posts be taken down.

Richard.
RNBW
Posts: 65
Joined: Thu Apr 05, 2018 9:21 pm

Re: Formatting Numeric Input

Post by RNBW »

Richard
There is the following notice on the JB Conforums site.

The backup is finished.
The forum is now set to read-only to prevent the need to create another backup.

Whether that means that it will remain as a read-only facility, I don't know. After the reaction on the LB forum, maybe I'd better not ask. I'll just wait to find out.
guest
Site Admin
Posts: 192
Joined: Tue Apr 03, 2018 1:34 pm

Re: Formatting Numeric Input

Post by guest »

RNBW wrote: Fri Apr 13, 2018 10:53 amWhether that means that it will remain as a read-only facility, I don't know.
I think everybody is assuming that, come Monday, the old forums will have disappeared. The fact that Conforums have been offering 'dumps' of their database to forum owners is highly suggestive of that, so I assume that the option of it "remaining" (read-only or otherwise) is slim. But we won't know for sure for a few more days.

My question wasn't really about the future of the old forums, but rather what plans the JB forum staff have, if any, to provide an archived copy which is accessible online after they've gone, as I have for the BBC BASIC and LBB forums. When I last looked at the LB forum they seemed to be backtracking on the whole idea, but after your experience I'm really not interested in ever visiting there again. :cry:

Richard.