Déclarer un classeur comme variable globale

je commence à écrire un code qui sera applicable à plusieurs classeurs, mais utilise toujours la même référence classeur. Le code aura beaucoup de sous-ensembles, et comme j'essaie d'éviter de limer une variable au classeur de référence dans chaque sous-ensemble, je voudrais les déclarer globaux.

j'ai d'Abord eu:

Global Locations As Excel.Workbook
Set Locations = Workbooks.Open("M:My DocumentsMSC ThesisItalyMergedlocXws.xlsx")

qui m'a donné:

"erreur de Compilation: non Valide en dehors de la procédure"

après quelques googling j'ai trouvé le suite de bits de code quelque part:

Public Const Locations As Excel.Workbook = "Workbooks.Open("M:My DocumentsMSC ThesisItalyMergedlocXws.xlsx")"

qui m'a donné:

"erreur de Compilation: Prévu: nom du type"


Edit:

Utilisation:

Public Const Locations As Excel.Workbook = "Workbooks.Open('M:My DocumentsMSC ThesisItalyMergedlocXws.xlsx')"

(guillemets Simples dans les Classeurs.Open) résultats que la même erreur que lors de l'utilisation de guillemets doubles.

Qui sait ce que je fais de mal?

Edit2:

j'ai aussi essayé de déclarer la variables dans le "ThisWorkbook", suivant cette réponse utilisation:

Private Sub Workbook_Open()
Dim Locations As Excel.Workbook
Dim MergeBook As Excel.Workbook
Dim TotalRowsMerged As String


Locations = Workbooks.Open("M:My DocumentsMSC ThesisItalyMergedlocXws.xlsx")
MergeBook = Workbooks.Open("M:My DocumentsMSC ThesisItalyMergedDURUM IT yields merged.xlsm")
TotalRowsMerged = MergeBook.Worksheets("Sheet1").UsedRange.Rows.Count
End Sub

Mais ensuite, il retourne un

"Objet Requis"

dans mon module.

Edit3:

j'ai maintenant ce qui fonctionne, mais a l'inconvénient d'avoir à copier l'ENSEMBLE des lignes dans tous les Sous, il y a une meilleure façon de le faire?

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
17
demandé sur Community 2015-07-21 13:27:27

11 réponses

je pense que la façon la plus universelle pour la variable globale de cahier de travail serait de créer un module avec un Public Property Get procédure. Vous pouvez le consulter sans appeler le premier code, et vous n'avez pas à vous inquiéter si le fichier est ouvert ou pas.

voici le code du module d'échantillonnage pour l'une des 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

Vous pouvez l'utiliser n'importe où dans le code comme une variable globale:

Sub Test()
  Debug.Print Locations.Worksheets.Count
End Sub
20
répondu BrakNicku 2015-09-03 08:55:08

Votre question implique que vous voulez mondiale classeur constante, pas une variable. Parce que VBA ne permet pas que des objets soient initialisés en dehors d'une procédure, vous ne pouvez pas avoir de constante objet. Le meilleur que vous pouvez faire est d'avoir un classeur public variable initialisée à un événement.


Vous pouvez déclarer une variable globale, mais vous ne pouvez pas exécuter de code pour affecter une valeur en dehors d'une procédure:

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

Donc dans un module normal you could have:

Public myBook As Excel.Workbook

Et Workbook_Open() événement:

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

alors vous pouvez utiliser myBook ailleurs dans votre code sans devoir le réattribuer.

Il pourrait être utile d'avoir un coup d'oeil à Puce Pearson article sur la portée des variables en VBA ici

6
répondu Sam 2018-05-08 21:48:18

ce que vous voulez est une sorte d'usine avec des propriétés statiques, par exemple dans un module séparé

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

pour utiliser, il suffit d'appeler la propriété où et quand vous en avez besoin, pas de variables supplémentaires (ou des ensembles pour eux) requis.

TotalRowsMerged = MERGEBOOK.Worksheets("Sheet1").UsedRange.Rows.Count
6
répondu Berryl 2015-09-03 07:10:53

C'est le mieux que je puisse trouver jusqu'à maintenant. Le résultat est qu'il n'y a maintenant qu'un seul endroit pour changer le nom du fichier, cependant j'ai encore besoin de copier la fonction SET dans chaque sous-programme. Pas complètement idéal, mais mieux que rien.

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
4
répondu Luuklag 2015-07-21 12:55:35

Chaque fois que je tombe sur ce, je déclare wb public constante chaîne de caractères:

public wb as string = "c:\location"

puis, tout au long du code dans le projet, vous pouvez vous référer à

workbooks(wb).anything
4
répondu user3476534 2015-09-03 08:57:54

C'est le genre de chose que je fais habituellement quand j'ai des variables globales qui doivent être correctement initialisées:

dans un module de code général, mettez le code suivant:

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

puis dans le module de code du classeur mettre:

Private Sub Workbook_Open()
    Initialize
End Sub

