Numeric Entry in an EditBox

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 10:37

I've just tried
DestroyWindow(Edit_Text(row,col))
instead of

Code: Select all

SendMessage(Edit_Text(row,col), WM_CLOSE, 0, 0)
with exactly the same result. Column 2 remains.
jj2007
Posts: 1210
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Postby jj2007 » Aug 07, 2018 11:03

dodicat wrote:I don't have "WinGUI.bi"
If dodicat had ever received an answer, I would be willing to check why column 2 remains.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 11:48

WinGUI.bi is the .bi file for Lothar Schirm's Simple WinAPI Library https://www.freebasic.net/forum/viewtopic.php?f=8&t=24617
jj2007
Posts: 1210
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Postby jj2007 » Aug 07, 2018 12:11

OK, thanks. Your problem lies in setUpGrid:

Code: Select all

   For row = 1 To NumOfRows
      For col = 1 To 5
           Edit_Text(row, col) = EditBox_New(...)
You do these loops three times, and there is considerable overlap, which means you create plenty of controls using some of the Edit_Text(row, col) slots more than once. When you try to WM_CLOSE or DestroyWindow them, only the last created get destroyed. The other ones stay in place.

Insert these three lines before every EditBox_New():

Code: Select all

         if Edit_Text(row, col) then
            print "ERROR for row ";row;", col ";col
         endif

Full code below.

Code: Select all

'=========================================================
' NumericEntryIntoGridOfTextboxes_BC2_Dev05C.bas
' Author: RNBW
' 7 August 2018
'--------------------------------------------------------------------------------------------------

'INSTRUCTIONS:
'Enter any text you want in col 2, rows 2 & 3.  It is superfluous to the exercise  and is only
'included for my own future use.
'Enter numbers into columns 3 and 4 in rows 2 and 3.  They will be automatically
'checked for numeric validity in the range 0 to 9, minus and period and for only one
'inclusion of minus and period and ensuring that the minus only occurs as the first
'character.  It will also print out ".123" as "0.123" and "-.123" as "-0.123"
'=========================================================
' TO DO:
' Totalling the rows and columns doesn't work.
' Format the numbers :
' As can be seen, the displayed numbers are a bit straggly.
' Format the numbers to a specific number of decimal places.
'=========================================================

#Include "\AllBasics\FreeBasic\WinGUI(12)\WinGUI.bi"

Dim  Shared As Long NumOfRows = 0
dim shared as long NumOfCols = 5
Dim Shared As String sRows, sCols

Dim Shared As HWND Window_Main, Static_Text, Label_a, Edit_a, Button_Num, Button_CloseGrid
Dim Shared As MSG msg
Dim Shared As String text, text2
Dim Shared As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
Dim Shared As HWND Button_Calc
Dim Shared As Long vPos, hPos, bWidth, bHeight, row, col
DIM Shared AS STRING sTxt, oldsTxt
DIM Shared AS INTEGER pos0
DIM Shared AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
DIM Shared AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
DIM Shared AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)


FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t

   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
      IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
      IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
      IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT

   a=ASC(MID(sTxt,1,1))
   IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1

   RETURN sNum1

END FUNCTION


'---------------------
' MAIN WINDOW
'---------------------
Sub OpenWindow_Main()
   Window_Main = Window_New(100, 100, 750, 400, "Numeric Input Into A Grid of Textboxes")
End Sub

OpenWindow_Main()

' Gadgets to state number of rows
Label_a = Label_New(10,10,270,20,"How many rows do you want to calculate",, Window_Main)
Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
Button_Num = Button_New(350,10,100,20, "Enter",, Window_Main)
Button_CloseGrid = Button_New(500,10,100,20, "Close Grid",, Window_Main)

'Open console
'Screen 12
'open cons for output as #1

Button_Calc = Button_New(10, 60, 100, 20, "Calculate!",, Window_Main)

   '-------------------------------
   '  SET UP THE GRID
   '-------------------------------
sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   vPos = 90: bHeight = 20
if 1 then
   For row = 1 To NumOfRows
      For col = 1 To 5
         Select Case col
            Case 1
               hPos = 10: bWidth = 65
            Case 2
               hPos = 75: bWidth = 380
         End Select
         if Edit_Text(row, col) then
            print "ERROR A for row ";row;", col ";col
         endif
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",, Window_Main)
      Next
   Next
   print "NEW A"
endif
if 1 then   ' Number 1 Number 2 Total
   FOR row = 1 to 1
      for col = 3 TO 5
         SELECT CASE col
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75
         END SELECT
         if Edit_Text(row, col) then
            print "ERROR B for row ";row;", col ";col
         endif
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",, Window_Main)
      NEXT
   NEXT
   print "NEW B"
endif

if 1 then   ' three right columns
   FOR row = 2 TO NumOfRows
      FOR col = 3 TO 5
         SELECT CASE col
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75
         END SELECT
         if Edit_Text(row, col) then
            print "ERROR C for row ";row;", col ";col
         endif
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_RIGHT, Window_Main)
      NEXT
   NEXT
   print "NEW C"
endif

   '-----------------------------------
   ' SET UP HEADINGS IN ROW 1
   '-----------------------------------
   row = 1
   For col = 3 To NumOfCols
      EditBox_SetText(Edit_Text(row,col), "Number" + Str(col-2))
   Next
   EditBox_SetText(Edit_Text(row,2), "Description")
   EditBox_SetText(Edit_Text(row,5), "TOTAL")


   '----------------------------------
   ' SET UP HEADINGS IN COL 1
   '----------------------------------
   col = 1
   For row = 2 To NumOfRows -1
      EditBox_SetText(Edit_Text(row,2), "Column 2")
