Autor: Max Kaffl (Nepumuk)  --- Aus Excel VBA - Gruppe: Tutorials

Symbolleisten (5) - Im VBA Editor - Absolut heftig!!!

Autor: Max Kaffl (Nepumuk) - Erstellt: --      - Letzte Revision: --Gruppenthema: 5 Folgen 1 2 3 4 5 Sie sind in Folge:5
Im fünften Teil werden sie eine Symbolleiste im VBA - Editor anlegen.

Dieser Code ist erst ab Excel 2000 lauffähig!


Da im Code Ereignisse ausgewertet werden, welche in vorhergehenden Versionen nicht zur Verfügung stehen.

Setzen sie einen Verweis auf „Microsoft Visual Basic for Applications Extensibility 5.3".


Ab Excel XP muss bei "Extras - Makro - Sicherheit - Vertrauenswürdige Quellen - Zugriff auf Visual Basic-Projekt vertrauen" ein Häkchen rein.


Aus der fertigen Mappe werden wir am Ende ein Addin erstellen, welches uns als Editierhilfe im VBA - Editor dient.

Die Buttons in den Symbolleisten des VBA - Editors können keine Makros über die OnAction - Eigenschaft starten. Die Ereignisse müssen in Klassenmodulen auswerten werden. Dazu stehen verschiedene Möglichkeiten zur Auswahl. Eine davon haben sie im dritten Teil schon kennen gelernt, als wir den Ctrl+Shift - Click ausgewertet haben. Neben diesem Click - Ereignis des Buttons, können wir das Change - Ereignis der CommandbarCombobox auswerten. Die Leisten in Editor haben noch eine weitere Eigenschaft, nämlich die CommandBarEvents - Eigenschaft, die das CommandBarEvents - Objekt zurück gibt, welches uns ebenfalls ein Click - Ereignis zur Verfügung stellt. Wir werden diese drei Möglichkeiten verwenden.

Für das Projekt werden folgende Komponenten benötigt:

·
Ein Standardmodul mit wahlfreiem Namen
·
Ein Klassenmodul mit dem Namen clscmbButton
·
Ein Klassenmodul mit dem Namen clscmbEvents
·
Ein Klassenmodul mit dem Namen clsPool
·
Ein Klassenmodul mit dem Namen clscmbDropdown

Kopieren sie die folgenden Routinen zum Erstellen und Löschen der Commandbar in das Standardmodul.

Starten sie das Makro prcCreateCommandBar nicht, bevor alle Codeteilen vollständig sind. Sie würden nur Fehlermeldungen produzieren.

Option Explicit

Private Declare Sub Sleep Lib "kernel32.dll" ( _
 ByVal dwMilliseconds As Long)
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" ( _
 ByVal lpClassName As String, _
 ByVal lpWindowName As String) As Long
Private Declare Function SetTimer Lib "user32.dll" ( _
 ByVal hWnd As Long, _
 ByVal nIDEvent As Long, _
 ByVal uElapse As Long, _
 ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32.dll" ( _
 ByVal hWnd As Long, _
 ByVal nIDEvent As Long) As Long
Private Declare Function SetWindowPos Lib "user32.dll" ( _
 ByVal hWnd As Long, _
 ByVal hWndInsertAfter As Long, _
 ByVal x As Long, _
 ByVal y As Long, _
 ByVal cx As Long, _
 ByVal cy As Long, _
 ByVal wFlags As Long) As Long

Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2

Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOACTIVATE = &H10
Private Const SWP_SHOWWINDOW = &H40

Public Enum Box_Title
 lInfo
 lAdvice
 lError
 lUser
 lExcel
End Enum

Private Const COMMANDBAR_NAME = "Private_VBE_Bar"

Private objPool As clsPool

