Service Pack für Office 2013 verfügbar

By , 2. März 2014

Vor wenigen Tagen hat Microsoft das Service Pack 1 für Office 2013 und SharePoint 2013 veröffentlicht. Das Service Pack soll vorallem die Stabilität und Sicherheit von Office 2013 und SharePoint 2013 erhöhen.

Die wichtigsten Änderungen:
Kompatibilität zu Windows 8.1 und Internetexplorer 11 wurde verbessert
Neue Apps für Office und APIs für Entwickler
Neues 3D Virtualisierungs Tool für Excel: Power Map
etc.

Wer viel Neues vom ServicePack erwartet, wird wahrscheinlich enttäuscht werden, das Hauptaugenmerk liegt hauptsächlich auf Stabilität und Sicherheit.
Beide Updates sind verfügbar im Microsoft Download Center:
Office 2013 SP1 32 Bit Version: http://www.microsoft.com/en-us/download/details.aspx?id=42017
Office 2013 SP1 64 Bit Version: http://www.microsoft.com/en-us/download/details.aspx?id=42006

Bis dahin
© 2014 Andreas Vogt

Factory Module verwenden

By , 2. März 2014

Man stelle sich vor man hat eine Klasse namens „Fahrzeug“, abgeleitet von dem Interface im Artikel zuvor, und Sie möchten neue Objekt erstellen. Üblicherweise geschieht das in folgender Weise:

    Dim car1 As Fahrzeug
    Set car1 = New Fahrzeug
    With car1
        .iFahrzeug_Farbe = 255
        .iFahrzeug_Geschwindigkeit = 100
        .iFahrzeug_Richtung = "Gerade aus"
        .iFahrzeug_Fahren
    End With

Mit der Anweisung Set car1 = New Fahrzeug wird das Objekt „car1“ zwar erstellt, das Objekt ist aber komplett ‚leer‘. Erst in den nachfolgenden Zeilen wird das Objekt mit Daten belegt. D.H. zum Erstellungszeitpunkt des Objektes stehen alle Eigenschaften auf 0 bzw. auf vbNullString.

Wäre es nicht Cool wenn man, um beim obigen Beispiel zu bleiben, das Objekt so erstellen könnte:

    Dim car1 As Fahrzeug
    Set car1 = New Fahrzeug(255,100,"Gerade aus")

Diese Möglichkeit gibt es in VBA leider nicht, aber wir können uns behelfen mit einer sogenannten Factory.

Zuerst benötigen wir in der Klasse „Fahrzeug“ einen Ersatz für den Standard-Konstruktor. Dazu erstellen wir eine öffentliche Prozedur, welche alle beim Start benötigten Werte als Parameter verlangt. Diese Parameter-Werte werden in dieser Prozedur einfach den Privaten Variablen zugewiesen. Und so sieht diese Prozedur für obiges Beispiel aus:

Public Sub Init(ByVal Color As Long, ByVal Speed As Long, ByVal Direction As String)
    m_farbe = Color
    m_geschwindigkeit = Speed
    m_richtung = Direction
End Sub

Danach erstellen wir ein Klassenmodul und benennen es z.B. „Factory“. Darin steht folgender Code:

Public Function CreateCar(lColor As Long, lSpeed As Long, cDirection As String) As Fahrzeug
    Dim objFahrzeug As Fahrzeug
    Set objFahrzeug = New Fahrzeug

    objFahrzeug.Init Color:=lColor, Speed:=lSpeed, Direction:=cDirection
    Set CreateCar = objFahrzeug
End Function

D.H. die Factory -Prozedur ruft den künstlichen Konstruktor in der Klasse „Fahrzeug“ auf, und übergibt die Startwerte.
Diese Factory Klasse kann viele Factory-Prozeduren für die unterschiedlichsten Klassen beinhalten, man muss nicht immer eine neue Factory-Klasse erstellen.

Verwendung:
Kommen wir zum obigen Beispiel zurück. Was sich als erstes ändert ist die Deklaration der Factory. Diese kann in einem Modul Private oder Public declariert werden. Wichtig ist dass die Factory mit dem Schlüsselwort New deklariert wird, da sonst das Objekt nicht erstellt wird:

Private CarFactory As New Factory

Das Erstellen des Objektes erfolgt dann so:

    Dim car1 As Fahrzeug
    Set car1 = CarFactory.CreateCar(255, 120, "links")
    car1.iFahrzeug_Fahren
    Set car1 = Nothing

Zusammenfassung
Durch die Factory können Klassen unabhängig von ihrer jeweiligen Implementierung verwendet werden, d.h. Klasse und aufrufender Code sind voneinander entkoppelt, und VBA rückt wieder ein Stück weiter in Richtung Objektorientierte Entwicklung. Daneben gibt es aber noch einen Handfesten Vorteil, der es Wert ist, sich mit Factories zu beschäftigen:
Jedes mal wenn ein Objekt instanziert wird, werden auch mit den notwendigen Eigenschaften gesetzt – da die Parameter in der Factory ja Muss-Parameter sind.