'       ShowWindow(Edit_Text(row,2), SW_MINIMIZE)
'       ShowWindow(Edit_Text(row,2), SW_RESTORE)
'       InvalidateRect(Edit_Text(row,2), 0, 1)
      For col = 1 To 1
         EditBox_SetText(Edit_Text(row,col), "Row" + Str(row-1))
      Next
   Next
   EditBox_SetText(Edit_Text(numOfRows,1), "TOTAL" )

end sub



'=============================================
'setUpGrid(2)
'=============================================

'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 300, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      ' CASE WM_LBUTTONDOWN
      'SELECT CASE msg.message
'       CASE WM_CREATE
'       print "CASE WM_CREATE"
'             NumOfRows = 9
'             setUpGrid(NumOfRows)
      CASE WM_TIMER
         if NumOfRows=0 then
          print "*";
            
               NumOfRows = 9
               setUpGrid(NumOfRows)
         endif
         'Check contents of the edit box every 300 millisecinds
         For row = 2 to NumOfRows
            FOR col = 3 TO 4
               sTxt = EditBox_GetText(Edit_Text(row,col))   'get text from edit box
               oldsTxt = sTxt      'make text the oldtext
               sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
               IF oldsTxt <> sTxt THEN
                  EditBox_SetText(Edit_Text(row,col), sTxt)   'if old text is not the same as the new text then use new text
                  pos0 = LEN(sTxt)   'position of character is the length of the current text
                  SENDMESSAGE(Edit_Text(row,col), EM_SETSEL, pos0, pos0)
               END IF
            NEXT col
         NEXT row
      CASE WM_LBUTTONDOWN
         if msg.hwnd = Button_Num then
            text = EditBox_GetText(Edit_a)
            NumOfRows = val(text)
            NumOfRows = NumOfRows + 2
            setUpGrid(NumOfRows)
            print NumOfRows
           
         Else
            ' Click Close Grid button to close grid
            ' This closes all down except for column 2
            if msg.hwnd = Button_CloseGrid THEN
               for row = 1 to NumOfRows
                  for col = 1 to  5
   ' SetLastError(0)
   SendMessage(Edit_Text(row,col), WM_CLOSE, 0, 0)
   ' print GetLastError(); " ";
                  next
               Next
               
            Else
               'If Calculate! button is clicked then carry out calculation
               IF msg.hwnd = Button_Calc THEN
                  totalCols(NumOfRows,col) = 0
                  FOR row = 2 to NumOfRows
                     FOR col = 3 TO 5
                        ' Total Rows--->
                        sTxt =  EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = VAL(sTxt)
                        totalRows(row,5) = numb(row, 3) + numb(row,4)
                        sTxt = STR(totalRows(row,5))
                        EditBox_SetText(Edit_Text(row,5), sTxt)
                        'Total Columns--->
                        sTxt = EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = val(sTxt)
                        totalCols(NumOfRows,col) =  totalCols(NumOfRows,col) +  numb(row-1,col)
                        'print row; "  "; col; "  "; numb(row,col)
                        sTxt = STR(totalCols(NumOfRows,col))
                        EditBox_SetText(Edit_Text(NumOfRows,col), sTxt)
                        print row; "  "; col; "  "; numb(row,col)
                     NEXT
                  NEXT
               end if
            END IF
         End if
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

End
BasicCoder2
Posts: 3391
Joined: Jan 01, 2009 7:03

Re: Numeric Entry in an EditBox

Postby BasicCoder2 » Aug 07, 2018 13:39

@jj2007,
Your example still seems to be producing one new grid over the old one?
In this simpler example I have added yShift and xShift to make this obvious.
Just click the "change dimensions" button and a random maxRow and maxCol will be chosen.
The top/left corner of the array of textboxes will be shifted each time.
So how would you delete the original array of textboxes before creating a new set?
I assume this would involve two nested loops and a call to some function to delete each textbox.

Code: Select all

' Datagrid2.bas

#Include "\AllBasics\FreeBasic\WinGUI(12)\WinGUI.bi"

Dim shared As HWND Window_Main, Edit_Data(20, 10), Button_Redim
Dim shared As MSG msg
Dim shared As Integer i, j

'Create the window with a data grid:
Window_Main = Window_New(100, 100, 900, 500, "Editable Datagrid")

sub setUpGrid(maxCol as integer,maxRow as integer)
    dim as integer yShift,xShift
    yShift = int(Rnd(1)*100)+10
    xShift = int(Rnd(1)*100)+10
    For i = 0 To maxCol
       For j = 0 To maxRow
          Edit_Data(i, j) = EditBox_New(j * 80+yShift, i * 20+xShift, 80, 20, "abc",, Window_Main)
          EditBox_SetText(Edit_Data(i, j), "text(" + Str(i) + ", " + Str(j) + ")")
       Next
    Next
end sub


setUpGrid(2,2)

Button_Redim = Button_New(350, 430, 200, 20, "change dimensions",, Window_Main)

'Main:
Do
   WaitEvent(Window_Main, msg)
   If msg.message = WM_LBUTTONDOWN And msg.hwnd = Button_Redim Then

            setUpGrid(int(Rnd(1)*8)+2,int(rnd(1)*8)+2)

   End If

Loop Until Window_Event_Close(Window_Main, msg)

End
Last edited by BasicCoder2 on Aug 07, 2018 20:03, edited 1 time in total.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 13:44

jj2007
Thank you for your help.

I'm afraid that solution didn't work for me. I still get column 2 left behind. However, I think the logic of what you said
OK, thanks. Your problem lies in setUpGrid:

Code: Select all
For row = 1 To NumOfRows
For col = 1 To 5
Edit_Text(row, col) = EditBox_New(...)
You do these loops three times, and there is considerable overlap, which means you create plenty of controls using some of the Edit_Text(row, col) slots more than once. When you try to WM_CLOSE or DestroyWindow them, only the last created get destroyed. The other ones stay in place.

