本课学习目标
- 理解为什么大型 Windows Forms 应用需要多个窗体。
- 在项目中新增第二个 Form。
- 使用 Show() 打开非模式窗体。
- 使用 ShowDialog() 打开模式窗体。
- 理解 Close() 与 Hide() 的区别。
- 使用构造函数把资料传给另一个窗体。
- 通过 Public ReadOnly Property 从子窗体取回结果。
- 使用 DialogResult.OK 判断用户是否确认。
- 理解主窗体、子窗体和对话框的角色。
- 完成一个带 Dashboard、学生输入窗体和 About 窗体的多窗体应用。
21.1 为什么要使用多个窗体?
当一个 Form 同时承担导航、资料输入、设置、报表和帮助功能时,界面与代码都会越来越复杂。拆成多个窗体可以让每个窗口专注于自己的任务。
主窗口
负责 Dashboard、导航和主要状态。
资料输入
负责新增或编辑学生资料。
辅助窗口
显示应用名称、版本和说明。
21.2 在项目中新增 Form
在 Solution Explorer 中对项目按右键,选择新增项目项,然后加入一个 Windows Form。
例如新增:
StudentForm.vb
再新增:
AboutForm.vb
项目现在可能包含:
MainForm.vb
StudentForm.vb
AboutForm.vb
21.3 使用 Show() 打开窗体
建立窗体对象:
Dim form As New AboutForm()
然后:
form.Show()
Show() 打开的是非模式(modeless)窗口。打开后,用户仍然可以回到主窗体继续操作。
21.4 使用 ShowDialog() 打开模式窗体
Dim form As New StudentForm()
form.ShowDialog()
ShowDialog() 打开模式(modal)窗口。在这个窗体关闭之前,用户通常不能继续操作主窗体。
适合工具窗口、About、辅助信息等允许用户同时操作其他窗体的场景。
适合新增记录、设置、确认等必须先完成当前操作才能回到主窗口的场景。
21.5 Close() 与 Hide()
Close()
Me.Close()
关闭当前窗体。通常关闭后,这个窗体对象就不再继续作为当前可见窗口使用。
Hide()
Me.Hide()
只是隐藏窗体,并没有真正关闭它。之后还可以再次 Show。
| 方法 | 结果 | 典型用途 |
|---|---|---|
| Show() | 显示非模式窗体 | 辅助窗口 |
| ShowDialog() | 显示模式窗体 | 输入、编辑、设置 |
| Hide() | 隐藏但保留窗体 | 临时隐藏 |
| Close() | 关闭窗体 | 完成操作或退出窗口 |
21.6 用构造函数把资料传给子窗体
假设 AboutForm 要显示当前登录用户名,可以通过构造函数传入。
AboutForm.vb
Public Class AboutForm
Public Sub New(userName As String)
InitializeComponent()
lblUser.Text =
"当前用户:" & userName
End Sub
End Class
MainForm.vb
Dim form As New AboutForm(
"Dr. Lee")
form.ShowDialog()
拥有 userName
构造函数接收
21.7 子窗体怎样把资料传回主窗体?
一种简单而清楚的方式,是让子窗体提供只读属性。
StudentForm.vb
Public ReadOnly Property StudentName As String
Get
Return txtStudentName.Text.Trim()
End Get
End Property
再加入:
Public ReadOnly Property CourseName As String
Get
Return txtCourse.Text.Trim()
End Get
End Property
成绩:
Public ReadOnly Property Score As Double
21.8 使用 DialogResult.OK 表示用户确认
在 StudentForm 放两个按钮:
btnOK
btnCancel
可以在 Designer 设置:
btnOK.DialogResult = OK
btnCancel.DialogResult = Cancel
或者在代码中设置:
Me.DialogResult =
DialogResult.OK
Me.Close()
MainForm 就可以判断:
Dim form As New StudentForm()
If form.ShowDialog() =
DialogResult.OK Then
' 用户确认了输入
End If
21.9 StudentForm:验证后返回资料
Public Class StudentForm
Public ReadOnly Property StudentName As String
Get
Return txtStudentName.Text.Trim()
End Get
End Property
Public ReadOnly Property CourseName As String
Get
Return txtCourse.Text.Trim()
End Get
End Property
Public ReadOnly Property Score As Double
Private Sub btnOK_Click(
sender As Object,
e As EventArgs) Handles btnOK.Click
If String.IsNullOrWhiteSpace(
txtStudentName.Text) Then
MessageBox.Show(
"请输入学生姓名。")
txtStudentName.Focus()
Exit Sub
End If
If String.IsNullOrWhiteSpace(
txtCourse.Text) Then
MessageBox.Show(
"请输入课程名称。")
txtCourse.Focus()
Exit Sub
End If
Dim scoreValue As Double
If Not Double.TryParse(
txtScore.Text,
scoreValue) Then
MessageBox.Show(
"请输入有效成绩。")
txtScore.Focus()
Exit Sub
End If
If scoreValue < 0 OrElse
scoreValue > 100 Then
MessageBox.Show(
"成绩必须介于 0 与 100。")
txtScore.Focus()
Exit Sub
End If
_Score = scoreValue
Me.DialogResult =
DialogResult.OK
Me.Close()
End Sub
Private Sub btnCancel_Click(
sender As Object,
e As EventArgs) Handles btnCancel.Click
Me.DialogResult =
DialogResult.Cancel
Me.Close()
End Sub
End Class
21.10 使用 Using 管理模式窗体
对于临时建立、显示、关闭后就不再使用的模式窗体,可以写:
Using form As New StudentForm()
If form.ShowDialog() =
DialogResult.OK Then
lblStudent.Text =
form.StudentName
End If
End Using
离开 Using 后,窗体会被释放。
21.11 Owner:指定父窗口
ShowDialog 可以指定拥有者:
form.ShowDialog(Me)
这里的 Me 是当前主窗体。这样可以让对话框在主窗体的上下文中显示,并维持更合理的窗口关系。
21.12 实作:学生管理 Dashboard
建立新的 Windows Forms 项目:
StudentManagementDashboard2026
建立三个窗体:
MainForm.vb
StudentForm.vb
AboutForm.vb
Dashboard
学生人数:2
最近加入:李明
MainForm 加入:
| 控件 | Name | 用途 |
|---|---|---|
| Button | btnAddStudent | 打开 StudentForm |
| Button | btnAbout | 打开 AboutForm |
| TextBox | txtStudents | Multiline = True;ReadOnly = True |
| Label | lblCount | 显示学生人数 |
MainForm 保存学生列表
Private ReadOnly students As New List(Of Student)()
新增学生按钮
Private Sub btnAddStudent_Click(
sender As Object,
e As EventArgs) Handles btnAddStudent.Click
Using form As New StudentForm()
If form.ShowDialog(Me) <>
DialogResult.OK Then
Exit Sub
End If
Dim student As New Student(
form.StudentName,
form.CourseName,
form.Score)
students.Add(student)
End Using
DisplayStudents()
End Sub
显示学生
Private Sub DisplayStudents()
txtStudents.Clear()
For Each student As Student In students
txtStudents.Text &=
student.GetSummary() &
Environment.NewLine &
"--------------------" &
Environment.NewLine
Next
lblCount.Text =
$"学生人数:{students.Count}"
End Sub
About 按钮
Private Sub btnAbout_Click(
sender As Object,
e As EventArgs) Handles btnAbout.Click
Using form As New AboutForm(
"Student Management Dashboard 2026")
form.ShowDialog(Me)
End Using
End Sub
AboutForm 构造函数
Public Class AboutForm
Public Sub New(
applicationName As String)
InitializeComponent()
lblTitle.Text =
applicationName
lblDescription.Text =
"Visual Basic 2026 多窗体应用示例"
End Sub
Private Sub btnClose_Click(
sender As Object,
e As EventArgs) Handles btnClose.Click
Me.Close()
End Sub
End Class
21.13 程序执行流程
用户点击“新增学生”。
使用 ShowDialog(Me) 打开模式输入窗体。
只有资料有效时才设置 DialogResult.OK。
从 StudentName、CourseName、Score 取得结果。
加入 List(Of Student),再刷新 Dashboard。
21.14 什么时候使用 Show,什么时候使用 ShowDialog?
| 窗口 | 建议 | 原因 |
|---|---|---|
| 新增学生 | ShowDialog | 主窗体需要等待输入结果。 |
| 设置窗口 | ShowDialog | 通常希望完成或取消设置后再继续。 |
| 工具窗口 | Show | 用户可以同时操作主窗口。 |
| About | 两者皆可 | 通常 ShowDialog 更简单,也很常见。 |
21.15 初学者常见错误
每次都直接使用默认窗体实例
教学中更建议明确 Dim form As New StudentForm(),对象生命周期更清楚。
ShowDialog 后不检查结果
用户可能按 Cancel。只有 DialogResult.OK 才应读取并保存输入。
Hide 代替 Close 后不断累积窗体
不再需要的窗口应关闭或释放,避免无意义地长期保留。
子窗体直接大量操作 MainForm 控件
更清楚的做法是通过属性、构造函数或返回结果传递资料,减少窗体之间过度耦合。
21.16 小练习
- 新增 SettingsForm,用 ShowDialog 打开。
- 让 SettingsForm 返回一个 Boolean,例如是否启用深色模式。
- 为 StudentForm 加入 StudentId,并传回 MainForm。
- 建立一个只使用 Show() 的 HelpForm,观察主窗体是否仍可操作。
- 在 AboutForm 显示通过构造函数传入的版本文字。
- 尝试把 StudentForm 的取消按钮设置为 DialogResult.Cancel。
- 新增“编辑学生”窗口,并让构造函数接收现有 Student 对象的资料作为初始值。
本课复习
- 为什么大型应用通常使用多个 Form?
- Show() 与 ShowDialog() 最大的区别是什么?
- Close() 与 Hide() 有什么不同?
- 构造函数适合把哪一类资料传给子窗体?
- 怎样让 StudentForm 把输入结果传回 MainForm?
- DialogResult.OK 有什么用途?
- 为什么 MainForm 应该检查 ShowDialog 的返回值?
- ShowDialog(Me) 中的 Me 是什么?
- Using 区块对临时模式窗体有什么好处?
- 为什么应避免让两个窗体直接互相操作大量控件?