Visual Basic 用户界面

来源:百度文库 编辑:神马文学网 时间:2024/04/27 23:27:31
界面样式

    如果使用过基于 Windows 的应用程序,也许已经注意到不是所有用户界面看上去或操作起来都一样。用户界面样式主要有两种:单文档界面 (SDI) 和多文档界面 (MDI)。SDI 界面的一个示例就是 Microsoft Windows 中的WordPad(记事本)应用程序(图 6.1)。在 WordPad 中,只能打开一个文档,想要打开另一个文档时,必须先关上已打开的文档。


    象 Microsoft Excel 和 Microsoft Word for Windows 这样的应用程序就是MDI 界面;它们允许同时显示多个文档,每一个文档都显示在自己的窗口中(图 6.2)。按照是否包含有能在窗口或文档之间进行切换的子菜单的Windows 菜单项,就能识别出 MDI 应用程序。
    要决定哪种界面样式最好,需要看应用程序的目的。一个处理保险索赔的应用程序可能要用多文档界面 MDI 样式,一个职员很可能会同时处理一个以上索赔,或者需要对两个索赔进行比较。另一方面,日历程序最好设成 SDI(单文档界面)样式,因为不大需要同时打开一个以上日历;在极少的情况下,可以再打开一个单文档界面应用程序的实例。

    SDI 样式更常用,《程序员指南》中的大多数实例都采用 SDI 应用程序。关于创建 MDI 应用程序有一些需要单独考虑的问题和技巧,放在本章后面“多文档界面 (MDI) 应用程序”一节。
    除了以上两个最常用的界面样式 SDI 与 MDI 外,第三种界面样式变得越来越流行,这就是资源管理器样式的界面(图 6.3)。资源管理器样式界面是包括有两个窗格或者区域的一个单独的窗口, 通常是由左半部分的一个树型的或者层次型的视图和右半部分的一个显示区所组成,如在 MicrosoftWindows 的资源管理器中所见到的那样。这种样式的界面可用于定位或浏览大量的文档、图片或文件。    除了本章所附的 MDI 与 SDI 应用程序示例,实用程序向导还提供了一种比较界面样式差别的方法。可以用向导来为每一种样式生成一个框架,然后观察它生成的窗体与代码。

    详细信息 要了解更多的关于 MDI 应用程序的知识,请参阅“多文档界面 (MDI) 应用程序”一节。有关窗体使用的基础,请参阅第三章“窗体、控件与菜单”。有关访问实用程序向导的信息,请参阅第四章“工程的管理”中“使用向导和外接程序”一节。

