【问题标题】:Macro "Doesn't Work" From Call on Separate Sheet单独工作表上调用宏“不起作用”
【发布时间】:2020-02-10 18:03:02
【问题描述】:

此宏按预期工作,通过批处理输入表上的按钮:

Sub BatchTriggerOFF()

    Sheets("Batch Input").Unprotect
    Sheets("Batch Input").Range("G3:J3").Value = "Off"
    Sheets("SQL LOGIC").Calculate
    Sheets("Batch Input").Range("A12").Select
    Sheets("Batch Input").Shapes.Range(Array("Group 12")).ZOrder msoSendToBack
    Sheets("Batch Input").Protect

End Sub

但是,当从同一工作簿中的不同工作表调用 BatchTriggerOFF 时,宏既不会更改 Range("G3:J3").Value 也不会更改 Shapes.Range(Array("Group 12")).ZOrder msoSendToBack。没有错误信息。

If Sheets("SQL LOGIC").Range("B1") = "On" Then Call BatchTriggerOFF

我尝试过事先取消对 Batch Input 表的保护,弄乱 Sheets("Batch Input").Activate, Sheets("Batch Input").Select,甚至尝试将 BatchTriggerOFF 一行一行的 VBA 直接粘贴到第二个宏,无济于事。

从第二个宏/工作表调用 BatchTriggerOFF 时似乎没有运行的原因是什么?

【问题讨论】:

  • 如果您使用F8 单步执行会发生什么?
  • 您是在Sheet Module 还是Standard module 工作?这对这个问题很重要。此外,请避免使用 Call,因为它已被弃用;尝试使用Application.Run "macroName", arg1, arg2(使用后期绑定)。
  • 切线相关,CodeName: Sheet1 应该对工作表模块是什么以及如何使用它们有所了解。
  • 另外,当我尝试Call SomeInaccessibleProcedure 时,我得到“编译错误:子或函数未定义” - 我挑战“没有错误消息”的前提:如果程序不在范围内,则代码无法编译。如果该过程在范围内,则调用该过程。我们需要更多细节。请回答@Cyril 的问题。
  • @Cyril,如果我理解正确,我相信我在标准模块中,因为所有宏都在 Modules 文件夹下。那是对的吗?另外,您对 Call 的评论是说它不适用于所有版本的 Excel 或其他版本吗?

标签: excel vba


【解决方案1】:

[...] 我提供的第二个代码本身就有问题,当 Range("B1") 中的值发生更改时,可能不会主动运行?

没错。标准模块中的过程需要某处来调用它。可以是工作表上的形状或按钮,也可以是其他 VBA 代码,但 something 需要以某种方式调用它。

Range("B1")Sheets("SQL LOGIC") 上发生更改时,任何程序都不会只知道运行:您需要在该工作表上更改单元格时“触发”代码。

这样做的方法是处理工作表模块的Change 事件。在 VBE 的 Project Explorer (Ctrl+R) 中找到您的“SQL LOGIC”表,双击它。在该特定工作表的代码隐藏模块中,从代码窗格顶部的左侧下拉列表中选择 Worksheet;右侧的下拉菜单应该是 SelectionChange,并且 VBE 应该添加了一个如下所示的私有过程:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

End Sub

从右侧下拉菜单中选择Change; VBE 创建一个如下所示的私有过程:

Private Sub Worksheet_Change(ByVal Target As Range)

End Sub

现在删除SelectionChange 处理程序,您不需要它,除非您需要跟踪用户选择的单元格。由于我们要跟踪已更改的单元格,我们将使用Change 工作表事件。每当用户或您的代码更改该工作表上的任何内容时,都会调用此过程。

由于我们只关心在更改特定单元格时运行代码,因此我们需要一个条件,涉及Target 参数。使用Application.Intersect 函数,如果两个指定范围不相交,我们可以获得Range 对象引用,即Nothing;如果不是 B1 发生了变化,我们可以使用这些信息来解决问题:

If Application.Intersect(Me.Range("B1"), Target) Is Nothing Then Exit Sub

Worksheet.Change 事件处理程序过程中,在该条件之后编写的任何代码,只会在单元格 B1 的值被修改后运行 - 无论是用户键入一个值,还是写入该单元格的任何其他代码(您如果您必须阻止在代码进行更改并且您不希望处理程序运行时触发该事件,则需要关闭 Application.EnableEvents

现在,单元格 B1 似乎不会更改,而是包含一个公式,其结果可能会在更改“批量输入”表后发生更改。 p>

如果是这种情况,那么Change 事件将不会在B1 重新计算并且现在评估为新值时触发,因为单元格没有更改,只有它的结果。

如果这是您的场景,那么您希望处理 Calculate 工作表事件,并让 成为您的触发器:

Private Sub Worksheet_Calculate()
    If Me.Range("B1").Value = "On" Then BatchTriggerOFF
End Sub

【讨论】:

  • 非常感谢您!按照您的指示,我能够使其按要求工作。我打算在不久的将来上一堂课什么的,并且擅长通过参考其他项目的 VBA 来拼凑我需要的东西,但我仍然是一个初学者。我非常感谢你清楚地解释了我做错了什么以及如何纠正它。
【解决方案2】:

如果您需要从任何(工作表)模块调用您的子程序,请将其移动到模块中!如果不指定其所属的模块名称,则无法调用工作表模块中的函数/子,就像您可以在模块中执行的操作一样。

【讨论】:

  • FWIW“工作表模块中的函数/子是私有的,即使你没有以这种方式定义它们”是虚假信息。
  • @Mathieu Guindon:你是对的......我只是想说该函数不能像公共函数一样调用,但我这样做的方式是错误的。我会更正答案。
猜你喜欢
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多