Hallo Liebes Forum,
Ich habe ein Problem das mich zur Verzweiflung bringt.
ich versuch es mal zu erklären.
Und zwar hab ich ein Modul geschrieben wo ein paar globale variablen und Funktionen drin sind
nix besonderes
nun benutze ich diese variablen und Funktionen in Formularen nix besonderes
Plötzlich funktionierte eine Funktion nicht mehr. nach suchen und suchen bin ich darauf gestoßen
mir die Definition der variablen im VBA code anzeigen zu lassen
alle variablen funktionieren bis auf die aus besagter Funktion dort steht dann,
" sprung nicht möglich da in Bibliothek vorhanden auf die derzeit nicht verwiesen wird "
der versuch diesen verweis hinzuzufügen scheiterte da dann die Fehlermeldung
"Name steht im Konflikt mit vorhandenen modul oder projekt"
woran kann das liegen ?
und wie kann ich es beheben ?
neuere variablen funktionieren noch einwandfrei
ältere variabeln nur mit alten vba code
wird jedoch die abfrage geändert taucht der fehler wieder auf
mir scheint es als hätte er eine ältere Bibliothek/Modul gespeichert oder bezieht sich auf die ältere Version ????
ich habe keine Ahnung mehr
ich hoffe ihr habt mein Problem verstanden und könnt mir helfen.
MfG
Joe0301
Hallo,
poste mal das gesamte Modul, das Du "geschrieben" hast und kennzeichne die Codezeile, an der die Fehlermeldung auftritt.
Mach zudem einen Screenshot vom Verweis-Fenster.
Zitatältere variabeln nur mit alten vba code
Was ist "alter VBA-Code"?
Option Compare Database
Option Explicit
Public Var1 As String
Public Var2 As String
Public Var3 As String
Public Var4 As String
Public Var5 As String
Public Function IstLeer(Ausdruck As Variant) As Boolean
'Quelle: http://www.dbwiki.net/
If Len(Trim(Ausdruck & vbNullString)) = 0 Then
IstLeer = True
Else
IstLeer = False
End If
End Function
Public Function OptionEinstellen(strOptionsname As String, strOptionswert As String) As Boolean
Dim db As DAO.Database
Set db = CurrentDb
db.Execute "UPDATE tab_optionen SET Optionswert = '" & strOptionswert & "' WHERE Optionsname = '" & strOptionsname & "'", dbFailOnError
If db.RecordsAffected = 1 Then
OptionEinstellen = True
Exit Function
Else
If db.RecordsAffected > 1 Then
db.Execute "DELETE FROM tab_optionen WHERE Optionsname = '" & strOptionsname & "'", dbFailOnError
End If
db.Execute "INSERT INTO tab_optionen(Optionsname, Optionswert) VALUES('" & strOptionsname & "', '" & strOptionswert & "')", dbFailOnError
If db.RecordsAffected = 1 Then
OptionEinstellen = True
Exit Function
End If
End If
End Function
Public Function fct1() As String
fct1 = Var1
End Function
Public Function fct2() As String
fct2 =Var2
End Function
Public Function fct3() As String
fct3 = Var3
End Function
Public Function fct4() As String
fct4 = Var4
End Function
Public Function fct5() As String
fct5 = Var5
End Function
'Funktion zum einlesen von .txt - Dateien. Wird für das Info Fenster verwendet
Public Function LoadText(ByVal FileName As String) As String
Dim F As Long, L As String, Res As String
F = FreeFile
Open FileName For Input As #F
While Not EOF(F)
Line Input #F, L
Res = Res & L & vbNewLine
Wend
Close #F
LoadText = Res
End Function
Das modul wie gesagt nix besonderes
Private Sub Befehl14_Click()
DoCmd.OpenForm "fm_datensatz_bearbeiten", , , "ID=" & Me!ID
Var3 = Me!Text19
Call fct3
End Sub
Das ist der code der nicht/halb funktioniert
das Formular wird geöffnet
jedoch die variable nicht gespeichert.
mit Rechtsklick auf Var3 unter Definition
kommt die Fehlermeldung wie erwähnt sprung nicht möglich.
folgend im anhang nochmal das verweisfenster
mit alten VBA Code meinte ich, das var3 in einem Formular das ich vor einem Monat geschrieben habe noch funktioniert
nur in einem neuen Formular nicht mehr.
MfG
Joe0301
Hallo,
was willst Du denn mit den VarX-Variablen und den fctX()-Funktionen bezwecken?
Die erfüllen im gezeigten Code gar keinen Sinn.
ZitatPrivate Sub Befehl14_Click()
DoCmd.OpenForm "fm_datensatz_bearbeiten", , , "ID=" & Me!ID
Var3 = Me!Text19 'Wo (in welchem Formular) befindet sich "Text19" ?
Call fct3 ' "Call" wird nur zum Aufruf für SUB-Prozeduren verwendet.
' Aufruf einer Funktion:
Msgbox "Der Wert aus Feld 'Text19' lautet: " & fct3
'gleichwertig ist hier: Msgbox "Der Wert aus Feld 'Text19' lautet: " & Var3
End Sub
Hallo,
Der code steht in einem Endlosformulas (fm_userdatensätze_anzeigen)
das Formular das geöffnet wird (fm_datensatz_bearbeiten) benötigt eine Abfrage die als Bedingung in einem Feld fct3() hat
der Code an sich Funktionierte
dazu nochmal zur Fehlerentstehung
ich fertigte eine Kopie von fm_userdatensätze_anzeigen an
in dieser Kopie funktionierte es plötzlich nicht mehr
und nach rechtsklick auf die Var3 dann auf Definition kommt besagte Fehlermeldung
Zitat
" sprung nicht möglich da in Bibliothek vorhanden auf die derzeit nicht verwiesen wird "
geh ich in fm_benutzeroberfläche mit rechtsklick auf die Var3 und dann auf Definition öffnet er das gezeigte Modul und makiert wie es soll Var3 Blau und zeigt mir an ja alles definiert
nur bei der Kopie funktioniert das nicht, mittlerweile tritt der fehler auch immer häufiger auf nach dem ich z.b. eine Abfrage geändert habe...
MfG
Joe0301
Hallo Joe,
Zitatdas Formular das geöffnet wird (fm_datensatz_bearbeiten) benötigt eine Abfrage die als Bedingung in einem Feld fct3() hat
Den Wert könntest du doch auch einfach per OpenArgs übergeben.
Oder, wenn du schon mit globalen Variablen (so verstehe ich deinen Code
jedenfalls) arbeiten willst, stelle diese auf öffentliche Propertys um.
Im Prinzip, statt Dim und Funktionsaufruf (Luftcode):
Private m_Var1 as String
'muss in den Modulkopf !
Public Property Set Var1(neuerWert as String)
m_Var1 = neuerWert
End Property
Public Property Get Var1() As String
Var1 = m_Var1
End PropertyIMO einfacher und sicherer wäre auch diese Variante möglich
Public Property Get Var1() As String
If m_Var1 = vbNullString Then
m_Var1 = Forms!fm_userdatensätze_anzeigen!Text19
End If
Var1 = m_Var1
End Propertygruss ekkehard
Ich vermute eher, dass eines Deiner Module oder das VBA-Projekt selbst einen unglücklichen Namen hat.
FWIW: die Funktionen können schon sinnvoll sein, wenn sie in Abfragen genutzt werden. Dann sollte man sie aber ordentlich taufen und für den Rückgabewert Variant als Datentyp vereinbaren, damit auch Null-Werte genutzt werden können.
Hallo, Danke für die antworten
@Beaker s.a
Danke für den Tipp, das werde ich mir auf jedenfall mal ansehen ob das sinnvoll für meine Anwendungen wäre, jedoch in meinem momentan engen Zeitfenster leider nicht komplett umsetzbar :(
@Lachtaube
Danke für die Antwort was verstehst du unter "unglücklichen" Namen, soll ich gucken ob andere Textfelder oder Felder in Tabellen den selben Namen haben ? oder wie ist das zu verstehen.
MfG
Joe0301
Ein unglücklich gewählter Name eines Moduls oder des Projekts wäre gleichlautend dem Namen einer globalen Variablen oder Methode (Sub/Function/Property).
Wie heißt denn Dein VBA-Modul?
Hallo,
Danke Danke Danke,
Ja das war es! der Variablenname entsprach der einer Feldes.
Ich hatte den Feldnamen im späterern Verlauf nochmal geändert, weswegen der Fehler erst später auftauchte
und die bereits bestehenden Definitionen noch gültig waren. Das erklärt zumindestens alles :D
MfG
Joe0301
@ekkehard,
wenn du erlaubst, würde ich gerne Property Set gegen Property Let ersetzen. ;)
Gruß
Josef
Hallo Josef,
Ja gerne :)
Mir war das später auch noch eingefallen, konnte es aber
nicht mehr ändern.
gruss ekkehard
Hallo ekkehard,
weil wir gerade beim Thema Properties sind:
Ich habe die Property Let/Get-Variante bisher nur als Verwendung in einem Klassenmodul gekannt, z.B.
http://www.accessblog.de/Archive/tag/globale-variablen (http://www.accessblog.de/Archive/tag/globale-variablen)
Du verwendest den Code aber nur in einem Standardmodul. Funktioniert ja auch, wie man sieht.
Ich frage mich nun, was ist der Unterschied (Vorteile/Nachteile) zwischen den beiden Varianten? Kannst du da was dazu sagen?
Gruß
Josef
Da Properties nur eine spezielle Form von Methoden darstellen, können diese auch genauso gut mit Funktionen bzw. Prozeduren abgebildet werden.
Properties in einem globalen Modul stehen anwendungsweit zur Verfügung (typische Beispiele: Datenbank-Instanz, Angemeldeter Benutzer, Bildschirmauflösung, Gewählte Sprachumgebung, etc.); Properties in einem Klassenmodul benötigen eine Klasseninstanz (i.d.R. Eigenschaften, die von Instanz zu Instanz variieren können).
Dem kann ich Nichts mehr hinzufügen.
...ich schon, denn Properties sind nichts anderes als Eigenschaften, Methoden dagegen eher Prozeduren bzw. Funktionen. Wie da eine Property "eine Art Methode" sein könnte, ist für mich nicht nachvollziehbar
Außer der Semantik gibt es keinen Unterschied zwischen Properties und Methoden.Option Compare Database
Option Explicit
Private mFoo
Private mBar
Public Property Get Foo()
Foo = mFoo
End Property
Public Property Let Foo(mValue)
mFoo = mValue
End Property
Public Function GetBar()
GetBar = mBar
End Function
Public Sub SetBar(mValue)
mBar = mValue
End Sub FWIW: Wer sich mit der Implementierung von COM-Interfaces beschäftigt, wird feststellen oder wissen, dass Direct-Interfaces (abgeleitet von IUnkown (https://msdn.microsoft.com/de-de/library/windows/desktop/ms680509(v=vs.85).aspx)) keine Properties enthalten können. Properties stehen erst in von IDispatch (https://msdn.microsoft.com/de-de/library/windows/desktop/ms221608(v=vs.85).aspx) abgeleiteten Interfaces (via Invoke-Methode) zur Verfügung.
Danke an alle für die Antworten,
und danke an Lachtaube für die ausführlichen Erklärungen.
Gruß
Josef
@Lachtaube,
nachdem du alles so schön erklärt hast, ;) möchte ich doch noch einmal auf meine Ausgangsfrage zurückkommen. Mir geht es um das oft diskutierte Thema, statt globaler Variablen z.B. Properties zu verwenden.
ZitatProperties in einem globalen Modul stehen anwendungsweit zur Verfügung (typische Beispiele: Datenbank-Instanz, Angemeldeter Benutzer, Bildschirmauflösung, Gewählte Sprachumgebung, etc.); Properties in einem Klassenmodul benötigen eine Klasseninstanz (i.d.R. Eigenschaften, die von Instanz zu Instanz variieren können).
Wenn ich nun statt der Variante mit dem Klassenmodul die Variante mit dem globalen Modul nehme, hätte ich doch weniger Schreibarbeit, weil ich
- keine Objektvariable im Klassenmodul brauche, z.B. Public glob As Klasse1
- das Klassenobjekt nicht setzen brauche, z.B. Set glob = New Klasse1
- und beim Aufruf keine Klasse angeben muss, z.B. glob.Benutzer = "Foo"
Brauche ich dann das aufwändigere Klassenmodul überhaupt, so wie es in den ganzen Beispielcodes im Internet angepriesen wird?
@Joe0301,
ich hoffe du verzeihst mir, dass ich deinen Thread etwas "missbrauche". ;)
Gruß
Josef
Hallo!
ZitatMir geht es um das oft diskutierte Thema, statt globaler Variablen z.B. Properties zu verwenden.
Ein Beispiel:
Angenommen es gibt eine Tabelle in der Anwendungseinstellungen gespeichert sind. Diese Einstellungen je Einsatz der Anwendung unterschiedlich, aber einmal eingestellt ändern sich diese Werte nur selten - zumindest ändern sich diese Werte nicht während der Anwendungslaufzeit.
Man könnte bei Bedarf mit DLookup & Co. die Werte immer aus der Tabelle auslesen, oder man hält sich den Wert im Speicher, damit man nicht so oft auf die Tabelle zugreifen muss.
private m_TemplatePath as String
public Property Get TemplatePath() as String
if len(m_TemplatePath) = 0 then
m_TemplatePath = ReadConfigDataFromTable("TemplatePath")
end if
TemplatePath = m_TemplatePath
end PropertyIm restlichen Code verwendest man die Property-Prozedur wie eine globale Variable.
Würde man eine globale Variable verwenden, müsste man sich darum kümmern, dass diese vor Verwendung initialisiert (mit passendem Wert befüllt) wurde.
Das übernimmt im obigen Fall die Property-Prozedur.
Ob diese Property-Prozedur in einem Standardmodul oder eine (selbstinstanzierenden) Klasse ist, ist meiner Meinung nach eher Geschmacksfrage.
Vergleich:
dim TemplateFile as String
TemplateFile = TemplatePath & "\Projekthandbuch.dotx"
' vs.
TemplateFile = Config.TemplatePath & "\Projekthandbuch.dotx"Bei der Klassenvariante ist im Code vielleicht etwas besser erkennbar, dass das ein Wert aus der Anwendungskonfiguration ist.
mfg
Josef
Hallo Josef,
danke für deine Antwort,
Zitatoder man hält sich den Wert im Speicher
aber man könnte doch den Wert auch über eine globale Variable im Speicher halten, z.B.
Public TemplatePath As String
Private Sub Form_Open(Cancel As Integer)
If Len(TemplatePath) = 0 Then
TemplatePath = ReadConfigDataFromTable("TemplatePath")
End If
End Sub
Oder welchen Vorteil hat deine Variante
Private m_TemplatePath As String
Public Property Get TemplatePath() As String
If Len(m_TemplatePath) = 0 Then
m_TemplatePath = ReadConfigDataFromTable("TemplatePath")
End If
TemplatePath = m_TemplatePath
End Property
gegenüber der obigen?
Gruß
Josef
Im vorliegenden Fall sorgt der Code selbst für eine gültige Initialisierung. Im Fall einer globalen Variablen wärest Du selbst für die Initialisierung verantwortlich. Bei einer handvoll globaler Variablen stellt das auch nicht unbedingt ein Problem dar - bei größeren Projekten verliert man aber schnell die Übersicht und handelt sich vermeidbare Fehler ein.
Ich stelle hier einmal das Motto auf: Soviel globale Variablen wie nötig und nicht so viele wie möglich.
Bei der Variante mit der globalen Variable musst du im Code dafür sorgen, dass diese vor der ersten Verwendung befüllt ist.
Wenn du das z. B. über ein Startformular regelst, musst du bei jeder neuen globalen Variable dafür sorgen, dass diese im Startformular initialisiert wird, und du musst dafür sorgen, dass das Startformular immer geladen wird.
=> du musst also beim Erstellen einer neuen Variable daran denken, dass diese auch geladen wird. Wenn du die Property-Prozedur verwendest, denkst du automatisch daran, weil der Prozedur-Code dafür sorgt und musst dir im restlichen Code keine Gedanken machen, ob die Initialisierung schon gelaufen ist.
Würde durch einen Laufzeitfehler der Variableninhalt der globalen Variable gelöscht, kommt ein falscher Wert bei der nächsten Verwendung an - außer du prüfst immer ob ein gültiger Wert enthalten ist => genau das macht die Property-Prozedur auch - aber eben nur an einer Stelle und nicht verteilt auf den restlichen Code.
Mit einer Property-Prozedur kannst du geprüft Werte übermitteln - sei es bei der Ausgabe als auch bei der Annahme.
Beispiel:
public property get AuswertungsMonat() as long
AuswertungsMonat = m_AuswertungsMonat
end property
public property Let AuswertungsMonat(byval NewValue as long)
if NewValue < 1 or NewValue > 12 then
err.Raise vbobjecterror, "AuswertungsMonat", NewValue & " ist kein gültiger Monat"
end if
m_AuswertungsMonat = NewValue
end property
Versuche das einmal mit einer globalen Variable umzusetzen und dabei sicherzustellen, dass an keiner einzigen Stelle im Code der Wert ungeprüft geändert wird.
Anm.: das gilt übrigens auch für die oben erwähnten Anwendungseinstellungen - diese Properties sind schreibgeschützt und können somit nirgends im Code irrtümlich verändert werden, solange es keine Let/Set-Prozedur gibt.
mfg
Josef
Hallo Lachtaube und Josef,
ich habe bisher nur den Code für die Steuerung der Properties gekannt, und immer wieder gehört, dass man sie "unbedingt ::)" statt globaler Variablen verwenden sollte, aber jetzt habe ich von euch mal praktische Gründe und Möglichkeiten (die Basics) für deren Verwendung erfahren.
Ich bedanke mich dafür.
Gruß
Josef