is correct. If I put them all in a single loop it works. Code below:

Code: Select all

'=========================================================
' NumericEntryIntoGridOfTextboxes_BC2_Dev05C.bas
' Author: RNBW
' 7 August 2018
'--------------------------------------------------------------------------------------------------

'INSTRUCTIONS:
'Enter any text you want in col 2, rows 2 & 3.  It is superfluous to the exercise  and is only
'included for my own future use.
'Enter numbers into columns 3 and 4 in rows 2 and 3.  They will be automatically
'checked for numeric validity in the range 0 to 9, minus and period and for only one
'inclusion of minus and period and ensuring that the minus only occurs as the first
'character.  It will also print out ".123" as "0.123" and "-.123" as "-0.123"
'=========================================================
' TO DO:
' Totalling the rows and columns doesn't work.
' Format the numbers :
' As can be seen, the displayed numbers are a bit straggly.
' Format the numbers to a specific number of decimal places.
'=========================================================

#Include "WinGUI.bi"

Dim  Shared As Long NumOfRows = 10
dim shared as long NumOfCols = 5
Dim Shared As String sRows, sCols

Dim Shared As HWND Window_Main, Static_Text, Label_a, Edit_a, Button_Num, Button_CloseGrid
Dim Shared As MSG msg
Dim Shared As String text, text2
Dim Shared As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
Dim Shared As HWND Button_Calc
Dim Shared As Long vPos, hPos, bWidth, bHeight, row, col
DIM Shared AS STRING sTxt, oldsTxt
DIM Shared AS INTEGER pos0
DIM Shared AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
DIM Shared AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
DIM Shared AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)


FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t

   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
      IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
      IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
      IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT

   a=ASC(MID(sTxt,1,1))
   IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1

   RETURN sNum1

END FUNCTION


'---------------------
' MAIN WINDOW
'---------------------
Sub OpenWindow_Main()
   Window_Main = Window_New(100, 100, 750, 400, "Numeric Input Into A Grid of Textboxes")
End Sub

OpenWindow_Main()

' Gadgets to state number of rows
Label_a = Label_New(10,10,270,20,"How many rows do you want to calculate",, Window_Main)
Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
Button_Num = Button_New(350,10,100,20, "Enter",, Window_Main)
Button_CloseGrid = Button_New(500,10,100,20, "Close Grid",, Window_Main)

'Open console
'Screen 12
'open cons for output as #1

Button_Calc = Button_New(10, 60, 100, 20, "Calculate!",, Window_Main)

   '-------------------------------
   '  SET UP THE GRID
   '-------------------------------
sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   vPos = 90: bHeight = 20
   For row = 1 To NumOfRows
      For col = 1 To 5
         Select Case col
            Case 1
               hPos = 10: bWidth = 65
            Case 2
               hPos = 75: bWidth = 380
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75   
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",, Window_Main)
      Next
   Next

   'FOR row = 1 to 1
   '   for col = 3 TO 5
   '      SELECT CASE col
   '         CASE 3 TO 4
   '            hpos =  col*65+(455-65*3) : bWidth = 65
   '         CASE 5
   '            hPos = (10+65+380)+(col-3)*65 : bWidth = 75
   '      END SELECT
   '      Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",, Window_Main)
   '   NEXT
   'NEXT

   'FOR row = 2 TO NumOfRows
   '   FOR col = 3 TO 5
   '      SELECT CASE col
   '         CASE 3 TO 4
   '            hpos =  col*65+(455-65*3) : bWidth = 65
   '         CASE 5
   '            hPos = (10+65+380)+(col-3)*65 : bWidth = 75
   '      END SELECT
   '      Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_RIGHT, Window_Main)
   '   NEXT
   'NEXT


   '-----------------------------------
   ' SET UP HEADINGS IN ROW 1
   '-----------------------------------
   row = 1
   For col = 3 To NumOfCols
      EditBox_SetText(Edit_Text(row,col), "Number" + Str(col-2))
   Next
   EditBox_SetText(Edit_Text(row,2), "Description")
   EditBox_SetText(Edit_Text(row,5), "TOTAL")


   '----------------------------------
   ' SET UP HEADINGS IN COL 1
   '----------------------------------
   col = 1
   For row = 2 To NumOfRows -1
      For col = 1 To 1
         EditBox_SetText(Edit_Text(row,col), "Row" + Str(row-1))
      Next
   Next
   EditBox_SetText(Edit_Text(numOfRows,1), "TOTAL" )

end sub



'=============================================
'setUpGrid(2)
'=============================================

'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 300, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      ' CASE WM_LBUTTONDOWN
      'SELECT CASE msg.message
      CASE WM_TIMER
         'Check contents of the edit box every 300 millisecinds
         For row = 2 to NumOfRows
            FOR col = 3 TO 4
               sTxt = EditBox_GetText(Edit_Text(row,col))   'get text from edit box
               oldsTxt = sTxt      'make text the oldtext
               sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
               IF oldsTxt <> sTxt THEN
                  EditBox_SetText(Edit_Text(row,col), sTxt)   'if old text is not the same as the new text then use new text
                  pos0 = LEN(sTxt)   'position of character is the length of the current text
                  SENDMESSAGE(Edit_Text(row,col), EM_SETSEL, pos0, pos0)
               END IF
            NEXT col
         NEXT row
      CASE WM_LBUTTONDOWN
         if msg.hwnd = Button_Num then
            text = EditBox_GetText(Edit_a)
            NumOfRows = val(text)
            NumOfRows = NumOfRows + 2
            setUpGrid(NumOfRows)
            print NumOfRows
           
         Else
            ' Click Close Grid button to close grid
            ' This closes all down except for column 2
            if msg.hwnd = Button_CloseGrid THEN
               for row = 1 to NumOfRows
                  for col = 1 to  5
                       SendMessage(Edit_Text(row,col), WM_CLOSE, 0, 0)
                  next
               Next
               
            Else
               'If Calculate! button is clicked then carry out calculation
               IF msg.hwnd = Button_Calc THEN
                  totalCols(NumOfRows,col) = 0
                  FOR row = 2 to NumOfRows
                     FOR col = 3 TO 5
                        ' Total Rows--->
                        sTxt =  EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = VAL(sTxt)
                        totalRows(row,5) = numb(row, 3) + numb(row,4)
                        sTxt = STR(totalRows(row,5))
                        EditBox_SetText(Edit_Text(row,5), sTxt)
                        'Total Columns--->
                        sTxt = EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = val(sTxt)
                        totalCols(NumOfRows,col) =  totalCols(NumOfRows,col) +  numb(row-1,col)
                        'print row; "  "; col; "  "; numb(row,col)
                        sTxt = STR(totalCols(NumOfRows,col))
                        EditBox_SetText(Edit_Text(NumOfRows,col), sTxt)
                        print row; "  "; col; "  "; numb(row,col)
                     NEXT
                  NEXT
               end if
            END IF
         End if
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

