Setting up a table with varying numbers of rows

Just starting out? Need help? Post your questions and find answers here.
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Setting up a table with varying numbers of rows

Post by RNBW »

I want to set up a small spreadsheet-like table, 7 columns wide (with varying widths) and up to 8 rows deep. The number of rows to be displayed will be input by the user before they are displayed on the screen. This figure could be anything between 1 and 8. So when displayed, the table would be anything between 1 row and 7 columns to 8 rows and 7 columns.

Data will be entered into the cells by the user which can then be read as variables and used in various formulae.

How would I go about this in Purebasic?
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Setting up a table with varying numbers of rows

Post by Keya »

a 2D string array?

Code: Select all

NumRows = 8
NumCols = 8

Dim MyArray.s(NumCols,NumRows)
 
;Fill the MyArray array with some values
For col = 1 To 8
  For row = 1 To 8
    MyArray(col,row) = "Col"+Str(col) + ",Row"+Str(row)
  Next row
Next col
you can also change the size of an array while preserving its contents using ReDim()
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

Hi Keya

Thanks for the quick reply.

It's not the array part that's the difficulty. Maybe I need to explain myself better. What I want to do is to display a table in the form of boxes (like a spreadsheet) which can vary between 1 row / 7 columns and 8 rows / 7 columns. The user will decide how many rows immediately before displaying the mini-spreadsheet. It's how you achieve this that I need to know.

