McBasic™Get McBasic™ ↗
Build 881
Hands-on · McBasic™ 0.5

Build a six-cell control array

Create one repeated interface, write one shared Change handler, and test lookup, visibility and missing-member recovery.

Step 1Choose a finished solution or a blank rebuild#

Open the extracted ControlArrayBoard.mcproj in a writable practice folder. The download already contains the complete grid: inspect it, but do not run Create Control Array on top of it. To rebuild from scratch, create a Desktop App, keep one startup Form named frmMain, and add the layout before pasting the code. This lesson needs McBasic™ 0.5.822 or a later compatible build.

Step 2Create the grid and the supporting controls#

Set the Form itself to these values:

PropertyValue
CaptionControl Array Board
Width580
Height300
MinWidth580
MinHeight300

For a blank rebuild, add one TextBox named txtCell with no Index yet. Set Left 24, Top 24, Width 64, Height 36, Text empty, MaxLength 1, Alignment Center and TabIndex 0. Keep Left/Top anchors. Do not paste indexed BASIC code before creating the array.

Create Control Array fieldValue
Columns3
Rows2
Spacing12
Group every0
Group spacing0
Start Index0

Select the template, choose Design → Create Control Array… and enter the values above. Create produces indexes 0–2 on the first row and 3–5 on the second. Their Left values are 24, 100 and 176; Top is 24 or 72. Give each member AccessibleName Cell 0 through Cell 5.

Add these ordinary, non-array controls directly to the Form. Keep Index empty. The Label uses WordWrap True; keep left/top anchors on the buttons and left/top/right on the Label.

Type / NameLeft, TopWidth × HeightCaptionTabIndex
Label / lblStatus24, 126520 × 60Readydefault
CommandButton / cmdClear24, 212120 × 32Clear6
CommandButton / cmdToggle156, 212120 × 32Hide / show 57
CommandButton / cmdInspect288, 212120 × 32Find cell 48
CommandButton / cmdMissing420, 212120 × 32Probe missing9

Step 3Connect six members to one procedure#

Bind Change on every txtCell member to the same txtCell_Change procedure. Its first argument identifies the member, so do not create txtCell0_Change and txtCell1_Change. Bind each button Click to its corresponding procedure. Form_Load is the Form lifecycle procedure.

OwnerEventProcedure
txtCell(0)…txtCell(5)ChangetxtCell_Change(ByVal Index As Integer)
cmdClearClickcmdClear_Click()
cmdToggleClickcmdToggle_Click()
cmdInspectClickcmdInspect_Click()
cmdMissingClickcmdMissing_Click()
frmMainLoadForm_Load()

Step 4Enter the complete Form code#

Replace frmMain.bas with this entire file. ClearCells sets mLoading before changing Text because programmatic edits also raise Change. UpdateStatus iterates existing members and avoids assuming that every number between the bounds exists. cmdInspect demonstrates typed references; cmdMissing catches a deliberately absent member.

frmMain.bas — complete file
Option Explicit

Private mLoading As Boolean

Private Sub Form_Load()
    ClearCells
End Sub

Private Sub ClearCells()
    Dim cell As TextBox
    mLoading = True
    For Each cell In txtCell
        cell.Text = ""
        cell.Visible = True
    Next
    mLoading = False
    UpdateStatus
End Sub

Private Sub UpdateStatus()
    Dim cell As TextBox
    Dim filled As Long
    For Each cell In txtCell
        If Len(cell.Text) > 0 Then filled = filled + 1
    Next
    lblStatus.Caption = filled & " of " & txtCell.Count & " cells filled; indexes " & txtCell.LBound & " to " & txtCell.UBound
End Sub

Private Sub txtCell_Change(ByVal Index As Integer)
    If mLoading Then Exit Sub
    UpdateStatus
End Sub

Private Sub cmdClear_Click()
    ClearCells
End Sub

Private Sub cmdToggle_Click()
    txtCell(5).Visible = Not txtCell(5).Visible
    UpdateStatus
End Sub

Private Sub cmdInspect_Click()
    Dim found As Control
    Dim field As TextBox
    Dim references(1) As TextBox
    Set references(0) = txtCell(0)
    Set references(1) = txtCell(5)
    Set found = Me.Controls("txtCell", 4)
    If TypeOf found Is TextBox Then
        Set field = found
        lblStatus.Caption = "Found " & field.Name & "(" & field.Index & "); " & Me.Controls.Count & " controls; last reference " & references(1).Index
    End If
End Sub

Private Sub cmdMissing_Click()
    Dim missing As TextBox
    Try
        Set missing = txtCell(99)
    Catch
        lblStatus.Caption = "Missing member: error " & Err.Number
    End Try
End Sub

Step 5Check the layout contract and save state#

This project has no external resources or dependencies. The full layout below is the downloadable solution, useful for checking names, Index values and event bindings. Save with Command–S and confirm Saved at plus the removal of Edited; a save failure leaves the unsaved state visible.

Complete frmMain.form.json
Exact layout
{
  "schemaVersion": 1,
  "formId": "main",
  "properties": {
    "Caption": "Control Array Board",
    "Width": 580,
    "Height": 300,
    "MinWidth": 580,
    "MinHeight": 300
  },
  "layout": {
    "mode": "Freeform",
    "unit": "DIP"
  },
  "controls": [
    {
      "id": "cell-0",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 0,
        "Left": 24,
        "Top": 24,
        "Width": 64,
        "Height": 36,
        "TabIndex": 0,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 0"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "cell-1",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 1,
        "Left": 100,
        "Top": 24,
        "Width": 64,
        "Height": 36,
        "TabIndex": 1,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 1"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "cell-2",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 2,
        "Left": 176,
        "Top": 24,
        "Width": 64,
        "Height": 36,
        "TabIndex": 2,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 2"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "cell-3",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 3,
        "Left": 24,
        "Top": 72,
        "Width": 64,
        "Height": 36,
        "TabIndex": 3,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 3"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "cell-4",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 4,
        "Left": 100,
        "Top": 72,
        "Width": 64,
        "Height": 36,
        "TabIndex": 4,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 4"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "cell-5",
      "name": "txtCell",
      "type": "McBasic.Standard.TextBox",
      "properties": {
        "Index": 5,
        "Left": 176,
        "Top": 72,
        "Width": 64,
        "Height": 36,
        "TabIndex": 5,
        "Text": "",
        "MaxLength": 1,
        "Alignment": "Center",
        "AccessibleName": "Cell 5"
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Change",
          "handler": "txtCell_Change"
        }
      ]
    },
    {
      "id": "status",
      "name": "lblStatus",
      "type": "McBasic.Standard.Label",
      "properties": {
        "Left": 24,
        "Top": 126,
        "Width": 520,
        "Height": 60,
        "Caption": "Ready",
        "WordWrap": true
      },
      "anchors": [
        "Left",
        "Top",
        "Right"
      ],
      "events": []
    },
    {
      "id": "cmdClear",
      "name": "cmdClear",
      "type": "McBasic.Standard.CommandButton",
      "properties": {
        "Left": 24,
        "Top": 212,
        "Width": 120,
        "Height": 32,
        "Caption": "Clear",
        "TabIndex": 6
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Click",
          "handler": "cmdClear_Click"
        }
      ]
    },
    {
      "id": "cmdToggle",
      "name": "cmdToggle",
      "type": "McBasic.Standard.CommandButton",
      "properties": {
        "Left": 156,
        "Top": 212,
        "Width": 120,
        "Height": 32,
        "Caption": "Hide / show 5",
        "TabIndex": 7
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Click",
          "handler": "cmdToggle_Click"
        }
      ]
    },
    {
      "id": "cmdInspect",
      "name": "cmdInspect",
      "type": "McBasic.Standard.CommandButton",
      "properties": {
        "Left": 288,
        "Top": 212,
        "Width": 120,
        "Height": 32,
        "Caption": "Find cell 4",
        "TabIndex": 8
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Click",
          "handler": "cmdInspect_Click"
        }
      ]
    },
    {
      "id": "cmdMissing",
      "name": "cmdMissing",
      "type": "McBasic.Standard.CommandButton",
      "properties": {
        "Left": 420,
        "Top": 212,
        "Width": 120,
        "Height": 32,
        "Caption": "Probe missing",
        "TabIndex": 9
      },
      "anchors": [
        "Left",
        "Top"
      ],
      "events": [
        {
          "event": "Click",
          "handler": "cmdMissing_Click"
        }
      ]
    }
  ],
  "components": []
}

Step 6Exercise every branch#

Run Check before Run. Then perform these actions in order:

ActionExpected result
Launch0 of 6 cells filled; indexes 0 to 5.
Enter A in cell 0 and B in cell 42 of 6 cells filled.
Hide / show 5 twiceCell 5 disappears and returns; Count remains 6.
Find cell 4Found txtCell(4); 11 controls; last reference 5.
Probe missingMissing member: error 340. The application stays usable.
ClearAll cells are empty and visible; count returns to 0 of 6.
Close and reopen the project, then RunThe saved layout and handlers still work.
Optional developer CLI
mcbasic check ControlArrayBoard.mcproj

Step 7Test a genuine gap#

Create a Git checkpoint or another practice copy. Delete txtCell(2) in the Designer and run Check. Run and Clear: the shared For Each code still works, Count is 5 and the highest Index remains 5. The existing lookup uses 4 and the visibility button uses 5, so neither refers to the deleted member. Restore the deleted member with Undo and repeat Check. Do not loop from LBound to UBound and assume index 2 still exists.

Continue with array editing and Target rules or the class-array lesson.

Source baseline 20f4bfed6b · Build manifest
Sources & maintenance

Original web explanation, reviewed against these repository sources. API tables and example files follow the implementation.

  • docs/manual/05-designing-forms.md
  • docs/manual/06-writing-mcbasic.md
  • docs/manual/21-language-reference.md
  • src/McBasic.Workspace/ControlArrayRules.cs
  • src/McBasic.Runtime.UI/McControlArray.cs
  • macos/McBasicIDE/Sources/ControlArrays.swift
  • macos/McBasicIDE/Sources/CreateControlArraySheet.swift
  • site/examples/ControlArrayBoard/ControlArrayBoard.mcproj
  • site/examples/ControlArrayBoard/frmMain.form.json
  • site/examples/ControlArrayBoard/frmMain.bas