多文档界面 (MDI) 应用程序

    多文档界面 (MDI) 允许创建在单个容器窗体中包含多个窗体的应用程序。像Microsoft Excel 与 Microsoft Word for Windows 这样的应用程序就具有多文档界面。
    MDI 应用程序允许用户同时显示多个文档,每个文档显示在它自己的窗口中。文档或子窗口被包含在父窗口中,父窗口为应用程序中所有的子窗口提供工作空间。例如:Microsoft Excel 允许创建并显示不同样式的多文档窗口。每个子窗口都被限制在 Excel 父窗口的区域之内。当最小化 Excel时,所有的文档窗口也被最小化,只有父窗口的图标显示在任务栏中。子窗体就是 MDIChild 属性设置为 True 的普通窗体。一个应用程序可以包含许多相似或者不同样式的 MDI 子窗体。
    在运行时,子窗体显示在 MDI 父窗体工作空间之内(其区域在父窗体边框以内及标题与菜单栏之下)。当子窗体最小化时,它的图标显示在 MDI 窗体的工作空间之内,而不是在任务栏中,如图 6.4 所示。

    注意 一个应用程序也可以包括标准的、不是包含在 MDI 窗体之内的非MDI 窗体。 MDI 应用程序中标准窗体的典型用法是显示       模式的对话框。
    MDI 窗体相似于具有一个限制条件的普通窗体。除非控件具有 Align 属性(如 PictureBox 控件)或者具有不可见界面(如 Timer 控件),否则不能将控件直接放置在 MDI 窗体上。

    创建 MDI 应用程序
    使用下列步骤来创建 MDI 窗体及其子窗体。
    要创建 MDI 应用程序,请按照以下步骤执行:
    1. 创建 MDI 窗体。
    从“工程”菜单中选取“添加 MDI 窗体”。
    注意 一个应用程序只能有一个 MDI 窗体。如果工程已经有了一个 MDI窗体,则该“工程”菜单上的“添加 MDI 窗体”命令就      不可使用。
    2. 创建应用程序的子窗体。
     要创建一个 MDI 子窗体,先创建一个新窗体(或者打开一个存在的窗体),然后把它的 MDIChild 属性设为 True。

    设计时使用 MDI 子窗体
    在设计时,子窗体不是限制在 MDI 窗体区域之内。可以添加控件、设置属性、编写代码以及设计子窗体功能,就像在其它 Visual Basic 窗体中做的那样。
    通过查看 MDIChild 属性或者检查工程资源管理器,可以确定窗体是否是一个 MDI 子窗体。如果该窗体的 MDIChild 属性设置为 True,则它是一个子窗体。Visual Basic 在“工程资源管理器”中为 MDI 窗体与 MDI 子窗体显示了特定的图标,如图 6.5 所示。

          图 6.5 工程资源管理器中的图标标明 MDI 子窗体、标准窗体和 MDI 窗体

    MDI 窗体运行时的特性
    在运行时,MDI 窗体及其所有的子窗体都呈现特定的性质:
    1.所有子窗体均显示在 MDI 窗体的工作空间内。像其它的窗体一样,用户能移动子窗体和改变子窗体的大小,不过,它们被限     制于这一工作空间内。
    2.当最小化一个子窗体时,它的图标将显示于 MDI 窗体上而不是在任务栏中。当最小化 MDI 窗体时,此 MDI 窗体及其所有子     窗体将由一个图标来代表。当还原 MDI 窗体时,MDI 窗体及其所有子窗体将按最小化之前的状态显示出来。
 3.当最大化一个子窗体时,它的标题会与 MDI 窗体的标题组合在一起并显示于 MDI 窗体的标题栏上(参见图 6.6)。

    4.通过设定 AutoShowChildren 属性,子窗体可以在窗体加载时自动显示(True) 或自动隐藏 (False)。
    5.活动子窗体的菜单(若有)将显示在 MDI 窗体的菜单栏中,而不是显示在子窗体中。

 

