精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● VB和Basic>>〓〓..技术文章连载..〓〓>>走近编程通过实例学VB>>走近编程通过实例学VB(六)

主题:走近编程通过实例学VB(六)
发信人: chenjz(不再哭傲江湖)
整理人: cobe(2001-01-19 09:20:28), 站内信件
走近编程通过实例学VB(六) 
 


 
     大家好,在这一章内,我们将完善编辑器中的一些功能,使其成为一个基本完善的编辑器软件。
    下面是现在的编辑器所存在的一些问题:
    问题1.当MDI窗口中没有任何编辑窗口时如何使编辑菜单失效?
    当MDI窗口中没有编辑窗口时编辑菜单、窗口菜单以及保存、另存为、打印菜单项应该无效,否则当用户点击菜单后会出现错误。那么我们需要在程序中加入一些语句来判断是否存在编辑窗口。实现的方法是:编写代码在编辑窗口关闭时判断程序中Name属性为 Form1 的窗口是否存在,如果不存在则使相关菜单无效。在前面的章节我们已经介绍过了窗体的UnLoad事件,该事件在窗体被卸载时引发,所以我们需要在UnLoad事件中写入判断代码:
    Dim iCount As Integer
    Dim aForm
    For Each aForm In Forms
    If aForm.Name="Form1" Then iCount=iCount+1
    Next
    If iCount=1 Then
    With MDIForm1
    .mEdit.Visible=False
    .mFilePrint.Enabled=False
    .mFileSave.Enabled=False
    .mFileSaveAs.Enabled=False
    .mWindow.Visible=False
    End With
    End If
    要判断程序中Name属性为Form1的窗口是否存在,首先要遍历程序中的所有窗体。我们可以通过访问Forms来实现。Forms属性代表一个集合,其中的每一个元素代表程序中加载的窗体。在上面的代码中我们使用了For Each…Next语句。该语句针对一个数组或集合中的每个元素,重复执行一组语句。在上面的程序中,我们针对窗体集合对象Forms中的每一个对象,判断它的Name属性是否为Form1,如果是则计数器加1。另外大家可以看到在判断窗体数量的If语句中,条件为iCount=1而不是0,这是因为UnLoad事件是在窗体被卸载时发生,也就是说窗体仍然存在,所以需要将判断条件设定为等于1。
    另外我们还需要在Form1的Load事件中加入以下代码:
    With MDIForm1
    .mEdit.Visible=True
    .mFilePrint.Enabled=True
    .mFileSave.Enabled=True
    .mFileSaveAs.Enabled=True
    .mWindow.Visible=True
    End With
    以使窗口装载后显示菜单。
    另外可以采取的一个办法是在模块中定义一个变量作为计数器,当建立或者打开一个文件后加1,关闭一个窗口时减1。当记数值为0时使菜单无效。大家可以自己考虑实现的办法。
    问题2.如何在关闭文档内容被改变的编辑窗口时提示保存?
    通过运行前面的程序可以看到,当改变编辑窗口中的文档内容之后关闭窗口,程序并不会提示用户保存文件。那么我们需要在编辑窗体关闭时判断其中的内容是否被修改并提示是否保存。在RTF控件中有一个Change事件,该事件在RTF中的文本内容被改变时引发,包括在使用LoadFile方法装载文件后。那么我们需可以在Form1窗体中定义一个Boolean类型变量作为标记,在Change事件中将其值设置为True。同时在打开一个文档后和文档保存后将标记设置为False。最后在窗体的UnLoad事件中加入代码通过标记判断文档是否被改变。如果是,提示用户保存文档。
    打开Form1的代码窗口,在通用区域添加如下代码:
    Dim bChanged As Boolean
    Property Get HasChanged() As Boolean
    HasChanged=bChanged
    End Property
    Property Let HasChanged(b As Boolean)
    bChanged=b
    End Property
    其中变量bChanged为判断文档改变与否的标记。而建立属性HasChanged则是让外部程序可以读取该标记。
    然后在RichTextBox1的Change事件中添加下面一句:
    bChanged=True
    在执行Form1中的子程序SaveFile保存文档之后,需要将该标记设置为False。这样我们就需要更改SaveFile程序,改变后的代码如下:
    If Me.OpenFile<>"" Then
    Me.RichTextBox1.SaveFile Me.OpenFile,rtfText
    bChanged = False
    Else
    With MDIForm1.CommonDialog1
    .Filter="所有文件(*.*)|*.*"
    .Flags=cdlOFNOverwritePrompt   设置标志为当文件已经存在时提示是否覆盖
    .ShowSave
    If .FileName<>"" Then     用户输入了正确的文件名并按确定键
    Me.RichTextBox1.SaveFile .FileName,rtfText
    Me.OpenFile=.FileName
    Me.Caption=.FileName
    bChanged=False
    End If
    End With
    End If
    改变子程序SaveFileAS为如下代码:
    With MDIForm1.CommonDialog1
    .FileName=Me.OpenFile
    .Flags=cdlOFNOverwritePrompt
    .Filter="所有文件(*.*)|*.*"
    .ShowSave
    If .FileName<>"" Then
    Me.RichTextBox1.SaveFile .FileName,rtfText
    Me.OpenFile=.FileName
    Me.Caption=.FileName
    bChanged=False
    End If
    End With
    在Form1的Unload事件中添加如下代码:
    If bChanged Then
    a=MsgBox("是否保存"+Me.Caption,vbYesNoCancel Or vbExclamation)
    If a=vbYes Then
    Me.SaveFile
    If Me.OpenFile="" Then
    Cancel=1
    End If
    ElseIf a=vbCancel Then
    Cancel=1
    End If
    End If
    在上面的程序中,如果bChanged为True,则程序弹出包含是、否、取消三个按钮的消息框,如果用户选择 是则调用SaveFile保存文档,选择取消则将事件中的Cancel设置为False阻止关闭窗体,而选择否则直接关闭窗体。
    打开MDIForm1的代码窗口,找到菜单项mFileOpen的Click事件代码。其中有一句:frmNew.Caption=strOpen    设置新窗体标题为文件名
    在下面再添加一句:frmNew.HasChanged=False。这样判断文档是否改变部分的代码全部完成了,大家可以运行一下程序,在编辑窗口中输入一些文本再关闭,看看程序的执行效果。
    问题3.如何完成菜单中的撤销键入、重复键入功能。
    在第4章中程序我们已经使用了一个API函数。在这里首先我们还要利用它实现撤销和重复功能,首先简单的对Windows API做一些说明。
    1)什么是API(Application Programing Interface 应用程序编制接口)
    笼统的讲,API是一系列的复杂的函数、消息和结构,它使编程人员可以通过不同的编程语言编制出运行在Windows下的应用程序。对于VB初学者来说。可以把API看成是Windows提供的一个大函数库,这个函数库包含以下的几类:基本窗体构造类、GDI(图形设备接口类)、系统服务类、多媒体类、网络类等。
    我们只需要在程序中定义其中的这些函数以后就可以使用它们了。就象上面的程序中所显示的那样。
    2)如何在程序中添加API函数定义
    VB提供了一个API Viewer的程序,点击Windows开始按钮,在菜单中选择Microsoft Visual Studio 6.0|Microsoft Visual Studio 6.0 Tools|API Text Viewer就可以启动API Viewer了。点击菜单中的File|Load text file项,在打开对话框中选择Win32API.txt打开。这时在Availbel Item列表中会显示API函数列表,我们可以通过在上面的文本框中输入函数的前几个字母找到需要的函数然后双击列表中的函数项来选择,例如找到BringWindowToTop函数项再双击,结果如图所示。
    点击Copy按钮就可以将选择的函数定义拷贝到剪贴版。点击Clear按钮可以清除所选择的函数。一个API函数定义一般是向下面这样的:
    Public Declare Function BringWindowToTop Lib "user32" Alias "BringWindowToTop"(ByVal hwnd As Long) As Long
    其中BringWindowToTop是函数名称,也就是我们在VB中使用的函数名称,Lib "user32"
    定义函数所在的外部函数库的名称,Alias "BringWindowToTop"部分中引号内的是函数在函数库中的真正的名称。括号部分内的是传递给函数处理的参数。为什么要加Byval呢?因为如果不加Byval的话,VB调用外部程序时传递给函数的将是参数变量的指针,而加Byval将传递变量的值给外部函数。
    上面我只向大家十分笼统的介绍了一下API,实际上真正掌握API调用是十分复杂的,如果现在不想了解的话,只需要把程序中的API函数看成是VB中的函数一样调用就可以了。如果要详细了解的话,建议大家购买本专门介绍VB调用API的书来看一下。并结合编程来掌握API调用的精髓。
    现在回到VB,打开Module窗口,在其中添加下面的定义:
    Public Const WM_USER=&H400
    Public Const EM_REDO=WM_USER+84
    Public Const EM_UNDO=&HC7
    Public Const EM_CANUNDO=&HC6
    Public Const EM_CANREDO=WM_USER+85
        然后打开MDIForm1窗口,在菜单mEditUndo的Click事件中添加下面的代码:
    SendMessageByRef Me.ActiveForm.RichTextBox1.hwnd,EM_UNDO,ByVal 0,ByVal 0
        在mEditRedo的Click事件中添加如下代码:
    SendMessageByRef Me.ActiveForm.RichTextBox1.hwnd,EM_REDO,ByVal 0,ByVal 0
    打开Form1,在RichTextBox1的Change事件中添加以下代码:
    If SendMessageByRef(RichTextBox1.hwnd,EM_CANUNDO,ByVal 0,ByVal 0) Then
     MDIForm1.mEditUndo.Enabled=True
    Else
    MDIForm1.mEditUndo.Enabled=False
    End If
    If SendMessageByRef(RichTextBox1.hwnd,EM_CANREDO,ByVal 0,ByVal 0) Then
    MDIForm1.mEditRedo.Enabled=True
    Else
    MDIForm1.mEditRedo.Enabled=False
    End If
    上面的程序中,RichTextBox1_Change事件中的代码负责当文本改变后,看是否可以执行撤销键入或者重复键入的操作。并根据结果设置撤销键入和重复键入菜单项的允许或禁止状态。
    运行程序,在编辑窗口中输入一些文字或执行剪切操作,然后再点击撤销键入或重复键入菜单项,看看程序运行的结果。
    问题4.如何添加弹出式菜单到编辑窗口?
    在Form1的RichTextBox1的MouseUp事件中添加如下代码:
    If Button=2 Then
    PopupMenu MDIForm1.mEdit
    End If
    就可以在运行时鼠标右键在编辑窗口上单击后显示MDIForm1的编辑菜单了,PopupMenu用以在 MDIForm 或 Form 对象上的当前鼠标位置或指定的坐标位置显示弹出式菜单。
    问题5.RTF控件是一个文字处理控件,所以如果文本超长后会自动换行。如何让它不自动换行呢?
    我们可以通过设置RTF控件的RightMargin属性来实现,该属性决定自动换行的右极限,也就是说,如果控件中一行文本长度超过了RightMargin的值的话,超长的部分会移动到下一行,那么我们可以通过把RightMargin设置为一个很大的值来实现不自动换行,在Form1的Load事件中加入以下代码:
    RichTextBox1.RightMargin=300000
    就可以了。
    到本章为止,现在的编辑器已经基本成型了,一般的编辑功能都已经具备了,在下一章内,将要向大家介绍如何进一步美化程序,例如如何添加工具栏、状态栏及使用等。
    本章功课:运行程序,看看现在在基本功能上还有什么不完善的地方,利用前面所学的,尝试改进它,另外如果有兴趣的话,可以了解一下Windows API调用。(未完待续)
      



----
我能翻译善写作熟电脑会说话可是为什么没工作?

[关闭][返回]