Viel Spass beim Experimentieren mit Klassen, Interface, Factory und Co.
Wenn es die Zeit erlaubt werde ich in den nächsten Tagen mal ein komplett-Beispiel hochladen mit Interface und Factory.

Bis dahin
© 2014 Andreas Vogt

Benutzerdefinierte Collections

By , 1. März 2014

Collections, auf Deutsch Auflistungen, begegnen uns beim Entwickeln in VBA eigentlich ständig, sei es die Auflistung aller Formulare (Forms), oder aller Steuerelemente in einem Formular (Controls). Neben diesen bereits vorhandenen Collections, ist es möglich auch eigene Collections zu erstellen. Dies geschieht mit der simplen Anweisung:
Dim CollectionName As New Collection.

Im Unterschied zu einem Array kann eine benutzerdefinierte Collection Werte und Objekte jeglichen Typs aufnehmen, eine Collection ist also nicht Typ gebunden. Ein weiterer, nicht zu unterschätzender Vorteil ist dieser, dass im Gegensatz zu einem Array – wo die Items nur durch ihre Ordnungszahl definiert sind – bei einer Collection als optionalen Parameter einen eindeutigen Bezeichner angegeben werden kann, über den auf das entsprechende Item zugegriffen werden kann.

Eine Benutzerdefinierte Collection verfügt über die Methoden „ADD“, „REMOVE“, „COUNT“ und „ITEM“, d.h. es gibt keine Edit-Methode. Will man ein Item ändern muss man es aus der Collection entfernen und geändert neu einfügen. Eine weitere Besonderheit benutzerdefinierter Collections ist, dass sie immer 1-Basiert sind, also das erste Element in einer Collection hat die Ordnungszahl 1, und nicht 0 wie bei einem Array.

Ein Beispiel:

Sub CollectionTest()
    Dim cBuch As New Collection
    Dim Ausgabe As String
    
    With cBuch
        .Add "Ken Getz", "Autor"
        .Add "VBA Developers Handbook", "Titel"
        .Add 922, "Seiten"
    End With
    
    Ausgabe = cBuch("Autor") & vbCrLf
    Ausgabe = Ausgabe & cBuch(2) & vbCrLf
    Ausgabe = Ausgabe & cBuch("Seiten") & " Seiten"
    MsgBox Ausgabe
End Sub

Wie man an diesem kleinen Beispiel sieht ist es egal ob ich cBuch(2) oder cBuch(„Titel“) schreibe. Der große Vorteil des Bezeichners ist, dass ich mir keine Gedanken machen muss an welcher Stelle ein Item steht, mit dem Bezeichner wird immer der richtige Wert verwendet.

Bis dahin
© 2014 Andreas Vogt

Arbeiten mit Interface-Klassen

By , 28. Februar 2014

Dass man mit Access auch objektorientiert entwickeln kann – wenn auch nicht völlig – dürfte hinlänglich bekannt sein. Klassenmodul erstellen, Methoden und Eigenschaften in als Prozeduren und Properties definieren, alles längst bekannt. Weniger bekannt aber ist die Verwendung von Interfaces bzw. Interface-Klassen.

Man stelle sich vor, man hat eine Klasse Auto, eine Klasse Motorrad und eine Klasse Fahrrad. 3 verschiedene Klassen, und doch werden die Methoden und Eigenschaften dieser Klassen in vielen Punkten identisch sein. Die Objekte aller 3 Klassen haben sicherlich die gemeinsamen Methoden „Fahren“, „Bremsen“ und „Lenken“. Außerdem die gemeinsamen Eigenschaften „Geschwindigkeit“, „Richtung“ und „Farbe“, um ein paar Beispiele zu nennen.

Diese Zusammenhänge lassen sich durch ein Interface abbilden, und das geschieht einfacher als man denkt. Ein Interface ist zuerst einmal nichts anderes als ein Klassenmodul, das man speziell benennt. Eingebürgert hat sich, dass man vor den Interface-Namen ein „i“ setzt. Wir erstellen also ein Klassenmodul, und benennen es „iFahrzeug“. Um jetzt die Struktur für Fahrzeuge in diesem Interface abzubilden erstellen wir darin alle Properties und Prozeduren wie oben benannt, aber ohne weiteren Code. Unser Interface sieht jetzt wie folgt aus:

Option Explicit

Property Get Geschwindigkeit() As Long
End Property
Property Let Geschwindigkeit(ByVal lSpeed As Long)
End Property

Property Get Richtung() As String
End Property
Property Let Richtung(ByVal cRichtung As String)
End Property

Property Get Farbe() As Long
End Property
Property Let Farbe(ByVal lColor As Long)
End Property

Sub Fahren()
End Sub

Sub Bremsen()
End Sub

Sub Lenken()
End Sub

Die Prozeduren und Properties dürfen nicht als private deklariert werden, sonst sind diese bei der Verwendung nicht verfügbar.
Interfaces können nur innerhalb Klassenmodulen und Formularmodulen (Formulare sind praktischer Weise ja auch Klassen) verwendet werden, nicht in Standard-Modulen. Die Einbindung in ein Klassenmodul findet mit dem Schlüsselwort „Implements“ statt. Dies erfolgt in der Klasse direkt nach den Optionen-Deklaration, in unserem Fall also: Implements iFahrzeug.

