我正在研究Excel 2010的数据采集前端。
我无法弄清楚将多个局部变量参数传递给Application.OnTime
的语法。
http://markrowlinson.co.uk/articles.php?id=10为单个变量作为参数提供了一个很好的例子,但对于如何将其推断为多个变量的解释我并不清楚。
在传递多个局部变量参数时,是否有人对"
和'
字符的正确嵌套有简明扼要的解释?
编辑:代码示例如下:Application.OnTime Now + TimeSerial(0, 0, 5), "'runScheduledReport """ & iArg1 & "","" & iArg2 & "" "" & iArg3 & "" ""'"
。
我知道我们在字符串中使用双引号作为转义字符,但无法确定传递的字符串的顺序。
答案 0 :(得分:7)
你必须考虑以下限制:
查找附加代码:
Option Explicit
Sub Test()
Dim strTest1 As String
Dim strTest2 As String
strTest1 = "This is test1"
strTest2 = "This is test2"
Application.OnTime Now + TimeSerial(0, 0, 1), "'CallMeOnTime """ & strTest1 & """,""" & strTest2 & "'"
Application.OnTime Now + TimeSerial(0, 0, 1), "'CallMeOnTime " & Chr$(34) & "Test" & Chr$(34) & "," & Chr$(34) & "Test" & Chr$(34) & "'"
Application.OnTime Now + TimeSerial(0, 0, 1), "'CallMeOnTime2'"
End Sub
Public Sub CallMeOnTime(strTest1 As String, strTest2 As String)
MsgBox ("test1: " & strTest1 & " test2:" & strTest2)
End Sub
Public Sub CallMeOnTime2()
MsgBox ("CallMeOnTime2")
End Sub
答案 1 :(得分:1)
只是想添加一个我认为有用的示例,参考this post on MrExcel。
具有多个不同类型参数的Application.OnTime(String和Integer)
Dim testName As String
Dim counter As Integer
...
' String then Integer argument
Application.OnTime Now + TimeValue("00:00:02"), "'TestSub """ & testName & """, " & counter & " '"
' Integer then String argument
Application.OnTime Now + TimeValue("00:00:02"), "'SubTest " & counter & ", """ & testName & """ '"
答案 2 :(得分:1)
Huhlo,
每次需要时,我都会为Application.OnTime
(或Application.Run
,类似)的参数使用棘手的语法。我经常来这里,也几次到达这里引用的其他链接。他们常常把我带到那儿,但几乎不完全。
因此,我花了一些时间为自己做一些可行的示例,以供将来参考,并且我最终也使自己确信我了解正在发生的事情。
所以我要分享我的解决方案,最后我想我可以回答有关.. 简洁地解释/证明语法 ...
的原始问题。出于两个原因,我故意提供非常完整的显式代码行:-
_ 1.如果只需要将其简化为更常用的简化版本,则很容易,反之,从更常见的简化形式到完整的显式形式,则很难。
_ 2.显示完整的显式代码行语法有助于我尝试解释语法,因此在完全回答问题时也需要这样做。
例如,当我们要在已关闭的工作簿中触发宏时,需要使用完整的显式语法来确保打开正确的文件。 (在这种情况下,将打开已关闭的工作簿。如果它具有完整的显式形式,则VBA Application.OnTime
代码行将进行此打开)
我正在使用2个示例文件。如果要尝试演示,则第一个应打开,第二个可以关闭或打开,但第二个应位于同一文件夹中。 (之所以需要将其放在同一文件夹中只是为了简化演示,-我组织了演示宏将在同一文件夹中查找关闭的工作簿。在实践中,如果您完全替换关闭的工作簿,则可以在任何位置此位(包括第一个"
),以及已关闭工作簿的完整路径和文件名
" & ThisWorkbook.Path & "\" & "UverFile.xls
因此,您可以使用以下形式替换最后一点:
C:\Elston\Desktop\MyFolder\UverFile.xls
完整的代码行将具有如下形式:
Application.OnTime Now(), "'C:\Elston\Desktop\MyFolder\UverFile.xls" & "'" & "!'Modul1.MacroUndermacroInUverFile 465, ""25""'"
。
打开工作簿-MainFile.xls:https://app.box.com/s/prqhroiqcb0qccewz5si0h5kslsw5i5h
MainFile.xls中的模块“ Modul1
”
Option Explicit
' Public variable code section
Private Pbic_Arg1 As String
Public Pbic_Arg2 As Double
Sub MainMacro() ' https://stackoverflow.com/questions/31439866/multiple-variable-arguments-to-application-ontime/31464597 http://markrowlinson.co.uk/articles.php?id=10
Rem 1
Debug.Print "Rem 1" & vbCr & vbLf & "This workbook module, single arrgument"
' This workbook module, single argument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.UnderMainMacro 465'": Debug.Print "!'Modul1.UnderMainMacro 465'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.UnderMainMacro ""465""'": Debug.Print "!'Modul1.UnderMainMacro ""465""'"
Application.OnTime Now(), "'Modul1.UnderMainMacro 465'" ' --- more usual simplified form. In this case I nned the extra Modul1. because Sub UnderMainMacro( ) is private
Debug.Print vbCr & vbLf & "UverFile module, single argument"
' UverFile module, single argument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'Modul1.MacroInUverFile 465'": Debug.Print "!'Modul1.MacroInUverFile 465'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'Modul1.MacroInUverFile ""465""'": Debug.Print "!'Modul1.MacroInUverFile ""465""'"
Debug.Print vbCr & vbLf & "Thisworkbook module, multiple arguments"
' Thisworkbook module, multiple arguments
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.UnderUnderMainMacro 465, 25'": Debug.Print "!'Modul1.UnderUnderMainMacro 465, 25'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.UnderUnderMainMacro 465, ""25""'": Debug.Print "!'Modul1.UnderUnderMainMacro 465, ""25""' "
Application.OnTime Now(), "'UnderUnderMainMacro 465, 25 '" ' --- more usual simplified form. I don't even need the extra Modul1. because it is not private
Debug.Print vbCr & vbLf & "UverFile module, multiple argument"
' UverFile module, multiple argument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'Modul1.MacroUnderMacroInUverFile 465, 25'": Debug.Print "!'Modul1.MacroUnderMacroInUverFile 465, 25'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'Modul1.MacroUndermacroInUverFile 465, ""25""'": Debug.Print "!'Modul1.MacroUndermacroInUverFile 465, ""25""'"
Debug.Print vbCr & vbLf & "mess about with argument positions"
' mess about with argument positions
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.UnderUnderMainMacro 465 , ""25"" '": Debug.Print "!'Modul1.UnderUnderMainMacro 465 , ""25"" '"
Debug.Print vbCr & vbLf & "This workbook first worksheet code module, single arrgument"
' This workbook first worksheet code module, single arrgument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWsCodeModule 465'": Debug.Print "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWcCodeModule 465'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWsCodeModule ""465""'": Debug.Print "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWcCodeModule ""465""'"
Debug.Print vbCr & vbLf & "UverFile first worksheet code module, single arrgument"
' UverFile first worksheet code module, single arrgument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModule 465'": Debug.Print "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModule 465'"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModule ""465""'": Debug.Print "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModule ""465""'"
Debug.Print vbCr & vbLf & "This workbook first worksheet code module, multiple arguments"
' This workbook first worksheet code module, multiple arguments
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWsCodeModuleMultipleArguments 465 , ""25"" '": Debug.Print "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWcCodeModuleMultipleArguments 465 , ""25"" '"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWsCodeModuleMultipleArguments ""465"" , 25 '": Debug.Print "!'" & ThisWorkbook.Worksheets.Item(1).CodeName & ".InLisWbFirstWcCodeModuleMultipleArguments ""465"" , 25 '"
Debug.Print vbCr & vbLf & "UverFile first worksheet code module, Multiple arrgument"
' UverFile first worksheet code module, Multiple arrgument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModuleMultipleArguments 465 , ""25"" '": Debug.Print "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModuleMultipleArguments 465 , ""25"" '"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & "UverFile.xls" & "'" & "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModuleMultipleArguments ""465"" , ""25"" '": Debug.Print "!'" & "Tabelle1" & ".InUverFileFirstWsCodeModuleMultipleArguments ""465"" , ""25"" '"
Debug.Print vbCr & vbLf & "Doubles do not have to be in quotes either ' This workbook module, double argument arrgument"
' Doubles do not have to be in quotes either ' This workbook module, double argument arrgument
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck 465.5 , ""25.4"" '": Debug.Print "!'Modul1.DoubleCheck 465.5 , ""25.4"" '"
Rem 2 Variables
Debug.Print vbCr & vbLf & "Rem 2 Variables" & vbCr & vbLf & "'2a) ""Pseudo"" variables use"
'2a) "Pseudo" variables use
Dim Arg1_str465 As String, Arg2_Dbl25 As Double
Let Arg1_str465 = "465.42": Let Arg2_Dbl25 = 25.4
' Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck Arg1_str465 , Arg2_Dbl25 '": Debug.Print "!'Modul1.DoubleCheck Arg1_str465 , Arg2Db_l25 '" ' This code line will not work, that is to say it will not find the varables and take 0 values when VBA later runs the Scheduled macro, Sub DoubleCheck( )
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck """ & Arg1_str465 & """ , """ & Arg2_Dbl25 & """ '": Debug.Print "!'Modul1.DoubleCheck """ & Arg1_str465 & """ , """ & Arg2_Dbl25 & """ '"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck """ & Arg1_str465 & """ , " & Arg2_Dbl25 & " '": Debug.Print "!'Modul1.DoubleCheck """ & Arg1_str465 & """ , " & Arg2_Dbl25 & " '"
Debug.Print vbCr & vbLf & "'2b) Real varable use"
'2b) Real varable use
Let Modul1.Pbic_Arg1 = "465.42": Let Pbic_Arg2 = 25.4
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck Modul1.Pbic_Arg1 , Pbic_Arg2 '": Debug.Print "!'Modul1.DoubleCheck Modul1.Pbic_Arg1 , Pbic_Arg2 '"
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.DoubleCheck Modul1.Pbic_Arg1, Pbic_Arg2'"
'' Debug.Print Pbic_Arg2 '' This gives 999.99 in Debug F8 mode , 25.4 in normal run
Rem 3 ByRef check
Application.OnTime Now(), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.ByRefCheck'"
Application.OnTime Now() + TimeValue("00:00:00"), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.ByRefCheck'"
Application.OnTime Now() + TimeValue("00:00:01"), "'" & ThisWorkbook.Path & "\" & ThisWorkbook.Name & "'" & "!'Modul1.ByRefCheck'"
End Sub
Private Sub UnderMainMacro(ByVal Nmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr
End Sub
Sub UnderUnderMainMacro(ByVal Nmbr As Long, ByVal NuverNmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr & ", Arg2 is " & NuverNmbr
End Sub
Sub DoubleCheck(ByVal DblNmr1 As Double, ByRef DblNmr2 As Double) ' provided the signature line is declared appropriately, all number argument types dont have to be in ""
MsgBox prompt:="Arg1 is " & DblNmr1 & ", Arg2 is " & DblNmr2
Let DblNmr2 = 999.99
End Sub
(上面是运行所有宏的主要模块)
MainFile.xls中的第一个工作表“ Tabelle1
”的工作表类模块
Option Explicit
Sub InLisWbFirstWsCodeModule(ByRef Nmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr
Let Nmbr = 999
End Sub
Sub InLisWbFirstWsCodeModuleMultipleArguments(ByVal Nmbr As Long, ByVal NuverNmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr & ", Arg2 is " & NuverNmbr
End Sub
。
。
已关闭的工作簿-UverFile.xls:https://app.box.com/s/u7r2jw79m8ou70otn7xcxced2qkot4w4
UverFile.xls中的模块“ Modul1
”
Option Explicit
Private Sub MacroInUverFile(ByVal Nmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr
End Sub
Sub MacroUnderMacroInUverFile(ByVal Nmbr As Long, ByVal NuverNmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr & ", Arg2 is " & NuverNmbr
End Sub
UverFile.xls中的第一个工作表“ Tabelle1
”的工作表类模块
Option Explicit
Sub InUverFileFirstWsCodeModule(ByVal Nmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr
End Sub
Sub InUverFileFirstWsCodeModuleMultipleArguments(ByVal Nmbr As Long, ByVal NuverNmbr As Long)
MsgBox prompt:="Arg1 is " & Nmbr & ", Arg2 is " & NuverNmbr
End Sub
。
。
我尝试给出了很多工作示例,我发现这些示例很有用,然后用作模板来修改以完全满足我的需求。
以下是有关工作原理的说明,这使语法更易于理解:
首先嵌套'
通常,这是VBA处理将任何空格都视为文字空间的方式(例如,而不是将其误认为是单独的参数)。您将在代码中看到,正如我在论坛文章中所发布的那样,我在所有代码行中都做了一些夸张的空格,这有助于拆分代码的两个主要部分
LHS,在简化/缩短使用过程中通常会被忽略
和
RHS,其中大多数都是必需的。 (很可能xou只能看到宏名称和参数。额外的模块代码名称使您可以在任何模块中使用宏(无论它们是私有的还是公共的)
为了清楚起见,我在&
之一的任一边上方的代码窗口中有一些夸张的空格,所以我是伪的
"---------LHS-------------" & "---------RHS------------------"
或类似的伪造
"String bit containg full path and file name what you mostly don't use" & "String bit containing the macro name and the arguments like you more typically see"
如果将代码复制并粘贴到VB编辑器代码窗口中,则&
两侧多余的多余空格将消失。但是,如果我要在LHS的路径字符串中添加空格,例如将文件名从UverFile.xls
更改为Uver File.xls
,那么,如预期的那样,发布到VB编辑器代码窗口。这是因为封闭的' '
所做的工作是确保所有内容均按原样提供。
在RHS上,我们还需要完全按照我们给出的方式获取信息。我的主意是,此字符串部分需要从开始检索时存储到缓冲区中,然后在运行计划的宏时由VBA进行伪物理放入。这就是为什么我可以添加一些流氓空格的原因,就像我在名为'弄乱参数位置的代码节中所做的那样,然后在代码行中的一些地方。当您发布到VB代码窗口中时,此修改也不会更改。这有助于我们了解嵌套的" "
可变参数位中的嵌套""
。
这比许多文献所建议的难得多。
只有在参数中提供字符串值时,才真正需要使用这些引号对。在VBA代码行中通常是这种情况,其中的引号引起一个字符串,该字符串指示已给出字符串。 (由于您已经在字符串中,因此每个引号都需要加倍,如要使单个引号出现在最终字符串中一样(如VBA所见),标准的VBA语法也是如此。) 如果您使用的是变量而不是硬编码,那么您将不需要显示的下一个复杂语法(前提是您的变量位于模块顶部的任何子例程之外)。我的意思是,在大多数情况下,通常会看到以下复杂的参数语法比所需的更为复杂
""" & Arg1 & """ , """ & Arg2 & """
在大多数情况下,上面的复杂形式可以简化为下面的这种形式
Arg1 , Arg2
要使用这种简化形式,变量必须在调度Application.OnTime
代码行的宏外部,并且必须在代码模块的顶部,否则,将在要设置的调度宏中稍后由VBA关闭,将不知道从何处获取变量。 (如果变量与调度模块不在同一模块中,则必须将它们声明为Public。最好显式引用它们,例如Module2.Arg1
或Sheet1.Arg1
或ThisWorkbook.Arg1
等)
因此,如果您使用“模块级”变量,则不必真正“复杂”语法。
但是,如果使用那种复杂的语法,它将具有将变量的值放在VBA放入其编写的代码行中的最终参数字符串中的作用,以便稍后运行调度的宏。如果使用该语法,并且您的变量是局部变量(也就是说,它们在调度宏中),则可能会被愚弄,以为您认为自己(即VBA在稍后排定的宏),正在使用变量。
实际上,您正在做的是将值硬编码到字符串中,然后最终由VBA在计划的宏中使用它。我想您可能会说,至少在实际使用中,这是在调度宏中使用变量。但是,我认为了解实际发生的情况有助于了解有时令人生畏的语法从何而来。关键是在这种情况下,您实际上并没有将变量放入参数中。您实际上是在使用调度宏中的变量对参数进行硬编码
在我的演示宏中,我指的是使用调度宏变量作为“伪”变量使用的方式。
此外,Nick P在回答中提出的要点是,在那个非常复杂的参数语法中,每个变量周围的引号中有4个在此处给出了最终需要看到的典型的双重封闭" "
对字符串值附近。如果示例中的变量之一(例如Arg2
)是数字,那么即使使用“技巧”使您看起来好像在调度宏中使用变量,也可以删除加上其中一些引号,尤其是VBA最终给出的引号,将" "
对括起来,将其简化为
""" & Arg1 & """ , " & Arg2 & "
那是尼克P所展示的。
_.____________________
检查宏名称和参数的右侧语法。
在所有编码中,每行Debug.Print
后都有一个Application.OnTime
。这显示的是字符串的实际RHS部分,VBA在运行计划的宏时稍后使用。这样就显示了包含宏名称和参数的部分。这有助于显示我试图传达的要点。
例如,在我称为“伪”变量的字符串中使用的字符串如下所示:
!'Modul1.DoubleCheck "465.42" , "25.4" '
或者,如前所述,如果变量(例如,第二个是数字),那么您也可以使用此
!'Modul1.DoubleCheck "465.42" , 25.4 '
对于我所说的Real变量用法,字符串“ seen”实际上必须使用变量名
!'Modul1.DoubleCheck Modul1.Pbic_Arg1 , Pbic_Arg2 '
只是为了澄清上面的最后一个代码行。计划的子例程为Sub DoubleCheck( )
,我将其放在代码模块中,其代码名为Modul1
在同一代码模块中,还将变量Pbic_Arg1
和Pbic_Arg2
的声明放置在模块的顶部。 Pbic_Arg1
是私人的,Pbic_Arg2
是公共的
如果您在步骤(F8)模式下尝试从VB编辑器运行我的编码,而您又打开了“即时窗口”,那么我认为这将有助于使所有内容变得清晰
摘要
最终,使语法正确并理解它的关键如下:
您必须对其进行安排,以使VBA“具有”(您可以通过提供的字符串的Debug.Print
进行检查)在右侧具有与手动方式类似的形式在代码行中写入参数以调用带有参数的子例程。
您可以在多个参数和分隔角之间添加一些额外的空格,就像您在典型的VBA调用代码行中手动键入一系列参数时可能会不小心做的那样。大概是VBA稍后,当它完全使用给定的字符串时,它会执行与您实际写入或粘贴此类内容时发生的操作类似的操作,其结果是删除了这些多余的空格。
括起来的' '
的意思是要指示VBA从字面上看完全像您编写的那样。在我的显式代码行中,LHS和RHS都需要它。更典型地,LHS被忽略。
任何使用许多双重或三对"
对的复杂组合都是一种技巧,可让您有效地使用调度Application.OnTime
代码中的调度宏内的变量线。
如果变量位于任何子例程之外的代码模块中,则将大大简化变量语法。在这种情况下,即使变量类型是字符串,您实际上也不需要在主字符串中使用任何引号。
(Application.OnTime
的完整第二个参数(与计划的宏及其参数有关)始终需要用引号对括起来。这就是Application.OnTime
的编写方式。 (这非常有用,因为您可以使用变量构建字符串,而不是局限于硬编码))
艾伦
参考
https://www.mrexcel.com/board/threads/calling-a-procedure-with-parameters.81724/#post398494
http://markrowlinson.co.uk/articles.php?id=10
P.S。
@ Holger Leichsenring-您好。我认为撇号必须将宏名称和参数括起来。任何数字类型都可以不带引号而传递。您要调用的宏可以驻留在任何模块中,在任何工作簿中(打开或关闭),并且不必为Public。 (我的天赋是Application.OnTime
使用与Application.Run
相同的接线,这比简单地调用sub更具优势,它将同时运行Public和Private subs(Difference between Calling a Sub and Application.Run)) / p>
格伦·艾伦