Use files, settings, JSON and the clipboard
Build a local service workbench with complete event handlers and no remote account requirement.
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
{
"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 property | Value |
|---|---|
Caption | "Service Workbench" |
Width | 660 |
Height | 410 |
MinWidth | 600 |
MinHeight | 360 |
| Type | Name | Parent |
|---|---|---|
| TextBox | txtName | Form |
| CommandButton | cmdSave | Form |
| CommandButton | cmdFile | Form |
| CommandButton | cmdJson | Form |
| TextBox | txtOutput | Form |
| CommandButton | cmdCopy | Form |
txtName · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 24 |
Width | 600 |
Height | 36 |
TabIndex | 0 |
AccessibleName | "Practice name" |
| Anchor edges | Left, Top, Right |
cmdSave · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 80 |
Width | 175 |
Height | 36 |
Caption | "Save preference" |
TabIndex | 1 |
cmdFile · exact Inspector values
| Property | Value |
|---|---|
Left | 220 |
Top | 80 |
Width | 180 |
Height | 36 |
Caption | "Write practice file" |
TabIndex | 2 |
cmdJson · exact Inspector values
| Property | Value |
|---|---|
Left | 420 |
Top | 80 |
Width | 180 |
Height | 36 |
Caption | "Inspect JSON" |
TabIndex | 3 |
txtOutput · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 140 |
Width | 600 |
Height | 160 |
MultiLine | True |
ReadOnly | True |
WordWrap | True |
TabIndex | 4 |
AccessibleName | "Operation result" |
| Anchor edges | Left, Top, Right, Bottom |
cmdCopy · exact Inspector values
| Property | Value |
|---|---|
Left | 24 |
Top | 320 |
Width | 175 |
Height | 36 |
Caption | "Copy result" |
TabIndex | 5 |
| Anchor edges | Left, Bottom |
Step 3Connect the events explicitly#
frmMain
| Object | Event | Procedure | Parameters |
|---|---|---|---|
cmdSave | Click | cmdSave_Click | Click() |
cmdFile | Click | cmdFile_Click | Click() |
cmdJson | Click | cmdJson_Click | Click() |
cmdCopy | Click | cmdCopy_Click | Click() |
| Form | Load | Form_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.
Option ExplicitPrivate Sub Form_Load()
Initialize state before enabling dependent actions. Keep the shared declarations and startup dependencies with this procedure.
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 SubPrivate Sub cmdSave_Click()
Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.
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 SubPrivate Sub cmdFile_Click()
Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.
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 SubPrivate Sub cmdJson_Click()
Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.
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 SubPrivate Sub cmdCopy_Click()
Follow the success, failure and cleanup paths together. Do not omit a guard or Finally block when entering this procedure.
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 SubCopy the complete frmMain.bas file
Replace the file once; do not append duplicate procedures.
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 SubStep 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:
mcbasic check ServiceWorkbench.mcproj
mcbasic run ServiceWorkbench.mcprojAcceptance 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.
20f4bfed6b · Build manifest