首页 > 解决方案 > 您可以中断 vba 代码以进行工作表选择吗?

问题描述

我会尽量在描述中尽可能清楚,所以这里什么都没有:

我创建了一个代码,用户在其中选择他的 excel 文件,然后宏将该文件中的Sheet文件复制到我的宏Workbook中。

MyFile = Application.GetOpenFilename()
    Workbooks.Open (MyFile)
        ActiveSheet.Copy After:=wbook.Sheets(1)
        ActiveSheet.Name = "Selected file"
    Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False

这是可行的,但我意识到,在某些情况下,所选文件可能有多个Sheets.

有没有办法编写宏,如果我选择的文件有 1 张它运行上面的代码,如果它有不止一张让我选择我想要的工作表然后运行其余代码?

标签: vbaexcel

解决方案


编辑:

  • 我想到了另一种方法来处理这个问题——也许更接近你正在寻找的东西。. .

    图像

这只是我偶尔使用 的基本暂停例程的扩展。

这是我的“常规”Pause例程(使用Timer函数):

Sub Pause(seconds As Single)
    Dim startTime As Single
    startTime = Timer                          'get current timer count
    Do
        DoEvents                               'let Windows "catch up"
    Loop Until Timer > startTime + seconds     'repeat until time's up
End Sub

...所以,它给了我一个想法。

老实说,我有点惊讶地发现这行得通,因为它基本上是同时运行两段代码


代码WaitForUserActivity

这是我在上面的演示中使用的代码:

Option Explicit
Public isPaused As Boolean

Sub WaitForUserActivity()                   'THE 'RUN DEMO' BUTTON runs this sub.

    Dim origSheet As String
    isPaused = True                                   'flag "pause mode" as "on"
    origSheet = ActiveSheet.Name                'remember current worksheet name

    MsgBox "This will 'pause' code execution until you" & vbLf & _
           "click the 'Continue' button, or select a different a worksheet."
    Application.StatusBar = "PAUSED: Click ""Continue"", or select a worksheet."

    Do                                       'wait for button click or ws change
        DoEvents        'yield execution so that the OS can process other events
    Loop Until (Not isPaused) Or (ActiveSheet.Name <> origSheet)

    If isPaused Then                           'the active worksheet was changed
        MsgBox "Worksheet '" & ActiveSheet.Name & "' was selected." _
              & vbLf & vbLf & "Now the program can continue..."
    Else                                                 'the button was clicked
        MsgBox "The 'Continue' button was clicked." _
              & vbLf & vbLf & "Now the program can continue..."
    End If
    Application.StatusBar = "Ready"
End Sub

Sub btnContinue()                          'THE 'CONTINUE' BUTTON runs this sub.
    isPaused = False                                 'flag "pause mode" as "off"
End Sub

运行演示

  • 将上述代码放在常规模块中
  • 确保工作簿至少有两个工作表
  • 创建两个命令按钮:
    • 一个用于“运行演示”按钮,分配宏:WaitForUserActivity
    • 一个用于“继续”按钮,分配宏:btnContinue
  • 点击“运行演示”按钮

代码中的关键命令是DoEventsFunction,它“产生执行以便操作系统可以处理其他事件”。

DoEvents将控制权交给操作系统。在操作系统完成处理其队列中的事件并且 SendKeys 队列中的所有键都已发送后,控制权被返回。

DoEvents对于简单的事情最有用,例如允许用户在启动后取消进程,例如搜索文件。对于长时间运行的进程,通过使用 Timer 或将任务委派给ActiveX EXE组件来更好地完成让出处理器 - 并且操作系统负责多任务处理和时间切片

每当您在事件过程中临时让出处理器时,请确保在第一次调用返回之前不会从代码的不同部分再次执行该过程;这可能会导致不可预测的结果。

中的更多详细信息(和警告)。



原答案:

一些建议的解决方案:

  1. 您可以提示用户指定哪个工作表,而不是“停止”代码。

    • 最简单的方法是InputBox用户输入 ID 号或以其他方式识别工作表。

    • 更复杂但更强大和更专业的将是在用户表单的帮助下的自定义对话框。网上有几个例子和教程,比如这个

  2. 您可以通过简单的计时器循环“暂停”执行以给用户一定的时间来选择工作表,甚至可以检查工作表名称以查看用户是否选择了新的工作表,如下所示:

    Dim startTime As Single, shtName As String
    If ThisWorkbook.Worksheets.Count = 1 Then
        MsgBox "There is only one worksheet in this workbook."
    Else
        shtName = ActiveSheet.Name 'get name of active sheet
        MsgBox "You have 5 seconds to select a worksheet after clicking OK.", _
            vbOKOnly + vbInformation, "Select a worksheet... fast!"
        startTime = Timer
        Do
            DoEvents
        Loop Until Timer > startTime + 5
    
        'check if user picked a new worksheet
        If ActiveSheet.Name = shtName Then
            MsgBox "You didn't select a new worksheet!"
        Else
            MsgBox "Thanks for selecting a new worksheet!"
        End If
    End If
    

    这有点做作,但可以工作,特别是如果进行适当的检查以确保您现在拥有正确的工作表。

  3. 我想您可以创建一个工作表事件过程,该过程将在激活工作表时运行,并检查全局变量以查看您的“导入过程”是否正在运行,如果是,请恢复您的代码......但这会很混乱而且令人困惑,并且需要代码存在于您“导入”的工作簿中。

  4. 或者,比其中任何一个更好的是根据工作表的内容以编程/逻辑方式确定您需要哪个工作表。有标题吗?某个日期?也许是最新的工作表?某个牢房里有什么东西?必须有一些东西可以将它与其他东西区分开来。

希望这能给您一些关于非线性解决方案的想法。


推荐阅读