End

So we are getting there.

The reason I used three loops was because of the formatting of the columns. In particular, I wanted columns 3 to 5 to be right justified. I have now lost that. Is there any way I can right justify these columns without setting up another grid.
jj2007
Posts: 1210
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Postby jj2007 » Aug 07, 2018 13:58

RNBW wrote:The reason I used three loops was because of the formatting of the columns. In particular, I wanted columns 3 to 5 to be right justified. I have now lost that. Is there any way I can right justify these columns without setting up another grid.
Sure:

Code: Select all

sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   Dim ES_x as Integer
   vPos = 90: bHeight = 20
   For row = 1 To NumOfRows
      For col = 1 To 5
         ES_x=ES_LEFT       ' ######### default ###########
         Select Case col
            Case 1
               hPos = 10: bWidth = 65
            Case 2
               hPos = 75: bWidth = 380
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65 : ES_x=ES_RIGHT
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75 : ES_x=ES_RIGHT
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "", ES_x, Window_Main)
      Next
   Next
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 14:04

jj2007

Thank you. I'll give that a try when I get back to my computer.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 14:29

jj2007
Rushed back to the computer (wouldn't it be great if you could run FreeBasic on a tablet -- Android).

I never thought of using a variable to set up the justification. It works perfectly. So now all columns justify correctly and setting up the grid and reizing it works properly.

We're definitely getting there.

For anyone who has been following the thread, the code is below:

Code: Select all

'=========================================================
' NumericEntryIntoGridOfTextboxes_jj_Dev05E.bas
' Author: RNBW
' 7 August 2018
'--------------------------------------------------------------------------------------------------

'INSTRUCTIONS:
'Enter any text you want in col 2, rows 2 & 3.  It is superfluous to the exercise  and is only
'included for my own future use.
'Enter numbers into columns 3 and 4 in rows 2 and 3.  They will be automatically
'checked for numeric validity in the range 0 to 9, minus and period and for only one
'inclusion of minus and period and ensuring that the minus only occurs as the first
'character.  It will also print out ".123" as "0.123" and "-.123" as "-0.123"
'=========================================================
' TO DO:
' Format the numbers :
' As can be seen, the displayed numbers are a bit straggly.
' Format the numbers to a specific number of decimal places.
'=========================================================

#Include "WinGUI.bi"

Dim  Shared As Long NumOfRows = 10
dim shared as long NumOfCols = 5
Dim Shared As String sRows, sCols

Dim Shared As HWND Window_Main, Static_Text, Label_a, Edit_a, Button_Num, Button_CloseGrid
Dim Shared As MSG msg
Dim Shared As String text, text2
Dim Shared As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
Dim Shared As HWND Button_Calc
Dim Shared As Long vPos, hPos, bWidth, bHeight, row, col
DIM Shared AS STRING sTxt, oldsTxt
DIM Shared AS INTEGER pos0
DIM Shared AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
DIM Shared AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
DIM Shared AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)


FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t

   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
      IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
      IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
      IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT

   a=ASC(MID(sTxt,1,1))
   IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1

   RETURN sNum1

END FUNCTION


'---------------------
' MAIN WINDOW
'---------------------
Sub OpenWindow_Main()
   Window_Main = Window_New(100, 100, 750, 400, "Numeric Input Into A Grid of Textboxes")
End Sub

OpenWindow_Main()

' Gadgets to state number of rows
Label_a = Label_New(10,10,270,20,"How many rows do you want to calculate",, Window_Main)
Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
Button_Num = Button_New(350,10,100,20, "Enter",, Window_Main)
Button_CloseGrid = Button_New(500,10,100,20, "Close Grid",, Window_Main)

'Open console
'Screen 12
'open cons for output as #1

Button_Calc = Button_New(10, 60, 100, 20, "Calculate!",, Window_Main)

   '-------------------------------
   '  SET UP THE GRID
   '-------------------------------
sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   Dim ES_x as Integer
   vPos = 90: bHeight = 20
   For row = 1 To NumOfRows
      For col = 1 To 5
         ES_x=ES_LEFT       ' ## default  left justified ##
         select Case col
            Case 1
               hPos = 10: bWidth = 65
            Case 2
               hPos = 75: bWidth = 380
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65: ES_x = ES_RIGHT    'right justify
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75: ES_x = ES_RIGHT   'right justify
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_x, Window_Main)
       Next
   Next

   
   '-----------------------------------
   ' SET UP HEADINGS IN ROW 1
   '-----------------------------------
   row = 1
   For col = 3 To NumOfCols
      EditBox_SetText(Edit_Text(row,col), "Number" + Str(col-2))
   Next
   EditBox_SetText(Edit_Text(row,2), "Description")
   EditBox_SetText(Edit_Text(row,5), "TOTAL")
   
   '----------------------------------
   ' SET UP HEADINGS IN COL 1
   '----------------------------------
   col = 1
   For row = 2 To NumOfRows -1
      For col = 1 To 1
         EditBox_SetText(Edit_Text(row,col), "Row" + Str(row-1))
      Next
   Next
   EditBox_SetText(Edit_Text(numOfRows,1), "TOTAL" )