Public Sub prcCreateCommandBar()
 Dim cmbPopup As CommandBarPopup
 Dim cmbButton As CommandBarButton
 Dim cmbDropdown As CommandBarComboBox
 Dim objButton(1 To 2) As clscmbButton
 Call prcDeleteCommandBar
 Set objPool = New clsPool
 Set objPool.prpcmbBar = Application.VBE.CommandBars.Add(Name:= _
 COMMANDBAR_NAME, Position:=msoBarTop, MenuBar:=False, _
 Temporary:=True)
 Call prcControlAdd(objParent:=objPool.prpcmbBar, _
 varControl:=cmbPopup, enumType:=msoControlPopup, _
 varCaption:="&Kopfzeilen")
 Call prcControlAdd(objParent:=cmbPopup, _
 varControl:=cmbButton, enumType:=msoControlButton, _
 varCaption:="Einf&ügen", varFaceId:=296, _
 enumStyle:=msoButtonIconAndCaption, varTag:="1")
 Set objButton(1) = New clscmbButton
 Set objButton(1).mcmbButton = cmbButton
 objPool.prpcolButtons.Add objButton(1)
 Call prcControlAdd(objParent:=cmbPopup, _
 varControl:=cmbButton, enumType:=msoControlButton, _
 varCaption:="L&öschen", varFaceId:=293, _
 enumStyle:=msoButtonIconAndCaption, varTag:="2")
 Set objButton(2) = New clscmbButton
 Set objButton(2).mcmbButton = cmbButton
 objPool.prpcolButtons.Add objButton(2)
 Call prcControlAdd(objParent:=objPool.prpcmbBar, _
 varControl:=cmbButton, enumType:=msoControlButton, _
 bolBeginGroup:=True, varCaption:="Want", varFaceId:=271, _
 enumStyle:=msoButtonIconAndCaption, _
 varTipText:="Variablennamen merken", _
 enumState:=msoButtonUp, varWidth:=55)
 Set objPool.prpcmbButton = cmbButton
 Set objPool.prpobjEvents = _
 Application.VBE.Events.CommandBarEvents(cmbButton)
 Call prcControlAdd(objParent:=objPool.prpcmbBar, _
 varControl:=cmbDropdown, enumType:=msoControlDropdown, _
 varWidth:=120, varDropDownWidth:=120, varDropDownLines:=12)
 Set objPool.prpobjDropdown = cmbDropdown
 Call prcAddItems(False)
 objPool.prpcmbBar.Visible = True
 Set cmbPopup = Nothing
 Set cmbButton = Nothing
 Set cmbDropdown = Nothing
End Sub

Public Sub prcDeleteCommandBar()
 Dim cmbmyBar As CommandBar
 If Not objPool Is Nothing Then
 If Not objPool.prpcmbBar Is Nothing Then _
 objPool.prpcmbBar.Delete
 Else
 For Each cmbmyBar In Application.VBE.CommandBars
 If cmbmyBar.Name = COMMANDBAR_NAME Then _
 cmbmyBar.Delete
 Next
 End If
 Set objPool = Nothing
End Sub

