vba - 在 VBA 中无法从工作簿事件处理程序 Workbook_BeforeClose 或 Workbook_Deactivate() 调用工作表中的子例程

标签 vba events scope event-handling subroutine

我正在制作一个启用 Excel VBA 的工作簿(RES 项目透视图),它有一个主表/工作表(RES 项目工作表),其中每行都有一个超链接打开另一个带有 Sheet1(Project Log)工作簿(0520-077-LACOFD-FJF-log.xlsm),该工作簿也启用了 VBA。 当填写 workbook(..log.xlsm) 和 Sheet1(项目日志) 辅助表时,我希望在主表中更新其中一些更改< strong>(RES 项目表)。

更新子例程UpdateMainProjectTable位于Sheet1(项目日志)中。从 Worksheet_changed 事件调用时它可以工作,但是当我尝试从工作簿事件 Workbook_BeforeClose(Cancel As Boolean)Workbook_Deactivate() 调用更新子例程时,我得到了编译错误“子或函数未定义”。 考虑到这是一个范围错误,我还尝试命名子例程 Sheet1.UpdateMainProjectTable,但随后我收到“运行时错误 1004 应用程序定义或对象定义错误”。

下面是工作簿中使用的事件处理程序的四个示例。我尝试了每一个,但在尝试调用 UpdateMainProjectTable 时,它们都产生了错误。前两篇只是放在一起仅供引用。我还附上了项目结构和错误的图片以供引用。

下面的两个子例程都在Workbook中,所以我在Sheet1前面加上前缀。当他们尝试调用 Sheet1.UpdateMainProjectTable 时,我收到“运行时错误 1004 应用程序定义或对象定义错误”。

Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Me.Saved = False Then Me.Save
Application.EnableEvents = False
Sheet1.UpdateMainProjectTable
Application.EnableEvents = True
End Sub


Private Sub Workbook_Deactivate()
Application.EnableEvents = False
Sheet1.UpdateMainProjectTable
Application.EnableEvents = True
End Sub 

下面的两个子例程在练习册中,我没有给子例程添加前缀。当他们尝试调用 UpdateMainProjectTable 时,我收到了编译错误“子或函数未定义”。

Private Sub Workbook_Deactivate()    
 Application.EnableEvents = False
UpdateMainProjectTable
Application.EnableEvents = True    
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
 If Me.Saved = False Then Me.Save
 Application.EnableEvents = False
UpdateMainProjectTable
Application.EnableEvents = True    
End Sub

根据答案的建议,我尝试了这个。

Private Sub Workbook_BeforeClose(Cancel As Boolean)
If Me.Saved = False Then Me.Save
Application.EnableEvents = False
With Sheet1
Call UpdateMainProjectTable
End With
Application.EnableEvents = True
End Sub 

但我收到“编译错误子或函数未定义”。 下面是我在 Sheet1(项目日志)中的子例程,它被声明为公共(public)

Public Sub UpdateMainProjectTable()    'This is the Main function to update the main table when the log is updated
                                'it open's the RES Project table if not open and

Dim fileName As String
Dim projId As String
Dim logEntry As String
Dim waitingNotCleared As Boolean
Dim rowWithMatch As Integer
Dim wbOpenOnEntry As Boolean
Dim wb As Workbook

'gets Projectlog filename--  this filename
fileName = ActiveWorkbook.Name

'check if RES Project Perspective.xlsm is open.  If not then open and close later at end of sub
wbOpenOnEntry = CheckIfWBOpen("RES Project Perspective.xlsm")
        If wbOpenOnEntry = False Then
            Set wb = Workbooks.Open(ActiveWorkbook.Path & "/../../RES Project Perspective.xlsm")
        End If

'uses filename to determine projid
projId = ExtractProjectIDFromFilename(fileName)
Debug.Print "projId = ExtractProjectIDFromFilename(fileName)   " & projId
'rowWithMatch = FindRowWithProjIDMatch(projId)
rowWithMatch = GetMatchRowNumber(projId)
Debug.Print "rowWithMatch = GetMatchRowNumber(projId)  " & rowWithMatch
MakeLogEntry (rowWithMatch)

'check if RES Project Perspective.xlsm is open.  If not then open and close later at end of sub
        If wbOpenOnEntry = False Then
            wb.Close savechanges:=True
        End If
End Sub

我希望这有帮助!

enter image description here

enter image description here

最佳答案

为了从工作表模块调用Sub/Function它不能是Private并且您必须显式调用它。

Sheet1.UpdateMainProjectTable 

如果您的程序不是 Private 并且存在于 Sheet1 中,则问题应该出现在被调用的 Sub 内部(我认为可能性较小) .

我觉得还需要强调一下,Sheet1 不是工作表名称!它是工作表模块名称。我的意思是,当在 VBE 中查看工作表模块时,您可以看到类似这样的内容:Sheet1(您的工作表名称)。如果 Sheet1 是括号之间的名称,则将是错误的...除非两者相同。

已编辑:我(现在)可以看到你的子。讨论 Workbook_Deactivate 事件调用:

fileName = ActiveWorkbook.Name 的意义不同,因为停用后,另一个工作簿处于事件状态。因此,请尝试使用 fileName = ThisWorkbook.Name 代替。对 Workbooks.Open(ActiveWorkbook.Path & ...) 执行相同的操作,在 Workbooks.Open(ThisWorkbook.Path & ...) 中对其进行转换。

最好还发布 CheckIfWBOpen 函数代码,或者至少检查其代码中是否不存在类似的内容。

使用错误的工作簿名称(事件工作簿名称)调用

ExtractProjectIDFromFilename。我不知道它的代码中还可能存在哪些其他引用。

由于还有一些其他函数调用(GetMatchRowNumberMakeLogEntry),因此也必须从类似的角度分析这些过程。

现在,我建议您尝试通过以下方式调试此事件中的调用:

  1. 按照建议将ActiveWorkbook更改为ThisWorkbook

  2. 在特定行上放置一个断点,然后按 F8 逐行运行代码,当代码在停用后停止时,查看在哪一行引发错误...

关于vba - 在 VBA 中无法从工作簿事件处理程序 Workbook_BeforeClose 或 Workbook_Deactivate() 调用工作表中的子例程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61799451/

相关文章:

c - C中静态全局变量和非静态全局变量的区别

vba - 检查外部封闭工作簿中是否存在工作表

visual-studio-2008 - 在 Crystal Report 中创建新模板,visual studio 2008

vba - 将多列中的值合并为一列

java - 检测用户何时在 Java 中按下回车键

javascript - 哪些 JavaScript 对象的原型(prototype)中有 addEventlistener?

c - 如何在 C 中引用与全局变量同名的局部变量?

vba - 将电子邮件从 Outlook 发送到 OneNote 的替代方法

c++ - QT:忽略复选框选择的关键事件

java - 用java的final关键字作弊