end sub


'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 300, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      ' CASE WM_LBUTTONDOWN
      'SELECT CASE msg.message
      CASE WM_TIMER
         'Check contents of the edit box every 300 millisecinds
         For row = 2 to NumOfRows
            FOR col = 3 TO 4
               sTxt = EditBox_GetText(Edit_Text(row,col))   'get text from edit box
               oldsTxt = sTxt      'make text the oldtext
               sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
               IF oldsTxt <> sTxt THEN
                  EditBox_SetText(Edit_Text(row,col), sTxt)   'if old text is not the same as the new text then use new text
                  pos0 = LEN(sTxt)   'position of character is the length of the current text
                  SENDMESSAGE(Edit_Text(row,col), EM_SETSEL, pos0, pos0)
               END IF
            NEXT col
         NEXT row
      CASE WM_LBUTTONDOWN
         if msg.hwnd = Button_Num then
            text = EditBox_GetText(Edit_a)
            NumOfRows = val(text)
            NumOfRows = NumOfRows + 2
            setUpGrid(NumOfRows)
            print NumOfRows
           
         Else
            ' Click Close Grid button to close grid
            if msg.hwnd = Button_CloseGrid THEN
               for row = 1 to NumOfRows
                  for col = 1 to  5
                       SendMessage(Edit_Text(row,col), WM_CLOSE, 0, 0)
                  next
               Next
               
            Else
               'If Calculate! button is clicked then carry out calculation
               IF msg.hwnd = Button_Calc THEN
                  totalCols(NumOfRows,col) = 0
                  FOR row = 2 to NumOfRows
                     FOR col = 3 TO 5
                        ' Total Rows--->
                        sTxt =  EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = VAL(sTxt)
                        totalRows(row,5) = numb(row, 3) + numb(row,4)
                        sTxt = STR(totalRows(row,5))
                        EditBox_SetText(Edit_Text(row,5), sTxt)
                        'Total Columns--->
                        sTxt = EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = val(sTxt)
                        totalCols(NumOfRows,col) =  totalCols(NumOfRows,col) +  numb(row-1,col)
                        'print row; "  "; col; "  "; numb(row,col)
                        sTxt = STR(totalCols(NumOfRows,col))
                        EditBox_SetText(Edit_Text(NumOfRows,col), sTxt)
                        print row; "  "; col; "  "; numb(row,col)
                     NEXT
                  NEXT
               end if
            END IF
         End if
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

End

Thank you very much for your help in resolving the above and to all others who have contributed.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 07, 2018 14:53

BasicCoder2 wrote:@jj2007,
Your example still seems to be producing one new grid over the old one?
In this simpler example I have added yShift and xShift to make this obvious.
Just click the "change dimensions" button and a random maxRow and maxCol will be chosen.
The top/left corner of the array of textboxes will be shifted each time.
So how would you delete the original array of textboxes before creating a new set?
I assume is would involve two nested loops and a call to some function to delete each textbox.


BasicCoder2
I do apologise. I addressed my response to your post to jj2007.

Eventually, we have got the problem sorted. See my post before this for the code.
BasicCoder2
Posts: 3391
Joined: Jan 01, 2009 7:03

Re: Numeric Entry in an EditBox

Postby BasicCoder2 » Aug 07, 2018 21:05

RNBW wrote:Eventually, we have got the problem sorted. See my post before this for the code.

If you [Enter] a new sized grid without hitting [Close Grid] the first one will remain and cannot be closed although subsequent ones created by [Enter] can be closed.
Perhaps a check that the first one is closed before an [Enter] can make a new one?
Or make closing the first array part of creating a new array so the [Close Grid] is not required.
in the simple example below I have used an eraseGrid() routine so no [Close Grid] required.
The array is placed at different parts of the screen because that is an easy way to spot if arrays have not been erased.
I was in fact a bit confused when first reading the thread as I assumed you were using an actual grid control not simply an array of textboxes.

Code: Select all

#Include "WinGUI.bi"

Dim shared As HWND Window_Main, Edit_Data(20, 10), Button_Redim
Dim shared As MSG msg
Dim shared As Integer i, j
dim shared as integer maxCol,maxRow

'Create the window with a data grid:
Window_Main = Window_New(100, 100, 900, 500, "Editable Datagrid")

sub eraseGrid()
    For i = 0 To maxCol
       For j = 0 To maxRow
            SendMessage(Edit_Data(i,j), WM_CLOSE, 0, 0)
       Next
    Next
end sub

sub setUpGrid()
    dim as integer yShift,xShift
    yShift = int(Rnd(1)*100)+10
    xShift = int(Rnd(1)*100)+10
    For i = 0 To maxCol
       For j = 0 To maxRow
          Edit_Data(i, j) = EditBox_New(j * 80+yShift, i * 20+xShift, 80, 20, "abc",, Window_Main)
          EditBox_SetText(Edit_Data(i, j), "text(" + Str(i) + ", " + Str(j) + ")")
       Next
    Next
end sub

maxCol = 5
maxRow = 5
setUpGrid()  'set up first grid

Button_Redim = Button_New(350, 430, 200, 20, "change dimensions",, Window_Main)

'Main:
Do
   WaitEvent(Window_Main, msg)
   If msg.message = WM_LBUTTONDOWN And msg.hwnd = Button_Redim Then
        eraseGrid()
        maxCol = int(Rnd(1)*8)+2
        maxRow = int(Rnd(1)*8)+2
        setUpGrid()
   End If

