Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1252to1256
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

UserForm an Function übergeben

UserForm an Function übergeben
Martin
Hallo liebe Excelfreunde,
ich übergebe eine UserForm an eine Function, kann aber in der Function nicht richtig auf die UserForm zugreifen:
Code UserForm:
Private Sub UserForm_Initialize()
Call StrnDic            'Übergabe ohne UserForm
Debug.Print Me.Caption  'das geht
Call StrnDic(Me)        'Übergabe mit UserForm
End Sub
Code Modul1:

Function StrnDic(Optional UF As UserForm) As Object
If UF Is Nothing Then
Debug.Print "Keine UserForm übergeben"
Else
Debug.Print "UserForm '" & UF.Caption & " 'übergeben"   'geht nicht
'Debug.Print UserForm1.Caption  'geht
End If
End Function
Mir ist klar, dass ich den Namen der UserForm auch als String übergeben könnte. Es geht mir (mal wieder) nur ums Prinzip. Für Antworten wäre ich (wie immer) sehr dankbar.
Viele Grüße
Martin

7
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Benutzer
Anzeige
AW: UserForm an Function übergeben
04.03.2012 21:57:32
Josef

Hallo Martin,
Function StrnDic(Optional UF As Object) As Object
  If UF Is Nothing Then
    Debug.Print "Keine UserForm übergeben"
  Else
    Debug.Print "UserForm '" & UF.Caption & " 'übergeben"
  End If
End Function



« Gruß Sepp »

Anzeige
AW: UserForm an Function übergeben
04.03.2012 22:02:22
Martin
Hallo Josef,
zunächst vielen Dank für deine schnelle Antwort. Gut, bei der Übergabe als Objekt klappt es. Aber kannst du mir auch erklären, warum es bei der Übergabe direkt als UserForm (...worum es sich ja handelt) nicht klappt?
Viele Grüße
Martin
AW: UserForm an Function übergeben
04.03.2012 22:16:44
Josef

Hallo Martin,
das weiß wohl nur MS.

« Gruß Sepp »

Anzeige
Schade, aber vielen lieben Dank! owT ;-)
04.03.2012 22:23:54
Martin
owT
AW: Schade, aber vielen lieben Dank! owT ;-)
04.03.2012 23:20:11
Nepumuk
Hallo,
weil du damit deine Userform1 an das Interface - MSForms-Userform übergibst. Deine Klasse hat aber den Namen "Userform1". Also würde es so gehen:
Function StrnDic(Optional UF As UserForm1) As Object
Deine Userform1-Klasse ist eine abgeleitet (Stichwort - Implements) Klasse der MSForms-Userform-Klasse. Und ein Interface (Schnittstellen-Klasse) kann die Eigenschaften der daraus abgeleiteten Klasse nicht übernehmen. Beschäftigt euch mal ein bisschen mit Polymorphismus und Implementierung, dann wird das vielleicht klarer.
Gruß
Nepumuk
AW: Schade, aber vielen lieben Dank! owT ;-)
04.03.2012 23:44:54
Martin
Hallo Nepumuk,
ich bin nur ein Laie, aber schon bei der Übergabe der UserForm an die Function hatte mir irgendwie das "Set ... As ..." gefehlt. (Ich hoffe, dass ich jetzt nicht völlig daneben liege!)
Woher hast dein Wissen über "Polymorphismus und Implementierung" bezogen? Kannst du mir eine Lesequelle empfehlen?
Viele Grüße
Martin
Anzeige
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
Anzeige

Links zu Excel-Dialogen

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige