Visual-Basic Klassen

VB6 erlaubt die Verwendung von Kassen, wenn auch nicht alle Funktionen unterstützt werden die zT. in anderen Sprachen enthalten sind (zB Vererbung.) Hier wird das Klassenmodell in VB6 beschrieben.

Allgemeines

Begriffserklärung

Einige Begriffe die man in Verbindung mit Klassen verwendet sind wichtig um die Beschreibungen zu verstehen. Um ein Überblick der verwendeten Begriffe zu erhalten sind sie hier kurz erklärt.

Begriff Bedeutung
Objekt-Orientiertes-Programmieren (OOP) Ist der Oberbegriff für alles rund um Klassen und ihren Eigenschaften. Es bedeutet kurz gesagt das Programmstrukturen sich nicht nur um Daten und Prozeduren drehen, sondern um Objekte welche alles enthalten was sie benötigen um mit ihren Daten umgeben zu können, inklusive der Prozeduren, all dies wird in Objekten gekapselt. Und es bedeutet auch das Programme nicht mehr linear strukturiert sein müssen sondern Ereignisse dann behandelt werden wenn sie auftreten.
Klasse Ist der Konstruktionsplan für Objekte, man könnte sie mit einem Type vergleichen mit dem Unterschied das nicht nur Daten sondern auch Prozeduren und noch mehr enthalten sein können. Eine Kasse enthält in sich alle Prozeduren die sie benötigt um mit den eigenen Daten umgehen zu können.
Objekt Ist die verkörpert einer Klasse die aus dem Konstruktionsplan erstellt wurde und Speicher deklariert. Ähnlich wie von einem Type eine Variable deklariert werden kann, kann von einer Klasse ein Objekt deklariert werden. Ein Objekt kann die Struktur einer Klasse selbst abbilden, oder auf ein anderes Objekt verweisen.
Instanz Wird aus einer Klasse ein Objekt erzeugt, wird dies Instanzieren genannt, ein Objekt ist dann eine Instanz der Klasse.
Referenz Ein Objekt kann auch eine Referenz also ein Verweis (oder Stellvertreter) zu einem instanzierten Objekt sein, das bedeutet das viele Objekte als Reverenzen auf die gleiche Instanz eines Objekts verweisen können. Ändert sich der Wert in der Instanz ändert sich dieser auch für alle Reverenzen, die ja die Werte selbst nicht enthalten sondern auf diese nur verweisen. (In VB6 sind alle Objekte Referenzen, die Instanzen werden Intern automatisch organisiert.)
Kapselung Anders als in Modulen sind da Public deklarierte Namen nicht einfach im gesamten Projekt sichtbar, sondern nur über des Objekts erreichbar. Namen können so besser abgegrenzt werden und Namensüberschneidungen verhindert werden. Public¦Friend bewirken das ein Name nach Außen sichtbar ist, sie bleiben aber an das Objekt gebunden.
Methoden (Method) Sind die Prozeduren (Sub Function) die in einem Objekt dessen Eigenschaften bearbeiten.
Eigenschaften (Property) Ist eine Schnittstelle für den Datenaustausch in und aus dem Objekt, die es auch ermöglicht zusätzliche Aktionen beim Schreiben und Lesen von Daten Auszuführen.
Ereignis (Event) Objekte können Ereignisse auslösen, das bedeutet das ein im Objekt deklariertes Ereignis als Prozedur in einem anderen Codeteil ausgeführt wird als im Objekt selbst. zB beim drücken auf ein Knopf wird ein Ereignis ausgelöst das in einem Formular bearbeitet werden kann.
Überladung Bedeutet das für eine Prozedur mehrere Varianten erlaubt sind, die zB. unterschiedliche Anzahl und Daten-Typen von Parametern erlauben. Das ermöglicht es unteranderem das eine Funktion für viele Daten-Typen gleichnamig verwendet werden kann. (Die Funktion Len() ist ein Beispiel, man kann Len() auf alle Datentypen anwenden, obwohl für jeden Daten-Type eine eigene Prozedur ausgeführt wird.) Leider unterstützt VB6 das Überladen von Prozeduren nicht.
Polymorphie Dieser eigentlich unnötig komplizierte aber in OOP häufig benutze Begriff bedeuten soviel wie Vielgestaltigkeit, das heißt das ein Algorithmus nicht an eine bestimmten Daten-Typ gebunden ist. Mehrere Klassen können die selben Eigenschaften oder Methoden bereitstellen und beim Aufruf der Eigenschaft¦Methode muß nicht bekannt zu sein zu welcher Klasse das betreffende Objekt gehört. Dies erleichtert das Programmierer da es so möglich ist Algorithmen nur einmal zu entwickeln und sie dann vielfältig in anderen Objekten benutzen zu können. (Überladung von Prozeduren, oder der Variant und Object Daten-Typ sind auch eine Form der Polymorphie. Leider unterstützt auch hier VB6 Polymorphie nicht vollständig (nicht über Vererbung, nur über Schnittstelle), zB. gibt es in VB6 eine Reihe unterschiedlicher Listen-Formate, es gibt aber keine Möglichkeit sie untereinander austauschbar zu verwenden. Aber es werden dennoch einige polymorphe Eigenschaften unterstützt.
Vererbung Bedeutet das eine Klasse Codes an andere Klassen vererben¦übertragen¦kopieren kann. so lassen sich Codes mit gleichen aufgaben in vielen Klassen verwenden ohne sie neu schreiben zu müssen. Vererbung kann auch mit der Polymorphie zusammenarbeitet und ermöglicht es so das nicht in jenem Klasse wiederholende Prozeduren immer wieder neu geschrieben werden müssen. Durch die Kapselung wäre sonst kein Austausch von Codes unter Klassen möglich, sie wären in den Klassen einsperren. Leider unterstützt VB6 Vererbung nicht, statteten wird eine Schnittstellen Kommunikation unterstützt welche aber weniger effizient ist.
Nicht-Linearität Durch die Ereignis-Orientierte Programmierung ist ein Programm nicht mehr linear, in dem Sinne wie es Codes in einem Standard-Modul sind. Ein Beispiel sind Benutzeroberflächen, in einem Linearen Programm müsse eine Schleife und ein Select-Case prüfen ob eine Aktion ausgeführt wurde die eine Prozedur und Aktionen auslöst, zB. beim Klicken auf ein Knopf oder Menü. Durch Event fällt dies weg, die Aktion wird dann ausgeführt wenn sie eintritt. Die Struktur eines Programms läßt sich deshalb nicht mehr linear abbilden, die Ereignisse verändern die Daten in einem Objekt wenn sie eintreten und theoretisch könne sie das auch gleichzeitig.
Task, Multitasking Prozeß oder Programm der in einer Multitasking Umgebung gleichzeitig mit anderen Tasks ausgeführt werden kann. Heutige Betriebsysteme verwenden alle Multithreading um mehrere Programme und Prozesse gleichzeitig laufen lassen zu können.
Thread, Multithreading Ein Thread ist ein Programmteil (innerhalb eines Task) welcher von einem anderen unabhängig arbeiten kann. So ist es möglich das auch innerhalb eines Programms verschiedene Aufgaben gleichzeitig bearbeiten werden können. Besonders interessant in Multi-Prozessor Systemen, aber auch in Single-Prozessor Systemen kann es Beschleunigung bringen wenn unterschiedlich Hardware aufgaben gleichzeitig stattfinden können. Es kann Probleme geben wenn Threads gleichzeitig die selben Daten benutzen¦verändern deshalb müssen Thread voneinander abgegrenzt (das sich keine Daten überschneiden), oder synchronisiert (Treads nacheinander bearbeiten) werden. Da zusätzlich Management Aufgaben anfallen die den Code auch verlangsamen können muß sich der Entwickler überlegen für welche Codes Treads sinnvoll sind. (VB6 erlaubt leider kein Multithreading)

Namensvergabe

  • Da in Objekten oft gleiche Aufgaben erfüllt und gleiche Daten bearbeitet werden müssen, ist es sinnvoll dies auch in alle Projekten gleich zu benennen. Auf diese Weise ist es viel leichter sich in Projekten zurecht zu finden, und da Objekte die Namen kapseln gibt es auch keine Probleme mit Namensüberschneidungen.
  • Das "_" Unterstrich-Zeichen kann zwar in Namen verwendet werden, könnte aber Konflikte mit Ereignisse auslösen, die den Unterstrich benutzen. (Siehe: Ereignis: Event)
  • Ansonsten gelten die gleichen Regeln wie auch bei der Benennung von Klassen Namen. (Siehe: Namensvergabe)


Hier eine Liste der gebräuchlichsten Namen in Klassen.

Wort Bedeutung
Methoden
Add, AddItem Fügt ein Element hinzu
Move, MoveItem Verschiebt ein Element an eine andere Position
Remove, RemoveItem Löscht ein Element
Clear Löscht den gesamten Inhalt
Eigenschaften
List Der Inhalt der Liste
Item Ein Element (aus einer Liste)
Index Den Index auf eine Position in einer Liste
Count Anzahl Elemente
Name Name des Objekts¦Elemente
Caption Titel, Sichtbarer Text des Objekts
Text Text-Inhalt im Objekt
Ereignisse
Initialize() Tritt auf, wenn eine Instanz (Objekt) einer Klasse erstellt wird.
Terminate() Tritt auf, wenn eine Instanz (Objekt) aus dem Speicher entfernt worden sind. (oder alle (Objekt-Verweise auf eine Instanz)
Load() Tritt auf, wenn ein Objekt (Formular oder Steuerelement) geladen wird.
Unload(Cancel As Integer) Tritt auf, unmittelbar bevor wenn ein Objekt (Formular oder Steuerelement) entfernt wird.
Activate() Tritt auf, wenn ein Objekt (Formular oder Steuerelement) zum aktiven wird.
Deactivate() Tritt auf, wenn ein Objekt (Formular oder Steuerelement) nicht mehr das aktive Fenster ist.

Klasse

  • Klassen-Module enthaten sozusagen ein Konstruktionsplan eines Objekts. Sie Enthalten alles was das Objekt braucht, also sowohl seine Dateien wie auch die Prozeduren (Methoden) um diese zu verwalten.
  • Von einer Klasse können beliebig viele Objekte erzeugt¦abgeleitet werden, Objekte sind sozusagen "Verkörperungen" einer Klasse.
  • Die Namen die Public sichtbar sind gehören zu der sogenannten Schnittstelle eines Objekts.
  • In VB6 ist es leider nicht möglich in einem Klassen-Modul mehrere Klassen unterzubringen. Ein Klassen-Modul gilt automatisch als eine Klasse.



  • Klassen können Eigenschaften, Methoden und Ereignisse enthalten.
Name Schlüsselworte Beschreibung
Eigenschaften Property (Get Let Set) Sind die Daten die im Objekt gespeichert werden, welche über Eigenschaftsprozeduren ausgetauscht und bearbeitet werden können.
Methoden Sub Function Sind die Prozeduren die im Objekt verfügbar sind.
Ereignisse Event RaiseEvent WithEvents Sind Aktionen die vom Objekt ausgelöst werden können und in anderen Objekten außerhalb der Ereignisquelle eine Prozedur aufrufen.

Unterschied: Klassen-Modul, Standard-Modul

Klassen-Modul Standard-Modul
Von Klassen lassen sich unbegrenzt viele Objekte und damit auch deren Werte erzeugen. In Modulen sind alle Werte nur einmal verfügbar.
Dadurch das Objekte instanziert werden müssen und auch wieder gelöscht werden können, existieren Prozeduren und Variablen nicht während der Ganzen Laufzeit. Ein Objekt kann auch Nothing oder Null enthalten. Prozeduren und Variablen existieren in Modulen während der gesamten Laufzeit.
Public Namen ist in Objekt gekabbelt und können nur über dieses erreicht werden. Public Namen sind im ganzen Projekt direkt sichtbar und können in allen Prozeduren verwendet werden.
In Klassen können Ereignisse ausgelöst werden, welche Prozeduren aufrufen. In Modulen existieren Ereignisse nicht.
Klassen können bei der "Erzeugen" und "Zerstören" Initialisierungen und Terminationen ausführen. Initialisierungen und Terminationen existiert in Standard-Modulen nicht.

Verbotene Namen

Einige Namen dürfen nicht verwendet werden da sie zu den zugrundeliegenden Schnittstellen "Unknown" und "Dispatch" gehören:
QueryInterface, AddRef, Release, GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, Invoke

Gültigkeitsbereich: Public Friend Private

  • Public hat nicht die gleiche Wirkung wie Public in Modulen, Namen sind nicht im ganzen Projekt sichtbar, sondern durch die Kapselung nur über das Objekt erreichbar und nach Außen sichtbar.
  • Es ist leider nicht möglich Public sichtbare Namen in einer Klasse wie in einem Modul zu deklarieren. Global sichtbare Namen müssen außerhalb von Klassen in einem Modul deklariert werden.
  • Konstanzern können leider überhaupt nicht Public dekoriert werden. (Das liegt daran das VB6 nicht unterschiedet ob eine Klasse nur innerhalb eines Projekts sichtbar sein muß, oder über dies hinaus wie zB. in eine DLL OCX. In extern sichtbaren Namen die nur zur Laufzeit aufgelöst werden können, gibt es keine Konstanten da Werte immer abgeholt und in einer Variable übertragen werden müssen.)
Schlüsselwort Beschreibung
Public Namen sind über das Objekt nach außen sichtbar für alle, auch außerhalb des Projekts. (In OCX DLL ActiveX usw. können Namen zugänglich sein.)
Friend Namen sind über das Objekt nach außen sichtbar für alle Prozeduren in einem Projekt, nicht aber außerhalb des Projekts.).
Private Namen sind nur innerhalb des Objekt unter den Prozeduren sichtbar (wie in Modulen auch.)

Friend

  • In Gegensatz zu Modulen kommt noch das Schlüsselwort Friend hinzu, für Friend gelten zusätzliche Einschränkungen
    • Kann nur in Formular-Modulen und Klassen-Modulen verwendet werden.
    • Kann nur Prozedurnamen, nicht Variablen oder Typen verwendet werden.
    • Eine Friend-Prozedur kann nur zur Compilierungszeit (nicht zur Laufzeit) auflösbar sein. (Friend-Prozeduren sind dadurch schneller aufrufbar.)
    • Nicht sichtbar für den Controller einer Instanz des Objekts und dadurch außerhalb des Projekts nicht sichtbar und gehören deshalb nicht zur der Schnittstelle. (in eine DLL OCX Datei sind Friend-Prozeduren nach Außen nicht erreichbar.)
    • Sie sind deshalb auch nicht sichtbar in Objekten die als allgemeine "As Object" deklariert wurden, da diese polymorph und nur zur Laufzeit auflösbar sind. Um auf Friend deklarierte Namen zugreifen zu können müssen Objekte explizit mit Klassennamen deklariert werden um zur Compilierungszeit auflösbar zu sein.
  • Nützlich ist Friend auch in ActiveX Komponenten, weil so Prozeduren innerhalb der Komponenten sichtbar sein können aber nicht außerhalb, was sie besser kapseln kann als ein Public wenn sie nach Außen auch nicht erreichbar sein sollen.

Me

  • Me gilt als Stellvertreter oder Verweis auf sich selbst, in das Objekt in dem sich das Me befindet. Es ist also sinnvoll immer dann wenn man eine interne Eigenschaft des Objekts ansprechen will dies nicht über den Namen zu tun sondern über das Schlüsselwort "Me". (zB. nicht "Form1.Unload" sondern "Me.Unload")

Eigenschaft: Property

  • Es können auch in einer Klasse Public Variabeln deklariert werden, aber mit Propertys (Eigenschaft) ist es möglich eine Schnittstelle für den Datenaustausch in und aus dem Objekt zu schaffen und so beim lesen und schrieben auf ein Property auch Codes auszuführen, (wie zB. eine Bereichsprüfung). Deshalb werden sie auch Eigenschaftsprozeduren genannt.
  • Sowohl für den Schreib- wie für den Lese-Vorgang wird separat in einer Eigenschaftsprozeduren Deklariert.
  • Wird die Schreib-Property (Let Set) weggelassen, gilt die Eigenschaft als Schreibgeschützt und kann außerhalb des Objektes nicht (direkt) geändert werden. So können anders als bei Variablen Werte nach Außen vor Veränderung geschützt werden.
    (zB. wird die Anzahl in einer Liste nicht durch Count bestimmt sondern nur zurückgegeben, durch eingefügten und gelöschten von Elementen wird Count Intern geändert.)
  • Public deklarierte Variabeln werden von VB6 intern als Property behandelt. (Die Verarbeitung ist also auch nicht schneller.)
  • Der Unterschied zwischen Methoden (Prozeduren) und Property (Eigenschaftsprozeduren) ist manchmal garnicht so leicht da ja beide eine Prozedur ausführen. Am Ende zählt ob es sich eher um eine Funktion oder um Werte handelt, und dementsprechend sollte die Wahl zwischen den beiden Möglichkeiten getroffen werden.
Ereignisprozedur Auslöser Beschreibung
Property Get Var1 = Prob1 Gibt den Wert einer Eigenschaft zurück.
Property Let Prob1 = Var1 Legt den Wert einer Eigenschaft fest.
Property Set Set Prob1 = Obj1 Legt den Wert einer Objekteigenschaft fest (d.h. einer Eigenschaft, die eine Referenz auf ein Objekt enthält).

Beispiel: Get Let Set

'======== Class1 (Eine Klasse die Property enthält)
 
'-------- Deklaration
 
'-- Interne Propertys speichern
Private Type PropertysInternType
    Prop1   As Long     ' Variable Deklarieren
    Prop2   As Class2   ' Objekt mit expliziter Klasse deklarieren (nur Objekte dieser Klasse sind übertragbar)
End Type
Private PropertysIntern As PropertysInternType
 
 
'-------- Code
 
'-- Variabeln-Property (Eigenschaftsprozeduren)
Public Property Get Prop1() As Long
    '{... Code}
    Prop1 = PropertysIntern.Prop1          ' der Wert wird zurückgegeben
End Property
 
Public Property Let Prop1(ByVal PropertyVal1 As Long)
    '{... Code}
    PropertysIntern.Prop1 = PropertyVal1   ' der Wert wird übernommen
End Property
 
 
'-- Variabeln-Property (Eigenschaftsprozeduren)
Public Property Get Prop2() As Class2
    '{... Code}
    Set Prop2 = PropertysIntern.Prop2          ' der Wert wird zurückgegeben
End Property
 
Public Property Set Prop2(ByVal PropertyVal1 As Class2)
    '{... Code}
    Set PropertysIntern.Prop2 = PropertyVal1   ' der Wert wird übernommen
End Property
 
 
 
'======== Externes Modul
 
Public Sub Main()
  Dim ObjP As New Class1     ' Instanz erstellen zum Prüfen der Property in "Class1"
 
  Dim Var1 As Long           ' Temporäre Variablen
  Dim Obj1 As New Class2
 
 
    ObjP.Prop1 = Var1        ' Ausführung: "Property Let Prop1", "Var1" wird ins Objekt geschrieben
    Var1 = ObjP.Prop1        ' Ausführung: "Property Get Prop1", der Wert wird zurückgegeben.
 
    Set ObjP.Prop2 = Obj1    ' Ausführung: "Property Set Prop2", "Obj1" wird ins Objekt geschrieben
    Set Obj1 = ObjP.Prop2    ' Ausführung: "Property Get Prop2", das Objekt wird zurückgegeben.
 
    Debug.Print ObjP.Prop1   ' Ausführung: "Property Get Prop1", und nur während der Entwicklungszeit !
 
End Sub

Beispiel: Variant

  • Wird ein Variant verwendet kann es auch sein das alle drei Eigenschaften gleichzeitig verwendet werden müssen um alle Möglichkeiten zu behandeln.


'-------- Deklaration
Private Type PropertysInternType
    Prop1   As Variant  ' Variable Deklarieren
End Type
Private PropertysIntern As PropertysInternType
 
 
'-------- Code im Objekt
 
Public Property Get Prop1() As Variant
    If IsObject(PropertysIntern.Prop1) Then
      ' Ist ein Objekt
      Set Prop1 = PropertysIntern.Prop1
    Else
      ' Ist kein Objekt
      Prop1 = PropertysIntern.Prop1
    End If
End Property
 
Public Property Set Prop1(ByVal Par1 As Variant)
    ' Ist ein Objekt
    Set PropertysIntern.Prop1 = Par1
End Property
 
Public Property Let Prop1(ByVal Par1 As Variant)
    ' Ist kein Objekt
    PropertysIntern.Prop1 = Par1
End Property
 
 
'-------- Code außerhalb vom Objekt
 
    Set Obj2 = Obj1.Prop1   ' Objekt Aufruf Get
    Var2 = Obj1.Prop1       ' Variable Aufruf Get
 
    Set Obj1.Prop1 = Obj2   ' Objekt Aufruf Set
    Obj1.Prop1 = Var2       ' Variable Aufruf Let

Beispiel: Parameter

  • Die Lesende Eigenschaftsprozedur "Get" benötigt keinen Parameter, die Schreibenden "Let" "Set" mindestens einen welcher den Wert übernimmt der zugewiesen wurde.
  • Die Eigenschaftsprozeduren müssen deckungsgleich sein, das heißt die Namen müssen gleich lauten und die Parameterangaben ebenfalls.
  • Werden mehrere Parameter verwendet ist der letzte Parameter der Übergabewert, die vorangehenden die zusätzlichen Parameter.
  • Der Datentyp des letzten Arguments in einer "Property Set"-Deklaration muß entweder ein Objekt-Typ oder der Daten-Typ Variant sein.


'-- Pseudocode
 
' D ist die Übergabe Variable (Objekt-Typ oder Variant)
 
Prop1 = D                      ' Diese Anweisung löst...
Public Property Let Prop1(D)   ' ... Diese Eigenschaftsprozedur aus
 
D = Prop1                                          ' Diese Anweisung löst...
Public Property Get Prop1() As {Daten-Typ von D}   ' ... Diese Eigenschaftsprozedur aus
 
Set D = Prop1                                      ' Diese Anweisung löst...
Public Property Set Prop1() As {Daten-Typ von D}   ' ... Diese Eigenschaftsprozedur aus
 
 
 
Prop1(A, B, C) = D                      ' Diese Anweisung löst...
Public Property Let Prop1(A, B, C, D)   ' ... Diese Eigenschaftsprozedur aus
 
D = Prop1(A, B, C)                                        ' Diese Anweisung löst...
Public Property Get Prop1(A, B, C) As {Daten-Typ von D}   ' ... Diese Eigenschaftsprozedur aus

PropertyBag

  • Für außerhalb des Projekts sichtbare Schnittstellen müssen diese über PropertyBag Organisiert werden, um einerseits die Namen sichtbar zu machen und anderseits die Daten zu initialisieren und zwischen zu speichern.
  • Ein gutes Beispiel dafür sind Benuzerdefinierte-Steuerelemente. Was man im Eigenschaftsfenster sehen und einstellen kann wird über das PropertyBag zur Verfügung gestellt.


WRITEME

ReadProperties

WriteProperties

Methode: Sub Function

  • Methoden sind Objekt-Prozeduren (Sub, Function) innerhalb einer Klasse, sie können genauso deklariert werden wie in einem Standard-Modul. (Siehe: Prozeduren)

Ereignis: Event RaiseEvent WithEvents

  • Methoden-Prozeduren und Eigenschafts-Prozeduren werden als nach Innen gerichtet bezechten da sie innerhalb des selbst Objekts stattfinden. Ereignisse die im Objekt ausgelöst werden lösen Aktionen außerhalb des Objekts selbst aus und werden auch deshalb als nach Außen gerichtet bezechten.



  • Ein Beispiel für Ereignisse sind auch in den Formularen zu finden, die Ereignisse automatisch erzeugen wenn ein Formularelement erzeugt wird. Die "WithEvents" und "Set-New" Deklaration wird dabei automatisch im Hinderung erzeugt und die WithEvents-Objekte nach den Elemente-Namen benannt. Wird also ein Knopf erzeugt mit dem Namen "Command1" wird ein "Command1" WithEvents-Objekte aus der Klasse "CommandButton" erzeugt und instanziert. zB. "Command1_Click" ist dann ein Ereignis das beim klicken auf den Knopf ausgelöst wird, wobei "Click" eines der Ereignisse aus der CommandButton-Klasse ist.
  • Ein anderes Beispiel für ein Ereignis wäre eine Rückmeldung für eine Fortschrittsanzeige in einer Methode die viel Zeit in Anspruch nimmt bevor sie beendet ist. Das ist auch deshalb nützlich weil eben Objekte all ihre Prozeduren in sich enthalten sollten, also auch die Verwaltung einer Fortschritts-Berechnung. So kann das aufgerufene Objekt über ein Ereignis dem aufrufenden Objekt mitteilen, wo es sich in der Berechnung befindet und diese Information kann auswerten und zB. anzeigen wenn das aufrufende Objekt ein Formular ist.


WRITEME

 

Interne Deklaration: Event

  • Event Ist die interne Deklaration weil sie im Objekt die Ereignis-Namen deklariert welche das Objekt auslösen kann. Dieses Objekt ist dann eine Ereignisquelle.
  • Event wird in Deklarationsbereich des Klassenmoduls verwendet um ein Ereignis zu deklarieren welches die Klasse auslösen kann.
  • Event können fast genauso deklariert werden wie Prozeduren, also auch mit Parametern und ByVal¦ByRet, bis auf einige ausnahmen.
    • Es können keine Rückgabe-Werte deklariert werden.
    • Es aber keine Optionalen Parameter oder ParamArray deklariert werden
    • Ereignis können nicht Private deklariert werden, da es ja kein Sinn macht ein Ereignis nur im eigenen Objekt auszulösen, dazu werden Methoden verwendet. Ereignis müssen außerhalb des Objekts Public sichtbar sein.


'-------- Deklaration
Public Event Evt1()                                                ' Ein Event wurde deklariert
Public Event Evt2(ByVal Par1 As Single, ByRef Cancel As Boolean)   ' "Cancel" kann hier als Abbruchs-Variable verwendet werden.

Ereignisse auslösen: RaiseEvent

  • Die über Event deklarierten Ereignisse können nun in der Klasse ausgelöst werden. Die funktioniert eigentlich wie bei einem Call nur diesmal über das Schlüsselwort RaiseEvent.


'-------- Code
    RaiseEvent Evt1                 ' das Deklarierte Ereignis wird ausgeführt
    RaiseEvent Evt2(Par1, Cancel)   ' hier werden Parameter übergeben, und über Cancel kann ein Rückgabewert verwendet werden um lange Prozesse abzubrechen.

Externe Deklaration: WithEvents

Ist die externe Deklaration weil sie Ereignisse eines anderen Objekts im eigenen zugänglich macht und hier das Ereignis ausgeführt wird das von der Ereignisquelle ausgelöst wurde.

  • WithEvents deklariert Ereignisse aus einem Objekt um diese abfangen zu können. Bei der Deklaration ist folgendes zu beachten.
    • Kann in nicht in Standard-Modulen verwendet werden, nur in Klassen-Modulen (also auch in Formularen).
    • WithEvents muß explizit mit Klassenname deklariert werden, polymorph "As Object" "As Variant" geht nicht.
    • WithEvents-Variablen können keine Arrays sein.
    • Wird WithEvents für ein Objekt aus einer Klasse deklariert die keine Ereignisquelle ist, also keine Event Deklarationen enthält, tritt ein Fehler auf.
  • Die Ereignisse werden nur dann ausgelöst, wenn auch eine Instanz der WithEvents Objekt-Variable erzeugt wurde, wird diese Objektvariable auf Nothing gesetzt, werden auch de Ereignisse nicht mehr ausgelöst.


'-------- Deklaration
Private WithEvents EvtClass1 As Class1   ' Es wird deklariert das Ereignisse aus der Klasse "Class1" ausgelöst werden können. Dies ist aber noch kein instanziertes Objekt, sondern nur eine Deklaration, Ereignisse werden noch nicht ausgeführt

Ereignisse ausführen: (WithEventsName_EventName)

  • Ist eine WithEvents-Variable deklariert und Instanziert, werden ausgelöste Ereignisse an die Ereignisprozeduren geleitet.
  • Die Ereignisprozeduren werden wie folgt deklariert WithEventsVariabelName_EreignisName(DeklarierteParameter). Die DeklarierteParameter werden so angegeben wie in Events deklariert.


'-------- Code
Private Sub Form_Initialize()   ' die Ereignis-Variable wird hier mein Initialisieren eines Formulars instanziert.
    Set EvtClass1 = New Class1  ' hier wird aus dem deklarierten Ereignis-Objekt eine Instanz erzeugt, erst jetzt werden Ereignisse auch ausgeführt.
End Sub
 
 
    Set EvtClass1 = Nothing     ' Steht irgendwo im Code eine Löschung der Ereignis-Objekt Instanz, werden keine Ereignisse mehr ausgeführt.
 
 
Private Sub EvtClass1_Evt1()
    '{...Code für das ausgelösten Ereignis}
End Sub
 
Private Sub EvtClass1_Evt2(ByVal Par1 As Single, ByRef Cancel As Boolean)
    '{...Code für das ausgelösten Ereignis}
    Cancel = True    ' in diesem Beispiel ist es möglich zeitaufwendige Prozesse durch "Cancel" abzubrechen.
End Sub

Beispiel

Dieses Beispiel enthält 2 Klassen, eine als Auslöser und eine als Ausführer von Ereignissen.

'======== "Class1": Klasse der Ereignis-Quelle
 
'-------- Deklaration
 
'-- Ereignisse deklarieren
Public Event Evt1()                                              ' Ein Event wurde deklariert
Public Event Evt2(ByVal Par1 As Single, ByRef Cancel As Boolean) ' Cancel kann hier als Abbruchs-Variable verwendet werden
 
 
'-------- Code
 
'-- Ist eine Test-Prozedur die Ereignisse auslöst
Public Sub TestEvt1(ByVal Par1 As Long)
  Dim Cancel As Boolean
 
    '{... Code mit Schleifen-Wiederholung und langer Laufzeit}
 
    RaiseEvent Evt1                       ' Ereignisse werden ausgelöst
    RaiseEvent Evt2(Par1, Cancel)
    If Cancel Then Exit Sub               ' Bricht die Prozedur ab
 
    '{... Code mit Schleifen-Wiederholung und langer Laufzeit}
 
End Sub
 
 
 
'======== "Class2": Klasse der Ereignis-Verarbeitung
 
'-------- Deklaration
Private WithEvents EvtClass1 As Class1  ' Es wird deklariert das in dieser Klasse Ereignisse aus einer anderen Klasse "Class1" ausgelöst werden können. Dies ist aber noch kein Instanziertes Objekt, sondern nur eine Deklaration, es werden noch keine Ereignisse ausgelöst.
 
 
'-------- Code
 
'-- Aktivieren der Ereignisausführung bei der Initialisierung
Private Sub Class2_Initialize()
    'Dim EvtClass1 As New Class1   ' Diese Deklaration einer WithEvents-Variable ist nicht zugelassen.
    Set EvtClass1 = New Class1     ' hier wird aus dem Deklarierten WithEvents-Objekt eine Instanz erzeugt. Erst jetzt werden Ereignisse ausgeführt.
End Sub
 
 
'-- Ereignisausführung
Private Sub EvtClass1_Evt1()
    Debug.Print "EvtClass1_Evt1"
    '{...Code }
End Sub
 
Private Sub EvtClass1_Evt2(ByVal Par1 As Single, ByRef Cancel As Boolean)
    Debug.Print "EvtClass1_Evt2" ' Wert aus der Ereignisquelle können über die Parameter verwandet werden.
    '{...Code }
    Cancel = True    ' in diesem Beispiel ist es möglich zeitaufwendige Prozesse über "Cancel" abzubrechen.
End Sub

Objekt

Nun können von einer Klasse Objekte erzeugt werden.

  • Wichtig ist nun das unterscheiden werden muß wischen deklarierten und instanziert¦referenziert Objekt-Variabeln. Während ein Standard Daten-Typ bereitsteht in dem Moment wo durch die Dim Deklaration Speicher zugewiesen wurde, kann ein Objekt nach einer Dim Deklaration zwar den Speicher reservieren, dennoch aber noch auf Nichts -> Nothing verweisen.
  • Dabei werden 2 Arten der Deklaration unterschieden, die Instanz einer Klasse und die Referenz zu einem Objekt. Für die Benutzung spielt dies keine so große Rolle, aber für die Geschwindigkeit.
    • Die Instanz ist sie Verkörperung einer Klasse zu einem Objekt. Sie enthält die tatsächlichen Daten des Objekts.
    • Die Referenz hingegen ist ein Verweis auf ein bereits bestehendes Objekt, sie enthält selbst die Daten nicht, sondern verweist intern über ein Zeiger auf das Tatsächliche Instanzierte Objekt welches die Daten enthält. Deshalb sind Referenzen auch langsamer als Instanzen da die Daten auf die sie verweisen erst geholt werden müssen bevor sie verwendet werden können.
    • Dabei übernimmt VB6 vieles auch automatisch, was in der Praxis manchmal auch vermissend und sogar zu problematisch sein kann. VB6 erzeugt Instanzen auf die zugegriffen wird automatisch, und zerstört¦löscht diese auch automatisch wenn keine verweise mehr auf die Instanz existieren. Es ist also auch Aufgabe des Programmierers die Codes so zu schreiben das er den Überblick über die Existenz von Objekten behalten kann. Am Ende des Programms sollten alle Objekte auf Nothing gesetzt werden. Auch da beim beenden des Programms alle Objekte gelöscht sein sollten.
      (Ein Beispiel ist hier das beenden eines Programms mit End. Da das Programm so abrupt unterbrochen wird, verbleiben Objekte also auch Formulare im Speicher).



  • Im Umgang mit Objekten müssen einige Dinge berücksichtigt werden und können so auch die Ausführungsgeschwindigkeit erhöhen.
    • Objekte sollten wenn möglich während der Compilierungszeit auflösbar sein, also explizite Deklaration von Kassen verwenden und nicht polymorphen Daten-Typen wie Object oder Variant. Dadurch fallen die zur Laufzeit sonst nötigen Überprüfungen weg. Zudem fallen mögliche Laufzeit Fehler weg die durch Objekte mit falschen Klassen-Zugehörigkeit entstehen könnten.
    • Die Hierarchie der Strukturen werden durch "." Punkte getrennt. VB6 führt dabei jedes mal Operationen aus, was um so langsamer ist je mehr Punkte verwendet werden. Wird dieses mit einem With Block verkürz, ist nicht nur die Schreibweise vereinfacht sondern auch die Ausführung schneller.
    • Temporäre-Variable verwendet um tief verschachtelte Elemente zur Berechnung zu verwenden (ähnlich wie man auch zugriffe auf Array-Elemente beschleunigen kann wenn man die Werte zwischenspeichert.)



  • Da Objekte instanziert¦referenziert werden müssen, ist es auch möglich das ein dekoriertes Objekt auch "Nichts -> Nothing" enthält.
    • Wird versucht auf ein leeres Objekt zuzugreifen wird ein Lautzeitfehler auftreten, deshalb ist es sinnvoll in solchen Fällen zuerst zu prüfen ob das Objekt überhaupt etwas enthält, (und wenn, dann kann man auch noch prüfen was genau).



  • Wird die Instanz erzeugt, tritt ein Initialize() Ereignis auf.
    Wird die Instanz gelöscht¦zerstört tritt ein Terminate() Ereignis auf.
  • Auch auf Objektnamen kann With angewendet werden.
  • Objekte können auch in Arrays deklariert werden.
  • Es können zwei polymorphe Daten-Typen verwendet werden statt einer expliziten Deklaration mit einem Klassennamen. Polymorphe Typen können nur während der Laufzeit (langsam) und nicht schon während der Compilierungszeit (schneller) aufgelöst werden. Zur Compilierungszeit auflösbare Variablen können über DispID oder virtual-table¦vtable aufgelöst werden. (Da VB6 keine Vererbung unterstützt ist dies die schnellste Variante.)
    • Object kann alle arten von Objekten aufnehmen, unabhängig von deren Klasse.
    • Variant kann sowohl Objekte wie auch Standard Daten-Typen aufnehmen.



  • Es gibt Unterschiede in der Verwendung von Dim Set und New.
Code ......................... Beschreibung
Dim ObjName As New ClassName Deklariert die Objekt-Variabe und bereitet eine Instanz vor, erzeugt sie aber noch nicht und "Class_Initialize()" Ereignis wird noch nicht ausgelöst. Die Instanz wird erst dann erzeugt wenn das erste man auf da Objekt zugegriffen wird.
Dim ObjName As ClassName Deklariert nur die Objekt-Variabe und bestimmt welcher Klasse sie angehört, Instanziert wird nichts. Die Deklaration sichert dabei am das Objekt-Variabe immer mit dem richtigen Klassen-Typ verwendet wird.
Set ObjName = New ClassName Deklariert die Objekt-Variabe und bestimmt welcher Klasse sie angehört, und erzeugt eine Instanz, "Class_Initialize()" Ereignis wird ausgelöst.
Set ObjName = ObjName2 Erzeugt ein Reverenz-Objekt und keine Instanz eines Objekts, also nur ein Verweis. Ändert sich Werte in der Instanz, ändern sich diese auch für alle Reverenz-Objekte die ja nur auf die Instanz verweisen. "Class_Initialize()" Ereignis in ObjName wird ausgelöst.
Set ObjName = Nothing Das Objekt wird freigegeben. Gibt es keine weiteren Referenzen mehr wird die Instanz des Objekt gelöscht¦zerstört. "Class_Terminate()" Ereignis in ObjName wird ausgelöst.
ObjName1 = ObjName2 Fehler: Das Kopieren des Inhalts eines Objekts auf ein anderes (ähnlich wie bei einem Type) ist so leider nicht möglich.



'---- Varianten der Objekt-Erzeugung
 
'-- Dim-New Deklaration
    Dim Obj1 As New Class1   ' hier wird die Variable "Obj1" von der Klasse "Class1" Deklariert, und eine Instanz vorbereiten aber nicht erzeugt
    Obj1.var1 = 1            ' die Instanz wird jetzt beim ersten Zugriff auf das Objekt erzeugt, "Class_Initialize()" Ereignis wird ausgeführt
 
 
'-- Set-New Deklaration, (dies ist die bevorzugte Schreibweise, da mit "Dim" immer nur deklariert wird, und "Set" die Instanzierung vornimmt.)
    Dim Obj1 As Class1       ' hier wird nur die Variable "Obj1" von der Klasse "Class1" deklariert, keine Instanz
    Set Obj1 = New Class1    ' Objekt wird deklariert und die Instanz gleich erzeugt, "Class_Initialize()" Ereignis wird ausgeführt
    Obj1.var1 = 1            ' alles steht bereit
 
 
'-- Set Deklaration (Objekt-Referenzen)
    Dim Obj1 As Class1
    Dim Obj2 As Class1
 
    Set Obj1 = New Class1    ' Objekt wird deklariert und die Instanz gleich erzeugt, "Class_Initialize()" Ereignis wird ausgeführt
    Set Obj2 = Obj1          ' Objekt-Referenz wird erzeugt, "Obj2" verweist auf "Obj1"
    Obj1.var1 = 1            ' Änderungen sind für "Obj1" und "Obj2" sichtbar.
    Debug.Print Obj2.var1
 
 
'-- Freigeben
    Set Obj1 = Nothing
 
 
'-- Fehler
    Dim Obj1 As Class1       ' hier wird nur die Variable "Obj1" von der Klasse "Class1" deklariert, keine Instanz
    Obj1.var1 = 1            ' dies verursacht ein Fehler den es existiert noch keine Instanz

Allgemeine Objekt-Typen

Typ Anwendung
Object Universaltyp, Alle Objekte
Variant Universaltyp, ist eigentlich kein Objekt aber kann auch Objekte aufnehmen
Form Alle Formulare in Anwendungen (einschließlich untergeordneter MDI-Formulare und des MDI-Formulars)
Control Alle Formular-Steuerelemente in Anwendungen
MDIForm Ein MDI-Formular in der Anwendung (wenn eines enthalten ist)

Fehler

  • Einige Objekt Deklarationen sind nicht zulässig.


'-- Folgende Elemente können nicht mit New erstellen werden
Dim Obj1 As New Integer     ' keine Standard Daten-Typen.
Dim Obj1 As New Control     ' keine allgemeiner Objekttypen.
Dim Obj1 As New ListBox     ' keine spezifische Steuerelementtypen.
Dim Obj1 As New lstNames    ' keine spezifischer Steuerelemente.

Objekte und Klassen ermitteln

  • Generische Objekt-Variablen (also mit As Object deklarierte Variablen) können Objekte unterschiedlichster Klassen enthalten. Ebenso können Variablen, die mit den integrierten Form- und Control-Typen von Visual-Basic deklariert wurden, Formulare und Steuerelemente unterschiedlicher Klassen enthalten.
  • Da ein Objekt unterschiedliche Klassen angehören können, enthalten sie auch unterschiedliche Daten und Funktionen. Um also korrekt auf ein spezielles Objekt reagieren zu können muß man dessen Klasse feststellen können.
    • Is Schlüsseltort prüft in einem If-Then ob zwei Objekte das gleiche Objekt abbilden¦verweisen.
    • TypeOf-Is Schlüsseltort prüft in einem If-Then ob ein Objekte einer Bestimmten Klasse angehört. TypeOf kann nur in If Anweisungen verwendet werden, es ist ein Schlüsselwort das zum If-Then gehört.
    • TypeName() Funktion gibt den Klassenname als String zurück, und kann daher überall verwendet werden. Dies ist aber durch die String-Operationen langsamer als TypeOf.


    ' Prüf ob es such um das gleiche Objekt handelt
    If Obj1 Is Obj2 Then
    End If
 
    ' Prüft ob es sich um ein Objekt aus der Klasse Class1 handelt
    If TypeOf Obj1 Is Class1 Then
    End If
 
    ' Prüft über den String-Name ob es sich um ein Objekt aus der Klasse Class1 handelt
    If TypeName(Obj1) = "Class1" Then
    End If

Komponenten

WRITEME

CreateObject

WRITEME

GetObject

WRITEME

Collection-Klasse

  • Collection ist eine Klasse die es ermöglicht mehrere Objekte ein einer Liste zusammenzufassen, wobei die Objekte einer beliebigen Klasse angehören können.
  • Die Liste beginnt mit 1.
  • Die Item Elemente sind vom Daten-Typ Variant, könne also beliebige Informationen aufnehmen (Standard Daten-Typen, Arrays und Objekte, nicht aber benutzerdefinierte Typen).
  • Und beim Einfügen und Löschen müssen Collections nicht wie Arrays neu redimensioniert werden. Ein Beispiel wäre die Auflistung aller Formularelemente in einem Formular.
  • Da Collection verschiedene Objekte aufnehmen und wieder löschen kann, und sich so die Reihenfolge und der Index ändert, ist es sinnvoll ein eindeutiger Schlüsselname festzulegen. Dies muß ein String sein, werden Zahlen als Schlüsselname verwendet sollten diese mit CStr() umgewandelt werden. Ein Schlüsselwort muß nicht unbedingt angeben werden. Über den Index sollte aber nur dann auf ein spezielles Element zugegriffen werden wenn man sicher ist das sich die Position eines eine einmal hinzugefügtes Element nie verändert.
  • Da der Zugriff in die Liste langsam ist, macht es Sinn ein Item auf eine Objekt-Variable (Dim deklariert da zur Compilierungszeit auflösbar) zu verwiesen, wenn mehrere Operationen damit durchgeführt werden. (Objektverweise in