将工作簿声明为全局variables

我开始编写一个代码,可以适用于多个工作簿,但始终使用相同的参考工作簿。 代码将有许多潜艇,因为我试图避免变暗参数工作簿中的每个子我想声明他们全球。

首先我有:

Global Locations As Excel.Workbook Set Locations = Workbooks.Open("M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx") 

哪给了我:

“编译错误:外部程序无效”

一些谷歌search后,我发现了以下代码的地方:

 Public Const Locations As Excel.Workbook = "Workbooks.Open("M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx")" 

哪给了我:

“编译错误:预期:types名称”


编辑:

使用:

 Public Const Locations As Excel.Workbook = "Workbooks.Open('M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx')" 

(Workbooks.Open语句内的单引号)导致与使用双引号相同的错误。

谁知道我在做什么错?

EDIT2:

我也尝试在“ThisWorkbook”中声明variables,使用下面的答案 :

 Private Sub Workbook_Open() Dim Locations As Excel.Workbook Dim MergeBook As Excel.Workbook Dim TotalRowsMerged As String Locations = Workbooks.Open("M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx") MergeBook = Workbooks.Open("M:\My Documents\MSC Thesis\Italy\Merged\DURUM IT yields merged.xlsm") TotalRowsMerged = MergeBook.Worksheets("Sheet1").UsedRange.Rows.Count End Sub 

但是,它会返回一个

“所需对象”

在我的模块内。

EDIT3:

我现在有这个工作,但有不得不复制SET行到每个小组的缺点,必须有一个更好的方法来做到这一点?

 Global Locations As Workbook Global MergeBook As Workbook Global TotalRowsMerged As String Sub Fill_CZ_Array() Set Locations = Application.Workbooks("locXws.xlsx") Set MergeBook = Application.Workbooks("DURUM IT yields merged.xlsm") TotalRowsMerged = MergeBook.Worksheets("Sheet1").UsedRange.Rows.Count 

我认为工作簿全局variables最普遍的方式是创build一个Public Property Get过程的模块。 您可以参考它,而不必先调用任何代码,并且不必担心文件是否打开。

以下是其中一个variables的示例模块代码:

 Private wLocations As Workbook Public Property Get Locations() As Workbook Const sPath As String = "M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx" Dim sFile As String If wLocations Is Nothing Then 'extract file name from full path sFile = Dir(sPath) On Error Resume Next 'check if the file is already open Set wLocations = Workbooks(sFile) If wLocations Is Nothing Then Set wLocations = Workbooks.Open(sPath) End If On Error GoTo 0 End If Set Locations = wLocations End Property 

您可以在代码中的任何地方将其用作全局variables:

 Sub Test() Debug.Print Locations.Worksheets.Count End Sub 

你的问题意味着你想要一个全局工作簿常量 ,而不是一个variables。 由于VBA不允许在过程之外初始化对象,所以不能有一个对象常量。 你可以做的最好的事情是在事件中初始化一个公共工作簿variables。


您可以声明一个全局variables,但不能执行代码以在过程之外分配一个值:

 Public myBook As Excel.Workbook Sub AssignWorkbook() Set myBook = Workbooks.Open("C:\SomeBook.xlsx") '// <~~ valid, inside sub End Sub Sub TestItWorked() MsgBox myBook.Name End Sub 

所以在一个正常的模块中你可以有:

 Public myBook As Excel.Workbook 

在你的Workbook_Open()事件中:

 Private Sub Workbook_Open() Set myBook = Workbooks.Open("C:\SomeOtherBook.xlsx") End Sub 

然后,您可以在代码中的其他地方使用myBook ,而无需重新分配它。

在这里可以看看Chip Pearson关于VBAvariables的文章

你想要的是某种具有静态属性的工厂,例如在一个单独的模块中

mFactoryWkbs

 Private m_WkbLocations As Workbook Private m_WkbMergeBook As Workbook Public Property Get LOCATIONS() As Workbook If m_WkbLocations Is Nothing Then Set m_WkbLocations= Workbooks.Open("wherever") End If Set LOCATIONS = m_WkbLocations End Property Public Property Get MERGEBOOK () As Workbook If m_WkbMergeBook Is Nothing Then Set m_WkbMergeBook = Workbooks.Open("wherever") End If Set MERGEBOOK = m_WkbMergeBook End Property 