Private Sub prcControlAdd( _
 ByRef objParent As Object, _
 Optional ByRef varControl As Variant, _
 Optional ByVal enumType As MsoControlType, _
 Optional ByVal varId As Variant, _
 Optional ByVal varBefore As Variant, _
 Optional ByVal varTemporary As Variant, _
 Optional ByVal bolBeginGroup As Boolean = False, _
 Optional ByVal varCaption As Variant, _
 Optional ByVal varFaceId As Variant, _
 Optional ByVal varOnAction As Variant, _
 Optional ByVal enumStyle As MsoButtonStyle, _
 Optional ByVal varTipText As Variant, _
 Optional ByVal enumState As MsoButtonState, _
 Optional ByVal varTag As Variant, _
 Optional ByVal enumLinkType As MsoCommandBarButtonHyperlinkType, _
 Optional ByVal bolEnabled As Boolean = True, _
 Optional ByVal bolVisible As Boolean = True, _
 Optional ByVal varWidth As Variant, _
 Optional ByVal varDropDownWidth As Variant, _
 Optional ByVal varDropDownLines As Variant)
 Dim cmbControl As CommandBarControl
 Select Case IIf(enumType, 1, 0) & IIf(IsMissing(varId), 0, 1) & _
 IIf(IsMissing(varBefore), 0, 1) & IIf(IsMissing(varTemporary), 0, 1)
 Case "0100": Set cmbControl = objParent.Controls.Add(ID:=varId)
 Case "0101": Set cmbControl = objParent.Controls.Add(ID:=varId, _
 Temporary:=varTemporary)
 Case "0110": Set cmbControl = objParent.Controls.Add(ID:=varId, _
 Before:=varBefore)
 Case "0111": Set cmbControl = objParent.Controls.Add(ID:=varId, _
 Before:=varBefore, Temporary:=varTemporary)
 Case "1000": Set cmbControl = objParent.Controls.Add(Type:=enumType)
 Case "1001": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 Temporary:=varTemporary)
 Case "1010": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 Before:=varBefore)
 Case "1011": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 Before:=varBefore, Temporary:=varTemporary)
 Case "1100": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 ID:=varId)
 Case "1101": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 ID:=varId, Temporary:=varTemporary)
 Case "1110": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 ID:=varId, Before:=varBefore)
 Case "1111": Set cmbControl = objParent.Controls.Add(Type:=enumType, _
 ID:=varId, Before:=varBefore, Temporary:=varTemporary)
 End Select
 With cmbControl
 .BeginGroup = bolBeginGroup
 If Not IsMissing(varCaption) Then .Caption = varCaption
 If Not IsMissing(varFaceId) Then .FaceId = varFaceId
 If Not IsMissing(varOnAction) Then .OnAction = varOnAction
 If enumStyle Then .Style = enumStyle
 If Not IsMissing(varTipText) Then .TooltipText = varTipText
 If enumState Then .State = enumState
 If Not IsMissing(varTag) Then .Tag = varTag
 If enumLinkType Then .HyperlinkType = enumLinkType
 .Enabled = bolEnabled
 .Visible = bolVisible
 If Not IsMissing(varWidth) Then .Width = varWidth
 If Not IsMissing(varDropDownWidth) Then _
 .DropDownWidth = varDropDownWidth
 If Not IsMissing(varDropDownLines) Then _
 .DropDownLines = varDropDownLines
 End With
 If Not IsMissing(varControl) Then Set varControl = cmbControl
 Set cmbControl = Nothing
End Sub

Private Sub prcAddItems(ByVal bolAll As Boolean)
 Dim varArray As Variant, varItem As Variant
 If bolAll Then
 varArray = Array( _
 "For - Next", _
 "For - Each", _
 "Do - Loop", _
 "While - Wend")
 Else
 varArray = Array( _
 "Do - Loop", _
 "While - Wend")
 End If
 With objPool.prpobjDropdown
 .Clear
 For Each varItem In varArray
 .AddItem varItem
 Next
 End With
End Sub

Sie werden als erstes wieder ein paar API - Aufrufe bemerken, welche später erklärt werden. Das erstellen der Commandbar und bestücken mit Steuerelenenten ist nun schon Routine und muss nicht näher erläutert werden. Auch das Verweisen an Klassen ist ihnen sicher geläufig.

Natürlich habe ich mir auch dieses mal ein paar Beispielroutinen entwickelt, aber wir wollen uns erst die Klassenmodule ansehen.

Das erste leitet aufgrund der Tag - Eigenschaft der Buttons das Click - Ereignis von zwei Buttons an zwei unterschiedliche Routinen. Die beiden Buttons werden über ein Collection - Objekt an die Klasse übergeben.

Fügen sie diesen Code in das Klassenmodul mit dem Namen "clscmbButton" ein.

Option Explicit

Public WithEvents mcmbButton As CommandBarButton

Private Sub Class_Terminate()
 Set mcmbButton = Nothing
End Sub

Private Sub mcmbButton_Click(ByVal Ctrl As CommandBarButton, _
 CancelDefault As Boolean)
 Select Case mcmbButton.Tag
 Case "1": Call prcInsertHeadLines
 Case "2": Call prcDeleteHeadLines
 End Select
End Sub

Der dritte Button löst das Events - Ereignis des VBE - CommandBar - Objektes aus und wird mit folgender Anweisung an die Klasse übergeben.

Set objEvents.prpBarEvents = Application.VBE.Events.CommandBarEvents(cmbButton)

Sie sehen, dass sich die Click - Ereignisse unterscheiden. Das erste bekommt einen Commandbarbutton das andere ein Commandbarcontrol als Objekt übergeben. Das heißt, es lassen sich auf diese weise allen Controls der VBE - Commandbars ein Click - Ereignis zuordnen.

