MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Visual Basic MDI应用程序开发指南

2022-05-052.3k 阅读

一、MDI 应用程序概述

(一)MDI 概念

MDI(Multiple Document Interface,多文档界面)是一种在一个应用程序中允许同时显示多个文档窗口的用户界面风格。在 MDI 应用程序中,有一个父窗口,称为 MDI 父窗体,它充当容器,而多个子窗口(MDI 子窗体)则包含在这个父窗体中。每个子窗口都可以独立操作,例如最大化、最小化、关闭等,但它们都在 MDI 父窗体的边界内。

MDI 应用程序常用于需要同时处理多个相关文档或数据集合的场景,比如文本编辑器(可同时打开多个文本文件)、绘图软件(可同时编辑多个图形文档)等。这种界面风格提供了一种高效且有序的方式来管理多个文档,用户可以方便地在不同文档之间切换和操作。

(二)MDI 应用程序的结构特点

  1. MDI 父窗体:它是整个 MDI 应用程序的主容器,通常包含菜单栏、工具栏等公共的用户界面元素,这些元素用于对所有子窗口进行统一的操作和管理。MDI 父窗体不能有模态对话框(Modal Dialog),并且其布局管理相对复杂,需要考虑如何合理地显示和排列多个子窗口。
  2. MDI 子窗体:每个子窗体代表一个独立的文档或任务单元。它们具有自己的标题栏、客户区等,但它们的大小和位置是相对于 MDI 父窗体的。子窗体可以被最大化、最小化或关闭,并且在最大化时,其标题会与 MDI 父窗体的标题合并显示,同时最大化按钮会被禁用。

二、Visual Basic 中 MDI 应用程序开发基础

(一)创建 MDI 父窗体

在 Visual Basic 中,创建 MDI 父窗体非常简单。首先,打开一个新的工程,然后选择“工程”菜单中的“添加 MDI 窗体”选项。此时,一个新的 MDI 窗体就会被添加到工程中。默认情况下,这个 MDI 父窗体的名称为“MDIForm1”。

下面是一个简单的代码示例,展示如何设置 MDI 父窗体的基本属性:

Private Sub MDIForm_Load()
    Me.Caption = "My MDI Application - Parent"
    Me.WindowState = vbNormal
End Sub

在上述代码中,MDIForm_Load 事件在 MDI 父窗体加载时触发。通过 Me.Caption 设置了 MDI 父窗体的标题为“My MDI Application - Parent”,Me.WindowState 设置其初始窗口状态为正常。

(二)创建 MDI 子窗体

创建 MDI 子窗体与创建普通窗体类似,但需要设置其 MDIChild 属性为 True,以表明该窗体是 MDI 子窗体。在工程中添加一个新的普通窗体,然后在属性窗口中将其 MDIChild 属性设置为 True。假设这个子窗体的名称为“ChildForm1”。

下面是一个简单的代码示例,用于在 MDI 父窗体中创建并显示这个子窗体:

Private Sub ShowChildForm()
    Dim child As New ChildForm1
    child.Show
End Sub

在上述代码中,定义了一个 ShowChildForm 过程,在这个过程中,首先使用 New 关键字创建了一个 ChildForm1 的实例,然后通过 Show 方法显示这个子窗体。

三、MDI 应用程序的用户界面设计

(一)菜单栏设计

  1. 主菜单栏与子菜单栏:在 MDI 应用程序中,菜单栏通常分为主菜单栏和子菜单栏。主菜单栏位于 MDI 父窗体上,包含对整个应用程序或所有子窗口通用的命令,如“文件”、“编辑”、“视图”等菜单。子菜单栏则根据不同子窗体的功能需求而有所不同,当某个子窗体获得焦点时,其对应的子菜单栏会显示在 MDI 父窗体的菜单栏位置,替换主菜单栏中特定的部分。
  2. 示例代码:假设在 MDI 父窗体的“文件”菜单中有“新建”、“打开”和“关闭”命令,在子窗体中有一个“格式”菜单。

在 MDI 父窗体的代码中:

Private Sub mnuFileNew_Click()
    ShowChildForm
End Sub

Private Sub mnuFileOpen_Click()
    '添加打开文件的代码逻辑
End Sub

Private Sub mnuFileClose_Click()
    Unload Me
End Sub

在子窗体的代码中:

Private Sub mnuFormatFont_Click()
    '添加设置字体的代码逻辑
End Sub