MDI NotePad 应用程序
    MDI NotePad 示例应用程序是一个简单的文本编辑器,它与 MicrosoftWindows 中包含的 NotePad 应用程序相似。不过,MDI NotePad 应用程序使用的是一个多文档界面 (MDI)。在运行时,若用户需要一个新文档(用该应用程序的“文件”菜单中的“新建”命令执行),应用程序就会创建子窗体的一个新实例。这就允许按其所需创建多个子窗体或文档。
    在 Visual Basic 中为了创建以文档为中心的应用程序,至少需要两个窗体:一个 MDI 窗体和一个子窗体。设计时,应创建一个 MDI 窗体以容纳该应用程序,再创建一个子窗体作为这个应用程序文档的模板。
    要创建自己的 MDI NotePad 应用程序,请按照以下步骤执行:
    1. 从“文件”菜单中,选取“新建工程”命令。
    2. 从“工程”菜单中,选取“添加 MDI 窗体”命令来创建容器窗体。现在,这个工程应当包含一个 MDI 窗体 (MDIForm1) 和     一个标准窗体(Form1)。
    3. 在 Form1 上创建一个文本框 (Text1)。
    4. 按下列方式为两个窗体和文本框设置属性。

    6. 在 mnuFileNew_Click 过程中增加以下代码:
    Private Sub mnuFileNew_Click ()
      ' 创建名为 NewDoc 的窗体 Form1 的一个新实例。
      Dim NewDoc As New Form1
      ' 显示此新窗体。
      NewDoc.Show
    End Sub
    这个过程创建并显示 Form1 的名为 NewDoc 的一个新实例(或其副本)。每当从“文件”菜单中选取“新建”命令时,将会创建一个与 Form1完全相同的副本(实例),它包含 Form1 所包含的所有控件和代码。
    7. 给 Form1 窗体的 Form_Resize 过程添加以下代码:
     Private Sub Form_Resize()
        ' 扩展文本框以放置当前子窗体。
        Text1.Height = ScaleHeight
        Text1.Width = ScaleWidth
     End Sub
    Form_Resize 事件过程的代码,像Form1 中的所有代码一样,能为 Form1的每一个实例所共享。当显示窗体的几个副本时,每个窗体都能识别各自的事件。当一个事件出现时,该事件过程的代码就会被调用。由于相同的代码为每个实例所共享,关于调用该代码的窗体是如何引用的,尤其是每个实例都具有相同的名字 (Form1) 时。这个问题将在本章后面的“使用 MDI 窗体及其子窗体”一节中讨论。    8. 按 F5 键可运行该应用程序。
    提示 除了本章提到的以外,Mdinote.vbp 示例应用程序还包含许多 MDI技巧。花一些时间对该示例代码进行全面研究会找到这些技巧。Sdinote.vbp 示例应用程序是同一应用程序转换为 SDI 样式的实现;比较这两个例子可以明白 MDI 和 SDI 技巧的差别。

    使用 MDI 窗体及其子窗体
    当 MDI 应用程序在一次会话中要打开、保存和关闭几个子窗体时,应当能够引用活动窗体和保持关于子窗体的状态信息。这个主题描述了一些用来指定活动子窗体或者控件、加载和卸载 MDI 窗体及其子窗体、以及保持子窗体的状态信息的编码技巧。

    指定活动子窗体或控件
    有时要提供一条命令,它用于对当前活动子窗体上具有焦点的控件进行操作。例如,假设想从子窗体的文本框中把所选文本复制到剪贴板上。在Mdinote.vbp 示例应用程序中,“编辑”菜单上的“复制”项的 Click 事件将会调用 EditCopyProc,它是把选定的文本复制到剪贴板上的过程。
    由于应用程序可以有同一子窗体的许多实例,EditCopyProc 需要知道使用的是哪一个窗体。为了指定这一点,使用 MDI 窗体的 ActiveForm 属性,该属性可以返回具有焦点的或者最后被激活的子窗体。
    注意 当访问 ActiveForm 属性时,至少应有一个 MDI 子窗体被加载或可见,否则会返回一个错误。
    当一个窗体中有几个控件时,也需要指定哪个控件是活动的。像 ActiveForm属性一样,ActiveControl 属性能返回活动子窗体上具有焦点的控件。下边是副本例程的示例,从子窗体菜单、MDI 窗体菜单或者是工具栏按钮上可对它进行调用。
    Private Sub EditCopyProc ()
      ' 将选定文本复制到剪贴板上。
      ClipBoard.SetText _
        frmMDI.ActiveForm.ActiveControl.SelText
    End Sub
    假如,正在编写被多个窗体实例调用的代码,不用窗体标识符访问窗体的控件或属性是一个好办法。例如,用 Text1.Height 引用 Form1上文本框的高度,而不是使用 Form1.Text1.Height。这样,该代码总是影响当前窗体。
    在代码中指定当前窗体的另一种方法是用 Me 关键字。用 Me 关键字来引用当前其代码正在运行的窗体。当需要把当前窗体实例的引用参数传递给过程时,这个关键字很有用。
    详细信息 有关通过 Dim 语句用 New 关键字来创建多个窗体实例的信息,请参阅第五章“编程基础”中的“变量、常数和数据类型概述”,以及《语言参考》的“Dim 语句”。有关通过 Dim 语句用 New 关键字来创建多个窗体实例的信息,请参阅“编程基础”中的“变量、常数和数据类型概述”,和《语言参考》的“Dim 语句”。

加载 MDI 窗体及其子窗体
    加载子窗体时,其父窗体(MDI 窗体)会自动加载并显示。而加载 MDI 窗体时,其子窗体并不会自动加载。
    在 MDI NotePad 示例中,子窗体是缺省的启动窗体,因而在程序运行时,子窗体和 MDI 窗体两者都会加载。如果在 MDI NotePad 应用程序中改变启动窗体为 frmMDI(在“工程属性”的“一般”选项卡上),然后运行应用程序,则只有 MDI 窗体被加载。当从“文件”菜单中选取“新建”命令时,才会加载第一个子窗体。
    AutoShowChildren 属性可用来加载隐藏状态的 MDI 子窗口,使它们处于隐藏状态直至用 Show 方法把它们显示出来。这就允许在子窗体变成可见之前更新标题、位置和菜单等各种细节。
    不能把 MDI 子窗体或者 MDI 窗体显示为模式窗体(用带 vbModal 参数的 Show 方法)。如果想在 MDI 应用程序中使用模式对话框,可使用MDIChild 属性设置为 False 的窗体。

    设置子窗体的大小和位置
    如果 MDI 子窗体具有大小可变的边框〔即 BorderStyle = 2),在其装载时,Microsoft Windows 将决定其初始的高度、宽度和位置。边框大小可变的子窗体,其初始大小与位置取决于 MDI 窗体的大小,而不是设计时子窗体的大小。当 MDI 子窗体的边框大小不可变(即 BorderStyle = 0,1 或 3)时,则它将用设计时的 Height 和 Width 属性被载入。
    如果设置 AutoShowChildren 为 False,则在 MDI 子窗体载入以后,把它设为可见状态之前,可以改变其位置。
    详细信息 请参阅《语言参考》的“AutoShowChildren 属性”和“ Show 方法”。

    维护子窗体的状态信息
    在用户决定退出 MDI 应用程序时,必须有保存信息的机会。为了使其能够进行,应用程序必须随时都能确定自上次保存以来子窗体中的数据是否有改变。
    通过在每个子窗体中声明一个公用变量来实现此功能。例如,可以在子窗体的声明部分声明一个变量:
    Public boolDirty As Boolean
    Text1 中的文本每改变一次时,子窗体文本框的 Change 事件就会将boolDirty 设置为 True。可添加此代码以指示自上次保存以来 Text1 的内容已经改变。
    Private Sub Text1_Change ()
       boolDirty = True
    End Sub
    反之,用户每次保存子窗体的内容时,文本框的 Change 事件就将 boolDirty设置为 False,以指示 Text1 的内容不再需要保存。在下列代码中,假设有一个叫做“保存”(mnuFileSave) 的菜单命令和一个用来保存文本框内容的名为 FileSave 的过程:
    Sub mnuFileSave_Click ()
        '保存 Text1 的内容。
        FileSave
        '设置状态变量。
        boolDirty = False
    End Sub

    用 QueryUnload 卸载 MDI 窗体
    当用户决定退出应用程序时,boolDirty 标志就很有用了。当用户从 MDI 窗体的“控制”菜单中选取“关闭”,或者从提供的菜单项,例如“文件”菜单上的“退出”命令,上述情况就会出现。如果用户使用 MDI 窗体的“控制”菜单来关闭应用程序,Visual Basic 将试图卸载 MDI 窗体。
    当 MDI 窗体被卸载时,QueryUnload 事件首先为 MDI 窗体调用,然后再为每一个打开的子窗体调用。如果在这些 QueryUnload 事件过程中没有代码,则取消 Unload 事件,然后,每一个子窗体被卸载,最后,MDI 窗体被卸载。
    由于 QueryUnload 事件在窗体卸载之前被调用,因此在窗体卸载前可以给用户一个机会来保存窗体。下述代码使用 boolDirty 标志来决定是否要提醒用户在子窗体卸载之前进行保存。请注意,可以在工程的任何地方访问公共窗体级变量值。这个代码假定有一个名叫 FileSave 的过程,它将 Text1的内容保存到一个文件中。
    Private Sub mnuFExit_Click()
        '当用户在 MDI 应用程序中选取“文件提出”命令时,卸载
        'MDI 窗体,为每个打开的子窗体调用 QueryUnload 事件。
        Unload frmMDI
        End
    End Sub
    Private Sub Form_QueryUnload(Cancel As Integer, _
        UnloadMode As Integer)
        If boolDirty Then
        '调用例程来询问用户且必要时保存文件。
        FileSave
        End If
    End Sub