要使用,只需在需要的地方调用属性,不需要额外的variables(或设置它们)。

 TotalRowsMerged = MERGEBOOK.Worksheets("Sheet1").UsedRange.Rows.Count 

每当我遇到这个,我宣布wb作为一个公共常量string:

 public wb as string = "c:\location" 

那么,在整个项目代码中,你可以参考

 workbooks(wb).anything 

这是迄今为止我能想到的最好的。 结果是现在只有一个地方可以改变文件名,但是我仍然需要在每个子程序中复制SET函数。 不完全理想,但更好,然后什么也没有。

 Public Const DESTBOOK = "DURUM IT yields merged.xlsm" Global Locations As Workbook Global MergeBook As Workbook Global TotalRowsMerged As String Sub Fill_CZ_Array() Set Locations = Application.Workbooks("locXws.xlsx") Set MergeBook = Application.Workbooks(DESTBOOK) TotalRowsMerged = MergeBook.Worksheets("Sheet1").UsedRange.Rows.Count 

您也可以使用类模块来完成此任务,并依靠类初始化程序在模块中使用它时为您完成工作:

称为cLocations的类模块:

 Public Workbook As Workbook Private Sub Class_Initialize() Set Workbook = Workbooks.Open("C:\Temp\temp.xlsx") End Sub 

你喜欢你的模块,或者任何地方的事情:

 Dim Locations As New cLocations Sub dosomething() Locations.Workbook.Sheets(1).Cells(1, 1).Value = "Hello World" End Sub 

然后,您可以使用Locations.Workbook来引用位置工作簿,并使用ThisWorkbook来引用代码运行的工作簿,并使用ActiveWorkbook引用具有焦点的工作簿。 这样,您可以从一个工作簿( ThisWorkbook )运行代码,使用位置工作簿( Locations.Workbook )作为参考,并遍历其他工作簿( ActiveWorkbook )以添加另一个自动化级别。

如果单步执行代码,则会看到类只在您点击需要的代码行时才初始化,而不是在加载工作簿时进行初始化。

我必须补充一点,在这种情况下,我认为如果你给我们一个更大的想法,我们可能会给你一个更好的问题的解决scheme,而不是你在编码时遇到的问题。

您还可以更进一步,抽象到应用程序级别,隐藏位置工作簿,甚至为已命名工作表提供智能感知,如果您明确知道其位置或名称:

class级模块:

 Private App As Application Public Workbook As Workbook Public NamedSheet As Worksheet Private Sub Class_Initialize() Set App = New Application App.Visible = False App.DisplayAlerts = False Set Workbook = App.Workbooks.Open("C:\Temp\temp.xlsx") 'maybe open read only too? Set NamedSheet = Workbook.Sheets("SomethingIKnowTheNameOfExplicitly") End Sub Public Sub DoSomeWork() 'ThisWorkbook refers to the one the code is running in, not the one we opened in the initialise ThisWorkbook.Sheets(1).Cells(1, 1).Value = Wb.Sheets(1).Cells(1, 1).Value End Sub Public Function GetSomeInfo() As String GetSomeInfo = NamedSheet.Range("RangeIKnowTheNameOfExplicitly") End Function 

然后在你的模块里,第一次使用这个variables时,它会被初始化成一行代码:

 Dim Locations As New cLocations Dim SomeInfo Sub DoSomething() SomeInfo = Locations.GetSomeInfo 'Initialised here, other subs wont re-initialise Locations.Workbook.Sheets(1).Cells(1, 1).Value = _ ThisWorkbook.Sheets(1).Cells(1, 1).Value Locations.NamedSheet.Cells(1,1).Value = "Hello World!" Locations.Workbook.Save End Sub 

此解决scheme只有在您知道将从参考工作簿中使用的所有工作表的编号和名称时才有效。

在您的模块中,为所有工作表声明工作表公共variables,如下所示:

 Public sht1 As Worksheet Public sht2 As Worksheet Public sht3 As Worksheet ... 

在应用程序加载事件中实例化这些公共variables。

 Sub Workbook_Open() Workbooks.Open ("your referenced workbook") 'Instantiate the public variables Set sht1 = Workbooks("Test.xlsm").Sheets("Sheet1") Set sht2 = Workbooks("Test.xlsm").Sheets("Sheet2") Set sht3 = Workbooks("Test.xlsm").Sheets("Sheet3") End Sub 

现在你可以参考这些全球工作表在你的子。

例如:

 Sub test() MsgBox sht1.Range("A1").Value MsgBox sht2.Range("A1").Value MsgBox sht3.Range("A1").Value End Sub 

如果创build了一个模块(如ExcelMod),并且在该模块中有一个公共函数或子例程Initialize(),而另一个称为Terminate(),则可以使用这些例程初始化和终止模块级variables。 例如,我曾经使用过这个:(注意,模块variables是在模块顶部声明的第一个东西。)

 Dim excelApp As Object, wb As Workbook, ws As Worksheet Sub Initialize() Set excelApp = CreateObject("Excel.Application") Set wb = Workbooks.Open("C:\SomeOtherBook.xlsx") End Sub Sub Terminate() Set excelApp = Nothing Set wb = Nothing End Sub 

variables是整个模块的一部分,只能用这些子程序进行初始化和终止。 您可以根据需要将variables传入和传出模块,并在所有这些模块子例程中使用它们,而无需再次设置。 如果您需要在另一个模块中使用,则需要像平常一样将它传递给该模块。

也正如其他人所提到的,您可以使用workbook_Open事件来调用初始化子项来创build对象,并根据需要只设置一次。

这是你以后?

如果我正确理解你的问题,你正在创build一个应用程序级别上的代码,而不是工作簿级别的代码。 在这种情况下,你为什么不创build一个加载项。

加载项中的所有代码都可以在应用程序级别访问所有打开的工作簿。

当我有全局variables需要正确初始化时,我通常会这样做:

在一个通用的代码模块中,input以下代码:

 Public Initialized As Boolean Public Locations As Workbook Sub Initialize() If Initialized Then Exit Sub Const fname As String = "M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx" On Error Resume Next Set Locations = Workbooks(Dir(fname)) On Error GoTo 0 If Locations Is Nothing Then Set Locations = Workbooks.Open(fname) End If Initialized = True End Sub 

然后在工作簿的代码模块中放上:

 Private Sub Workbook_Open() Initialize End Sub 

此外,在任何可能启动代码的“网关”子或函数(例如事件处理程序,UDF等)中,将Initialize (或可能: If Not Initialized Then Initialize )作为第一行。 通常情况下,大多数潜艇不会直接启动,并可以依靠由呼叫者正确设置的Locations 。 如果你需要testing一些不能正确运行的东西,那么你可以直接在立即窗口中直接initialize

您可能需要创build一个加载项,或使用一个类模块来处理属性,…

但是我不确定在常规模块中它会比简单的声明 更干净 ,并且在打开工作簿时调用该过程也可以完成这个任务。

(我一直在使用这种方法很多时候都没有被打扰过)

所以你可以在(专用或不专用)常规模块中使用它

 'Set the path to your files Public Const DESTBOOK = "M:\My Documents\MSC Thesis\Italy\Merged\DURUM IT yields merged.xlsm" Public Const LOCBOOK = "M:\My Documents\MSC Thesis\Italy\Merged\locXws.xlsx" 'Declare all global and public variables Global Locations As Workbook Global MergeBook As Workbook Global TotalRowsMerged As String 'Set all variable (Procedure call from Workbook_Open) Sub Set_All_Global_Variables() Set Locations = Set_Wbk(LOCBOOK) Set MergeBook = Set_Wbk(DESTBOOK) TotalRowsMerged = MergeBook.Worksheets("Sheet1").UsedRange.Rows.Count '... End Sub 'Function to check if the workbook is already open or not Function Set_Wbk(ByVal Wbk_Path As String) As Workbook On Error Resume Next Set Set_Wbk = Workbooks(Dir(Wbk_Path)) On Error GoTo 0 If Set_Wbk Is Nothing Then Set Set_Wbk = Workbooks.Open(Wbk_Path) End If End Function 

调用过程设置ThisWorkbook模块中的所有variables

 Private Sub Workbook_Open() Set_All_Global_Variables End Sub