Loop Until Window_Event_Close(Window_Main, msg)

End
jj2007
Posts: 1210
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Postby jj2007 » Aug 08, 2018 0:42

BasicCoder2 wrote:If you [Enter] a new sized grid without hitting [Close Grid] the first one will remain
More precisely (see above):
If you use Edit_Text(row, col) = EditBox_New(...) twice for the same row, col, then you have created two independent controls with two different handles stored to the same place in memory. Only the last handle in (row, col) can be used to delete the second control; so the first control cannot be deleted.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 08, 2018 8:22

jj2007 wrote:
BasicCoder2 wrote:If you [Enter] a new sized grid without hitting [Close Grid] the first one will remain
More precisely (see above):
If you use Edit_Text(row, col) = EditBox_New(...) twice for the same row, col, then you have created two independent controls with two different handles stored to the same place in memory. Only the last handle in (row, col) can be used to delete the second control; so the first control cannot be deleted.

Absolutely correct. This is what I am finding.
I am looking at ways around this at the moment. BasicCoder2 has given me some ideas. I'll post when I've come up with a solution(s), or when i am screaming for help.
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 08, 2018 10:49

I decided to come up with my own solution to get over the problem of resizing the grid, as follows:

1. When initially setting up the grid, immediately close the Textbox containing the entry, so it is now unavailable to the user to change the grid size again.
2. If the user wishes to resize the grid, the resize button is clicked. This action opens a new textbox control where the original was closed. The user can now use this as before to size the grid, after which the entry textbox is closed again.
3. To keep resizing, follow items 1. and 2. again.

I have also made the TOTAL column READ-ONLY, so it cannot be altered.

I want to make the bottom row TOTALs READ-ONLY, but I'm struggling with this at the moment.

The total revised code is shown below:

Code: Select all

'=========================================================
' NumericEntryIntoGridOfTextboxes_Dev05G.bas
' Author: RNBW
' 8 August 2018
'--------------------------------------------------------------------------------------------------

'INSTRUCTIONS:
'Enter any text you want in col 2, rows 2 & 3.  It is superfluous to the exercise  and is only
'included for my own future use.
'Enter numbers into columns 3 and 4 in rows 2 and 3.  They will be automatically
'checked for numeric validity in the range 0 to 9, minus and period and for only one
'inclusion of minus and period and ensuring that the minus only occurs as the first
'character.  It will also print out ".123" as "0.123" and "-.123" as "-0.123"
'=========================================================
' TO DO:
' Format the numbers :
' As can be seen, the displayed numbers are a bit straggly.
' Format the numbers to a specific number of decimal places.
'=========================================================

#Include "WinGUI.bi"

Dim  Shared As Long NumOfRows = 10
dim shared as long NumOfCols = 5
Dim Shared As String sRows, sCols

Dim Shared As HWND Window_Main, Static_Text, Label_a, Edit_a, Button_Num, Button_CloseGrid, Label_b
Dim Shared As MSG msg
Dim Shared As String text, text2
Dim Shared As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
Dim Shared As HWND Button_Calc
Dim Shared As Long vPos, hPos, bWidth, bHeight, row, col
DIM Shared AS STRING sTxt, oldsTxt
DIM Shared AS INTEGER pos0
DIM Shared AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
DIM Shared AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
DIM Shared AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)


FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t

   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
      IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
      IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
      IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT

   a=ASC(MID(sTxt,1,1))
   IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1

   RETURN sNum1

END FUNCTION


'---------------------
' MAIN WINDOW
'---------------------
Sub OpenWindow_Main()
   Window_Main = Window_New(100, 100, 750, 400, "Numeric Input Into A Grid of Textboxes")
End Sub

OpenWindow_Main()

' Gadgets to state number of rows
'sub identifyGrid(NumOfRows)
Label_a = Label_New(10,10,270,20,"How many rows do you want to calculate",, Window_Main)
Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
Button_Num = Button_New(350,10,100,20, "Enter",, Window_Main)
'end sub

'sub resizeGrid(NumOfRows)
Label_b =  Label_New(10,40,350,20,"To resize the grid FIRST click resize button",, Window_Main)
Button_CloseGrid = Button_New(350,40,100,20, "Resize Grid",, Window_Main)
'end sub

'Open console
'Screen 12
'open cons for output as #1

Button_Calc = Button_New(10, 60, 100, 20, "Calculate!",, Window_Main)

   '-------------------------------
   '  SET UP THE GRID
   '-------------------------------
sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   Dim ES_x as Integer
   vPos = 90: bHeight = 20
   For row = 1 To NumOfRows
      For col = 1 To 5
         ES_x=ES_LEFT       ' ## default  left justified ##
         select Case col
            Case 1
               hPos = 10: bWidth = 65
            Case 2
               hPos = 75: bWidth = 380
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65: ES_x = ES_RIGHT    'right justify
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75: ES_x = ES_RIGHT or ES_READONLY   'right justify
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_x, Window_Main)
       Next
   Next

   
   '-----------------------------------
   ' SET UP HEADINGS IN ROW 1
   '-----------------------------------
   row = 1
   For col = 3 To NumOfCols
      EditBox_SetText(Edit_Text(row,col), "Number" + Str(col-2))
   Next
   EditBox_SetText(Edit_Text(row,2), "Description")
   EditBox_SetText(Edit_Text(row,5), "TOTAL")
   
   '----------------------------------
   ' SET UP HEADINGS IN COL 1
   '----------------------------------
   col = 1
   For row = 2 To NumOfRows -1
      For col = 1 To 1
         EditBox_SetText(Edit_Text(row,col), "Row" + Str(row-1))
      Next
   Next
   EditBox_SetText(Edit_Text(numOfRows,1), "TOTAL")

