AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VB编程

在VB6中用命令行为模式控制GUI动作

51自学网 http://www.wanshiok.com


建立GUI

   该程序的GUI由Form1表现,它包含了一个图像(image)控件,在该控件中有一个球的位图。该窗体还包含了一个对象集合,我把这个集合作为先前命令的堆栈。通过把每条命令添加到该集合的末尾,以及从集合末尾弹出命令,我可以相反地跟踪命令的执行过程。从本质上来说,该集合扮演了堆栈的角色。我在命令执行之后压入(push)命令,弹出(pop)命令调用Undo操作。

   为了演示Undo操作,我定义了Edit|Undo菜单和Edit|Rewind操作。Undo从堆栈中弹出一条命令并调用Undo。Rewind弹出所有命令,在每个命令上调用Undo。列表2包含了Form1的代码。

   列表2

Option Explicit

Private stack As Collection
Private Const MOVEMENT_AMOUNT As Integer = 50

Private Sub AboutMenu_Click()
  Const About As String = "Command Pattern Demo" + vbCrLf + _
    "Copyright (c) 2004. All Rights Reserved" + vbCrLf + _
    "Written By Paul Kimmel. pkimmel@softconcepts.com"

  MsgBox About, vbInformation + vbOKOnly, "About"

End Sub

Private Sub ExitMenu_Click()
  End
End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Select Case KeyCode
   Case vbKeyBack
    UndoCommand
   Case vbKeyLeft
    Call ProcessCommand(New LeftCommand)
   Case vbKeyUp
    Call ProcessCommand(New UpCommand)
   Case vbKeyRight
    Call ProcessCommand(New RightCommand)
   Case vbKeyDown
    Call ProcessCommand(New DownCommand)
  End Select
End Sub

Private Function PopStack() As ICommand
  On Error GoTo Catch
  Debug.Print "Stack count: " & stack.Count
  If (stack.Count = 0) Then
   Beep
   Set PopStack = Nothing
   Exit Function
  End If

  Set PopStack = stack.Item(stack.Count)
  Call stack.Remove(stack.Count)
  Exit Function
  Catch:
   Debug.Print Err.Description
   Set PopStack = Nothing
End Function

Private Sub PushStack(ByVal command As ICommand)
  On Error GoTo Catch
  Call stack.Add(command)
  Debug.Print "Stack count: " & stack.Count
  Exit Sub
  Catch:
   Debug.Print Err.Description
End Sub

Public Sub UndoCommand()
  Dim command As ICommand
  Set command = PopStack()
  If (command Is Nothing) Then Exit Sub
  command.Undo
End Sub

Private Sub ProcessCommand(ByVal command As ICommand)
  Set command.Form = Me
  command.Execute
  Call PushStack(command)
End Sub

Public Sub MoveDown()
  Debug.Print "Moving Down"
  If (Image1.Top > Height) Then
   Image1.Top = 0 - Image1.Height + MOVEMENT_AMOUNT
  Else
   Image1.Top = Image1.Top + MOVEMENT_AMOUNT
  End If
End Sub

Public Sub MoveUp()
  Debug.Print "Moving Up"
  If (Image1.Top + Image1.Height < 0) Then
   Image1.Top = Height - MOVEMENT_AMOUNT
  Else
   Image1.Top = Image1.Top - MOVEMENT_AMOUNT
  End If
End Sub

Public Sub MoveLeft()
  Debug.Print "Moving Left"
  If (Image1.Left + Image1.Width < 0) Then
   Image1.Left = Width - MOVEMENT_AMOUNT
  Else
   Image1.Left = Image1.Left - MOVEMENT_AMOUNT
  End If
End Sub

Public Sub MoveRight()
  Debug.Print "Moving Right"
  If (Image1.Left > Width) Then
   Image1.Left = 0 - Image1.Width + MOVEMENT_AMOUNT
  Else
   Image1.Left = Image1.Left + MOVEMENT_AMOUNT
  End If
End Sub

Private Sub Form_Load()
  Set stack = New Collection
End Sub

Private Sub RewindMenu_Click()
  While stack.Count > 0
   UndoCommand
  Wend
End Sub

Private Sub UndoMenu_Click()
  Call UndoCommand
End Sub

   下一步,我通过把窗体的KeyPreview属性设置为True并建立与该按键相关的命令对象,把有关的方向箭头按键与每条命令关联起来。例如vbKeyUp应该建立一个UpCommand对象。接着我处理这些命令(我也可以使用工厂创建型模式把命令对象的创建过程移动到命令类的内部)。

   ProcessCommand被定义为把Form1的指针赋予某个命令的Form属性、执行该命令并把该命令压入集合堆栈中。你没有必要实现一个堆栈,但是如果你没有跟踪命令执行的次序,那么使用Undo操作是不可能的。

检查UML中的工作

   如果你了解UML,那么你应该知道图1基本上概括了本文的内容。如果你不了解UML(它是一个很好的技巧),这种简单的类图表也不难理解。线(Line)表现了关系。菱形(Diamond)表现了完整的和局部的关系,也就是集合体。完整的关系带有菱形,而部分的却没有。方向键表现了联合关系(associations),它与集合关系大致相当,三角形表现了继承(inheritance),被继承的东西带有三角形。虚线和方向线表明了依赖关系和必要的信息。

   请查看图1,从逻辑上讲,LeftCommand、RightCommand、DownCommand和UpCommand都继承自ICommand。命令与窗体有关联,但是并不是拥有窗体--这是由它们的Form属性表现出来的。Form依赖于命令,这是因为它是该Form的操作被调用的方式,并且Form与集合有聚合关系,因为Form负责处理集合的生命周期。

   这些定义并非UML中精确的技术。例如,我们可以区分继承(称为一般化)和接口继承(称为实现),但是说明却是遵循实用主义的。

回顾简单的堆栈表现

   本文中的技术要求你通晓一些堆栈表现的知识。当我还是一名密歇根州大学(Michigan State University)大学生的时候,我就必须实现堆栈,在那个时候这是很困难的。初学编程的人可以从这儿的堆栈快速回顾中受益,在VB6中很容易使用集合实现堆栈,并且非常有用。
堆栈是一种遵循后进先出(LIFO)规则的数据结构,它受到两种基本的操作(push和pop)。给堆栈添加内容的时候必须使用push操作,删除内容的时候使用pop操作。调用push添加的最后的内容在调用pop的时候会被最先取出。例如,如果你有一个整数堆栈,并且压入了1、2、3、4、5,那么5次调用pop的时候会得到5、4、3、2、1。因此,堆栈是用于向后跟踪的很好的数据结构,有趣的是,它也是你的CPU跟踪运行的代码路径的基本原理。

   但是,集合要成为堆栈仅仅依赖于你插入和删除内容的位置。通过在集合的末尾插入和删除内容,设计堆栈只需要少量的代码。例如,用collection.Add实现push调用,用collection.Remove(collection.Count)实现pop调用。简单地把集合的尾部作为数据结构的头部高效地把集合转换成了简单的堆栈。你在列表2的PushStack和PopStack方法中可以看到例子。

   最后,你还可以对本文的例子进行很好的修改。把集合、PushStack和PopStack移动到一个Stack类可以使窗体更加整洁,并且建立了一个良好的通用堆栈类。采用这种方式改善代码的设计称为重构(refactoring)。学习代码重构是学习模式的良好补充。

工具的品质

   在本文中你学习了一种工具--命令行为模式。如果发现被调用的行为需要被撤销,或者使用的代码过于复杂,那么我希望你能够记起这个简单但是功能强大的工具,其实本文讨论的其它一些概念--UML、模式和重构本质上也是工具。

   任何任务都不可能有完美的工具(有句谚语是这样说的"如果你只拥有锤子,那么一切问题都是钉子")。我的父亲常说工匠通常是由于他们工具的品质而知名的。换句话说,你所拥有的工具越多,你能实现的功能也就越多。

 
 

上一篇:真没想到VB也可以这样用之指针技术  下一篇:VB设计Win2000下截获IP数据包程序