Vb6 当用户取消时,如何优雅地从嵌套子程序的中间退出?
(我正在使用VB6,但我想这在大多数其他语言中都会出现。) 我有一个GUI按钮,它调用一个需要一两分钟才能完成的例程。我希望不耐烦的用户能够第二次点击按钮,让它在任何时候优雅地退出例程 我使用了一个静态变量使其工作得很好(参见下面的代码),但我正在清理项目,我想将For/Next循环放入它自己的函数中,因为它在项目中的几个不同位置都是必需的 但是这样做会破坏for/next中嵌入的静态标志,所以我需要做一些更改。在我对公共(全球)变量做一些胡思乱想的事情之前,我想我应该问问其他(更聪明的,也许实际上受过计算机科学教育的)人在面对这个问题时做了什么 所以基本上我的问题是如何复制这个:Vb6 当用户取消时,如何优雅地从嵌套子程序的中间退出?,vb6,Vb6,(我正在使用VB6,但我想这在大多数其他语言中都会出现。) 我有一个GUI按钮,它调用一个需要一两分钟才能完成的例程。我希望不耐烦的用户能够第二次点击按钮,让它在任何时候优雅地退出例程 我使用了一个静态变量使其工作得很好(参见下面的代码),但我正在清理项目,我想将For/Next循环放入它自己的函数中,因为它在项目中的几个不同位置都是必需的 但是这样做会破坏for/next中嵌入的静态标志,所以我需要做一些更改。在我对公共(全球)变量做一些胡思乱想的事情之前,我想我应该问问其他(更聪明的,也许实
Private Sub DoSomething_Click()
Static ExitThisSub As Boolean ' Needed for graceful exit
If DoSomething.Caption = "Click To Stop Doing Something" Then
ExitThisSub = False ' this is the first time we've entered this sub
Else ' We've re-entered this routine (user clicked on button to stop it)
ExitThisSub = True ' Set this so we'll see it when we exit this re-entry
Exit Sub '
End If
DoSomething.Caption = "Click To Stop Doing Something"
For i = 0 To ReallyBigNumber
Call DoingSomethingSomewhatTimeConsuming
If ExitThisSub = True Then GoTo ExitThisSubNow
DoEvents
Next
' The next line was missing from my original example,
' prompting appropriate comments
DoSomething.Caption = "Click To Do Something"
Exit Sub
ExitThisSubNow:
ExitThisSub = False ' clear this so we can reenter later
DoSomething.Caption = "Click To Do Something"
End Sub
当我将for/next循环移到它自己的函数时
我想我会将ExitThisSub更改为一个公共变量,退出一些长时间的计算,从而退出新的for/next sub,然后以相同的方式单击DoSomething
但当我使用全局变量时,我总是觉得自己是个业余爱好者(我也是),有没有更优雅的解决方案?您需要某种共享变量,以便for循环和按钮可以通信。我将for循环(及其相关代码)放在命令对象中。我的VB已经生锈了,但我认为您可以使用自己的“全局”变量和函数声明模块。您可以将所有代码移动到一个模块中,只需像现在一样检查全局变量
我对您发布的代码示例的主要关注与用户取消无关,而是与其他所有内容有关:您通过读取按钮文本来检查您的运行状态,而不是通过另一种方式进行检查(设置按钮文本是因为运行状态,它应该存储在一个变量中);您使用GOTO来退出for循环,而不是中断(VB有中断吗?),并且您将清理代码放在正常流程之外,而在我看来,无论用户是否取消,它都可以运行。一个可能的替代方法是将繁重的工作功能卸载到新线程。然后,如果用户想要取消,您可以直接杀死该线程,也可以向该线程发送消息
如上所述,通过按钮名进行切换是一个非常常见的技巧,如果只有几个按钮状态,则非常安全。我一直使用全局布尔变量,如bUserPressedCancel,以及循环中的DoEvents。优雅,斯梅莱根,它的作品
我同意Shinny先生的观点,即根据标题的价值进行测试不是一个好主意。如果在设计器中更改按钮上的文本,将破坏代码。最好不要依赖文本的措辞来运行代码。您可以在表单的模块级将变量声明为private。 这不是一个全局变量,而是一个模块级变量。 然后您可以将它传递给您创建的函数,并在函数中检查它 但是要小心这些事件。它基本上意味着允许windows消息循环处理消息。这意味着用户不仅可以再次单击您的按钮,还可以关闭表单并执行其他操作。所以,当您在这个循环中时,您无论如何都需要设置一个模块级变量,因为您需要在表单的QueryLoad和任何事件处理程序中检查它 您还可以使用控件本身的Tag属性来存储排序标志。但我不认为它更优雅。 我也喜欢使用两个不同的按钮。把一个藏起来,把另一个拿出来。这样,取消代码和运行代码在不同的事件处理程序中分离 下面是一些处理卸载方面的示例代码来扩展我的答案。 在这里,如果您通过x停止,它会提示您。如果你通过任务管理器杀人,它会优雅地死去
Option Explicit
Private Enum StopFlag
NotSet = 0
StopNow = 1
StopExit = 2
End Enum
Private m_lngStopFlag As StopFlag
Private m_blnProcessing As Boolean
Private Sub cmdGo_Click()
Dim lngIndex As Long
Dim strTemp As String
m_lngStopFlag = StopFlag.NotSet
m_blnProcessing = True
cmdStop.Visible = True
cmdGo.Visible = False
For lngIndex = 1 To 99999999
' check stop flag
Select Case m_lngStopFlag
Case StopFlag.StopNow
MsgBox "Stopping - Last Number Was " & strTemp
Exit For
Case StopFlag.StopExit
m_blnProcessing = False
End
End Select
' do your processing
strTemp = CStr(lngIndex)
' let message loop process messages
DoEvents
Next lngIndex
m_lngStopFlag = StopFlag.NotSet
m_blnProcessing = False
cmdGo.Visible = True
cmdStop.Visible = False
End Sub
Private Sub cmdStop_Click()
m_lngStopFlag = StopFlag.StopNow
End Sub
Private Sub Form_Load()
m_blnProcessing = False
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Select Case UnloadMode
Case vbFormControlMenu, vbFormCode
If m_blnProcessing Then
Cancel = True
If MsgBox("Unload Attempted - Cancel Running Process?", vbOKCancel + vbDefaultButton1 + vbQuestion, "Test") = vbOK Then
m_lngStopFlag = StopFlag.StopExit
End If
End If
Case Else
m_lngStopFlag = StopFlag.StopExit
Cancel = True
End Select
End Sub
在您需要进行本地化或任何其他需要独立于逻辑更改UI的事情之前,该功能一直有效。我将使用Tag属性或私有模块级变量。然后你可以独立于逻辑改变标题。如果是我,我会使用两个按钮——一个去,一个停。单击“转到”时,“停止”按钮可见。STOP的Click事件只是隐藏了自己——就是这样 然后,您的循环可以简单地检查停止按钮是否仍然可见。如果不是,那意味着它被点击了,你应该跳出去
您的控件是具有窗体范围的静态对象…如果您不想进行纯计算,VB6中的线程处理非常复杂。感谢您在按钮名称切换方面为我提供支持!:-)我知道使用按钮文本会带来一些风险,但是用“正确”的方式来做会增加更多的代码。我认为这两个方面最好的是在代码中定义按钮文本并在整个过程中使用它,所以如果它发生变化;它到处都在变化。我知道没有中断命令,但你让我查找它,我应该使用“退出”,谢谢。清理代码在“Exit Sub”之后,因此它不会意外运行。我这样做是因为我看到其他人就是这样做的-从来没有想过它是否理想。你也可以使用控件的tag属性。Exit For和Exit do是VB退出循环的两种方式。@Fred:在你的示例中,看起来清理代码应该在循环结束后运行,不管发生什么,否则按钮文本将不会重置。使用常量来存储按钮文本会有所帮助,但我仍然认为这种模式从根本上是错误的。