end sub


'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 300, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      ' CASE WM_LBUTTONDOWN
      'SELECT CASE msg.message
      CASE WM_TIMER
         'Check contents of the edit box every 300 millisecinds
         For row = 2 to NumOfRows
            FOR col = 3 TO 4
               sTxt = EditBox_GetText(Edit_Text(row,col))   'get text from edit box
               oldsTxt = sTxt      'make text the oldtext
               sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
               IF oldsTxt <> sTxt THEN
                  EditBox_SetText(Edit_Text(row,col), sTxt)   'if old text is not the same as the new text then use new text
                  pos0 = LEN(sTxt)   'position of character is the length of the current text
                  SENDMESSAGE(Edit_Text(row,col), EM_SETSEL, pos0, pos0)
               END IF
            NEXT col
         NEXT row
      CASE WM_LBUTTONDOWN
         if msg.hwnd = Button_Num then
            text = EditBox_GetText(Edit_a)
            NumOfRows = val(text)
            NumOfRows = NumOfRows + 2
            setUpGrid(NumOfRows)
            SendMessage(Edit_a, WM_CLOSE, 0, 0)
            print NumOfRows
           
         Else
            ' Click Close Grid button to close grid
            if msg.hwnd = Button_CloseGrid THEN
               for row = 1 to NumOfRows
                  for col = 1 to  5                       
                       DestroyWindow(Edit_Text(row,col))
                  next
               Next
                Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
               
            Else
               'If Calculate! button is clicked then carry out calculation
               IF msg.hwnd = Button_Calc THEN
                  totalCols(NumOfRows,col) = 0
                  FOR row = 2 to NumOfRows
                     FOR col = 3 TO 5
                        ' Total Rows--->
                        sTxt =  EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = VAL(sTxt)
                        totalRows(row,5) = numb(row, 3) + numb(row,4)
                        sTxt = STR(totalRows(row,5))
                        EditBox_SetText(Edit_Text(row,5), sTxt)
                        'Total Columns--->
                        sTxt = EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = val(sTxt)
                        totalCols(NumOfRows,col) =  totalCols(NumOfRows,col) +  numb(row-1,col)
                        sTxt = STR(totalCols(NumOfRows,col))
                        EditBox_SetText(Edit_Text(NumOfRows,col), sTxt)
                        print row; "  "; col; "  "; numb(row,col)
                     NEXT
                  NEXT
               end if
            END IF
         End if
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

End
RNBW
Posts: 186
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Postby RNBW » Aug 08, 2018 16:18

The following may not be something that everyone wants to do, I have formatted the number cells so that they display numbers to 3 decimal places after the calculation button is clicked. Of course this can be changed in the program to other figures or REMd out if preferred.

I now also have the last row and the right hand column of the grid Read Only. The code for the last row is a bit clumsy and I have repeated the code for the other rows again, but this last row has the ES_READONLY style included, whereas the other rows only have the ES_READONLY style in the last column.

I think this is about as far as I want to go with this particular exercise, but I am open to suggestions for better ways to achieve what I have done. Just one thing: please don't suggest not using a grid of textboxes. I have a particular reason for doing this, so it won't change.

I hope the code is of use to others and you are of course free to use all or part of it for your own use, obviously at your own risk. I will give no guarantee that it is error free.

Code: Select all

'=========================================================
' NumericEntryIntoGridOfTextboxes_Dev05H.bas
' Author: RNBW
' 8 August 2018
'--------------------------------------------------------------------------------------------------

'INSTRUCTIONS:
'Enter any text you want in col 2, rows 2 & 3.  It is superfluous to the exercise  and is only
'included for my own future use.
'Enter numbers into columns 3 and 4 in rows 2 and 3.  They will be automatically
'checked for numeric validity in the range 0 to 9, minus and period and for only one
'inclusion of minus and period and ensuring that the minus only occurs as the first
'character.  It will also print out ".123" as "0.123" and "-.123" as "-0.123"
'The final display presents the numbers to 3 decimal places
'=========================================================
' TO DO:
' ?
'=========================================================

#Include "WinGUI.bi"
#include "string.bi"
 
Dim  Shared As Long NumOfRows = 10  'this is an arbitrary value, it doesn't seem to matter
dim shared as long NumOfCols = 5
Dim Shared As String sRows, sCols

Dim Shared As HWND Window_Main, Static_Text, Label_a, Edit_a, Button_Num, Button_CloseGrid, Label_b
Dim Shared As MSG msg
Dim Shared As String text, text2
Dim Shared As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
Dim Shared As HWND Button_Calc
Dim Shared As Long vPos, hPos, bWidth, bHeight, row, col
DIM Shared AS STRING sTxt, oldsTxt
DIM Shared AS INTEGER pos0
DIM Shared AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
DIM Shared AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
DIM Shared AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
dim shared as double number


FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t

   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
      IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
      IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
      IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT

   a=ASC(MID(sTxt,1,1))
   IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1

   RETURN sNum1

END FUNCTION


'---------------------
' MAIN WINDOW
'---------------------
Sub OpenWindow_Main()
   Window_Main = Window_New(100, 100, 750, 400, "Numeric Input Into A Grid of Textboxes")
End Sub

OpenWindow_Main()

' Gadgets to state number of rows
'sub identifyGrid(NumOfRows)
Label_a = Label_New(10,10,270,20,"How many rows do you want to calculate",, Window_Main)
Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
Button_Num = Button_New(350,10,100,20, "Enter",, Window_Main)
'end sub

'sub resizeGrid(NumOfRows)
Label_b =  Label_New(10,40,350,20,"To resize the grid FIRST click resize button",, Window_Main)
Button_CloseGrid = Button_New(350,40,100,20, "Resize Grid",, Window_Main)
'end sub

