-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathtutorial-forms.html
More file actions
363 lines (304 loc) · 19 KB
/
tutorial-forms.html
File metadata and controls
363 lines (304 loc) · 19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tutorial: Working with Forms - HarbourBuilder Documentation</title>
<link rel="stylesheet" href="../assets/css/docs.css">
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>mermaid.initialize({startOnLoad:true, theme:'dark'});</script>
</head>
<body>
<!-- Header -->
<div class="header">
<a class="logo" href="index.html">
<span>HB</span> HarbourBuilder Docs
</a>
<nav>
<input class="search-box" type="text" placeholder="Search docs..." oninput="doSearch(this.value)">
<button class="lang-btn active">EN</button>
<a class="lang-btn" href="../es/index.html">ES</a>
<a class="lang-btn" href="../pt/index.html">PT</a>
<button class="theme-toggle" onclick="toggleTheme()">☼</button>
</nav>
</div>
<!-- Sidebar -->
<div class="sidebar">
<div class="nav-section">
<h3 id="getting-started">Getting Started</h3>
<a href="index.html">Overview</a>
<a href="quickstart.html">Quick Start</a>
<a href="installation.html">Installation</a>
<a href="architecture.html">Architecture</a>
</div>
<div class="nav-section">
<h3 id="component-palette">Component Palette</h3>
<a href="controls-standard.html">Standard (11)</a>
<a href="controls-additional.html">Additional (10)</a>
<a href="controls-native.html">Win32 / Cocoa / GTK3 (9)</a>
<a href="controls-system.html">System (2)</a>
<a href="controls-dialogs.html">Dialogs (6)</a>
<a href="controls-database.html">Data Access (9)</a>
<a href="controls-internet.html">Internet (9)</a>
<a href="controls-threading.html">Threading (8)</a>
<a href="controls-ai.html">AI (7)</a>
<a href="controls-erp.html">ERP / Business (12)</a>
</div>
<div class="nav-section">
<h3 id="ide-features">IDE Features</h3>
<a href="form-designer.html">Form Designer</a>
<a href="object-inspector.html">Object Inspector</a>
<a href="code-editor.html">Code Editor</a>
<a href="two-way-tools.html">Two-Way Tools</a>
<a href="debugger.html">Debugger</a>
<a href="ai-assistant.html">AI Assistant</a>
<a href="build-run.html">Build & Run</a>
</div>
<div class="nav-section">
<h3 id="tutorials">Tutorials</h3>
<a href="tutorial-hello.html">Hello World</a>
<a href="tutorial-forms.html" class="active">Working with Forms</a>
<a href="tutorial-events.html">Event Handling</a>
<a href="tutorial-database.html">Database CRUD</a>
<a href="tutorial-webserver.html">Web Server</a>
<a href="tutorial-ai.html">AI Integration</a>
<a href="tutorial-transformer.html">Transformer</a>
</div>
<div class="nav-section">
<h3 id="reference">Reference</h3>
<a href="ref-properties.html">Properties A-Z</a>
<a href="ref-events.html">Events A-Z</a>
<a href="ref-methods.html">Methods A-Z</a>
<a href="ref-commands.html">xBase Commands</a>
<a href="ref-functions.html">HB_FUNC Bridge</a>
</div>
<div class="nav-section">
<h3 id="platforms">Platforms</h3>
<a href="platform-windows.html">Windows</a>
<a href="platform-macos.html">macOS</a>
<a href="platform-linux.html">Linux</a>
<a href="platform-android.html">Android <span class="badge new">New</span></a>
<a href="platform-ios.html">iOS <span class="badge planned">Planned</span></a>
</div>
</div>
<!-- Content -->
<div class="content">
<div class="breadcrumbs">
<a href="index.html">Docs</a> <span>/</span> Tutorials <span>/</span> Working with Forms
</div>
<h1>Tutorial: Working with Forms</h1>
<p>Most real-world applications need more than one window. In this tutorial you will build a
multi-form project with a main form and a settings dialog. You will learn how to open forms
modally, pass data between them, and configure common form properties.</p>
<h2 id="step-1-set-up-the-project">Step 1: Set Up the Project</h2>
<ol>
<li>Create a new project called <code>MultiFormDemo</code> via <strong>File → New Project</strong>.</li>
<li>The IDE creates <code>main.prg</code> with a starter form.</li>
<li>We will add a second source file for the settings form in the next step.</li>
</ol>
<h2 id="step-2-design-the-main-form">Step 2: Design the Main Form</h2>
<ol>
<li>Open <code>main.prg</code> in the Form Designer.</li>
<li>Set the form title to <code>"Multi-Form Demo"</code> and size to <code>700, 500</code>.</li>
<li>Add a <strong>Label</strong> at the top to display the current username — set <code>cValue</code> to <code>"User: (none)"</code>.</li>
<li>Add a <strong>Button</strong> with <code>cPrompt</code> set to <code>"Open Settings"</code>.</li>
</ol>
<p>Your main form code will look like this:</p>
<pre><span class="pp">#include</span> <span class="st">"hbbuilder.ch"</span>
<span class="kw">function</span> <span class="fn">Main</span>()
<span class="kw">local</span> oForm, oLblUser, oBtnSettings
<span class="cmd">DEFINE FORM</span> oForm <span class="cmd">TITLE</span> <span class="st">"Multi-Form Demo"</span> ;
<span class="cmd">SIZE</span> <span class="nb">700</span>, <span class="nb">500</span> <span class="cmd">FONT</span> <span class="st">"Segoe UI"</span>, <span class="nb">10</span>
@ <span class="nb">30</span>, <span class="nb">50</span> <span class="cmd">LABEL</span> oLblUser <span class="cmd">VALUE</span> <span class="st">"User: (none)"</span> ;
<span class="cmd">OF</span> oForm <span class="cmd">SIZE</span> <span class="nb">300</span>, <span class="nb">24</span>
@ <span class="nb">80</span>, <span class="nb">50</span> <span class="cmd">BUTTON</span> oBtnSettings <span class="cmd">PROMPT</span> <span class="st">"Open Settings"</span> ;
<span class="cmd">OF</span> oForm <span class="cmd">SIZE</span> <span class="nb">140</span>, <span class="nb">36</span> ;
<span class="cmd">ACTION</span> <span class="fn">OpenSettings</span>( oForm, oLblUser )
<span class="cmd">ACTIVATE FORM</span> oForm <span class="cmd">CENTERED</span>
<span class="kw">return</span> <span class="kw">nil</span></pre>
<h2 id="step-3-create-the-settings-form">Step 3: Create the Settings Form</h2>
<ol>
<li>Select <strong>File → New Form</strong> to add a second form to the project. Name it <code>settings.prg</code>.</li>
<li>In the Form Designer for <code>settings.prg</code>, set the title to <code>"Settings"</code> and size to <code>400, 300</code>.</li>
<li>Add a <strong>Label</strong> with <code>cValue</code> <code>"Your name:"</code> at row 30, col 30.</li>
<li>Add a <strong>TextBox</strong> (<code>TGet</code>) next to the label for the user to type their name.</li>
<li>Add a <strong>CheckBox</strong> below with <code>cPrompt</code> <code>"Enable dark mode"</code>.</li>
<li>Add two buttons: <strong>"OK"</strong> and <strong>"Cancel"</strong> at the bottom.</li>
</ol>
<h2 id="step-4-implement-showmodal-and-data-passing">Step 4: Implement ShowModal and Data Passing</h2>
<p>The key technique is to call <code>ShowModal()</code> on the settings form. This blocks the main form
until the user closes the dialog. After the modal form closes, you read back the values the
user entered.</p>
<pre><span class="kw">static function</span> <span class="fn">OpenSettings</span>( oMainForm, oLblUser )
<span class="kw">local</span> oSettings, oGetName, oChkDark, oBtnOK, oBtnCancel
<span class="kw">local</span> cName := <span class="st">""</span>, lDark := .F., nResult
<span class="cmd">DEFINE FORM</span> oSettings <span class="cmd">TITLE</span> <span class="st">"Settings"</span> ;
<span class="cmd">SIZE</span> <span class="nb">400</span>, <span class="nb">300</span> <span class="cmd">FONT</span> <span class="st">"Segoe UI"</span>, <span class="nb">10</span> ;
<span class="cmd">STYLE</span> <span class="st">"dialog"</span>
@ <span class="nb">30</span>, <span class="nb">30</span> <span class="cmd">LABEL</span> oLbl <span class="cmd">VALUE</span> <span class="st">"Your name:"</span> ;
<span class="cmd">OF</span> oSettings <span class="cmd">SIZE</span> <span class="nb">100</span>, <span class="nb">24</span>
@ <span class="nb">30</span>, <span class="nb">140</span> <span class="cmd">GET</span> oGetName <span class="cmd">VAR</span> cName ;
<span class="cmd">OF</span> oSettings <span class="cmd">SIZE</span> <span class="nb">220</span>, <span class="nb">24</span>
@ <span class="nb">70</span>, <span class="nb">30</span> <span class="cmd">CHECKBOX</span> oChkDark <span class="cmd">VAR</span> lDark ;
<span class="cmd">PROMPT</span> <span class="st">"Enable dark mode"</span> ;
<span class="cmd">OF</span> oSettings <span class="cmd">SIZE</span> <span class="nb">200</span>, <span class="nb">24</span>
@ <span class="nb">220</span>, <span class="nb">180</span> <span class="cmd">BUTTON</span> oBtnOK <span class="cmd">PROMPT</span> <span class="st">"OK"</span> ;
<span class="cmd">OF</span> oSettings <span class="cmd">SIZE</span> <span class="nb">90</span>, <span class="nb">32</span> ;
<span class="cmd">ACTION</span> ( oSettings:<span class="fn">nModalResult</span> := <span class="nb">1</span>, oSettings:<span class="fn">Close</span>() )
@ <span class="nb">220</span>, <span class="nb">280</span> <span class="cmd">BUTTON</span> oBtnCancel <span class="cmd">PROMPT</span> <span class="st">"Cancel"</span> ;
<span class="cmd">OF</span> oSettings <span class="cmd">SIZE</span> <span class="nb">90</span>, <span class="nb">32</span> ;
<span class="cmd">ACTION</span> ( oSettings:<span class="fn">nModalResult</span> := <span class="nb">0</span>, oSettings:<span class="fn">Close</span>() )
nResult := oSettings:<span class="fn">ShowModal</span>( oMainForm )
<span class="kw">if</span> nResult == <span class="nb">1</span>
oLblUser:<span class="fn">SetValue</span>( <span class="st">"User: "</span> + cName )
<span class="kw">if</span> lDark
oMainForm:<span class="fn">SetDarkMode</span>( .T. )
<span class="kw">else</span>
oMainForm:<span class="fn">SetDarkMode</span>( .F. )
<span class="kw">endif</span>
<span class="kw">endif</span>
<span class="kw">return</span> <span class="kw">nil</span></pre>
<div class="info-box tip">
<strong>ShowModal vs. Show</strong>
<p>Use <code>ShowModal( oParent )</code> when the user must complete the dialog before returning to the parent.
Use <code>Show()</code> for non-blocking windows that the user can switch between freely.</p>
</div>
<h2 id="step-5-form-properties-reference">Step 5: Form Properties Reference</h2>
<p>Here are the most commonly used form properties you can set in the Object Inspector or in code:</p>
<table style="width:100%; border-collapse:collapse; margin:1em 0;">
<tr style="border-bottom:1px solid #444;">
<th style="text-align:left; padding:8px;">Property</th>
<th style="text-align:left; padding:8px;">Type</th>
<th style="text-align:left; padding:8px;">Description</th>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>cTitle</code></td>
<td style="padding:8px;">String</td>
<td style="padding:8px;">Text shown in the form's title bar.</td>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>nWidth</code> / <code>nHeight</code></td>
<td style="padding:8px;">Numeric</td>
<td style="padding:8px;">Form dimensions in pixels.</td>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>lMaximize</code></td>
<td style="padding:8px;">Logical</td>
<td style="padding:8px;">Whether the maximize button is enabled.</td>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>lMinimize</code></td>
<td style="padding:8px;">Logical</td>
<td style="padding:8px;">Whether the minimize button is enabled.</td>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>lResizable</code></td>
<td style="padding:8px;">Logical</td>
<td style="padding:8px;">Whether the user can resize the form.</td>
</tr>
<tr style="border-bottom:1px solid #333;">
<td style="padding:8px;"><code>cStyle</code></td>
<td style="padding:8px;">String</td>
<td style="padding:8px;"><code>"normal"</code>, <code>"dialog"</code>, or <code>"toolwindow"</code>.</td>
</tr>
<tr>
<td style="padding:8px;"><code>nModalResult</code></td>
<td style="padding:8px;">Numeric</td>
<td style="padding:8px;">Return value after <code>ShowModal()</code>. Set before calling <code>Close()</code>.</td>
</tr>
</table>
<h2 id="step-6-build-and-test">Step 6: Build and Test</h2>
<ol>
<li>Press <strong>F9</strong> to build and run.</li>
<li>Click <strong>"Open Settings"</strong> on the main form — the settings dialog appears modally.</li>
<li>Type a name, toggle the checkbox, and click <strong>OK</strong>.</li>
<li>The main form label updates to show the name you entered.</li>
<li>Open the dialog again and click <strong>Cancel</strong> — the main form remains unchanged.</li>
</ol>
<!-- Screenshot placeholder: Main form showing "User: Antonio" after the settings dialog was submitted -->
<h2 id="class-based-form-format">Class-Based Form Format</h2>
<p>HarbourBuilder also supports a class-based form format that matches the IDE designer's output. This format is useful for more complex applications:</p>
<pre><span class="pp">#include</span> <span class="st">"hbbuilder.ch"</span>
<span class="kw">CLASS</span> TForm1 <span class="kw">FROM</span> TForm
<span class="cm">// IDE-managed Components</span>
<span class="kw">DATA</span> oLblUser <span class="cm">// TLabel</span>
<span class="kw">DATA</span> oBtnSettings <span class="cm">// TButton</span>
<span class="cm">// Event handlers</span>
<span class="kw">METHOD</span> BtnSettingsClick()
<span class="kw">METHOD</span> CreateForm()
<span class="kw">ENDCLASS</span>
<span class="kw">METHOD</span> <span class="fn">CreateForm</span>() <span class="kw">CLASS</span> TForm1
::<span class="nb">Title</span> := <span class="st">"Multi-Form Demo"</span>
::<span class="nb">Left</span> := <span class="nb">100</span>
::<span class="nb">Top</span> := <span class="nb">100</span>
::<span class="nb">Width</span> := <span class="nb">700</span>
::<span class="nb">Height</span> := <span class="nb">500</span>
::<span class="nb">FontName</span> := <span class="st">"Segoe UI"</span>
::<span class="nb">FontSize</span> := <span class="nb">10</span>
@ <span class="nb">30</span>, <span class="nb">50</span> <span class="cmd">LABEL</span> ::oLblUser <span class="cmd">VALUE</span> <span class="st">"User: (none)"</span> <span class="cmd">OF</span> Self <span class="cmd">SIZE</span> <span class="nb">300</span>, <span class="nb">24</span>
@ <span class="nb">80</span>, <span class="nb">50</span> <span class="cmd">BUTTON</span> ::oBtnSettings <span class="cmd">PROMPT</span> <span class="st">"Open Settings"</span> <span class="cmd">OF</span> Self <span class="cmd">SIZE</span> <span class="nb">140</span>, <span class="nb">36</span>
<span class="cm">// Event wiring</span>
::oBtnSettings:<span class="nb">OnClick</span> := { || ::BtnSettingsClick() }
<span class="kw">return</span> <span class="kw">nil</span>
<span class="kw">METHOD</span> <span class="fn">BtnSettingsClick</span>() <span class="kw">CLASS</span> TForm1
<span class="kw">local</span> oSettings := TSettings():New()
oSettings:<span class="fn">ShowModal</span>( Self )
<span class="kw">if</span> oSettings:<span class="nb">nModalResult</span> == <span class="nb">1</span>
::oLblUser:<span class="nb">cText</span> := <span class="st">"User: "</span> + oSettings:<span class="nb">cUserName</span>
<span class="kw">endif</span>
<span class="kw">return</span> <span class="kw">nil</span>
<span class="kw">FUNCTION</span> <span class="fn">Form1</span>()
<span class="kw">LOCAL</span> oForm := TForm1():<span class="fn">New</span>()
oForm:<span class="fn">CreateForm</span>()
oForm:<span class="fn">Activate</span>()
<span class="kw">RETURN</span> oForm</pre>
<h3 id="using-oncreate-for-initialization">Using OnCreate for Initialization</h3>
<p>For initialization that requires child controls to have their HWNDs created, use the <code>OnCreate</code> event:</p>
<pre><span class="kw">function</span> <span class="fn">Form1Create</span>( oSelf )
<span class="cm">// This runs after all child controls have been created</span>
oSelf:oList:<span class="fn">SetItems</span>( { <span class="st">"Item 1"</span>, <span class="st">"Item 2"</span>, <span class="st">"Item 3"</span> } )
oSelf:oLblStatus:<span class="nb">cText</span> := <span class="st">"Ready"</span>
<span class="kw">return</span> <span class="kw">nil</span></pre>
<p>The IDE automatically detects functions named <code>FormNCreate</code> and wires them to the form's <code>::OnCreate</code> event.</p>
<h2 id="form-lifecycle-flow">Form Lifecycle Flow</h2>
<div class="mermaid">
graph TD
A["Main Form<br/>ACTIVATE FORM CENTERED"] --> B["User clicks<br/>Open Settings"]
B --> C["Settings Form<br/>ShowModal( oMainForm )"]
C --> D{"User action"}
D -->|"OK"| E["nModalResult = 1<br/>Close()"]
D -->|"Cancel"| F["nModalResult = 0<br/>Close()"]
E --> G["Main form reads<br/>cName and lDark"]
F --> H["Main form ignores<br/>dialog values"]
style A fill:#58a6ff,stroke:#388bfd,color:#0d1117
style C fill:#d2a8ff,stroke:#bc8cff,color:#0d1117
style E fill:#3fb950,stroke:#2ea043,color:#0d1117
style F fill:#f0883e,stroke:#d18616,color:#0d1117
</div>
<div class="info-box tip">
<strong>Next step</strong>
<p>Now that you can work with multiple forms, continue to the <a href="tutorial-events.html">Event Handling</a>
tutorial to learn about all the event types available in HarbourBuilder.</p>
</div>
<!-- Table of Contents Rail -->
<div class="toc-rail">
<h4>On This Page</h4>
<a href="#getting-started" class="toc-h3 active">Getting Started</a>
<a href="#component-palette" class="toc-h3">Component Palette</a>
<a href="#ide-features" class="toc-h3">IDE Features</a>
<a href="#tutorials" class="toc-h3">Tutorials</a>
<a href="#reference" class="toc-h3">Reference</a>
<a href="#platforms" class="toc-h3">Platforms</a>
<a href="#step-1-set-up-the-project" class="toc-h2">Step 1: Set Up the Project</a>
<a href="#step-2-design-the-main-form" class="toc-h2">Step 2: Design the Main Form</a>
<a href="#step-3-create-the-settings-form" class="toc-h2">Step 3: Create the Settings Form</a>
<a href="#step-4-implement-showmodal-and-data-passing" class="toc-h2">Step 4: Implement ShowModal and Data Passing</a>
<a href="#step-5-form-properties-reference" class="toc-h2">Step 5: Form Properties Reference</a>
<a href="#step-6-build-and-test" class="toc-h2">Step 6: Build and Test</a>
<a href="#class-based-form-format" class="toc-h2">Class-Based Form Format</a>
<a href="#using-oncreate-for-initialization" class="toc-h3">Using OnCreate for Initialization</a>
<a href="#form-lifecycle-flow" class="toc-h2">Form Lifecycle Flow</a>
</div>
<script src="../assets/js/docs.js"></script>
</body>
</html>