首页 > 解决方案 > 在 VBA 中,无法从工作簿事件处理程序 Workbook_BeforeClose 或 Workbook_Deactivate() 调用工作表中的子例程

问题描述

我正在制作一个启用 Excel VBA 的工作簿(RES Project Perspective)有一个主表/工作表(RES Project Sheet),每行都有一个超链接可以打开另一个工作簿(0520-077-LACOFD-FJF-log.xlsm)使用同样启用了 VBA的Sheet1(项目日志) 。workbook(..log.xlsm ) 和Sheet1(Project Log)填写辅助表时,我希望在主表(RES Project Sheet)中更新其中的一些更改。

更新子例程UpdateMainProjectTableSheet1(Project Log)中。它在从 Worksheet_changed 事件调用时起作用,但是当我尝试从工作簿事件Workbook_BeforeClose(Cancel As Boolean)Workbook_Deactivate()调用更新子例程时,我收到编译错误“未定义子或函数”。确定它是一个范围错误我也尝试命名子例程Sheet1.UpdateMainProjectTable,但后来我得到“运行时错误 1004 应用程序定义或对象定义错误”。

以下是工作簿中使用的四个事件处理程序示例。我尝试了每一个,他们在尝试调用UpdateMainProjectTable时都产生了一个错误。在前两个ex中,他们只是放在一起,以供参考。我还包括了项目结构的图片和参考的错误。

下面的两个子例程都在工作簿中,所以我在 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 

下面的两个子例程都在 Woorkbook 中,我不给子例程加前缀。在他们尝试调用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(Project Log) 中的子程序,它被声明为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

我希望这有帮助!

在此处输入图像描述

在此处输入图像描述

标签: vbaeventsscopeevent-handlingsubroutine

解决方案


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

Sheet1.UpdateMainProjectTable 

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

我觉得有必要还强调一下,Sheet1 不是表名!它是工作表模块名称。我的意思是,在 VBE 中查看您的工作表模块时,您会看到如下内容:Sheet1 (Your sheet name). 如果Sheet1是括号之间的名称,那就错了……除非两者相同。

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

fileName = ActiveWorkbook.Name没有同样的意义,因为停用后,另一个工作簿处于活动状态。因此,请尝试fileName = ThisWorkbook.Name改用。对 做同样的Workbooks.Open(ActiveWorkbook.Path & ...事情,将其转换为Workbooks.Open(ThisWorkbook.Path & ....

最好也发布CheckIfWBOpen功能代码,或者至少检查其代码中是否存在类似的东西。

ExtractProjectIDFromFilename使用错误的工作簿名称(活动工作簿之一)调用。我不知道它的代码中还可能存在哪些其他引用。

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

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

  1. ActiveWorkbook按照ThisWorkbook建议更改;

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


推荐阅读