Natürlich ließe sich der dritte Button auch über das Click - Ereignis des Commandbarbuttons steuern, aber ich wollte ihnen diese Möglichkeit auch vorstellen. Sie steht übrigens schon in Excel97 zur Verfügung.

Fügen sie diesen Code in das Klassenmodul mit dem Namen "clscmbEvents" ein.

Option Explicit

Private WithEvents mobjEvents As CommandBarEvents

Private Sub Class_Terminate()
 Set mobjEvents = Nothing
End Sub

Private Sub mobjEvents_Click(ByVal CommandBarControl As Object, _
 Handled As Boolean, CancelDefault As Boolean)
 Call prcTryToSaveVariable
End Sub

Friend Property Set prpBarEvents(ByVal objEvents As CommandBarEvents)
 Set mobjEvents = objEvents
End Property

Weil wir beim dritten Button verschiedene Eigenschaften durch einen Klick ändern, wurde der Button an eine eigene Klasse verwiesen.

Wir könnten das Objekt auch über Application.VBE.CommandBars(COMMANDBAR_NAME).Cotrols(2) ansprechen. Wenn sie sich aber nun entschließen, vor diesem Button noch ein anderes Control einzufügen, müssen sie im kompletten Code alle diese Objektverweise ändern. Bei der Benutzung eines Klassenmoduls, kann uns die Position des Buttons gleichgültig sein, da wir Projektweit garantiert das richtige Objekt ansprechen.

In der Klasse verwalten wir alle Variablen und Objekte, die wir sonst auf Modul- oder Projektebene hätten deklarieren müssen. Dadurch kommen wir mit einer einzigen öffentlichen Variablen aus.

Fügen sie diesen Code in das Klassenmodul mit dem Namen " clsPool" ein.

Option Explicit

Private mcmbBar As CommandBar
Private mcmbButton As CommandBarButton
Private mcolButtons As Collection
Private menumTitle As Box_Title
Private mstrVariable As String
Private mobjEvents As clscmbEvents
Private mobjDropdown As clscmbDropdown

Private Sub Class_Initialize()
 Set mcolButtons = New Collection
 Set mobjEvents = New clscmbEvents
 Set mobjDropdown = New clscmbDropdown
End Sub

Private Sub Class_Terminate()
 Set mcolButtons = Nothing
 Set mcmbBar = Nothing
 Set mcmbButton = Nothing
 Set mobjEvents = Nothing
 Set mobjDropdown = Nothing
End Sub

Public Property Get prpcmbBar() As CommandBar
 Set prpcmbBar = mcmbBar
End Property

Public Property Set prpcmbBar(ByVal cmbBar As CommandBar)
 Set mcmbBar = cmbBar
End Property

Public Property Get prpcmbButton() As CommandBarButton
 Set prpcmbButton = mcmbButton
End Property

Public Property Set prpcmbButton(ByVal cmbButton As CommandBarButton)
 Set mcmbButton = cmbButton
End Property

Public Property Get prpcolButtons() As Collection
 Set prpcolButtons = mcolButtons
End Property

Public Property Get prpenumTitle() As Box_Title
 prpenumTitle = menumTitle
End Property

Public Property Let prpenumTitle(ByVal enumTitle As Box_Title)
 menumTitle = enumTitle
End Property

Public Property Get prpstrVariable() As String
 prpstrVariable = mstrVariable
End Property

Public Property Let prpstrVariable(ByVal strVariable As String)
 mstrVariable = strVariable
End Property

Public Property Set prpobjEvents(ByVal objEvents As CommandBarEvents)
 Set mobjEvents.prpBarEvents = objEvents
End Property

Public Property Get prpobjDropdown() As CommandBarComboBox
 Set prpobjDropdown = mobjDropdown.prpDropdown
End Property

Public Property Set prpobjDropdown(ByVal objDropdown As CommandBarComboBox)
 Set mobjDropdown.prpDropdown = objDropdown
End Property