de plus, dans n'importe quelle Sous-Fonction Ou fonction de" passerelle " (par exemple, gestionnaires d'événements, UDFs, etc.) qui pourrait lancer votre code, mettre Initialize (ou peut-être: If Not Initialized Then Initialize) comme première ligne. Généralement, la plupart des sous-marins ne seront pas lancés directement et peuvent compter Locations avoir correctement paramétré par l'appelant. Si vous avez besoin de tester quelque chose qui ne fonctionnera pas correctement si la variable n'est pas définie, alors vous pouvez taper initialize directement dans la Fenêtre exécution.

3
répondu John Coleman 2015-09-02 15:55:43

Vous pouvez aussi le faire avec un module de classe et de s'appuyer sur la classe initialiser à faire le travail pour vous quand il est utilisé dans le module:

module de classe appelé cLocations:

Public Workbook As Workbook

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

Et où vous le souhaitez dans votre module, ou n'importe où ailleurs:

Dim Locations As New cLocations

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

Et puis, vous pouvez simplement utiliser Locations.Workbook pour désigner l'emplacement du classeur, et ThisWorkbook pour consulter le classeur le code s'exécute et ActiveWorkbook pour consulter le classeur qui a concentrer. De cette façon, vous pouvez exécuter votre code à partir d'un classeur (ThisWorkbook), à l'aide du classeur des emplacements (Locations.Workbook) comme référence et itérate par rapport à d'autres classeurs (ActiveWorkbook) pour ajouter un autre niveau d'automatisation.

Si vous parcourez le code, vous verrez que la classe n'est initialisé lorsque vous avez touché une ligne de code qui l'exige, et non pas lorsque le classeur est chargé.

je dois ajouter cependant, dans ce cas, je pense que si vous nous donnez une image un peu plus grande de ce que vous êtes essayer de réaliser nous pourrions être en mesure de vous donner une solution à un meilleur problème que celui que vous avez frappé en codant.

vous pouvez aussi aller plus loin, et abstraire au niveau de l'application, garder le classeur des localisations caché, et même fournir intellisense pour les feuilles nommées si vous connaissez leur position ou leur nom explicitement:

module de classe:

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

Et puis dans votre module, la première fois que vous utilisez la variable sera initialisée en une seule ligne de code:

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
3
répondu 2015-09-02 21:13:00

Cette solution ne fonctionnera que si vous connaissez les numéros et les noms de toutes les feuilles de travail que vous utiliserez à partir du classeur référencé.

dans votre module, déclarez la variable publique de la feuille de travail pour toutes vos feuilles de travail comme suit:

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

instanciez ces variables publiques dans l'événement Application load.

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

vous pouvez maintenant renvoyer ces feuilles de travail globales dans votre sub.

Par exemple:

Sub test()
    MsgBox sht1.Range("A1").Value
    MsgBox sht2.Range("A1").Value
    MsgBox sht3.Range("A1").Value
End Sub
3
répondu ManishChristian 2015-09-03 12:38:42

si vous créez un Module dites ExcelMod et que dans ce Module vous avez une fonction publique ou un sous-programme Initialize() et un autre appelé Terminate() vous pouvez initialiser et terminer les variables de niveau du Module en utilisant ces routines. Par exemple, j'ai utilisé cette avant: (Notez que les variables de module sont la première chose déclarée en haut du module.)

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

Les variables font partie du module entier et ne sont initialisées et terminées qu'avec ces sous-programmes. Vous pouvez passez les variables à l'intérieur et à l'extérieur du module comme vous le souhaitez et utilisez-les dans tous les sous-programmes de ce module sans avoir à les définir à nouveau. Si vous devez utiliser dans un autre module, vous devrez le passer à ce module comme vous le feriez normalement.

comme d'autres l'ont mentionné, vous pouvez utiliser l'événement workbook_Open pour appeler la sous-fonction d'initialisation pour créer les objets et ne les définir qu'une seule fois si nécessaire.

Est-ce que vous êtes après?

3
répondu Clint Street 2015-09-08 16:51:30

si je comprends bien votre question, vous créez un code qui devrait fonctionner au niveau de l'application et non au niveau du classeur. Dans ce cas, pourquoi ne pas vous créer un complément.

Tout le code à l'intérieur de l'add-on avoir accès à tous les classeurs ouverts au niveau de l'application.

2
répondu cyboashu 2015-08-30 21:23:27

vous pouvez créer un Add-In, ou utiliser un module de classe pour travailler avec les propriétés, ...

Mais je ne suis pas sûr que ça va être que nettoyeur qu'un simple déclaration dans un module normal et un appel à cette procédure au classeur est ouvert va faire le truc juste trop belle .

(j'ai été en utilisant cette méthode pour un certain temps et n'ai pas été dérangé)

alors vous pouvez l'utiliser dans un (dédié ou non) module:

'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

Et appeler la procédure définissant toutes les variables dans le module ThisWorkbook:

Private Sub Workbook_Open()
    Set_All_Global_Variables
End Sub
1
répondu R3uK 2015-09-03 08:19:35