|
Teil 3
Das weitere ist ein schönes Beispiel für den sinnvollen Einsatz einer Klasse. Die Klasse clsPosSize sorgt sowohl für die Speicherung der einmal festgelegten Position und Größe eines Komponententyps als auch für die Positionierung anhand der gespeicherten Werte. Da ja jederzeit neue Komponententypen das Licht der VB-Welt erblicken können, vermeiden wir damit eine feste Codierung, die sich allein auf bekannte Modultypen beschränken müsste.
Die im gesamten AddIn-Modul zur Verfügung stehende Collection mPosSizes nimmt die verschiedenen Instanzen zu jedem einzelnen Komponententyp auf. Zunächst wird auf gut Glück probiert, eine Instanz der Klasse mit der entsprechenden ID als Key in der Collection ausfindig zu machen. Schlägt der Versuch fehl, wird eine neue Instanz der Klasse angelegt und über den Aufruf der Methode Init dieser Klasse initialisiert.
On Error Resume Next
Set nPosSize = mPosSizes(nID)
On Error GoTo 0
If nPosSize Is Nothing Then
Set nPosSize = New clsPosSize
nPosSize.Init nID
mPosSizes.Add nPosSize, nID
End If
Bei dieser Initialisierung wird die ermittelte ID übergeben. Springen wir an dieser Stelle in die Prozedur der Init-Methode der clsPosSize-Klasse.
Public Sub Init(iID As String)
pID = iID
pHeight = CLng(GetSetting(kVBEWindowControl, pID, "Height", 0))
pWidth = CLng(GetSetting(kVBEWindowControl, pID, "Width", 0))
pLeft = CLng(GetSetting(kVBEWindowControl, pID, "Left", 0))
pTop = CLng(GetSetting(kVBEWindowControl, pID, "Top", 0))
End Sub
Zuerst wird die übergebene ID in der Variablen pID festgehalten. Dann werden aus der Windows-Registrierung mit GetSetting die Werte für die Größe und die Position passend zur ID gelesen. Sollten die Werte noch nicht gespeichert sein, gibt GetSetting die Vorgabe 0 zurück. Die Werte werden hier nur für die Instanz festgehalten, jedoch noch nicht weiter verwendet.
Wieder zurück im AddIn-Modul wird das DesignerWindow unsichtbar gemacht. Manche Implementierungen von ActiveX-Desiger-Modulen scheinen die Unart zu haben, sichtbar zu werden, wenn sie positioniert werden, auch wenn sie zuvor unsichtbar waren - und diese Unart pflegen die VB-eigenen Code-Module anscheinend auch.
Dann wird die Move-Methode der Klasse aufgerufen
With nDesignerWindow
.Visible = False
nPosSize.Move nDesignerWindow
Zusammen mit diesem Aufruf wird das DesignerWindow übergeben.
Public Sub Move(iWindow As Window)
If CBool(pWidth) And CBool(pHeight) Then
With iWindow
.Left = pLeft
.Top = pTop
.Width = pWidth
.Height = pHeight
End With
End If
End Sub
Nur wenn für den Komponententyp bereits eine Positionierung festgelegt worden ist, enthalten pWidth und pHeight gültige Werte (> 0). Und nur dann wird das Fenster jetzt positioniert.
Falls ein neues Projekt bereits mehrere Designer-Komponenten enthalten sollte, ist es sinnvoll, nur das Fenster des ersten zu öffnen und anzuzeigen - alle weiteren sollten geschlossen bleiben.
If Not nFirst Then
nFirst = True
.Visible = True
Else
.Visible = False
End If
End With
End If
Set nPosSize = Nothing
Dann wird die Referenz auf die Designer-Instanz der Positionierungs-Klasse wieder freigegeben. Das gleiche Spiel wiederholt sich nun für das Code-Modul des Designers, bzw. es findet nun für eine reine Code-Komponente statt (Standard-Modul, Klassen-Modul). Für diese wird das zu positionierende Fenster über die Eigenschaft CodeModule und wiederum deren Eigenschaft CodePane herangezogen. Die ID für eine reine Code-Komponente braucht nicht ermittelt zu werden - sie ist in der Konstanten kCodeWindow ("CodeWindow") festgelegt.
Set nCodeWindow = .CodeModule.CodePane.Window
nID = kCodeWindow
On Error Resume Next
Set nPosSize = mPosSizes(nID)
On Error GoTo 0
If nPosSize Is Nothing Then
Set nPosSize = New clsPosSize
nPosSize.Init nID
mPosSizes.Add nPosSize, nID
End If
With nCodeWindow
.Visible = False
nPosSize.Move nCodeWindow
If Not nFirst Then
nFirst = True
.Visible = True
Else
.Visible = False
End If
End With
End With
Next
End If
End Sub
Wird nun beim Hinzufügen einer weiteren Komponente zu einem Projekt das Ereignis eVBComponentsEvents_ItemAdded ausgelöst, wird das im Prinzip gleiche Verfahren für die betreffende Komponente angewandt. Der einzige bedeutendere Unterschied besteht in der Prüfung auf die Jungfräulichkeit hin. Da eine Komponente auf mehreren Dateien aufsetzen kann, steht dementsprechend eine Sammlung (bzw. ein Array) für mehrere Dateinamen zur Verfügung. Wir brauchen hier jedoch nur nachschauen, ob es einen ersten Dateinamen gibt.
Private Sub eVBComponentsEvents_ItemAdded(ByVal VBComponent _
As VBIDE.VBComponent)
Dim nFirst As Boolean
Dim nDesignerWindow As Window
Dim nCodeWindow As Window
Dim nPosSize As clsPosSize
Dim nID As String
With VBComponent
If Len(.FileNames(1)) = 0 Then
nID = CStr(.Type) & .DesignerID
Set nDesignerWindow = .DesignerWindow
If Not (nDesignerWindow Is Nothing) Then
nID = "D" & CStr(.Type) & .DesignerID
On Error Resume Next
Set nPosSize = mPosSizes(nID)
On Error GoTo 0
If nPosSize Is Nothing Then
Set nPosSize = New clsPosSize
nPosSize.Init nID
mPosSizes.Add nPosSize, nID
End If
With nDesignerWindow
.Visible = False
nPosSize.Move nDesignerWindow
If Not nFirst Then
nFirst = True
.Visible = True
Else
.Visible = False
End If
End With
End If
Set nPosSize = Nothing
Set nCodeWindow = .CodeModule.CodePane.Window
nID = kCodeWindow
On Error Resume Next
Set nPosSize = mPosSizes(nID)
On Error GoTo 0
If nPosSize Is Nothing Then
Set nPosSize = New clsPosSize
nPosSize.Init nID
mPosSizes.Add nPosSize, nID
End If
With nCodeWindow
.Visible = False
nPosSize.Move nCodeWindow
If Not nFirst Then
nFirst = True
.Visible = True
Else
.Visible = False
End If
End With
End If
End With
End Sub
Nun brauchen wir nur noch ein wenig aufzuräumen, damit die Grundfunktionalität des VBEWindowControl-AddIns fertig ist. Wird ein Projekt entfernt, ist es zuvor das aktive Projekt gewesen. Der Ordnung halber wird daher beim Eintreffen des Ereignisses eProjectEvents_ItemRemoved der Ereignisempfänger eVBComponents freigegeben.
Private Sub eProjectEvents_ItemRemoved(ByVal VBProject _
As VBIDE.VBProject)
Set eVBComponentsEvents = Nothing
End Sub
Private Sub eProjectEvents_ItemActivated(ByVal VBProject _
As VBIDE.VBProject)
Set eVBComponentsEvents = mVBE.Events.VBComponentsEvents(VBProject)
End Sub
Danach trifft jedoch sogleich das Ereignis eProjectEvents_ItemActivated ein, wenn noch andere Projekte geladen sind. Dieses nutzen wir, um den Ereignisempfänger eVBComponents nun erneut für das jetzt aktive Projekt zu installieren. Sind keine Projekte mehr geladen und wird statt dessen ein komplett neues Projekt geladen, wird der Ereignisempfänger automatisch im oben beschriebenen Ereignis eProjectEvents_ItemAdded installiert.
Das totale Aufräumen findet beim Entladen des AddIns im Ereignis AddinInstance_OnDisconnection statt, unabhängig vom in RemoveMode übergebenen Wert.
Private Sub AddinInstance_OnDisconnection(ByVal RemoveMode _
As AddInDesignerObjects.ext_DisconnectMode, _
custom() As Variant)
Set mPosSizes = Nothing
Set ePjFDesignerCmdButtonEvent = Nothing
Set ePjFCodeWindowCmdButtonEvent = Nothing
Set ePjMCodeWindowCmdButtonEvent = Nothing
Set ePjFRestoreDesignerCmdButtonEvent = Nothing
Set ePjFRestoreCodeWindowCmdButtonEvent = Nothing
Set ePjMRestoreCodeWindowCmdButtonEvent = Nothing
Set eVBComponentsEvents = Nothing
Set eProjectEvents = Nothing
Set mVBE = Nothing
End Sub
|