Das Ereignis des DropDowns ist das Change - Ereignis, welches wir im vierten Klassenmodul auswerten. Dieses ist nicht vergleichbar mit dem Change - Ereignis einer Combobox. Das Change - Ereignis einer Combobox wird nur bei einer tatsächlichen Änderung seiner Value - Eigenschaft ausgelöst. Die CommandbarCombobox reagiert schon auf das auf- und zuklappen der Datenliste. Kommt also dem Click - Ereignis eines Buttons näher. Darum auch die Abfrage, ob überhaupt ein Wert ausgewählt wurde.

Fügen sie diesen Code in das Klassenmodul mit dem Namen "clscmbDropdown" ein.

Option Explicit

Private WithEvents mcmbDropdown As CommandBarComboBox

Private Sub Class_Terminate()
 Set mcmbDropdown = Nothing
End Sub

Private Sub mcmbDropdown_Change(ByVal Ctrl As CommandBarComboBox)
 If Ctrl.Text <> "" Then Call prcTryToAddCode(Ctrl.Text)
End Sub

Friend Property Get prpDropdown() As CommandBarComboBox
 Set prpDropdown = mcmbDropdown
End Property

Friend Property Set prpDropdown(ByVal cmbDropdown As CommandBarComboBox)
 Set mcmbDropdown = cmbDropdown
End Property

Nun zu den Makros, die durch unsere Controls ausgelöst werden. Diese kommen zu der Erstellprozedur der Commandbar in das Standardmodul.

Da wir uns im Editor bewegen, haben wir es mit einem ganz neuen Objekt, nämlich dem VBE - Objekt zu tun, welches eine Eigenschaft des Application - Objektes ist. Es werden ihnen ungewohnte Eigenschaften und Methoden begegnen. Nähere Erläuterungen zu diesem Objekt finden sie in ihrer VBA - Hilfe, wenn sie VBE als Suchbegriff eingeben.

Das erste fügt unterhalb der Option - Anweisungen einen Informationsblock in das aktive Modul ein.

Das zweite Makro löscht diesen Kopf wieder. Damit dieses die Kopfzeilen von anderen Kommentaren unterscheiden kann, setzen wir beim erstellen, zwischen das Hochkomma und das erste sichtbare Zeichen, das unsichtbare Ascii - Zeichen 160.

Public Sub prcInsertHeadLines()
 Dim lngOptionLines As Long, lngHeadLine As Long
 Dim varHeadLineArray As Variant
 Dim strHeadLine As String
 varHeadLineArray = Array("", "*", "**", "**", _
 Chr$(169) & " by: " & Application.UserName, "**", _
 "Revision: 1.00.01", "**", _
 "Revision Date: " & CStr(Date), "**", _
 "Description: New Modul", "**", "**", "*", "")
 With Application.VBE.ActiveCodePane.CodeModule
 For lngOptionLines = 1 To 5
 If Left$(Trim$(.Lines(lngOptionLines, 1)), 6) <> "Option" _
 Then Exit For
 Next
 For lngHeadLine = 0 To UBound(varHeadLineArray)
 Select Case varHeadLineArray(lngHeadLine)
 Case "": strHeadLine = ""
 Case "*": strHeadLine = "'" & Chr$(160) & String$(80, "*")
 Case "**": strHeadLine = "'" & Chr$(160) & "**" & _
  String$(76, " ") & "**"
 Case Else: strHeadLine = "'" & Chr$(160) & "**" & _
  String$(8, " ") & varHeadLineArray(lngHeadLine) & _
  String$(68 - Len(varHeadLineArray(lngHeadLine)), " ") & "**"
 End Select
 .InsertLines lngOptionLines + lngHeadLine, strHeadLine
 Next
 End With
End Sub

Public Sub prcDeleteHeadLines()
 Dim lngHeadLine As Long, lngLine As Long
 With Application.VBE.ActiveCodePane.CodeModule
 For lngHeadLine = .CountOfLines To 1 Step -1
 If InStr(1, .Lines(lngHeadLine, 1), Chr$(160)) Then
 .DeleteLines (lngHeadLine)
 If lngLine = 0 Then lngLine = lngHeadLine Else _
  lngLine = lngLine - 1
 End If
 Next
 If lngLine <> 0 Then
 For lngHeadLine = lngLine To .CountOfLines
 If Trim$(.Lines(lngLine, 1)) = "" Then _
  .DeleteLines (lngLine) Else Exit For
 Next
 End If
 End With