'Open console
'Screen 12
'open cons for output as #1

Button_Calc = Button_New(10, 60, 100, 20, "Calculate!",, Window_Main)

   '-------------------------------
   '  SET UP THE GRID
   '-------------------------------
sub setUpGrid(NumOfRows as long)
    reDim As HWND Edit_Text(1 To NumOfRows, 1 To NumOfCols)
   reDIM AS DOUBLE numb(2 TO NumOfRows, 3 TO NumOfCols)
   reDIM AS DOUBLE totalRows(2 TO NumOfRows, NumOfCols)
   reDIM AS DOUBLE totalCols(NumOfRows, 3 TO NumOfCols)
   Dim ES_x as Integer
   vPos = 90: bHeight = 20
   For row = 1 To NumOfRows-1
      For col = 1 To 5
         ES_x=ES_LEFT       ' ## default  left justified ##
         select Case col
            Case 1
               hPos = 10: bWidth = 65: ES_x=ES_LEFT
            Case 2
               hPos = 75: bWidth = 380: ES_x=ES_LEFT
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65: ES_x = ES_RIGHT    'right justify
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75: ES_x = ES_RIGHT or ES_READONLY   'right justify
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_x, Window_Main)
       Next
   Next
   ' This is a bit clumsy but is the best I could come up with
   ' It takes the last row of the grid which includes the column totals
   ' and makes them READONLY.
  For row = NumOfRows To NumOfRows
      For col = 1 To 5
         ES_x=ES_LEFT       ' ## default  left justified ##
         select Case col
            Case 1
               hPos = 10: bWidth = 65:  ES_x=ES_LEFT or ES_READONLY
            Case 2
               hPos = 75: bWidth = 380 : ES_x=ES_LEFT or ES_READONLY
            CASE 3 TO 4
               hpos =  col*65+(455-65*3) : bWidth = 65: ES_x = ES_RIGHT or ES_READONLY    'right justify
            CASE 5
               hPos = (10+65+380)+(col-3)*65 : bWidth = 75: ES_x = ES_RIGHT or ES_READONLY   'right justify
         End Select
         Edit_Text(row, col) = EditBox_New(hPos, vPos+bHeight*(row-1), bWidth+1, bHeight+1, "",ES_x, Window_Main)
       Next
   Next
   
   '-----------------------------------
   ' SET UP HEADINGS IN ROW 1
   '-----------------------------------
   row = 1
   For col = 3 To NumOfCols
      EditBox_SetText(Edit_Text(row,col), "Number" + Str(col-2))
   Next
   EditBox_SetText(Edit_Text(row,2), "Description")
   EditBox_SetText(Edit_Text(row,5), "TOTAL")
   
   '----------------------------------
   ' SET UP HEADINGS IN COL 1
   '----------------------------------
   col = 1
   For row = 2 To NumOfRows -1
      For col = 1 To 1
         EditBox_SetText(Edit_Text(row,col), "Row" + Str(row-1))
      Next
   Next
   EditBox_SetText(Edit_Text(numOfRows,1), "TOTAL")

end sub


'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 300, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      ' CASE WM_LBUTTONDOWN
      'SELECT CASE msg.message
      CASE WM_TIMER
         'Check contents of the edit box every 300 millisecinds
         For row = 2 to NumOfRows
            FOR col = 3 TO 4
               sTxt = EditBox_GetText(Edit_Text(row,col))   'get text from edit box
               oldsTxt = sTxt      'make text the oldtext
               sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
               IF oldsTxt <> sTxt THEN
                  EditBox_SetText(Edit_Text(row,col), sTxt)   'if old text is not the same as the new text then use new text
                  pos0 = LEN(sTxt)   'position of character is the length of the current text
                  SENDMESSAGE(Edit_Text(row,col), EM_SETSEL, pos0, pos0)
               END IF
            NEXT col
         NEXT row
      CASE WM_LBUTTONDOWN
         if msg.hwnd = Button_Num then
            text = EditBox_GetText(Edit_a)
            NumOfRows = val(text)
            NumOfRows = NumOfRows + 2
            setUpGrid(NumOfRows)
            SendMessage(Edit_a, WM_CLOSE, 0, 0)
            print NumOfRows
           
         Else
            ' Click Close Grid button to close grid
            if msg.hwnd = Button_CloseGrid THEN
               for row = 1 to NumOfRows
                  for col = 1 to  5                       
                       DestroyWindow(Edit_Text(row,col))
                  next
               Next
                Edit_a = EditBox_New(300,10,30,20,"", ES_CENTER or WS_BORDER, Window_Main)
               
            Else
               'If Calculate! button is clicked then carry out calculation
               IF msg.hwnd = Button_Calc THEN
                  totalCols(NumOfRows,col) = 0
                  FOR row = 2 to NumOfRows
                     FOR col = 3 TO 5
                        ' Total Rows--->
                        sTxt =  EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = VAL(sTxt)
                        sTxt = format(numb(row,col), "###0.000")
                        EditBox_SetText(Edit_Text(row,col), sTxt)
                        totalRows(row,5) = numb(row, 3) + numb(row,4)
                        sTxt = format(totalRows(row,5), "####0.000")
                        EditBox_SetText(Edit_Text(row,5), sTxt)
                        'Total Columns--->
                        sTxt = EditBox_GetText(Edit_Text(row,col))
                        numb(row,col) = val(sTxt)
                        totalCols(NumOfRows,col) =  totalCols(NumOfRows,col) +  numb(row-1,col)
                        sTxt = format(totalCols(NumOfRows,col), "####0.000")                       
                        EditBox_SetText(Edit_Text(NumOfRows,col), sTxt)
                        print row; "  "; col; "  "; numb(row,col)
                     NEXT
                  NEXT
               end if
            END IF
         End if
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

End

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 3 guests