AW: Schade, aber vielen lieben Dank! owT ;-)
05.03.2012 01:52:11
Nepumuk
Hallo,
nein, das geht auch mit Set nicht. Nochmal, es gibt eine "Grundklasse" Userforms aus der FM20.dll. Diese Klasse ist eine Schnittstelle aus der sich die deine Userforms ableiten. Hier mal ein Beispiel für so eine Schnittstelle die ich benutze um aus einer Datenbank zu lesen:
' **********************************************************************
' Modul: clsDatabaseRead Typ: Klassenmodul
' **********************************************************************
Option Explicit
Option Base 0
Option Compare Text
Public Property Let AppendixCommit(ByVal RHS As String)
End Property
Public Property Let AppendixHistory(ByVal RHS As String)
End Property
Public Property Get DataArrayData() As clsDatabaseDataArray
End Property
Public Property Get DataArrayForced() As clsDatabaseDataArray
End Property
Public Property Set Database(ByVal RHS As Object)
End Property
Public Property Let DatabaseTimeOut(ByVal RHS As Long)
End Property
Public Property Let ProjectAvailable(ByRef RHS() As Long)
End Property
Public Property Get ProjectAvailable() As Long()
End Property
Public Property Let ProjectKey(ByVal RHS As String)
End Property
Public Property Let ReadArchive(ByVal RHS As Boolean)
End Property
Public Property Let ReadHistory(ByVal RHS As Boolean)
End Property
Public Property Let SingleProject(ByVal RHS As Boolean)
End Property
Public Property Get DatabaseError() As clsDatabaseError
End Property
Public Property Get DatabaseMessage() As clsDatabaseMessage
End Property
Public Property Let TableData(ByVal RHS As String)
End Property
Public Property Let TableForced(ByVal RHS As String)
End Property
Public Function ReadData() As Boolean
End Function
Weil unterschiedliche Datenbanken unterschiedlichen Code benötigen (die können zwar alle SQL, aber ganz gleich sind sie nicht) habe ich eine Schnittstelle in der alle Eigenschaften und Methoden definiert sind. Aus dieser Schnittstelle leite ich nun die verschiedenen Klassen zum Lesen in verschiedenen Datenbanken ab. Das sieht dann so aus (Ausschnitt):
' **********************************************************************
' Modul: clsDatabaseReadADODB Typ: Klassenmodul
' **********************************************************************
Option Explicit
Option Base 0
Option Compare Text
Implements clsDatabaseRead
Private mstrAppendixCommit As String
Private mstrAppendixHistory As String
Private mobjData As clsDatabaseDataArray
Private mobjForced As clsDatabaseDataArray
Private mobjDatabase As Object
Private mobjDatabaseError As clsDatabaseError
Private mobjDatabaseMessage As clsDatabaseMessage
Private mlngDatabaseTimeOut As Long
Private mlngProjectAvailable() As Long
Private mstrProjectKey As String
Private mblnReadArchive As Boolean
Private mblnReadHistory As Boolean
Private mblnSingleProject As Boolean
Private mstrTableData As String
Private mstrTableForced As String
Private Sub Class_Initialize()
Const PROCEDURENAME = "Class_Initialize: clsDatabaseReadADODB"
If gblnTraceFlag Then Call LOGGER_Log_Trace(PROCEDURENAME)
If gblnWorkFlag Then On Error GoTo ErrorHandling
If gblnWorkFlag Then Application.EnableCancelKey = xlDisabled
If gblnLoopActive And Not gblnLoopNoError Then Exit Sub
Set mobjData = New clsDatabaseDataArray
Set mobjForced = New clsDatabaseDataArray
Set mobjDatabaseError = New clsDatabaseError
Set mobjDatabaseMessage = New clsDatabaseMessage
Exit Sub
ErrorHandling:
Call mobjDatabaseError.Add(Erl, Err.Number, Err.Description, PROCEDURENAME)
End Sub
Private Sub Class_Terminate()
Const PROCEDURENAME = "Class_Terminate: clsDatabaseReadADODB"
If gblnTraceFlag Then Call LOGGER_Log_Trace(PROCEDURENAME)
If gblnWorkFlag Then On Error GoTo ErrorHandling
If gblnWorkFlag Then Application.EnableCancelKey = xlDisabled
If gblnLoopActive And Not gblnLoopNoError Then Exit Sub
Set mobjData = Nothing
Set mobjForced = Nothing
Set mobjDatabaseError = Nothing
Set mobjDatabaseMessage = Nothing
Set mobjDatabase = Nothing
Exit Sub
ErrorHandling:
Call mobjDatabaseError.Add(Erl, Err.Number, Err.Description, PROCEDURENAME)
End Sub
Private Property Let clsDatabaseRead_AppendixCommit(ByVal RHS As String)
mstrAppendixCommit = RHS
End Property
Private Property Let clsDatabaseRead_AppendixHistory(ByVal RHS As String)
mstrAppendixHistory = RHS
End Property
Private Property Get clsDatabaseRead_DataArrayData() As clsDatabaseDataArray
Set clsDatabaseRead_DataArrayData = mobjData
End Property
Private Property Get clsDatabaseRead_DataArrayForced() As clsDatabaseDataArray
Set clsDatabaseRead_DataArrayForced = mobjForced
End Property
Private Property Set clsDatabaseRead_Database(ByVal RHS As Object)
Set mobjDatabase = RHS
End Property
Private Property Let clsDatabaseRead_DatabaseTimeOut(ByVal RHS As Long)
mlngDatabaseTimeOut = RHS
End Property
Mit dem Schlüsselwort Implements wird der Bezug auf die Schnittstelle definiert. Das Beispiel ist die Klasse zum Lesen per ADODB aus einer SQL-Server - Datenbank. Es gibt daneben noch Klassen zum Lesen aus Oracle- und Accress-Datenbanken. Vorteil ist, es gibt nur ein Hauptprogramm für alle Datenbanken, da darin immer nur auf die Schnittstelle zugegriffen wird. Hinter der Schnittstelle verbirgt sich je nach Datenbank eine andere Klasse. Ich muss also im Hautprogramm nur eine Case-Anweisung einfügen um die neue Leseklasse an die Schnittstelle zu verweisen, und eine neue Leseklasse fertig.
Angefangen hat das ganze mit der MSDN-Library für VB6.0, da hab ich das im Kapitel über Klassen gelesen, aber erst mal keine praktische Verwendung dafür gehabt. Erst mit dem Zugriff auf Datenbanken tat sich die Notwendigkeit auf den Programmieraufwand zu reduzieren.
Lukas hat auf meine Anregung hin mal was dazu geschrieben:
http://www.office-loesung.de/ftopic253106_0_0_asc.php
Das meiste was du dazu im Netz lesen kannst bezieht sich auf VB.net und die C-Dialekte da ist das zwar ganz ähnlich, aber in den Sprachen gibt es noch zusätzliche Möglichkeiten.
An dem obigen Code wird auch vielleicht klar was du machst. Du übergibst die Klasse "clsDatabaseReadADODB" an die Schnittstelle "clsDatabaseRead". Diese hat aber keine Variablen zum Speichern z.B. der "ProjectAvailable"-Eigenschaft. Darum wäre auch der Versuch diese aus der Klasse zu lesen zum Scheitern verurteilt weil sie immer leer ist.
Also eigentlich ist dein Userform nur eine abgeleitete Klasse aus der abgeleiteten Klasse UnknownX (das X steht für eine laufenden Nummer). Deine Userform-Klasse hat die Eigenschaften und Methoden aus der Unknown-Klasse geerbt. Darum ist es anderes als in VBA mit Implements nicht zwingend erforderlich alle Eigenschaften und Methoden im Code zu definieren. Aber ich denke das geht jetzt zu weit.
Gruß
Nepumuk