End Sub

Das dritte Makro versucht einen markierten Text in eine Variable zu übernehmen, welcher dann als Schleifenzähler in einer For - Next oder For Each - Next Schleife eingesetzt wird. Ist dies erfolgreich, dann bekommt der Button ein anderes Icon, eine andere Caption und zeigt die Variable im Tooltiptext an. War es erfolglos, wird eine MsgBox ausgegeben.

Wenn sie z.B. in einer Deklarationszeile mit einem Doppelklick die Variable "meineVariable" markieren und mit einem Klick auf den Button übernehmen. dann haben die damit generierten Schleifen, folgendes Aussehen:

For meineVariable = 1 To x

Next

For Each meineVariable In x

Next


Public Sub prcTryToSaveVariable()
 Dim lngStartLine As Long, lngStartColumn As Long
 Dim lngEndColumn As Long, lngEndLine As Long
 Dim strTemp As String
 With Application.VBE.ActiveCodePane
 .GetSelection lngStartLine, lngStartColumn, _
 lngEndLine, lngEndColumn
 strTemp = .CodeModule.Lines(lngStartLine, 1)
 strTemp = Mid$( _
 strTemp, lngStartColumn, _
 lngEndColumn - lngStartColumn)
 With objPool
 .prpstrVariable = Trim$(strTemp)
 If .prpstrVariable <> "" And _
 lngStartLine = lngEndLine And _
 InStr(1, .prpstrVariable, " ") = 0 Then
 With .prpcmbButton
  .Caption = " Ok "
  .FaceId = 59
  DoEvents
  Sleep 500
  .Caption = "Have"
  .FaceId = 270
  .State = msoButtonDown
  .TooltipText = objPool.prpstrVariable
 End With
 Call prcAddItems(True)
 Else
 With .prpcmbButton
  .Caption = "Want"
  .FaceId = 271
  .State = msoButtonUp
  .TooltipText = "Variablennamen merken"
 End With
 Call prcAddItems(False)
 Call prcMsgBox(strMsgText:="Keine gültige Markierung gefunden.", _
 enumStyle:=vbExclamation, enumTitle:=lAdvice)
 End If
 End With
 End With
End Sub

Die vierte und fünfte Routine versucht, die aus dem DropDown ausgewählte Schleife, in den Editor einzufügen. Mit der Methode GetSelection wird die aktuelle Position des Cursors ermittelt. Der Code eingefügt und mit der SetSelection - Methode der Cursor neu positioniert.

Public Sub prcTryToAddCode(ByVal strCodeName As String)
 Dim lngStartLine As Long, lngStartColumn As Long, lngDumy As Long
 With Application.VBE.ActiveCodePane
 .GetSelection lngStartLine, lngStartColumn, lngDumy, lngDumy
 With .CodeModule
 If Trim$(.Lines(lngStartLine, 1)) = "" Then
 If .ProcOfLine(lngStartLine, vbext_pk_Proc) <> "" Or _
  .ProcOfLine(lngStartLine, vbext_pk_Let) <> "" Or _
  .ProcOfLine(lngStartLine, vbext_pk_Set) <> "" Or _
  .ProcOfLine(lngStartLine, vbext_pk_Get) <> "" Then
  Call prcAddCode(strCodeName, lngStartLine, _
  lngStartColumn)
  Else
  Call prcMsgBox(strMsgText:= _
  "Nur innerhalb einer Prozedur.", _
  enumStyle:=vbExclamation, enumTitle:=lAdvice)
  End If
 Else
 Call prcMsgBox(strMsgText:="Die Zeile ist nicht leer." & vbLf & _
  vbLf & "Plazieren sie den Cursor an der Einfügemarke.", _
  enumStyle:=vbExclamation, enumTitle:=lAdvice)
 End If
 End With
 End With
End Sub

