McBasic™Get McBasic™ ↗
Build 881
Hands-on tutorial · Data & services

Use files, settings, JSON and the clipboard

Build a local service workbench with complete event handlers and no remote account requirement.

1 Form / control designs1 complete BASIC filesOriginal web lesson

Form_Load restores a preference with a default. Save preference persists only a validated name. Write practice file deliberately overwrites the lesson-owned service-workbench-practice.txt, then reads it back using strict UTF-8. Inspect JSON checks for the names member and an empty array before using zero-based Json.At. Copy result uses the system clipboard; log messages deliberately omit the entered name.

Step 1Prepare a safe practice project#

Extract the archive into a new writable folder, separate from your own application. Open ServiceWorkbench.mcproj in McBasic™. Keep every declared source, layout, resource and migration file together.

To reconstruct it yourself, create a DesktopApp project and add the files declared below. In the complete project, follow these steps as a guided rebuild: replace each named source file once and Check after all its procedures are present.

Exact project configuration
ServiceWorkbench.mcproj
{
  "schemaVersion": 1,
  "projectId": "mcbasic-web-service-workbench",
  "name": "ServiceWorkbench",
  "kind": "DesktopApp",
  "language": {
    "dialect": "McBasic1",
    "requireExplicit": true,
    "compare": "Binary",
    "defaultArrayBase": 0
  },
  "application": {
    "bundleIdentifier": "org.mcbasic.web.serviceworkbench",
    "version": "1.0.0",
    "buildNumber": "1",
    "startupFormId": "main",
    "shutdownMode": "OnStartupFormClosed"
  },
  "forms": [
    {
      "id": "main",
      "typeName": "frmMain",
      "layout": "frmMain.form.json",
      "code": "frmMain.bas"
    }
  ],
  "modules": [],
  "classes": [],
  "tests": [],
  "references": [],
  "resources": [],
  "targets": [
    "osx-arm64"
  ],
  "capabilities": []
}

Step 2Build the Form and set its properties#

frmMain

Select the Form first and set its properties. Add containers before their children. These are initial Designer values, not statements to paste into a procedure.

Form propertyValue
Caption"Service Workbench"
Width660
Height410
MinWidth600
MinHeight360
TypeNameParent
TextBoxtxtNameForm
CommandButtoncmdSaveForm
CommandButtoncmdFileForm
CommandButtoncmdJsonForm
TextBoxtxtOutputForm
CommandButtoncmdCopyForm
txtName · exact Inspector values
PropertyValue
Left24
Top24
Width600
Height36
TabIndex0
AccessibleName"Practice name"
Anchor edgesLeft, Top, Right
cmdSave · exact Inspector values
PropertyValue
Left24
Top80
Width175
Height36
Caption"Save preference"
TabIndex1
cmdFile · exact Inspector values
PropertyValue
Left220
Top80
Width180
Height36
Caption"Write practice file"
TabIndex2
cmdJson · exact Inspector values
PropertyValue
Left420
Top80
Width180
Height36
Caption"Inspect JSON"
TabIndex3
txtOutput · exact Inspector values
PropertyValue
Left24
Top140
Width600
Height160
MultiLineTrue
ReadOnlyTrue
WordWrapTrue
TabIndex4
AccessibleName"Operation result"
Anchor edgesLeft, Top, Right, Bottom
cmdCopy · exact Inspector values
PropertyValue
Left24
Top320
Width175
Height36
Caption"Copy result"
TabIndex5
Anchor edgesLeft, Bottom

Step 3Connect the events explicitly#

frmMain

ObjectEventProcedureParameters
cmdSaveClickcmdSave_ClickClick()
cmdFileClickcmdFile_ClickClick()
cmdJsonClickcmdJson_ClickClick()
cmdCopyClickcmdCopy_ClickClick()
FormLoadForm_Load()

Step 4Enter the complete behavior#

Open the named source file. Enter declarations first, then every procedure. Expand a procedure for its full body, or copy the complete file. Helpers are required: do not stop after entering the first Click handler.

frmMain.bas

Enter these declarations at file scope, before the procedures.

frmMain.bas · declarations
Option Explicit
Private Sub Form_Load()

Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.

frmMain.bas · Form_Load
Private Sub Form_Load()
    txtName.Text = CStr(Settings.Get("practice-name", "Ada"))
    txtOutput.Text = "This lesson writes only its own practice file in the app data folder."
End Sub
Private Sub cmdSave_Click()

Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.

frmMain.bas · cmdSave_Click
Private Sub cmdSave_Click()
    Dim clean As String
    clean = Trim$(txtName.Text)
    If Len(clean) = 0 Then
        txtOutput.Text = "Enter a name before saving the preference."
        txtName.SetFocus
        Exit Sub
    End If
    Try
        Settings.Set "practice-name", clean
        txtOutput.Text = "Preference saved. Close and reopen to verify it."
        Log.Info "Practice preference saved."
    Catch failure As McException
        txtOutput.Text = "Preference error: " & failure.Message
    End Try
End Sub
Private Sub cmdFile_Click()

Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.

