LB Booster
Programming >> Liberty BASIC language >> Numeric entry into a textbox
http://lbb.conforums.com/index.cgi?board=lblang&action=display&num=1462715049

Numeric entry into a textbox
Post by RNBW on May 8th, 2016, 1:44pm

There have been some recent posts on the Liberty Basic Conforums site regarding numeric entry into a textbox and this is a continuation of the subject.

The following code checks for and allows for "-" at the beginning of a number and for ".". It doesn't check for more than one decimal point nor does it check for "." at the end of a number. Numbers cannot be formatted with "," to distinguish thousands, etc.

The code is mainly based on that by Brandon Parker and a code function by GaRPMorE. My own input is very small, amounting to tinkering only, so the credit goes to Brandon Parker and GaRPMorE.

Code:
 '==================================================
 ' NUMERIC INPUT CHECK DEMO
 '==================================================
 ' Originally by Brandon Parker Liberty Basic 
 ' Conforums Re: Error Messege
 ' « Reply #3 on: Yesterday at 10:47pm »
 '--------------------------------------------------
 ' Modifications by RNBW 7 May 2016
 '--------------------------------------------------
 ' Modification to SLEEP period from 1 to 300
 ' (allows you to see the unacceptable
 ' character displayed before deletion.
 '--------------------------------------------------
 ' remchar$() has been replaced by the function
 ' num$(d$) posted by GaRPMorE in his post 
 ' « Reply #6 on: Apr 22nd, 2016, 7:23pm » and
 ' modified by RNBW.  
 ' This should enable compatibility with
 ' earlier versions of LB, including the PRO version
 ' This version does not appear to be compatible 
 ' with JustBasic
 '==================================================

    NoMainWin
    Dim ControlName$(2)
    WindowWidth = 130
    WindowHeight = 150
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)


    TextboxColor$ = "white"
    TextBox #main.textbox1,   5,  32, 100,  30
    TextBox #main.textbox2,   5,  75, 100,  30
    Open "untitled" For Window As #main
    #main, "Font Georgia 12"
    #main "TrapClose Quit"

    ControlName$(1) = "#main.textbox1"
    ControlName$(2) = "#main.textbox2"

While Hwnd(#main)
    Scan
    For i = 1 To 2
         Call checkInput ControlName$(i)
    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                         
 


What would be useful is if someone could come up with the code to check for more than one "." and for dealing with "." at the end of a number.

Re: Numeric entry into a textbox
Post by Richard Russell on May 8th, 2016, 2:45pm

on May 8th, 2016, 1:44pm, RNBW wrote:
What would be useful is if someone could come up with the code to check for more than one "."

Easy:

Code:
function HasMoreThanOneDot(n$)
    HasMoreThanOneDot = instr(n$, ".", instr(n$, ".") + 1) <> 0
end function 

Quote:
and for dealing with "." at the end of a number.

It's debatable whether that should be rejected. If .123 is a valid number why shouldn't 123. be too? Certainly many languages (including LBB) accept is as valid, although LB doesn't. It's trivial to test for if you want to, especially if the LB 4.5.0 endswith() function is available:

Code:
function EndsWithADot(n$)
    EndsWithADot = endswith(n$, ".")
end function 

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 8th, 2016, 3:37pm

Hi Richard

Thank you for your response.

I'm not too bothered about the "." at the end of the number. I'd be going on to format the number to "###" or whatever decimal places anyway.

Your code for the more than one "." is what I am really looking for. It might be because it's Sunday and the sun is shining, but I can't for the life of me think how to incorporate it into the code.

Ray
Re: Numeric entry into a textbox
Post by Richard Russell on May 8th, 2016, 4:07pm

on May 8th, 2016, 3:37pm, RNBW wrote:
I can't for the life of me think how to incorporate it into the code.

The code you listed does not check the entered number for validity, rather it filters the entered number to remove invalid characters. So it's performing an entirely different task.

You can't use a similar approach in the case of having more than one dot, because there's no way the program can determine which is the 'wanted' dot and which the 'unwanted' one. Only the user knows that.

I answered the question you asked: What would be useful is if someone could come up with the code to check for more than one "." but it wasn't the right question!

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 8th, 2016, 4:23pm

Hi Richard

Of course you are correct. What I was hoping for was someone to come up with code that would carry out the check as each character is entered.

I'd come to the same conclusion as yourself that the function didn't achieve that. So, unless someone can come up with some clever code, I shall have to carry out a further check after the whole number has been entered.

Thanks for your help

Ray
Re: Numeric entry into a textbox
Post by Richard Russell on May 8th, 2016, 6:58pm

on May 8th, 2016, 4:23pm, RNBW wrote:
What I was hoping for was someone to come up with code that would carry out the check as each character is entered.

Ah, so it's always the first decimal point typed that is the correct one? If you somehow know that to be the case then of course it's trivial to reject a second one. That's not the same thing as checking for more than one dot, since the filtering will ensure there never can be.

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 9th, 2016, 07:34am

Point taken!

So the only safe way to do it is to check the final entered number and if there is more than one "." then to give a warning to that effect and let the user decide which is the correct "." and re-enter the number.
Re: Numeric entry into a textbox
Post by Richard Russell on May 9th, 2016, 09:43am

on May 9th, 2016, 07:34am, RNBW wrote:
Point taken!

Would that be "decimal point" taken? grin

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 18th, 2016, 10:20am

I have tidied up the routine a little:
* increased the number of textboxes from 2 to 3
* instead of separate textboxes, made them into a grid
* made the borders thinner
* made the entry right justified (like calculator entry)

It still needs the issue of more than one decimal point to be dealt with. I think this will have to be a Notice with a warning for the user to ensure just one decimal point.

Here's the code to date. Hope it's of use.

Code:
 '==================================================
 ' NUMERIC INPUT CHECK DEMO
 '==================================================
 ' Originally by Brandon Parker Liberty Basic 
 ' Conforums Re: Error Messege
 ' « Reply #3 on: Yesterday at 10:47pm »
 '--------------------------------------------------
 ' Modifications by RNBW 7 May 2016
 '--------------------------------------------------
 ' Modification to SLEEP period from 1 to 300
 ' (allows you to see the unacceptable
 ' character displayed before deletion.
 '--------------------------------------------------
 ' remchar$() has been replaced by the function
 ' num$(d$) posted by GaRPMorE in his post 
 ' « Reply #6 on: Apr 22nd, 2016, 7:23pm » and
 ' modified by RNBW.  
 ' This should enable compatibility with
 ' earlier versions of LB, including the PRO version
 ' This version does not appear to be compatible 
 ' with JustBasic
 '==================================================

    NoMainWin
    NumOfTB = 3
    Dim ControlName$(NumOfTB)
    WindowWidth = 130
    WindowHeight = 250
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    bWidth = 100
    bHt = 30

    TextboxColor$ = "white"
    Stylebits #main.textbox1, _ES_RIGHT, _WS_BORDER, 0, 0
    TextBox #main.textbox1, 5, 30, bWidth, bHt+1
    Stylebits #main.textbox2, _ES_RIGHT, _WS_BORDER, 0, 0
    TextBox #main.textbox2, 5, 60, bWidth, bHt+1
    Stylebits #main.textbox3, _ES_RIGHT, _WS_BORDER, 0, 0
    Textbox #main.textbox3, 5, 90, bWidth, bHt+1
    
    Open "untitled" For Window As #main
    #main, "Font Georgia 12"
    #main "TrapClose Quit"

    'ControlName$(1) = "#main.textbox1"
    'ControlName$(2) = "#main.textbox2"
    'ControlName$(3) = "#main.textbox3"
    For i = 1 to NumOfTB
       ControlName$(i) = "#main.textbox" + str$(i)
    next    

While Hwnd(#main)
    Scan
    For i = 1 To NumOfTB
         Call checkInput ControlName$(i)
    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     
 

Re: Numeric entry into a textbox
Post by RNBW on May 19th, 2016, 2:01pm

I am trying to extend the use of Brandon Parker's code for numeric entry. In my last post I produced code for a small grid consisting of 3 textboxes.

This worked pretty well, so I thought I would try a 3 x 3 grid.

I just can't get it to work.

Code:
    NoMainWin
    Row = 3: Col =3
    Dim TB$(Row, Col)
    WindowWidth = 240
    WindowHeight = 200
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

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

    TextboxColor$ = "white"
    Stylebits #main.tb1, _ES_RIGHT, _WS_BORDER, 0, 0
    TextBox #main.tb1, 20, 30, bWidth, bHt+1
    Stylebits #main.tb2, _ES_RIGHT, _WS_BORDER, 0, 0
    TextBox #main.tb2, 20, 60, bWidth, bHt+1
    Stylebits #main.tb3, _ES_RIGHT, _WS_BORDER, 0, 0
    Textbox #main.tb3, 20, 90, bWidth, bHt+1

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

    For i = 1 to Row
       For j = 1 to Col   
       TB$(i,j) = "#main.tb" + str$(i) + str$(j)
       Next
    Next

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$"  'THIS IS WHERE THE ERROR COMES UP
    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
 
 


I have marked the line in the code where the error is reported (Invalid channel at line 72).

I don't seem to be able to get my head around it. Has anybody any ideas?
Re: Numeric entry into a textbox
Post by Richard Russell on May 19th, 2016, 3:41pm

on May 19th, 2016, 2:01pm, RNBW wrote:
I don't seem to be able to get my head around it. Has anybody any ideas?

I am surprised that this should have given you difficulty. The error occurs in this line:

Code:
    #controlName$ "!contents? txt$" 

so it's clear that the variable controlName$ doesn't contain a valid handle. The next step in debugging is to find out what it does contain, which you can easily do either by printing it to the MAINWIN or using the debugger. What you will find is this:

Code:
controlName$ = "#main.tb11" 

Now you can see why the error occurs: there is no control with the handle #main.tb11!

Here is a corrected version of the program which does not raise an error (LBB only of course):

Code:
    NoMainWin
    Row = 3: Col =3
    Dim TB$(Row, Col)
    WindowWidth = 400
    WindowHeight = 200
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

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

    TextboxColor$ = "white"
    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
           TB$(i,j) = "#main.tb" + str$(i) + str$(j)
           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 

Richard.
Re: Numeric entry into a textbox
Post by RNBW on May 19th, 2016, 4:07pm

Thank you Richard for the corrected code. I'm afraid the blank look on my face is a bit more frequent these days. I could see what the problem was, the blank bit was nothing happening between the ears to solve it.

I thought I should have maphandle in there, but I didn't need it when I was using just a single dimension array. so I thought I was missing something, which clearly I was.


Re: Numeric entry into a textbox
Post by Richard Russell on May 19th, 2016, 5:18pm

on May 19th, 2016, 4:07pm, RNBW wrote:
I thought I should have maphandle in there, but I didn't need it when I was using just a single dimension array.

In your 1D version you created the textboxes individually, rather than in a loop (with only three that wasn't too onerous) so you didn't need MAPHANDLE. But with a 2D grid of boxes it's much easier to create them using a nested loop, and increasingly so when the number of rows or columns increases.

As has been discussed here before, as soon as the number of rows and columns exceeds 10 you have to be a bit more careful about constructing the handles. The simple

Code:
TB$(i,j) = "#main.tb" + str$(i) + str$(j) 

won't cut it in that case because (for example) i = 11, j = 1 would give exactly the same handle as i = 1, j = 11!

Richard.

Re: Numeric entry into a textbox
Post by Richard Russell on May 19th, 2016, 8:20pm

on May 19th, 2016, 5:18pm, Richard Russell wrote:
But with a 2D grid of boxes it's much easier to create them using a nested loop, and increasingly so when the number of rows or columns increases.

This is of course an advantage that LBB has over LB, but it seems that nobody dares mention that at the LB Community Forum, where there is currently a parallel thread (despite it having been stated in the past that such a reference to LBB is allowed).

Richard.
Re: Numeric entry into a textbox
Post by Rod on May 20th, 2016, 08:00am

Just in case it isn't obvious leading zeroes is one solution.

Code:
dim TB$(11,11)
j=1
i=11
TB$(i,j) = "#main.tb" + str$(i) + str$(j)
print TB$(i,j)
TB$(i,j) = "#main.tb" + right$("00"+str$(i),2) + right$("00"+str$(j),2)
print TB$(i,j)
 

Re: Numeric entry into a textbox
Post by Richard Russell on May 20th, 2016, 08:34am

on May 20th, 2016, 08:00am, Rod wrote:
Just in case it isn't obvious leading zeroes is one solution.

Indeed, or a simple separator character might be even easier:

Code:
    TB$(i,j) = "#main.tb"; i; "x"; j 

Richard.
Re: Numeric entry into a textbox
Post by RNBW on May 22nd, 2016, 3:28pm

on May 20th, 2016, 08:34am, Richard Russell wrote:
Indeed, or a simple separator character might be even easier:

Code:
    TB$(i,j) = "#main.tb"; i; "x"; j 

Richard.


Interesting. I didn't know that you could do that. You could write:

Code:
TB$(i,j) = "#main.tb"; "r"; i; "c"; j
 


to make it clear the row and column definition.

Re: Numeric entry into a textbox
Post by Richard Russell on May 22nd, 2016, 4:23pm

User cundo at the LB Community Forum has posted a solution for a grid of textboxes, involving initially creating each one as a separate window (which is the only way you can do it in a loop in LB). Although messy - and slow - compared with the LBB method, it's a workable approach if LB compatibility is essential.

As documented in the Compatibility section of the LBB Help file (subsection 4), a small modification to his code is necessary to make it work in LBB. I've listed the revised program below (it still works in LB 4.5.0):

Code:
    NoMainWin
    WindowWidth = 640
    WindowHeight = 480
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)
    stylebits   #main, 0, _WS_VISIBLE, 0, 0
    Open "Window" for Window_nf as #main
        #main "trapclose [quit]"
    for y = 1 to 15 ' create the controls
      for x= 1 to 6
      ctrl=ctrl+1 ' number of controls
        textbox #temp.t1,(100*x)-99, (25*y)-24,100,25
            stylebits #temp, 0, _WS_VISIBLE, 0, 0
            Open "" for Window_popup as #temp
            maphandle #temp.t1, "#";ctrl;".t1" ' required for LBB
            maphandle #temp, "#";ctrl
      next x
    next y

    for i = 1 to ctrl 'attach the controls to the main handler and show them
      h$= "#";i;".t1"
      call setParent hWnd(#main) , hWnd(#h$)
      call ShowWindow hWnd(#h$), 1
    next i

    call ShowWindow hWnd(#main), 1

 [chkInput]
  Timer 0
  for u = 1 to ctrl
    controlName$="#";u;".t1"
    #controlName$ "!contents? txt$"
    new$= remchar$(txt$,"abcdefghijklmn�opqrstuvwxyz")
    if new$<>txt$ Then
        #controlName$ new$
        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

  next
 Timer 72, [chkInput]
wait

    [quit]
    close #main
    for i = 1 to ctrl
        closeMePlease$ = "#";i
        close #closeMePlease$
    next
    end

sub setParent parent,child
    calldll #user32, "SetParent",_
        child as ulong,_
        parent as ulong,_
        r as void
End sub

Sub ShowWindow hWnd, flag
    'SW_HIDE = 0
    'SW_NORMAL = 1
    CallDLL #user32, "ShowWindow",hWnd as uLong, flag As Long, r As void
End Sub

'include lb45func.bas 

Richard.
Re: Numeric entry into a textbox
Post by RNBW on May 23rd, 2016, 10:00am

To get the stylebits working properly in LBB should the stylebits for the textbox be:

Code:
stylebits #temp.t1, 0, _WS_BORDER, 0, 0
 


This enables you to get rid of the double border with the textboxes

Code:
textbox #temp.t1,(100*x)-100+50, (25*y)-25+50,100+1,25+1
 


Whilst the code does enable a grid to be set up in LB, using it with LBB is a bit slow setting up. Also, the fact that a list of 90 textbox controls is set up (1-90) it is not going to be as easy to access the controls as using the grid I have previously set up with RR help where the controls are accessed via row,col.


Re: Numeric entry into a textbox
Post by Richard Russell on May 23rd, 2016, 11:36am

on May 23rd, 2016, 10:00am, RNBW wrote:
Whilst the code does enable a grid to be set up in LB, using it with LBB is a bit slow setting up.

It's quite slow in both LB and LBB, because it involves creating such a lot of windows. Maybe it's a little slower in LBB, because window creation is not normally on the critical path so has not been optimised. But either way if the time taken to create all those windows is an issue you could in many circumstances display a screen with instructions, or a dialog box requesting some input from the user, or just a logo, in order for that time not to be so noticeable.

After all it's only something you ever have to do once, sometime during program initialisation. You don't need to wait until the 'grid' is required before creating it, when the delay might indeed be more irritating. I often see programs that close and then reopen windows, when they could much more quickly hide and then re-show them.

Quote:
Also, the fact that a list of 90 textbox controls is set up (1-90) it is not going to be as easy to access the controls as using the grid I have previously set up with RR help where the controls are accessed via row,col.

That's completely unrelated to the method used. Whether you create the boxes using LBB's nicer method or using cundo's method to achieve LB compatibility, it's entirely up to you whether you name the handles by a single value 1-90 or by row and column.

Strangely I find myself having to defend LB against unfair criticism in this case!

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 23rd, 2016, 1:31pm

I was not critising the code. I was making observations. I think the code is quite clever and gets over the problem of setting up a grid of textboxes in LB. However, I would suggest that accessing the textboxes via a row/col method is easier (and I think clearer) than trying to deal with a 90 item list of controls. It does mean that you'll have to set up the handles to deal with it.

In respect of speed; in this instance I found that the grid was displayed almost instantly in LB, whereas in LBB it could be seen building up a line of textboxes at a time before finally displaying the whole grid. As you say this can be overcome by creating the grid in the background, before displaying it.

Personally, I wouldn't use this method in LBB, because the grid solution that you came up with for me some time ago it's a much easier system to use.
Re: Numeric entry into a textbox
Post by Richard Russell on May 23rd, 2016, 4:00pm

on May 23rd, 2016, 1:31pm, RNBW wrote:
However, I would suggest that accessing the textboxes via a row/col method is easier

I think you missed my point. The choice of how to name the textbox handles, either as a single number 1-90 or as row/col, is completely unrelated to the technique used to create those boxes. User cundo chose to use the single-number method, and in so doing has caused you to consider it one of the disadvantages of his approach, but it isn't. He could equally well have used the row/col method, and with hindsight it would have been better, because it would have avoided your misunderstanding.

Quote:
I found that the grid was displayed almost instantly in LB, whereas in LBB it could be seen building up a line of textboxes at a time before finally displaying the whole grid.

I don't understand that. The code posted by cundo, and the slightly modified LBB-compatible code I posted, both created the window with the WS_VISIBLE style bit cleared and only 'showed' it after all the text boxes had been created. So there shouldn't have been any way you could see it "building up a line of textboxes at a time" because it was coded to do that 'invisibly'.

Here are the comparative figures for the code I posted (timed from the start of the code to showing the fully-populated grid):

LB 4.5.0: approx. 1.2 seconds
LBB 3.04: approx. 1.5 seconds

So as I said LBB is indeed a little slower, but (on my PC at least) there isn't anything like the difference that you reported, and LB 4.5.0 is far from "instant".

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 23rd, 2016, 4:36pm

Richard

I don't think we are really disagreeing on the first point. Cundo only took his code so far, for numeric entry. He didn't need to consider how the entered numbers would be accessed. If he had, he may have changed it to row/col handles (but then again, he may not). I just think that it would be easier to do it with row/col handles. I'm not critising his code nor your comments, just pointing out my own preference.

In respect of the second point. Ignore all that I said. I made some adjustments to the code and unfortunately missed out _WS_VISIBLE and this is the cause of the problem. Reinstating this shows that there is very little difference in the time to display the grid.

Re: Numeric entry into a textbox
Post by RNBW on May 25th, 2016, 4:59pm

on May 23rd, 2016, 10:00am, RNBW wrote:
Whilst the code does enable a grid to be set up in LB, using it with LBB is a bit slow setting up. Also, the fact that a list of 90 textbox controls is set up (1-90) it is not going to be as easy to access the controls as using the grid I have previously set up with RR help where the controls are accessed via row,col.



I have tried to set up Cundo's code using controls in a row/col basis instead of just a long list of controls. I have first set it up to display headers in Row 1 for the columns and Column 1 for the rows. Then tried to set up reading from the other textboxes and printing to the main window. This works but both the grid and the printed data flashes. It seems to be related to the Timer. If you increase the timer value the rate of flash slows. I've played around with various alternatives to contentName$ and h$, to try to get outside the chkInput loop, but it doesn't work. What am I doing wrong?

Code:
'=========================================
' NumInputGrid_LB_LBB_1F.bas
'=========================================
' Sets up Grid of textboxes
' Works by setting up each textbox as a
' pop-up window and then showing them on
' a child window
' Initial Code by Cundo on Liberty Basic
' Forum 20 May 2016 #reply 17
'=========================================

    'NoMainWin

    '--------------------------
    ' Set up #main window size
    '--------------------------
    maxRows = 10: maxCols =9
    dim disp$(maxRows,maxCols)
    WindowWidth = 1000
    WindowHeight = 480
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    '------------------
    ' OPEN THE #main WINDOW
    '------------------
    stylebits   #main, 0, _WS_VISIBLE, 0, 0
    Open "Window" for Window_nf as #main
        #main "trapclose [quit]"

    '-------------------------
    ' CREATE THE CONTROLS
    '-------------------------
    for row = 1 to maxRows
      for col = 1 to maxCols
        textbox #temp.t1,(100*col)-100+50, (25*row)-25+50,100+1,25+1
            stylebits #temp.t1, _ES_RIGHT, _WS_VISIBLE OR _WS_BORDER, 0, 0
            Open "" for Window_popup as #temp
            maphandle #temp.t1, "#";row;col;".t1" ' required for LBB
            maphandle #temp, "#";row;col
      next col
    next row

    '------------------------------------------------------
    'attach the controls to the main handler and show them
    '------------------------------------------------------
    for row = 1 to maxRows
       for col = 1 to maxCols
          h$= "#";row;col;".t1"
          call setParent hWnd(#main) , hWnd(#h$)
          call ShowWindow hWnd(#h$), 1
       next col
    next row

    call ShowWindow hWnd(#main), 1


 [chkInput]
  Timer 0
  for row = 1 to maxRows
     for col = 1 to maxCols
        controlName$="#";row;col;".t1"
        #controlName$ "!contents? txt$"
        new$= remchar$(txt$,"abcdefghijklmn?opqrstuvwxyz")
        if new$<>txt$ Then
           #controlName$ new$
           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
     next col
  next row

 Timer 300, [chkInput]


 '----------------------------------
 ' PRINT ROW NUMBER IN FIRST COLUMN
 '----------------------------------
 for row = 2 to maxRows
    h$ = "#";row;1;".t1"
    #h$ "Row ";row-1
 next row

 '-----------------------------------
 ' PRINT COLUMN NUMBERS IN FIRST ROW
 '-----------------------------------
 for col = 2 to maxCols
    h$ = "#";1;col;".t1"
    #h$ "Col ";col-1
 next col

 '--------------------
 ' GET DATA FROM GRID
 '--------------------
 for row = 2 to maxRows
    for col = 2 to maxCols
    controlName$="#";row;col;".t1"
    #controlName$ "!contents? txt$"
    disp$(row,col) = txt$
    print txt$
    next col
 next row

wait

    [quit]
    close #main    
    for row = 1 to maxRows
        for col = 1 to maxCols
           h$= "#";row;col
           closeMePlease$ = h$
           close #closeMePlease$
        next col
    next row
    end

sub setParent parent,child
    calldll #user32, "SetParent",_
                     child as ulong,_
                     parent as ulong,_
                     r as void
End sub

Sub ShowWindow hWnd, flag
    'SW_HIDE = 0
    'SW_NORMAL = 1
    CallDLL #user32, "ShowWindow",hWnd as uLong, flag As Long, r As void
End Sub

'include lb45func.bas  
 

Re: Numeric entry into a textbox
Post by Richard Russell on May 25th, 2016, 5:54pm

on May 25th, 2016, 4:59pm, RNBW wrote:
What am I doing wrong?

The code is working as designed, as far as I can see. You are rejecting any non-numeric characters in the boxes, so when you print (say) "Col 4" to a box the "Col" part fails the validity-check and it gets replaced with just "4"; similarly with the "Row n" boxes.

If your intention was that the row and column 'label' boxes should not be subject to the numeric-character-only check then you should exclude them from it, for example by changing the looping code as follows:

Code:
  for row = 2 to maxRows
     for col = 2 to maxCols 

But I would say the real problem is a poor choice of array indices. In my opinion it would make much more sense to number the 'label' boxes as column 0 and row 0, and then the 'active' part of the grid would start at column 1 and row 1.

I've made that change in the listing below, and - since this is a support forum for LBB - I've modified the code to use the nicer (and faster) LBB method rather than the LB method. I think we've pretty much established that maintaining compatibility with LB has no value.

Code:
'=========================================
' NumInputGrid_LBB_1F.bas
'=========================================
' Sets up Grid of textboxes
' This version is LBB only
' Forum 20 May 2016 #reply 17
'=========================================

    NoMainWin

    '--------------------------
    ' Set up #main window size
    '--------------------------
    maxRows = 10: maxCols = 8
    dim disp$(maxRows,maxCols)
    WindowWidth = 1000
    WindowHeight = 480
    UpperLeftX=int((DisplayWidth-WindowWidth)/2)
    UpperLeftY=int((DisplayHeight-WindowHeight)/2)

    '-------------------------
    ' CREATE THE CONTROLS
    '-------------------------
    for row = 0 to maxRows
      for col = 0 to maxCols
        textbox #main.tb,100*col+50, 25*row+50,100+1,25+1
        stylebits #main.tb, _ES_RIGHT, _WS_BORDER, 0, 0
        maphandle #main.tb, "#main.tb";row;"x";col
      next col
    next row

    '------------------
    ' OPEN THE #main WINDOW
    '------------------
    stylebits   #main, 0, _WS_VISIBLE, 0, 0
    Open "Window" for Window_nf as #main
        #main "trapclose [quit]"

    call ShowWindow hWnd(#main), 1

    '----------------------------------
    ' PRINT ROW NUMBER IN FIRST COLUMN
    '----------------------------------
    for row = 1 to maxRows
       h$ = "#main.tb";row;"x0"
       #h$ "Row ";row
    next row

    '-----------------------------------
    ' PRINT COLUMN NUMBERS IN FIRST ROW
    '-----------------------------------
    for col = 1 to maxCols
       h$ = "#main.tb0x";col
       #h$ "Col ";col
    next col


 [chkInput]
  Timer 0
  for row = 1 to maxRows
     for col = 1 to maxCols
        controlName$="#main.tb";row;"x";col
        #controlName$ "!contents? txt$"
        new$= remchar$(txt$,"abcdefghijklmn?opqrstuvwxyz")
        if new$<>txt$ Then
           #controlName$ new$
           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
     next col
  next row

 Timer 300, [chkInput]


 '--------------------
 ' GET DATA FROM GRID
 '--------------------
 for row = 1 to maxRows
    for col = 1 to maxCols
    controlName$="#main.tb";row;"x";col
    #controlName$ "!contents? txt$"
    disp$(row,col) = txt$
    print txt$
    next col
 next row

    wait

[quit]
    close #main    
    end

Sub ShowWindow hWnd, flag
    'SW_HIDE = 0
    'SW_NORMAL = 1
    CallDLL #user32, "ShowWindow",hWnd as uLong, flag As Long, r As void
End Sub

'include lb45func.bas 

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 25th, 2016, 6:42pm

Richard

Thank you for your response.

There remains a problem. If you REM NoMainwin. The print txt$ in the GET DATA routine should print out the results to the mainwin. These continue to flash as the data is input into the grid (I reduced the number of rows/cols to 3/4 so not too much data) and to scroll. When all data is entered, the flashing and scrolling does not end until the top window is closed just leaving the mainwin. The data displayed is in excess of what should be seen and always seems to start with 24.

I'm scratching my head.


Re: Numeric entry into a textbox
Post by Richard Russell on May 25th, 2016, 7:39pm

on May 25th, 2016, 6:42pm, RNBW wrote:
If you REM NoMainwin. The print txt$ in the GET DATA routine should print out the results to the mainwin. These continue to flash as the data is input into the grid

I'm afraid I don't know what you mean; I don't see anything unexpected. As you're outputting a large number of lines (one for every cell in the grid) every 300 milliseconds or so, the mainwin is pretty much constantly scrolling. There's no 'flashing' as such (here) but the scrolling means nothing stays still long enough to read!

Did you perhaps mean to output the data in a grid on the mainwin, so that it never needs to scroll? You could do that as follows:

Code:
 '--------------------
 ' GET DATA FROM GRID
 '--------------------
 for row = 1 to maxRows
    for col = 1 to maxCols
    controlName$="#main.tb";row;"x";col
    #controlName$ "!contents? txt$"
    disp$(row,col) = txt$
    locate 10*col,row
    print txt$;
    next col
 next row 

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 25th, 2016, 8:44pm

on May 25th, 2016, 7:39pm, Richard Russell wrote:
I'm afraid I don't know what you mean; I don't see anything unexpected. As you're outputting a large number of lines (one for every cell in the grid) every 300 milliseconds or so, the mainwin is pretty much constantly scrolling. There's no 'flashing' as such (here) but the scrolling means nothing stays still long enough to read!


Perhaps flash was not the correct description. As I said, I reduced the number of textboxes to a 3 row x 4 col grid. This was printed several times in mainwin.

I thought with the for..next loop in the GET DATA section, it would print out the data from 12 textboxes, starting with cell 1/1 through to cell 3/4. It prints it out several times, which accounts for the scrolling.

Thanks for the code for printing out in grid form.

At the end of the day, on LBB given the choice of this method or creating a grid as previous postings some time ago, I will stick with the latter. It is easier to create and edit and does all that I could ask for. Once again, I thank you for your help with that.

With regards to LB, I shall post the code I produced on the LB site, and hopefully someone there will come up with a solution for LB.

Richard, as usual, you come up with the goods!
Re: Numeric entry into a textbox
Post by Richard Russell on May 25th, 2016, 9:11pm

on May 25th, 2016, 8:44pm, RNBW wrote:
As I said, I reduced the number of textboxes to a 3 row x 4 col grid. This was printed several times in mainwin.

I am still not really understanding. What difference did you expect reducing to "a 3 row x 4 col grid" to make? It's still outputting 12 lines every 300ms, that's more than 36 lines every second, which is far too fast for anybody to read and of course will mean it starts to scroll almost immediately!

Quote:
I thought with the for..next loop in the GET DATA section, it would print out the data from 12 textboxes, starting with cell 1/1 through to cell 3/4. It prints it out several times, which accounts for the scrolling.

Again you say "it prints out several times" as if this was a surprise. Did you not mean to put the printing routine in your TIMER handler? Having done so of course it prints out "several times": it prints out every 300ms!

Quote:
hopefully someone there will come up with a solution for LB.

But surely (until I modified it) your solution was for LB! I thought that was the whole point of you using the 'cundo' method of creating the boxes initially as separate windows.

Richard.

Re: Numeric entry into a textbox
Post by RNBW on May 25th, 2016, 9:44pm

I thought I had put the print routine outside the timer handler. So this is where I went wrong.

Your final solution is for LBB only. So there code I had produced up to then I shall post on LB, because I don't have time to take it any further.

As I said in my last post, I'll use the textbox grid system developed some weeks ago for LBB. It would be nice though if someone on LB could produce the relevant code to let Cundo's methods be used on LB. I don't know when I will be able to get back to it.