Sobald man das getan hat steht das Interface zur Nutzung bereit. Dies macht sich durch den Eintrag von iFahrzeug in der linken oberen Auswahlliste bemerkbar (Unterhalb der Symbolleiste). Wählt man darin iFahrzeug aus, wird die erste Property bereits in die Klasse eingefügt. Klickt man anschließend auf die rechte obere Auswahlliste, so sind die restlichen Properties und Prozeduren auswählbar, und können einfach in die Klasse eingefügt werden. Spätestens jetzt sollte die Verwendung von Interfaces klar geworden sein.

Mittels einem Interface wird definiert welche Methoden und Eigenschaften eine Klasse mindestens haben muss!. Das Bedeutet alle in dem Interface definierten Prozeduren und Properties müssen auch in die Klasse übernommen werden. Macht man das nicht so erhält man einen Fehler wenn man das Projekt Kompelliert.

Fügt man die restlichen Properties und Methoden ein, sollte die Klasse jetzt wie folgt aussehen:

Option Compare Database
Option Explicit

Implements iFahrzeug

Private Sub iFahrzeug_Fahren()
End Sub

Private Sub iFahrzeug_Bremsen()
End Sub

Private Sub iFahrzeug_Lenken()
End Sub

Private Property Get iFahrzeug_Farbe() As Long
End Property

Private Property Let iFahrzeug_Farbe(ByVal RHS As Long)
End Property

Private Property Let iFahrzeug_Geschwindigkeit(ByVal RHS As Long)
End Property

Private Property Get iFahrzeug_Geschwindigkeit() As Long
End Property

Private Property Let iFahrzeug_Richtung(ByVal RHS As String)
End Property

Private Property Get iFahrzeug_Richtung() As String
End Property

Jetzt kann man relativ einfach jede Klasse (Auto, Motorrad, Fahrrad) nach dieser „Vorschrift“ erstellen, auscoden und nach Bedarf erweitern.

Fassen wir mal zusammen:

  • Interfaces sind Daten- und Zugriffsstrukturen, welche den Zugriff und die Steuerung von Objekten regeln
  • Vereinfacht gesagt ist ein Interface eine Struktur an Methoden und Eigenschaften.
  • Interfaces sind bestimmte Klassenmodule, die nach einem Schema benannt werden.
  • Interfaces enthalten nur die Rümpfe der Prozeduren und Properties. Code darin würde ignoriert werden.
  • Eingebunden in Klassenmodulen (oder Formular-Code) werden diese mit dem Schlüsselwort „Implements“
  • Objektorientiert Entwickeln ist Cool 😉

Und nun viel Spass beim Experimentieren mit OOP und Interfaces.

Bis dahin
© 2014 Andreas Vogt

Array definieren mal anderst

By , 27. Februar 2014

Arrays werden entweder per Array() Anweisung definiert, oder auch durch den Split() Befehl.
Auf eine andere bzw. erweiterte Möglichkeit bin ich kürzlich gestoßen beim Entwickeln eines Benutzersteuerelementes mit VB6.
Dort ging es u.a. darum, Steuerelemente beim Klick auf einen Button zu plazieren und sichtbar zu machen.

Die Größe und Position der Steuerelemente habe ich dabei wie folgt definiert:

Private Sub Form_Open(Cancel As Integer)
    Dim sizeArr(8) As Variant
    Dim i As Long
    sizeArr(0) = Array("cmdClose", 2350, 23, 306, 975)
    sizeArr(1) = Array("Linie1", 47, 2412, 2066, 2066)
    sizeArr(2) = Array("Linie2", 47, 2412, 697, 697)
    sizeArr(3) = Array("lblMonat", 23, 47, 454, 2381)
    sizeArr(4) = Array("zurueck", 142, 120, 227, 227)
    sizeArr(5) = Array("vor", 142, 2160, 227, 227)
    sizeArr(6) = Array("MonatJahr", 120, 480, 255, 1575)
    sizeArr(7) = Array("Heute", 2066, 47, 255, 2381)
    sizeArr(8) = Array("Rechteck1", 23, 47, 2280, 2381)

Das bedeutet also, jedem einzelnen Array-Element wurde ein weiteres Array zugewiesen.
Der Zugriff auf einen bestimmten Wert, z.B. auf „lblMonat“ lautet dann: sizeArr(3)(0)

Und um wieder zum Beispiel aus der Praxis zurückzukommen, hier der restliche Code, der die Steuerelemente dimensioniert, positioniert und sichtbar schaltet:

    For i = LBound(sizeArr) To UBound(sizeArr)
        With Controls(sizeArr(i)(0))
            .Top = sizeArr(i)(1)
            .Left = sizeArr(i)(2)
            .Height = sizeArr(i)(3)
            .Width = sizeArr(i)(4)
            .Visible = True
        End With
    Next i
End Sub

Bis dahin
© 2014 Andreas Vogt

OfficeFolders theme by Themocracy