frmMain.bas · cmdFile_Click
Private Sub cmdFile_Click()
    Dim destination As String
    destination = AppPaths.DataFile("service-workbench-practice.txt")
    Try
        File.WriteText destination, "Practice name: " & txtName.Text & Environment.NewLine
        File.AppendText destination, "Written by the service workbench."
        txtOutput.Text = destination & Environment.NewLine & File.ReadText(destination)
    Catch failure As McException
        txtOutput.Text = "File error " & CStr(failure.Number) & ": " & failure.Message
    End Try
End Sub
Private Sub cmdJson_Click()

Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.

frmMain.bas · cmdJson_Click
Private Sub cmdJson_Click()
    Dim document As JsonValue
    Dim names As JsonValue
    Dim first As String
    Try
        document = Json.Parse("{""names"":[""Ada"",""Grace""],""active"":true}")
        If Not Json.Has(document, "names") Then
            txtOutput.Text = "The document has no names member."
            Exit Sub
        End If
        names = Json.Get(document, "names")
        If Json.Count(names) = 0 Then
            txtOutput.Text = "The list is empty."
            Exit Sub
        End If
        first = CStr(Json.Value(Json.At(names, 0)))
        txtOutput.Text = "First name: " & first & Environment.NewLine & "Count: " & CStr(Json.Count(names))
    Catch failure As McException
        txtOutput.Text = "JSON error: " & failure.Message
    End Try
End Sub
Private Sub cmdCopy_Click()

Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.

frmMain.bas · cmdCopy_Click
Private Sub cmdCopy_Click()
    Try
        Clipboard.SetText txtOutput.Text
        Log.Info "Practice result copied."
    Catch failure As McException
        txtOutput.Text = "Clipboard error: " & failure.Message
    End Try
End Sub
Copy the complete frmMain.bas file

Replace the file once; do not append duplicate procedures.

frmMain.bas
Option Explicit

Private Sub Form_Load()
    txtName.Text = CStr(Settings.Get("practice-name", "Ada"))
    txtOutput.Text = "This lesson writes only its own practice file in the app data folder."
End Sub

Private Sub cmdSave_Click()
    Dim clean As String
    clean = Trim$(txtName.Text)
    If Len(clean) = 0 Then
        txtOutput.Text = "Enter a name before saving the preference."
        txtName.SetFocus
        Exit Sub
    End If
    Try
        Settings.Set "practice-name", clean
        txtOutput.Text = "Preference saved. Close and reopen to verify it."
        Log.Info "Practice preference saved."
    Catch failure As McException
        txtOutput.Text = "Preference error: " & failure.Message
    End Try
End Sub

Private Sub cmdFile_Click()
    Dim destination As String
    destination = AppPaths.DataFile("service-workbench-practice.txt")
    Try
        File.WriteText destination, "Practice name: " & txtName.Text & Environment.NewLine
        File.AppendText destination, "Written by the service workbench."
        txtOutput.Text = destination & Environment.NewLine & File.ReadText(destination)
    Catch failure As McException
        txtOutput.Text = "File error " & CStr(failure.Number) & ": " & failure.Message
    End Try
End Sub

Private Sub cmdJson_Click()
    Dim document As JsonValue
    Dim names As JsonValue
    Dim first As String
    Try
        document = Json.Parse("{""names"":[""Ada"",""Grace""],""active"":true}")
        If Not Json.Has(document, "names") Then
            txtOutput.Text = "The document has no names member."
            Exit Sub
        End If
        names = Json.Get(document, "names")
        If Json.Count(names) = 0 Then
            txtOutput.Text = "The list is empty."
            Exit Sub
        End If
        first = CStr(Json.Value(Json.At(names, 0)))
        txtOutput.Text = "First name: " & first & Environment.NewLine & "Count: " & CStr(Json.Count(names))
    Catch failure As McException
        txtOutput.Text = "JSON error: " & failure.Message
    End Try
End Sub

Private Sub cmdCopy_Click()
    Try
        Clipboard.SetText txtOutput.Text
        Log.Info "Practice result copied."
    Catch failure As McException
        txtOutput.Text = "Clipboard error: " & failure.Message
    End Try
End Sub

Step 5Keep resources and storage reproducible#

No external resource or migration files are declared. Any inline migration, seed data or local JSON is present in the code above. Runtime application data and private preferences are not included in the archive.

Step 6Check, run and test the result#

Save all files and run Check. Resolve diagnostics before Run. Developer CLI users can work from the extracted folder:

Developer CLI
mcbasic check ServiceWorkbench.mcproj
mcbasic run ServiceWorkbench.mcproj

Acceptance checklist

  • Save a name, close the app and reopen: the preference is restored.
  • Try an empty name and confirm nothing is saved.
  • Write the practice file and confirm both lines are read back.
  • Inspect JSON: the first name is Ada and the count is 2.
  • Copy the result and paste it into a disposable text document.

Step 7Make one change and repeat the tests#

Change the local JSON array to empty and confirm the handler reports the empty state without indexing it.

Save a working Git checkpoint first. Change one behavior, Check again and repeat the acceptance checklist. Compare with the downloaded solution if a regression appears.

Source baseline 20f4bfed6b · Build manifest