Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

UserForm an Function übergeben

Forumthread: 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
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
Anzeige
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
;
Anzeige
Anzeige

Infobox / Tutorial

UserForm an Function übergeben in VBA


Schritt-für-Schritt-Anleitung

  1. UserForm erstellen: Erstelle eine UserForm in deinem Excel-VBA-Projekt. Gehe dazu in den VBA-Editor (Alt + F11), klicke mit der rechten Maustaste auf „VBAProject (dein Projektname)“ und wähle „UserForm einfügen“.

  2. Code zur Initialisierung hinzufügen: Füge den folgenden Code in das UserForm-Modul ein. Dieser Code ruft die Funktion StrnDic auf und übergibt die UserForm.

    Private Sub UserForm_Initialize()
       Call StrnDic(Me) ' Übergabe mit UserForm
    End Sub
  3. Funktion erstellen: Erstelle eine Funktion im Modul, die die UserForm als Parameter akzeptiert. Achte darauf, die UserForm als Object zu deklarieren, um auf die Eigenschaften zugreifen zu können.

    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
  4. Testen: Starte die UserForm (F5 im VBA-Editor) und beobachte das Immediate-Fenster (Strg + G), um die Ausgabe zu sehen.


Häufige Fehler und Lösungen

  • Fehler: "Keine UserForm übergeben"

    • Lösung: Stelle sicher, dass du die UserForm korrekt übergibst. In der UserForm_Initialize-Methode muss Call StrnDic(Me) verwendet werden.
  • Fehler: "UserForm '...' übergeben" wird nicht angezeigt

    • Lösung: Überprüfe, ob die UserForm tatsächlich initialisiert ist und der Code in der UserForm_Initialize-Subroutine korrekt ist.

Alternative Methoden

Wenn du die UserForm nicht direkt übergeben möchtest, kannst du auch den Namen der UserForm als String übergeben. Hier ist ein Beispiel:

Function StrnDic(Optional UFName As String) As Object
    If UFName = "" Then
        Debug.Print "Keine UserForm übergeben"
    Else
        Debug.Print "UserForm '" & UFName & "' übergeben"
    End If
End Function

Du würdest dann Call StrnDic(Me.Name) in der UserForm verwenden.


Praktische Beispiele

Hier ist ein einfaches Beispiel für die Verwendung der StrnDic-Funktion:

Private Sub UserForm_Initialize()
    Call StrnDic(Me) ' Übergabe der UserForm
End Sub

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"
        MsgBox "Willkommen in der UserForm: " & UF.Caption
    End If
End Function

In diesem Beispiel wird zusätzlich eine MessageBox angezeigt, die den Titel der UserForm ausgibt.


Tipps für Profis

  • VBA Implements: Nutze das Implements-Schlüsselwort, um eine Schnittstelle zu definieren, die deine UserForms implementieren können. Dies ermöglicht eine bessere Struktur und Wiederverwendbarkeit deines Codes.

  • Debugging: Verwende Debug.Print, um Informationen während der Ausführung zu protokollieren. Dies hilft dir, den Fluss deines Codes besser zu verstehen und Fehler schneller zu identifizieren.


FAQ: Häufige Fragen

1. Warum kann ich nicht direkt auf die Eigenschaften der UserForm zugreifen? Die UserForm muss als Object oder spezifisch als UserForm1 übergeben werden, um auf ihre Eigenschaften zugreifen zu können.

2. Was ist der Unterschied zwischen der Übergabe als UserForm und als Object? Die Übergabe als UserForm gibt dir direkten Zugriff auf alle Eigenschaften dieser spezifischen Form, während die Übergabe als Object allgemeiner ist und möglicherweise nicht alle spezifischen Eigenschaften verfügbar macht.

3. Gibt es eine Möglichkeit, mehrere UserForms mit einer Funktion zu verwalten? Ja, du kannst eine Parameterliste oder eine Collection verwenden, um mehrere UserForms an die Funktion zu übergeben und sie innerhalb der Funktion zu verarbeiten.

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige