什么';在VB6中使用按钮标题作为变量有什么不好?

什么';在VB6中使用按钮标题作为变量有什么不好?,vb6,Vb6,我在上一个问题()中收到了一些合理的批评性反馈,因为我使用了命令按钮的标题作为状态变量。我这样做是因为它效率高,只需很少的代码就可以同时满足两到三个目的,但我理解它如何也会导致问题,特别是我最初介绍它的方式有点马虎 我觉得这值得自己讨论,所以这里有一个相同的想法,经过一些清理和修改,以“正确地”完成它(这基本上意味着在一个地方定义字符串,这样您的代码就不会因为更改命令按钮的文本而开始失败)。我知道我的变量和控件命名约定很差(好的,不存在),所以请提前道歉。但我想把重点放在状态变量讨论的标题上 现

我在上一个问题()中收到了一些合理的批评性反馈,因为我使用了命令按钮的标题作为状态变量。我这样做是因为它效率高,只需很少的代码就可以同时满足两到三个目的,但我理解它如何也会导致问题,特别是我最初介绍它的方式有点马虎

我觉得这值得自己讨论,所以这里有一个相同的想法,经过一些清理和修改,以“正确地”完成它(这基本上意味着在一个地方定义字符串,这样您的代码就不会因为更改命令按钮的文本而开始失败)。我知道我的变量和控件命名约定很差(好的,不存在),所以请提前道歉。但我想把重点放在状态变量讨论的标题上

现在我们开始:

' Global variables for this form
Dim DoTheThingCaption(1) As String
Dim UserCancel, FunctionCompleted As Boolean

Private Sub Form_Initialize()
  ' Define the possible captions (is there a #define equivalent for strings?)
  DoTheThingCaption(0) = "Click to Start Doing the Thing"
  DoTheThingCaption(1) = "Click to Stop Doing the Thing"

  ' Set the caption state when form initializes
  DoTheThing.Caption = DoTheThingCaption(0)
End Sub

Private Sub DoTheThing_Click() ' Command Button

If DoTheThing.Caption = DoTheThingCaption(0) Then
  UserCancel = False ' this is the first time we've entered this sub
Else ' We've re-entered this routine (user clicked on button again
     ' while this routine was already running), so we want to abort
  UserCancel = True ' Set this so we'll see it when we exit this re-entry
  DoTheThing.Enabled = False 'Prevent additional clicks
  Exit Sub
End If

' Indicate that we're now Doing the Thing and how to cancel
DoTheThing.Caption = DoTheThingCaption(1)

For i = 0 To ReallyBigNumber
  Call DoSomethingSomewhatTimeConsuming
  If UserCancel = True Then Exit For ' Exit For Loop if requested
  DoEvents ' Allows program to see GUI events
Next

' We've either finished or been canceled, either way
' we want to change caption back
DoTheThing.Caption = DoTheThingCaption(0)

If UserCancel = True Then GoTo Cleanup

'If we get to here we've finished successfully
FunctionCompleted = True
Exit Sub '******* We exit sub here if we didn't get canceled ******* 

Cleanup:
'We can only get to here if user canceled before function completed

FunctionCompleted = False
UserCancel = False ' clear this so we can reenter later
DoTheThing.Enabled = True 'Prevent additional clicks

End Sub  '******* We exit sub here if we did get canceled ******* 
就是这样。这样做还有什么不好的地方吗?这只是一个风格问题吗?有没有其他东西能让我以更理想或更易于维护的方式实现这四点

  • 即时GUI反馈,用户按下按钮已导致操作
  • 在用户已经注意到如果不需要操作如何取消的位置,即时GUI反馈
  • 用户启动/取消操作的单键方式(减少GUI上的混乱)
  • 一个简单、即时的命令按钮,用于禁用以防止多个关闭请求

  • 我可以看到一个问题可能是代码和GUI之间的紧密耦合(以多种方式),因此我可以看到这对于大型项目(或者至少是大型GUI)来说是一个大问题。这恰好是一个较小的项目,只有2或3个按钮可以接受这种“处理”。

    这种技术最大的一个问题是它使用字符串作为布尔值。根据定义,布尔变量只能有两个状态,而字符串可以有任意数量的状态

    现在,您已经通过依赖预定义字符串数组来定义命令按钮文本的允许值,在某种程度上缓解了这种情况下固有的危险。这就留下了一些较小的问题:

    • 关于当前和可用状态,逻辑不够明确(表单实际上有四种可能的状态:未启动、已启动、已完成、已启动但正在取消)-维护需要仔细观察按钮文本和布尔变量状态之间的潜在交互,以确定当前状态是/应该是什么。单个枚举将使这些状态显式,使代码更易于阅读和理解,从而简化维护
    • 您依赖控件属性(按钮文本)的行为来保持与公开属性值类型(字符串)的行为一致。这种假设使得将旧的VB6代码迁移到新的语言/平台变得非常困难
    • 字符串比较比布尔变量的简单测试慢得多。在这种情况下,这无关紧要。一般来说,避免它同样容易

    • 您正在使用DoEvents来模拟多线程(与问题没有直接关系……但是,呃)

      • 我在处理(非常旧的)代码(按钮标题作为变量)时遇到的最大问题是全球化是一场噩梦。。。。我不得不移动一个旧的vb6应用程序来使用英语和德语。。。这花了几个星期,甚至几个月

        你也在使用goto's。。。。。也许需要一些重构来使代码可读

        **根据评论进行编辑 我只会在每个进程的顶部使用vb6中的goto; 错误转到myErrorHandler


        然后在程序的最底层,我会有一个将err传递给全局处理程序的单行程序来记录错误。

        我认为最好将标题文本与处理状态分离。此外,后藤也让人难以阅读。这是我的重构版本

        Private Const Caption_Start As String = "Click to Start Doing the Thing"
        Private Const Caption_Stop As String = "Click to Stop Doing the Thing"
        
        Private Enum eStates
          State_Initialized
          State_Running
          State_Canceled
          State_Completed
        End Enum
        
        Private Current_State As eStates
        
        Private Sub Form_Initialize()
        
          DoTheThing.Caption = Caption_Start
          Current_State = State_Initialized
        
        End Sub
        
        Private Sub DoTheThing_Click()
        
          If Current_State = State_Running Then
        
            'currently running - so set state to canceled, reset caption'
            'and disable button until loop can respond to the cancel'
            Current_State = State_Canceled
            DoTheThing.Caption = Caption_Start
            DoTheThing.Enabled = False
        
          Else
        
            'not running - so set state and caption'
            Current_State = State_Running
            DoTheThing.Caption = Caption_Stop
        
            'do the work'
            For i = 0 To ReallyBigNumber
              Call DoSomethingSomewhatTimeConsuming
        
              'at intervals check the state for cancel'
              If Current_State = State_Canceled Then
                're-enable button and bail out of the loop'
                DoTheThing.Enabled = True
                Exit For
              End If
        
              DoEvents
        
            Next
        
            'did we make it to the end without being canceled?'
            If Current_State <> State_Canceled Then
              Current_State = State_Completed
              DoTheThing.Caption = Caption_Start
            End If
        
          End If
        
        End Sub
        
        Private Const Caption\u Start As String=“单击开始操作”
        Private Const Caption_Stop As String=“单击以停止操作”
        私人地产
        状态u已初始化
        国家运行
        州政府取消
        州政府已完成
        结束枚举
        作为不动产的私有当前状态
        私有子表单_初始化()
        DoTheThing.Caption=Caption\u Start
        当前状态=已初始化状态
        端接头
        私有子点点击()
        如果当前状态=运行状态,则
        '当前正在运行-因此将状态设置为已取消,重置标题'
        '和禁用按钮,直到循环可以响应取消'
        当前状态=已取消状态
        DoTheThing.Caption=Caption\u Start
        DoTheThing.Enabled=False
        其他的
        '未运行-因此设置状态和标题'
        当前状态=运行状态
        DoTheThing.Caption=Caption\u Stop
        “完成工作”
        对于i=0到ReallyBigNumber
        呼叫DoSomethingSomewhatTimeConsuming
        '每隔一段时间检查取消状态'
        如果当前状态=已取消状态,则
        '重新启用按钮并退出循环'
        DoTheThing.Enabled=True
        退出
        如果结束
        多芬特
        下一个
        “我们没有被取消就完成了吗?”
        如果当前状态已取消,则
        当前状态=状态完成
        DoTheThing.Caption=Caption\u Start
        如果结束
        如果结束
        端接头
        
        除了像DJ在中那样删除GOTos外,您的方法没有任何错误。按钮标题只能有两种状态,您可以使用这两种状态来定义代码中的流

        然而,我有两个原因可以解释为什么我会采取不同的做法:

      • 当你想将你的程序翻译成另一种语言时,你的方法会产生问题(以我的经验,你应该一直计划这样做),因为字幕会在另一种语言中改变
      • 它违背了将用户界面与程序流分离的原则。这可能不是一个重要的问题