(二)工具栏设计

  1. 工具栏的作用:工具栏为用户提供了快速访问常用命令的方式,它通常包含一系列的按钮,每个按钮对应一个特定的功能。在 MDI 应用程序中,工具栏可以放置在 MDI 父窗体上,提供对所有子窗口都适用的操作,也可以根据子窗体的不同,在子窗体上添加特定的工具栏。
  2. 创建工具栏:以在 MDI 父窗体上创建工具栏为例,可以使用 Visual Basic 的“部件”对话框添加“Microsoft Windows Common Controls 6.0”部件,然后在 MDI 父窗体上添加一个 Toolbar 控件。通过设置 Toolbar 控件的属性和添加按钮来完成工具栏的设计。
Private Sub MDIForm_Load()
    With Toolbar1
      .Buttons.Add 1, "new", "新建", 1
      .Buttons.Add 2, "open", "打开", 1
      .Buttons.Add 3, "save", "保存", 1
    End With
End Sub

Private Sub Toolbar1_ButtonClick(ByVal Button As MSComctlLib.Button)
    Select Case Button.Key
        Case "new"
            ShowChildForm
        Case "open"
            '添加打开文件的代码逻辑
        Case "save"
            '添加保存文件的代码逻辑
    End Select
End Sub

在上述代码中,在 MDIForm_Load 事件中向 Toolbar1 添加了三个按钮,分别对应“新建”、“打开”和“保存”功能。在 Toolbar1_ButtonClick 事件中,根据用户点击的按钮执行相应的操作。

四、MDI 子窗体的管理与操作

(一)子窗体的显示与隐藏

  1. 显示子窗体:如前面代码示例所示,通过创建子窗体的实例并调用 Show 方法来显示子窗体。可以根据不同的条件和需求,在不同的事件过程中调用显示子窗体的代码。例如,当用户点击“新建”按钮时,显示一个新的子窗体。
  2. 隐藏子窗体:使用 Hide 方法可以隐藏子窗体。例如,当用户点击子窗体的“最小化”按钮时,可以将子窗体隐藏而不是关闭。
Private Sub ChildForm1_Resize()
    If Me.WindowState = vbMinimized Then
        Me.Hide
    End If
End Sub

在上述代码中,在子窗体的 Resize 事件中,当子窗体的窗口状态变为最小化时,将其隐藏。

(二)子窗体的排列与切换

  1. 子窗体的排列:MDI 父窗体提供了几种排列子窗体的方式,如水平平铺、垂直平铺和层叠排列。可以通过代码来实现这些排列方式。例如,要实现水平平铺子窗体:
Private Sub mnuArrangeHorizontal_Click()
    Me.Arrange vbTileHorizontal
End Sub

在上述代码中,当用户点击“水平平铺”菜单项时,调用 MDI 父窗体的 Arrange 方法,并传递 vbTileHorizontal 参数来实现水平平铺子窗体。 2. 子窗体的切换:用户可以通过点击子窗体的标题栏或在任务栏中选择相应的子窗体来切换子窗体。此外,也可以通过代码来切换子窗体。例如,在 MDI 父窗体的代码中,可以使用 SetFocus 方法将焦点设置到指定的子窗体。

Private Sub mnuSwitchToChild1_Click()
    Dim child As ChildForm1
    For Each child In MDIForm1.MDIChildren
        If TypeOf child Is ChildForm1 Then
            child.SetFocus
            Exit For
        End If
    Next
End Sub

在上述代码中,通过遍历 MDI 父窗体的所有子窗体,找到 ChildForm1 类型的子窗体并将焦点设置到它上面。

五、MDI 应用程序的数据共享与通信

(一)通过全局变量共享数据

  1. 原理:在 Visual Basic 中,可以定义全局变量来在不同的窗体(包括 MDI 父窗体和子窗体)之间共享数据。全局变量在工程的标准模块中定义,所有窗体都可以访问这些变量。
  2. 示例:首先在工程中添加一个标准模块(选择“工程”菜单中的“添加模块”),然后在标准模块中定义全局变量:
Public SharedData As String

在 MDI 父窗体中可以对这个全局变量进行赋值:

Private Sub MDIForm_Load()
    SharedData = "Initial data"
End Sub

在子窗体中可以读取和修改这个全局变量:

Private Sub ChildForm1_Load()
    Text1.Text = SharedData
    SharedData = "Data modified in child form"
End Sub

(二)通过事件驱动进行通信

  1. 原理:不同的窗体之间可以通过定义和触发事件来进行通信。例如,子窗体可以触发一个事件,MDI 父窗体可以捕获这个事件并执行相应的操作。
  2. 示例:在子窗体中定义一个事件:
