我会在说明中尽量保持清楚,因此这里什么也没做:
我创建了一个代码,用户在其中选择自己的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张纸,它将运行上面的代码,并且如果有多张纸,让我选择我想要的表,然后运行其余的代码,是否可以编写宏?
答案 0 :(得分:5)
这只是我偶尔使用的基本 暂停 例程的扩展。
这是我的“常规” Pause
例程(使用Timer
function):
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
代码中的关键命令是DoEvents
Function,它“产生执行力,以便操作系统可以处理其他事件。”
DoEvents
将控制权传递给操作系统。在操作系统完成处理其队列中的事件并且已发送SendKeys队列中的所有键之后,将返回控件。
DoEvents
对于简单的事情最为有用,例如允许用户在进程启动后取消进程,例如搜索文件。对于长时间运行的进程,使用计时器或将任务委派给ActiveX
EXE
组件可以更好地完成处理器的生产-操作系统负责多任务处理和time slicing。每次在事件过程中暂时让处理器产生结果时,确保在第一次调用返回之前不会从代码的其他部分再次执行该过程;这可能会导致不可预测的结果。
source上的其他详细信息(和警告)。
一些建议的解决方案:
您可以提示用户来指定哪个工作表,而不是“停止”代码。
您可以“暂停”执行,以简单的计时器循环为用户提供一定的时间来选择工作表,甚至可以检查工作表名称以查看用户是否选择了一个新的文件,如下所示:
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
这有点曲折,但可以使用,尤其是如果进行适当检查以确保您现在拥有正确的工作表。
我想您可以创建一个工作表事件过程,该事件过程将在激活工作表时运行,并检查一个全局变量以查看您的“导入过程” 是否是运行,如果是这样,则继续您的代码...,但这会造成混乱和混乱,并且要求代码在您要“导入”的工作簿中存在。
< / li>或者,优于任何一个将是基于工作表的内容以编程方式/ 逻辑地确定所需的工作表。有标题吗?某个日期?也许最新的工作表?某个单元中有东西吗?必须有一些与众不同的地方。
希望这会为您提出一些非线性解决方案的想法。
答案 1 :(得分:1)
总体而言,我会推荐ashleedawg的解决方案,但如果您 坚持维护您的代码结构,您的代码可以看起来 像这样的东西:
您可以使用.Count
对象(或Sheets
)的Worksheets
属性来区分工作簿具有的工作表数量(如果您不想包括Chart
s),然后使用InputBox
检查要查找的工作表。
MyFile = Application.GetOpenFilename()
Workbooks.Open (MyFile)
If ThisWorkbook.Sheets.Count = 1 Then
ThisWorkbook.ActiveSheet.Copy After:=wbook.Sheets(1)
ThisWorkbook.ActiveSheet.Name = "Selected File"
Else
Dim checkfor As String
checkfor = InputBox("What Sheet should I execute the code for?")
Dim i As Integer
For i = 0 To ThisWorkbook.Sheets.Count
If Trim(LCase(checkfor)) = Trim(LCase(Sheets(i).Name))) Then
ThisWorkbook.Sheets(i).Copy After := wbook.Sheets(1)
ThisWorkbook.Sheets(i).Name = "Selected file"
End If
Next i
End If
Workbooks.Open (MyFile)
ActiveWorkbook.Close SaveChanges:=False
可能需要进一步调整,因为我不确定您到底想要实现什么。