Private Sub prcAddCode(ByVal strCodeName As String, _
 ByVal lngStartLine As Long, _
 ByVal lngStartColumn As Long)
 With Application.VBE.ActiveCodePane
 Select Case strCodeName
 Case "For - Next"
 .CodeModule.ReplaceLine lngStartLine, _
  String(lngStartColumn - 1, " ") & _
  "For " & objPool.prpstrVariable & " = 1 To x" & vbCrLf & _
  String(lngStartColumn + 3, " ") & vbCrLf & _
  String(lngStartColumn - 1, " ") & "Next"
 .SetSelection lngStartLine, _
  Len(.CodeModule.Lines(lngStartLine, 1)), _
  lngStartLine, Len(.CodeModule.Lines(lngStartLine, 1)) + 1
 Case "For - Each"
 .CodeModule.ReplaceLine lngStartLine, _
  String(lngStartColumn - 1, " ") & _
  "For Each " & objPool.prpstrVariable & " In x" & vbCrLf & _
  String(lngStartColumn + 3, " ") & vbCrLf & _
  String(lngStartColumn - 1, " ") & "Next"
 .SetSelection lngStartLine, _
  Len(.CodeModule.Lines(lngStartLine, 1)), _
  lngStartLine, Len(.CodeModule.Lines(lngStartLine, 1)) + 1
 Case "Do - Loop"
 .CodeModule.ReplaceLine lngStartLine, _
  String(lngStartColumn - 1, " ") & "Do" & vbCrLf & _
  String(lngStartColumn + 3, " ") & vbCrLf & _
  String(lngStartColumn - 1, " ") & "Loop"
 .SetSelection lngStartLine + 1, lngStartColumn + 4, _
  lngStartLine + 1, lngStartColumn + 4
 Case "While - Wend"
 .CodeModule.ReplaceLine lngStartLine, _
  String(lngStartColumn - 1, " ") & "While x" & vbCrLf & _
  String(lngStartColumn + 3, " ") & vbCrLf & _
  String(lngStartColumn - 1, " ") & "Wend"
 .SetSelection lngStartLine, _
  Len(.CodeModule.Lines(lngStartLine, 1)), _
  lngStartLine, Len(.CodeModule.Lines(lngStartLine, 1)) + 1
 End Select
 End With
End Sub

Die folgenden Routinen werden benötigt, um eine MsgBox auszugeben. Wozu der Aufwand? Versuchen sie es einmal mit einem Dreizeiler, der eine MsgBox ausgibt. Starten sie diesen mit F5 aus dem Editor. Sie werden feststellen, dass sie automatisch aus dem Editor zur Tabellenansicht gelangen. Das wollen wir damit vermeiden. Da aber, wenn die Box angezeigt wird, kein Makro mehr läuft, verwenden wir einen Trick. Wir starten vor der MsgBox einen Timer. Dieser beendet sich als erstes sofort wieder. Dann sucht eine weitere Routine mit Hilfe der FindWindow - Funktion nach dem Fenster der Box. Wird es gefunden, dann passiert folgendes. Das Fenster des VBA - Editors wird mit der API - Funktion " SetWindowPos" in den Vordergrund gebracht und anschließend das Fenster der Box vor das, des Editors. Ist doch gar nicht schwer, wenn man weiß wie es geht.

Private Sub prcMsgBox(ByVal strMsgText As String, _
 Optional ByVal enumStyle As VbMsgBoxStyle, _
 Optional ByVal enumTitle As Box_Title = lExcel)
 objPool.prpenumTitle = enumTitle
 SetTimer FindWindow("XLMAIN", Application.Caption), 0, 1, _
 AddressOf prcTimer
 MsgBox Prompt:=strMsgText, Buttons:=enumStyle, _
 Title:=fncBoxTitle
 Call SetWindowPos(Application.VBE.MainWindow.hWnd, _
 HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE _
 Or SWP_NOACTIVATE Or SWP_SHOWWINDOW)
End Sub

Private Sub prcTimer(ByVal hWnd As Long, ByVal nIDEvent As Long, _
 ByVal uElapse As Long, ByVal lpTimerFunc As Long)
 Call prcKillTimer
 Call prcSetWindow
End Sub

Private Sub prcKillTimer()
 KillTimer FindWindow("XLMAIN", Application.Caption), 0
End Sub