I originally did this in LB Booster (Liberty Basic) using a loop to set up the table (the concept code was kindly produced by Richard Russell and I modified it to meet my requirements. I want to be able to do something similar in Purebasic but I can't work out how to do it.
infratec
Always Here
Always Here
Posts: 7576
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Setting up a table with varying numbers of rows

Post by infratec »

Hi,

maybe something like that:

Code: Select all

OpenWindow(0, 0, 0, 800, 600, "Runtime ListIconGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)

TextGadget(0, 10, 10, 50, 20, "Rows:")
SpinGadget(1, 70, 10, 50, 20, 1, 10, #PB_Spin_ReadOnly|#PB_Spin_Numeric)
SetGadgetState(1, 1)
ButtonGadget(2, 130, 10, 30, 20, "Set")

ListIconGadget(3, 10, 40, 780, 550, "1", 80)

Columns = 1

Repeat
  
  Event = WaitWindowEvent()
  
  Select Event
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 2
          If IsGadget(3)
            NewColumns = GetGadgetState(1)
            If NewColumns > Columns
              For i = Columns To NewColumns
                AddGadgetColumn(3, i, Str(i + 1), 80)
              Next i
              Columns = NewColumns
            ElseIf NewColumns < Columns
              For i = Columns To NewColumns Step -1
                RemoveGadgetColumn(3, i)
              Next i
            EndIf
          EndIf
      EndSelect
      
    Case #PB_Event_CloseWindow
      Exit = #True
  EndSelect
  
Until Exit
Bernd
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

Hi Bernd

Thank you for your response, it was an interesting bit of code, because I've not done much with listboxes yet. Unfortunately, not what I am looking for.

If you imagine a spreadsheet made up of textboxes, with 7 columns of various widths and with rows between 1 and 8 (the number of rows being chosen by the user at runtime. That's what I'm trying to achieve.

I'm working on it and managed to get a single column of textboxes, but it seems to be a bit of a bodge and I think there must be a better way.

The code I've used is shown below (it's in a vary rough state as I've just been playing with it but it should give an idea of what I'm after.

Code: Select all


;produces a single column of textboxes

#WindowWidth  = 390
#WindowHeight = 350

If OpenWindow(0, 100, 200, #WindowWidth, #WindowHeight, "PureBasic - Gadget Demonstration", #PB_Window_MinimizeGadget)
    
  Top = 10
  gHt = 24
  gNum.i
  
  FrameGadget(#PB_Any, 10, Top, 370, 290, "Player...") : Top+20

For x = 1 To 6
  gNum = x-1
  StringGadget(gNum+x,  20, Top, 200, gHt, "")
  Debug gNum
  Top = Top+gHt
Next

  
  ButtonGadget(2, 295, Top+gHt*4, 72, gHt, "Useless")  : Top+35
  
; the following is just a bit of useless code 
  Repeat
    Event.l = WaitWindowEvent()
    Select Event
      Case 1  ; dummy selection
    EndSelect
    
  Until Event = #PB_Event_CloseWindow Or Quit = #True
  
EndIf
What I have found is that if you remove the -1 in gNum = x-1 and the +1 in StringGadget(gNum+x, .... then a column is of textboxes is printed out, but one textbox is missing.

I have still to start with more than one column, but any help is appreciated.

Best regards

Ray
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Setting up a table with varying numbers of rows

Post by srod »

That is because one of the string gadgets will have a gadget# equal to 2. The button gadget then overwrites it (since it uses the same gadget#) and thus destroys the relevant string gadget. You need to think more carefully about the gadget#'s and make sure that none are repeated.

The following might get you started.

Code: Select all

;produces a single column of textboxes

#WindowWidth  = 840
#WindowHeight = 350

If OpenWindow(0, 100, 200, #WindowWidth, #WindowHeight, "PureBasic - Gadget Demonstration", #PB_Window_MinimizeGadget)
  For row=0 To 6
    For col = 0 To 7
      StringGadget(row*8+col, 20 + col*100, 10 + row*24, 100, 24, "")
    Next
  Next
  
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Gadget
        Debug "Event fired on Gadget : " + Str(EventGadget())
    EndSelect
  Until Event = #PB_Event_CloseWindow Or Quit = #True
  
EndIf
I may look like a mule, but I'm not a complete ass.
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

Thanks

What you have produced is on the way to what I am looking for. I'll have a close look at your explanation and at your code and see if I can modify it to what I am looking for.

Ray
Amilcar Matos
User
User
Posts: 43
Joined: Thu Nov 27, 2014 3:10 pm
Location: San Juan, Puerto Rico

Re: Setting up a table with varying numbers of rows

Post by Amilcar Matos »

@RNBW
Hope this helps you. :D

Code: Select all

;{ ==Code Header Comment==============================
;        Name/title: StringGadgetsSpreadsheet.pb 
;   Executable name: StringGadgetsSpreadsheet.exe
;           Version: 1.0
;            Author: Amílcar Matos Pérez
;     Collaborators: Based on Srod concept.
;    Translation by: 
;       Create date: 05/Feb/2016
; Previous releases: 
; This Release Date: 
;  Operating system: Windows  [X]GUI
;  Compiler version: PureBasic 5.41 (x64)
;         Copyright: (C)2015 AMP All rights reserved.
;           License: Free to use. Author credit kindly requested. All common disclaimers apply.
;         Libraries: 
;     English Forum: http://www.purebasic.fr/english/viewtopic.php?f=13&t=64765
;      French Forum: 
;      German Forum: 
;  Tested platforms: Windows
;       Description: To create a table of string gadgets as defined by the user.
;       Advertising: Honest, dependable, on time coding help for your commercial projects,
;                    please send a private message to Amílcar Matos Pérez in the PureBasic forum.
; ====================================================
;.......10........20........30........40........50........60........70........80
;}

EnableExplicit

;{ Constants
#WindowWidth    = 840  
#WindowHeight   = 350  
#CellWidth      = 100  
#CellHeight     = 24   
#XMargin        = 20   
#YMargin        = 10   
#MaxNbOfRows    = 8    
#MaxNbOfColumns = 7    
#MinNbOfRows    = 1     ;  minimum number of rows.
#MinNbOfColumns = 1     ;  minimum number of columns. 
                        ;}

;{ constants control - raise a debugging warning for any true condition.
If #MinNbOfRows > #MaxNbOfRows 
  MessageRequester ("Info", "Minimum number of rows exceed the maximum number allowed.", #MB_ICONQUESTION)
  End
EndIf

If #MinNbOfColumns > #MaxNbOfColumns
  MessageRequester ("Info", "Minimum number of columns exceed the maximum number allowed.", #MB_ICONQUESTION)
  End
EndIf
;}

;{ Variable exposure
Global Dim AllTableGadgetNbs(0)
Global GoBtn.l   
Global NewCols.l 
Global NewRows.l 
Global SpinCols.l
Global SpinRows.l
Global Flags.l
Global Title$
Global Event.l 
Global Quit.l
;}

Declare.l Caribbean_Window_Events(Event)
Declare.l StringGadgetsTableMaker(MaxRows, MaxCols, Array AllTableGadgetNbs(1))  
Declare.l GadgetsEraser(Array AllTableGadgetNbs(1))  

;{ Main program.
Flags  = #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
Title$ = "Playing with string gadgets on a nice caribbean day."
If OpenWindow(0, 0, 0, #WindowWidth, #WindowHeight, Title$, Flags)
  
  StringGadgetsTableMaker(#MaxNbOfRows, #MaxNbOfColumns, AllTableGadgetNbs())
  TextGadget (#PB_Any, 730, 24, 50, 20, "Rows:")
  TextGadget (#PB_Any, 730, 48, 50, 20, "Cols:")
  Flags    = #PB_Spin_ReadOnly|#PB_Spin_Numeric
  SpinRows = SpinGadget  (#PB_Any, 770, 24, 50, 20, 1, 8, Flags)  
  SpinCols = SpinGadget  (#PB_Any, 770, 48, 50, 20, 1, 7, Flags)  
  GoBtn    = ButtonGadget(#PB_Any, 770, 74, 30, 30, "Go")                                            
  
  Repeat
    Event = WaitWindowEvent()
    Quit  = Caribbean_Window_Events(Event)
  Until Quit = 0
  
EndIf

; All the opened windows are closed automatically by PureBasic.
End
;} 

Procedure.l Caribbean_Window_Events(Event)
  
  Select Event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False
      
    Case #PB_Event_Gadget
      Select EventGadget()            
        Case SpinRows
        Case SpinCols
        Case GoBtn
          ; erase previous table.
          GadgetsEraser(AllTableGadgetNbs())            
          
          ; Get new row and column values. Assign minimum values if needed.
          NewRows = GetGadgetState(SpinRows)
          If NewRows < #MinNbOfRows Or
             NewRows > #MaxNbOfRows
            ; minimum number of rows
            NewRows = #MinNbOfRows
          EndIf
          
          NewCols = GetGadgetState(SpinCols)
          If NewCols < #MinNbOfColumns Or
             NewCols > #MaxNbOfColumns
            ; minimum number of colums
            NewCols = #MinNbOfColumns
          EndIf
          
          ; Build new table.
          StringGadgetsTableMaker(NewRows, NewCols, AllTableGadgetNbs())
          
        Default
          ; Other events.
          Debug "Event fired on Gadget : " + Str(EventGadget())
      EndSelect
      
  EndSelect
  
  ProcedureReturn #True
  
EndProcedure

Procedure.l StringGadgetsTableMaker(MaxRows, MaxCols, Array AllTableGadgetNbs(1))
  ; To build a new table.
  
  ;{ Protected variables
  Protected ArrayRowNb.l                   
  Protected CellGadgetNb.l                 
  Protected GadgetPosX.l                    
  Protected GadgetPosY.l                    
  Protected Row.l
  Protected Col.l
  ;}
  
  ; Test incoming values.
  If MaxRows < 0 Or
     MaxCols < 0
    ProcedureReturn #False
  EndIf
  
  ReDim AllTableGadgetNbs(MaxRows * MaxCols)
  For Row = 0 To MaxRows - 1     ; less one because count starts at zero.
    
    For Col = 0 To MaxCols - 1 
      GadgetPosX   = #XMargin + (Col * #CellWidth )
      GadgetPosY   = #YMargin + (Row * #CellHeight)
      CellGadgetNb = StringGadget(#PB_Any, GadgetPosX , GadgetPosY, #CellWidth, #CellHeight, #Empty$)  
      ArrayRowNb   = (Row * MaxCols) + Col
      AllTableGadgetNbs(ArrayRowNb) = CellGadgetNb
      If Row = 0
        ; Put a letter in the heading row. Letter starts with 'A'.
        SetGadgetText(CellGadgetNb, Chr('A' + Col))  ;<= newbies look here; a purebasic self documenting no magic numbers trick!
      EndIf      
    Next Col
    
    If Row > 0
      ; Put a number on the first box of each row. Number starts at one.
      ArrayRowNb   = (Row * MaxCols) + 0  ;<= this formula is different from the above.
      CellGadgetNb = AllTableGadgetNbs(ArrayRowNb)
      SetGadgetText(CellGadgetNb, Str(Row))
    EndIf
    
  Next Row
  
  ProcedureReturn #True
  
EndProcedure

Procedure.l GadgetsEraser(Array AllTableGadgetNbs(1))
  ; To erase screen gadgets.
  
  ;{ Protected variables
  Protected GadgetNb.l
  Protected MaxRows.l
  Protected Row.l
  ;}
  
  MaxRows = ArraySize(AllTableGadgetNbs())
  
  For Row = 0 To MaxRows - 1  ;zero based counting.
    
    ; Get each gadget number from the array.
    GadgetNb   = AllTableGadgetNbs(Row)                       
    ; Erase each string gadget.
    FreeGadget(GadgetNb)
    
  Next Row
  
  ; Erase the old gadget number list.
  ReDim AllTableGadgetNbs(0)
  
  ProcedureReturn #True
  
EndProcedure

User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Setting up a table with varying numbers of rows

Post by TI-994A »

RNBW wrote:I want to set up a small spreadsheet-like table, 7 columns wide (with varying widths) and up to 8 rows deep. The number of rows to be displayed will be input by the user before they are displayed on the screen....
Here's a simple text grid to illustrate the implementation of your requirements. It uses string gadgets, so the cells are editable, laid out evenly to fit the given size. This could easily be modified to accommodate varying cell-widths, and even replaced with text-gadgets for read-only cells. The grid is encapsulated within a container gadget, allowing it to be moved easily. Two convenience functions have been included to set the cell values and row-visibility.

Code: Select all

Enumeration 
  #MainWindow 
  #ToggleView
  #MoveGrid
EndEnumeration

Dim myTextGrid(7, 6)

Procedure TextGrid(x, y, width, height, Array gridInfo(2))
  Protected cellSpacing = 5
  Protected rows = ArraySize(gridInfo(), 1)
  Protected columns = ArraySize(gridInfo(), 2)
  Protected cellX = cellSpacing, cellY = cellSpacing
  Protected cellHeight = (height - (cellSpacing * (rows + 2))) / (rows + 1)
  Protected cellWidth = (width - (cellSpacing * (columns + 2))) / (columns + 1)
    
  gridID = ContainerGadget(#PB_Any, x , y, width, height, #PB_Container_Flat)
  
  For row = 0 To rows
    For column = 0 To columns
      gridInfo(row, column) = StringGadget(#PB_Any, cellX, cellY, cellWidth, cellHeight, 
                                           "Cell " + Str(row) + ", " + Str(column), 
                                           #PB_Text_Center | #PB_String_BorderLess)
      SetGadgetColor(gridInfo(row, column), #PB_Gadget_BackColor, #White)
      cellX + (cellWidth + cellSpacing)
    Next column
    cellX = cellSpacing
    cellY + (cellHeight + cellSpacing)
  Next row
  
  CloseGadgetList()
  
  ProcedureReturn gridID
EndProcedure 

Procedure ShowGridRows(row, state = #False)
  Shared myTextGrid()
  For column = 0 To ArraySize(myTextGrid(), 2)
    HideGadget(myTextGrid(row, column), state)
  Next column 
EndProcedure

Procedure SetGrid(row, column, text.s, frontColour = 0, backColour = 16777215)
  Shared myTextGrid()
  SetGadgetText(myTextGrid(row, column), text)
  SetGadgetColor(myTextGrid(row, column), #PB_Gadget_FrontColor, frontColour)  
  SetGadgetColor(myTextGrid(row, column), #PB_Gadget_BackColor, backColour)
EndProcedure

wFlags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered
OpenWindow(#MainWindow, #PB_Any, #PB_Any, 1000, 700, "Simple Text Grid", wFlags)
ButtonGadget(#ToggleView, 10, 650, 980, 40, "CLICK TO TOGGLE-VIEW LAST TWO ROWS")
ButtonGadget(#MoveGrid, 10, 600, 980, 40, "CLICK TO MOVE TEXT GRID")
myGrid = TextGrid(10, 10, 700, 400, myTextGrid())

SetGrid(0, 0, "Click cell to edit...")
SetGrid(0, 1, "Manually set...", RGB(255, 255, 0), RGB(255, 0, 0))
SetGrid(3, 3, "Another one...", RGB(0, 0, 255), RGB(0, 255, 255))
SetGrid(6, 5, "Me too!", RGB(0, 100, 0), RGB(0, 255, 0))

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = 1
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #MoveGrid
          x = Random(300, 10)
          y = Random(200, 10)
          ResizeGadget(myGrid, x, y, #PB_Ignore, #PB_Ignore)
        Case #ToggleView
          If state
            state = #False
          Else
            state = #True
          EndIf
          ShowGridRows(6, state)
          ShowGridRows(7, state)
      EndSelect
  EndSelect
Until appQuit = 1
Hope you'd find it useful. :wink:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

Thank you very much srod, Amilcar Matos and TI-994A for the code that you have provided. You have all given me ideas and code that I can put to use. I'll have a good look at your code and see how best to make use of it.

Thank you again!
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

Working on srod's solution first, I've modified it and produced code for a grid. It's worth noting the code line

Code: Select all

StringGadget(gNum, xpos, vpos+row*rowHigh-rowHigh, width+1, rowHigh+1, "")
Adding the 1 to width and rowHigh results in a much thinner line to the borders of the grid. I don't know why this happens and don't claim the idea to be mine. This work-around was provided by Richard Russell in LB Booster Conforums. I'm pleased to see it work in Purebasic as well.

The code for the grid is:

Code: Select all

[color=#00BF00];produces a grid of textboxes[/color]

#WindowWidth  = 900
#WindowHeight = 350

If OpenWindow(0, 100, 200, #WindowWidth, #WindowHeight, "PureBasic - Grid Demonstration", #PB_Window_MinimizeGadget)

TotalRows = 12

vpos = 50 : rowHigh = 20 

lDist.i = 30

For row = 1 To TotalRows
  For col = 1 To 8
    
    Select col
      [color=#00BF00];First column[/color] 
      Case 1
        xpos = lDist : width = 65
     [color=#00BF00] ;Second Column[/color] 
      Case 2 
        xpos = lDist+65 : width = 380
      [color=#00BF00];Columns 3 To 8[/color]
      Case 3,4,5,6,7,8 
        xpos = lDist+col*65+(445-65*3) : width = 65
    EndSelect
            
    gNum.i = row*8-8+col
    [color=#00BF00]; NOTE: add 1 to both width and rowHigh and this removes the duplication 
    ; of the border of boxes, resulting in a thinner line.[/color]
    StringGadget(gNum, xpos, vpos+row*rowHigh-rowHigh, width+1, rowHigh+1, "")
    Debug gNum
  Next col   
Next row 

 Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Gadget
        Debug "Event fired on Gadget : " + Str(EventGadget())
    EndSelect
  Until Event = #PB_Event_CloseWindow Or Quit = #True
 
EndIf
My next steps:
1.. Make the number of rows variable
2.. Make it possible to add text into boxes
3.. Make it possible to extract text from boxes
4.. Utilise the extracted text from boxes into variables for further use in the program

I know these seem pretty obvious but I am using it as a bit of a tutorial for myself.

I'm also going to look at the code provided by Amilcar Matos and TI-994A.

I'm still working on it!
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

I've just looked at my last posting.

A bit disappointing, I was hoping that the comments would show up in green.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Setting up a table with varying numbers of rows

Post by srod »

It is no mystery.

The 'borders' of the grid are simply the borders of the string gadgets. By using the +1 you are effectively overlapping the gadgets which means the bottom border of one gadget overlaps the top border of the gadget below it and so on.
I may look like a mule, but I'm not a complete ass.
User avatar
TI-994A
Addict
Addict
Posts: 2698
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Setting up a table with varying numbers of rows

Post by TI-994A »

RNBW wrote:...I was hoping that the comments would show up in green.
Colour tags work only in normal text blocks...

Code: Select all

[color=#00BF00]...but are ignored in code blocks[/color]
:wink:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
RNBW
User
User
Posts: 71
Joined: Thu Jan 02, 2014 5:01 pm

Re: Setting up a table with varying numbers of rows

Post by RNBW »

srod

You are correct with your explanation of why the "+1" trick works. The effect is not noticeable except for making the grid lines thinner. If instead you use, say, "+10" (obviously you wouldn't) then you can see the effect on the last row and last column which become larger by this amount.

If you want to have a small space between the textboxes in the grid, then use "-1" or "-2". It's a neat solution.

However, my reason for mentioning it was because none of the contributors had used it and not many, in my experience are aware of it (that is in various computer languages). It's a handy tip and can make a grid look a lot smarter (much more like a spreadsheet).

Anyway, thanks again for the code you produced. It showed I wasn't too far away with the code I had written for LB Booster, but I was not aware how to convert it to Purebasic.

Ray
Post Reply