Public Event DataChanged(ByVal newData As String)

Private Sub Command1_Click()
    Dim newData As String
    newData = "New data from child"
    RaiseEvent DataChanged(newData)
End Sub

在 MDI 父窗体中捕获这个事件:

Private Sub ChildForm1_DataChanged(ByVal newData As String)
    Label1.Caption = newData
End Sub

在上述代码中,当子窗体中的 Command1 按钮被点击时,触发 DataChanged 事件,并传递新的数据。MDI 父窗体捕获这个事件并将新数据显示在 Label1 上。

六、MDI 应用程序的高级特性与技巧

(一)处理子窗体的关闭事件

  1. 确认关闭操作:当用户试图关闭 MDI 子窗体时,通常需要确认用户是否真的要关闭该子窗体,特别是当子窗体中有未保存的数据时。可以在子窗体的 QueryUnload 事件中进行处理。
Private Sub ChildForm1_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    If Text1.Modified Then
        Dim result As Integer
        result = MsgBox("您有未保存的数据,是否保存?", vbYesNoCancel + vbQuestion, "确认关闭")
        Select Case result
            Case vbYes
                '添加保存数据的代码逻辑
            Case vbCancel
                Cancel = 1
        End Select
    End If
End Sub

在上述代码中,当子窗体触发 QueryUnload 事件时,如果文本框 Text1 的内容被修改,弹出一个消息框询问用户是否保存。如果用户选择“取消”,则取消关闭操作(设置 Cancel 为 1)。

(二)MDI 应用程序的打印功能

  1. 打印子窗体内容:在 MDI 应用程序中,打印功能通常针对子窗体的内容。可以使用 Visual Basic 的 Printer 对象来实现打印。例如,要打印子窗体上一个文本框的内容:
Private Sub mnuPrint_Click()
    Printer.Print Text1.Text
    Printer.EndDoc
End Sub

在上述代码中,当用户点击“打印”菜单项时,将文本框 Text1 的内容发送到打印机,并通过 Printer.EndDoc 结束打印作业。

  1. 打印预览:实现打印预览可以使用 CommonDialog 控件。首先在工程中添加“Microsoft Common Dialog Controls 6.0”部件,然后在子窗体上添加一个 CommonDialog 控件。
Private Sub mnuPrintPreview_Click()
    CommonDialog1.Flags = cdlPDReturnDC
    CommonDialog1.ShowPrinter
    Dim hDC As Long
    hDC = CommonDialog1.hDC
    Printer.Print "Print preview content"
    Printer.EndDoc
    ReleaseDC 0, hDC
End Sub

在上述代码中,当用户点击“打印预览”菜单项时,通过 CommonDialog1.ShowPrinter 显示打印预览对话框,并在预览中打印相应的内容。

七、MDI 应用程序的调试与优化

(一)常见调试问题及解决方法

  1. 子窗体显示异常:如果子窗体显示位置或大小不正确,可能是在设置子窗体属性时出现错误。检查子窗体的 MDIChild 属性是否正确设置为 True,以及在显示子窗体时是否正确设置了其初始位置和大小。例如,确保在显示子窗体时没有使用错误的坐标系统或错误地设置了 LeftTop 属性。
  2. 菜单和工具栏操作异常:如果菜单或工具栏的命令执行不正确,检查事件处理过程中的代码逻辑。确保菜单项和工具栏按钮的 Click 事件处理过程中调用了正确的函数或过程,并且参数传递正确。例如,在保存文件的操作中,检查文件保存路径和文件名的获取是否正确。

(二)性能优化

  1. 资源管理:在 MDI 应用程序中,尤其是当有多个子窗体同时打开时,资源管理非常重要。及时释放不再使用的对象资源,例如关闭子窗体时,确保关闭相关的文件句柄、数据库连接等。可以在子窗体的 Unload 事件中添加清理资源的代码。
Private Sub ChildForm1_Unload(Cancel As Integer)
    '关闭文件句柄
    If Not fileHandle Is Nothing Then
        fileHandle.Close
        Set fileHandle = Nothing
    End If
    '关闭数据库连接
    If Not conn Is Nothing Then
        conn.Close
        Set conn = Nothing
    End If
End Sub
  1. 优化代码逻辑:避免在频繁调用的事件过程中执行复杂的计算或 I/O 操作。例如,在子窗体的 Resize 事件中,尽量减少不必要的绘图操作或数据读取,以免影响性能。如果需要在 Resize 事件中进行一些调整,可以考虑使用延迟加载或按需加载的方式,只有在必要时才执行复杂的操作。