Private Sub prcSetWindow() '#32770 default class name for dialog boxes
 Dim lnghWnd As Long
 lnghWnd = FindWindow("#32770", fncBoxTitle)
 If lnghWnd <> 0 Then
 Call SetWindowPos(Application.VBE.MainWindow.hWnd, _
 HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE _
 Or SWP_NOACTIVATE Or SWP_SHOWWINDOW)
 Call SetWindowPos(Application.VBE.MainWindow.hWnd, _
 lnghWnd, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE _
 Or SWP_NOACTIVATE Or SWP_SHOWWINDOW)
 End If
End Sub

Private Function fncBoxTitle() As String
 Select Case objPool.prpenumTitle
 Case lInfo: fncBoxTitle = "Information"
 Case lAdvice: fncBoxTitle = "Hinweis"
 Case lError: fncBoxTitle = "Fehler"
 Case lUser: fncBoxTitle = Application.UserName
 Case lExcel: fncBoxTitle = "Microsoft Excel"
 End Select
End Function

Das letzte Makro dient nur dazu unseren Verweis zu überprüfen und gegebenenfalls neu zu setzen. Die Identifizierung erfolgt dabei über die GUID (Globally Unique Identifier), was uns unabhängig von unterschiedlichen Installationspfaden macht.

Das Makro kann einen von Anfang an fehlenden Verweis nicht setzen, da beim öffnen der Mappe ein Kompilierungsfehler erzeugt wird!!!

Public Sub prcSetReferences()
 Dim intIndex As Integer
 Dim bolfound As Boolean
 With ThisWorkbook.VBProject.References
 For intIndex = 1 To .Count
 If .Item(intIndex).GUID = _
 "{0002E157-0000-0000-C000-000000000046}" Then
 If .Item(intIndex).IsBroken Then _
  .Remove .Item(intIndex) Else _
  bolfound = True: Exit For
 End If
 Next
 If Not bolfound Then .AddFromGuid _
 GUID:="{0002E157-0000-0000-C000-000000000046}", _
 Major:=5, Minor:=3
 End With
End Sub

Schlussendlich nun noch die Ereignisroutinen der Mappe, welche beim öffnen die Commandbar erstellen und beim schließen wieder löschen.

Diese kommen natürlich in das Klassenmodul der Mappe.

Option Explicit

Private Sub Workbook_BeforeClose(Cancel As Boolean)
 Call prcDeleteCommandBar
End Sub

Private Sub Workbook_Open()
 Call prcSetReferences
 Call prcCreateCommandBar
End Sub

Speichern sie die Mappe. Wählen sie im Dialog, in der unteren Combobox, als Dateityp "Microsoft Excel-Add-In (*.xla) [letzter Eintrag in der Liste]. Ob sie ihren Addin - Ordner, welcher als Standardordner angeboten wird, benutzen wollen, bleibt ihnen überlassen. Schließen sie Excel nun und öffnen sie es mit einer leeren Mappe. Wählen sie über den AddIns-Manager das erstellte Addin (eventuell über Durchsuchen). Wechseln sie in den VBA - Editor und testen das Ergebnis.

Beachten sie dabei, dass die Klassen zerstört und die Variablen zurückgesetzt werden, wenn sie diesen Code in dem Addin selbst anwenden!


Das Beispiel kann natürlich nur als Anregung gedacht sein, das ganze weiter zu entwickeln. Wie wäre es denn mit einem kleinen Userform, in welches sie ihre Kopfdaten eingeben können (diese lassen sich in der Tabelle des Addins speichern), oder einen Button zum automatischen ändern der Versionsnummer und des Revisionsdatums, oder, oder .... Ihrer Fantasie sind keine Grenzen gesetzt.

Das war jetzt wirklich schwer. Lauter neue Objekte mit ihren Eigenschaften, Methoden und Ereignissen. Verdauen sie das erst einmal. In nächsten Teil werden wir eine Commandbar in ein Userform einbauen. Nicht ein Popup, das hatten wir schon, sondern eine richtige Symbolleiste. Und wer dann immer noch nicht genug hat, der darf noch mit Hilfe von API - Funktionen eine Menüleiste in ein Userform integrieren.



Weitere Artikel der Gruppe: Tutorials Aus Excel VBA
Nach oben