VB: Vergleiche und Entscheidungen funktionierten nicht

Dieser Thread ist Teil einer Diskussion zu einem Artikel:  Zum News-Artikel gehen

Fritz50

Stammgast
Hallo zusammen

Vergleiche und Entscheidungen funktionierten nicht. Eine Variante funktioniert, aber ich möchte wissen, warum die andere Lösung nicht funktioniert..
Die Funktion ist folgende: Aus einer Reihe von Werten sollen diese einer Gruppe zugeteilt werden. Die Werte sind in einer ComboBox aufgelistet. Abhängig wie die ComboBox intialisiert, funktioniert die Selektion oder eben nicht. Wenn die ComboBox aus einer Liste initialisiert wird. funktioniert die Selektion nicht. Wenn die ComboBox mit .AddItem gefüllt wird, funktioniert die Selektion. Der Programmcode ist praktisch identisch, Stimmt etwa mit Variablentypen nicht? Note 9.75 müsste immer ein Pluszeichen ausgeben.

Auch in der folgenden Codesequenz habe ich ein Problem erlebt.

Dim Note As Variant
Note = Val(NoteB.Value)

ResultatB.Value = "" ' löschen
If ((Val(NoteB.Value) <= "10") And (Val(NoteB.Value) >= "9.5")) Then
If ResultatA.Value <> "o" Then
MsgBox "Resultate nicht verträglich. Prüfen!", vbExclamation
' OR vbCritical
Else
ResultatB.Value = "+"
End If
End If
Wenn ich (Val(NoteB.Value)) durch Variable ‘Note’ (=Val(NoteB.Value)) ersetze, erhalte die gleichen Fehler (falsche Ergebnisse). NateA, B, ResultatA, B sind allesammt ComboBoxen.



Schönen Abend und Schöne Grüss
Fritz
 

Anhänge

  • Test_Noten.zip
    20,1 KB · Aufrufe: 1

nochEinAndreas

Stammgast
Hallo Fritz,

ich habe deinen Code noch nicht völlig durchgesehen. Was mir aber schon aufgefallen ist: Du vergleichst numerische Werte mit Strings, z.B.:
Code:
Val(ComboBox1.Value) <= "10"
Combobox1.Value liefert immer einen Text. Deswegen hast du es schon ganz richtig gemacht, dass du diesen Text mit der Val-Funktion in eine Zahl umwandelst. Aber dann vergleichst du diese Zahl mit dem Text (!) "10". Das kann u.U. gut gehen. Die Gefahr ist aber recht groß, dass Excel damit Blödsinn macht. Also nimm mal die Anführungszeichen raus.
Und dann, was ich eben auch erst rausgefunden habe: Wenn du die Liste für eine ComboBox über RowSource belegst, werden Zahlen mit Dezimalkomma statt Dezimalpunkt in die Liste eingetragen, egal, was in Excel als Dezimaltrenner eingestellt ist. Die Val-Funktion, die du später benutzt, kommt aber nur mit Dezimalpunkt zurecht. Du musst also Vor dem Vergleich, das Komma in einen Punkt verwandeln:
Code:
If ((Val(Replace(TextBox2.Value, ",", ".")) <= ....
Mehr habe ich erst mal nicht getestet.

Grüße, Andreas
 

nochEinAndreas

Stammgast
Ich muss meinen letzten Beitrag noch ein Bisschen korrigieren:
Wenn eine ComboBox mit RowSource belegt wird, dann benutzt sie den Dezimaltrenner, der in Windows eingestellt ist, unabhängig davon, was in Excel eingestellt ist. Um auf der sicheren Seite zu sein, tut man also gut daran, Replace zu benutzen. So ist man auf alle Fälle sicher, dass Val den Dezimalpunkt bekommt, den es braucht.

Gruß, Andreas
 

Fritz50

Stammgast
Hallo Andreas,

Dein Tip hat mir sehr weitergeholfen. Danke. Erstaunt habe ich feststellen müssen, dass wir das Thema schon einmal behandelt haben (vor fast genau zwei Jahren). Sorry, dass ich da nicht mehr recherchiert habe. Damals haben wir die Erweiterung mit Replace “,“ , “.“ nicht erwähnt, wahrscheinlich weil ich die ComboBox mit AddItem initialisiert habe.

Ich habe dann noch den Versuch gemacht den Wert in eine Zahl zu ändern mit den Formeln Wert + 0 resp. Wert * 1.

' tbx_TextBox2.Value = (ComboBox2.Value) * 1 ' Fehler: Typen unverträglich ausser ganze Zahlen 10, 9
tbx_TextBox2.Value = Val(ComboBox2.Value) * 1 ' schneidet die Kommastellen weg


Dann plagt mich noch ein anderes Problem resp. zuerst die Frage: Kann man Ereignisse unterdrücken?
Die Ausgangslage ist diese: 4 ComboBox Elemente. Deren Inhalte sind Startnummer A, Name A, Startnummer B, Name B. Die Startnummern sind den Namen zugeordnet und umgekehrt.

Wenn ich eine Startnummer A wähle, soll auch der Name A angezeigt werden oder umgekehrt. Und wenn eine Relation zu Name B oder Startnummer B besteht, sollen auch diese Werte enstprechend angepasst werden. (im Change_Ereignis)

Das gleiche möchte ich für Startnummer B und Name B. Vorerst ohne die Relation zu A zu prüfen oder herzustellen.. (im Change_Ereignis)

Was mir auffällt, wenn ich den Wert in einer ComboBox ändere (im ChangeEreignis einer andern ComboBox), gibt’s für diese ComboBox auch ein ChangeEreignis. Wenn dann u.U. ein Wert leer bleibt, bekomme ich gar Laufzeitfehler, weil eine Suche fehl schlägt. Das gibt u.U. ein hin und her von Ereignissen.

Darum die Frage: kann man Changeereignisse unterdrücken? Ich möchte schon mit dem ChangeEreignis arbeiten, wenn ich in der DropBock selektiere.
Oder braucht es das MouseUp-Ereignis? (kann 2x kommen, wenn man die Liste öffnet und nachher einen Wert wählt)

Ich habe da Ereignisse gefunden, die ich aber in Excel VB nicht angeboten bekomme und die ich grad nicht mehr finde, aber in der Art: „DropDownListe öffnen“ und „DropdownListe schliessen“). Ist es ComboBox.AfterUpdate? (bei Access)

Gruss
Fritz
 
Zuletzt bearbeitet:

Fritz50

Stammgast
Nachtrag:
Ich habe da etwas gefunden. Kann/muss ich bei den möglichen ChangeEreignis-Routinen folgendes "Abbruch-Kriterium" einbauen?

If Me.ComboBox1.ListIndex = -1 Then Exit Sub

Solange der Eintrag nicht aus der DropDown-Liste kommt, bleibt der Index ja -1. Ja, und wenn ich einen Wert in die ComboBox schreibe, wird der Index ja auf -1 gesetzt (auch wenn der gleiche Wert in der DropDown-Liste steht).

Gruss
Fritz
 

nochEinAndreas

Stammgast
Guten Abend Fritz,

schau dir mal Application.EnableEvents an:
Wenn du möchtest, dass Ereignisprozeduren nicht ausgeführt werden, dann
Code:
Application.EnableEvents = False
Wenn sie wieder ausgeführt werden sollen, dann
Code:
Application.EnableEvents = True

Grüße, Andreas
 

Fritz50

Stammgast
Hallo Andreas,

Ich bin noch nicht ganz am Ziel. Ich muss die Ereignisprozeduren nochmal genauer anschauen, ob vielleicht zu viele Abhängigkeiten programmiert sind (Zirkelbezug, Ereignisprozedur1 führt zu einen Ereignis2, dieses zur Ereignisprozedur2 diese zu einen Ereignis3 und zur Ereignisprozedur3. Diese kann/könnte wieder Ereignis1 auslösen.)
Dann frage ich mich, ob die nächste Ereignisprozedur (es sind immer ChangeEreignisse) nicht "viel" später abgearbeitet wird als die Sequenz in der aktuellen Prozedur , die ja meist kurz ist. Mit andern Worten , dass EnableEvents schon lang wieder True ist.

Application.EnableEvents = False

Codesequenz, die das nächste Changeereignis auslöst ( im meinem Fall aber nicht berücksichtigt werden sollte, darum ja die Zeile davor)

Application.EnableEvents =True

Ich habe auch Versuche gemacht, die die Ereignisse mit einer Variablen zu steuern. Dies scheint zu funktionieren CommandButton2 / UserForm2

Dann hänge ich nochmal eine Datei an. Beim "spielen" düften die teilweise unerwünschten Ergebnisse schnell auffallen.
Abhängig von der mit ******* markierten Zeile reagiert die Applikation anders.
Wenn die Combobox1 geändert wird, sollte nur ComboBox2 inkrementiert werden. Der Einfluss auf ComboBox3 sollte immer unterdrückt werden

Schönen Abend
Fritz
 

Anhänge

  • Test_Noten.zip
    20,1 KB · Aufrufe: 2

nochEinAndreas

Stammgast
Hallo Fritz,

hast du eventuell eine falsche Datei hochgeladen? Ersten gibt es keine Zeile, die mit ******* gekennzeichnet ist, und zweitens vergleichst du immer noch numerische Werte mit Texten!

Grüße, Andreas
 

Fritz50

Stammgast
Hallo Andreas,

Ja, es ist die falsche Datei. Beim Zippen oder sonst irgendwie schiefgelaufen.
 

Anhänge

  • Test_Noten.zip
    35,6 KB · Aufrufe: 5

nochEinAndreas

Stammgast
Guten Abend Fritz,

hier ist jetzt deine überarbeitete Mappe. Ich habe alle meine Kommentare direkt in den Code geschrieben, immer begonnen mit eine Zeile
+++++++++++++++++++++++++++++++++++++++++++++
damit du es leichter findest.
Ich habe einiges geändert und denke, es funktioniert jetzt alles so, wie du es wolltest.
Den Fehler in der Zeile, die du mit ******** markiert hattest, konnte ich nur teilweise nachvollziehen.

Bei Fehlersuchen hilft es mir immer, wenn ich den Code schrittweise mit F8 laufen lasse. So kann ich Variableninhalte beobachten und Verzweigungen nachvollziehen. Falls du damit noch nicht gearbeitet hast, kann ich es nur empfehlen.

Grüße und einen schönen Abend,
Andreas
 

Anhänge

  • Test_Noten.zip
    39,8 KB · Aufrufe: 5

nochEinAndreas

Stammgast
Korrektur:
Fritz, Ich habe deinen Code noch einmal durchgeschaut. Das mit der Variablen bEnableChangeEvents funktioniert natürlich doch. ich würde diese Lösung allerdings nur benutzen, wenn nur Teile einer Ereignisprozedur nicht ausgeführt werden sollen. Wenn, wie hier, eine Prozedur überhaupt nicht loslaufen soll, würde ich mit Application.EnableEvents arbeiten.

Grüße, Andreas
 

Fritz50

Stammgast
Hallo Andreas,

Noch ein paar Gedanken zu den Themen und Danke für die Hilfe:

Bei der Diskussion um Anführungszeichen, Text und Zahlen noch folgende Gedanken. Das ist mein Verständnis dazu.

Zeichen in Anführungszeichen sind Werte, Zeichen ohne Anführungszeichen sind Variablen.
(ist auch bei Assemblerprogrammierung so)

„Variable“, „Text“, „27“ usw. sind Texte

Variable, Text etc. sind Variablennamen, auch wenn beide nicht so sinnvoll sind, aber doch Variablen.

Unterscheidet VB zwischen Zeichen und Ziffern (Ziffern sind auch Zeichen/Charakter).?
Die Namen Variable, Text, Anzahl usw. sind Variablen, könnte doch 27 auch eine Variable sein.


Zur TextBox2_Exit Prozedur; war vielleicht auch nur ein Versuch. Denn das TextBox2_Change Ereignis kommt bei jeder Änderung in der TextBox2. Wenn ich mehrere Zeichen/Ziffern eingebe, kommt dieses Ereignis jedesmal.
Und dann kann ich mit vorstellen, dass eine Prozedur nochmal aufgerufen werden soll (etwas aktualisieren, schadet ja nicht), wenn der Wert in der TextBox nicht geändert wurde. Das geht dann z.B. mit der ExitEreignis.


Zur Zeile mit den ************* (UserForm3)
ComboBox1.Value = Val(ComboBox1.Value) + 1 ' ****************

Ohne diese Zeile ist der „Ring“ unterbrochen. Ereignis3 löst kein Ereignis1 mehr aus.
Dann hat aber auch eine Änderung in ComboBox3 keinen Einfluss auf die andern Anzeigen.

Application.EnableEvents = False/True funktioniert hier nicht. > Kettenreaktion auf Werte wie 94/93/93 (wenn ComboBox1 1 gewählt)

Ereignis1 > Ereignis2 > Erwignis3 > Ereignis1 .. u.s.w

Grüsse
Fritz
 

nochEinAndreas

Stammgast
Hallo Fritz,

erst mal zu den Variablen und Werten:
Variablennamen in VBA
  • können aus Kleinbuchstaben, Großbuchstaben, Ziffern und _ bestehen.
  • müssen mit einem Buchstaben beginnen.
Gültigen Namen wären also, dasIstEineVariable, Text_Nummer_7, Int_dieZahl14.
Nicht zulässig wäre z.B. 25_EineZahl oder 17.9.

Ein Wert kann z.B. ein Text sein. Dieser muss dann in "" eingeschlossen sein. "Heute ist schönes Wetter" ist ein Text.
Ein Wert kann auch eine Zahl sein, dann wird sie nicht in Anführungszeichen eingeschlossen. 56.87 ist eine Zahl. VBA verlangt hier auch zwingend den Punkt als Dezimaltrenner. Ein Komma geht nicht.

Eine Variable, die nicht mit Dim dimensioniert wird, ist von Typ Variant, d.h. sie kann jeden beliebigen Wert aufnehmen.
derText = "hallo Welt" geht als genau so wie derText = 27.8
Wird eine Variable als bestimmter Typ dimensioniert, kann sie nur Werte dieses Typs aufnehmen, z.B.:
Dim zahl As Integer
zahl = 7

Dim Zahl As Integer
zahl = "eine Zahl"

geht nicht. Typen unverträglich!

Wenn man Texte vergleicht, muss man sehr aufpassen, z.B.

If "526" > "35874" ist wahr! Texte werden Zeichen für Zeichen nach ihrem ASCII Code vergleichen. Hier ist die 5 von 526 größer als die 3 von 35874.

Der Vergleich von Texten beschränkt sich normalerweise darauf, ob sie gleich oder ungleich sind. Größer und kleiner machen meist keinen Sinn.

Wenn man Texte mit Zahlen vergleicht (was ja eigentlich keinen Sinn macht) führt VBA ein gewisses Eigenleben:
if 512 > "6" ergibt WAHR. Offensichtlich wandelt hier VBA vor dem Vergleich den Text "6" in die Zahl 6 um.
Ich würde mich aber nicht darauf verlassen, dass das immer so klappt. Man sollte immer nur Zahlen mit Zahlen vergleichen.

So viel für jetzt. Zu deinen Prozeduren komme ich vermutlich morgen.

Gruß, Andreas
 

nochEinAndreas

Stammgast
Hallo Fritz,

hier jetzt endlich noch ein paar Anmerkungen zu dem Rest deines Posting #12:
Zur TextBox2_Exit Prozedur; war vielleicht auch nur ein Versuch. Denn das TextBox2_Change Ereignis kommt bei jeder Änderung in der TextBox2. Wenn ich mehrere Zeichen/Ziffern eingebe, kommt dieses Ereignis jedesmal.
Und dann kann ich mit vorstellen, dass eine Prozedur nochmal aufgerufen werden soll (etwas aktualisieren, schadet ja nicht), wenn der Wert in der TextBox nicht geändert wurde. Das geht dann z.B. mit der ExitEreignis.
Ja schon. Aber die TextBox2 wird doch nur vom Makro gefüllt. Da schreibt er den ListIndex von ComboBox2 hinein. Oder soll dort auch etwas von Hand eingetragen werden? Wenn ja, was?

Zur Zeile mit den ************* (UserForm3)
ComboBox1.Value = Val(ComboBox1.Value) + 1 ' ****************

Ohne diese Zeile ist der „Ring“ unterbrochen. Ereignis3 löst kein Ereignis1 mehr aus.
Dann hat aber auch eine Änderung in ComboBox3 keinen Einfluss auf die andern Anzeigen.
Ich hatte ja in den Code von UserForm3 als Kommentar geschrieben, dass ich diesen Code aus Zeitgründen nicht verändert hatte. Es ist also noch dein Originalcode mit Unzulänglichkeiten. Schau dir noch mal den berichtigten Code von UserForm2 an. Da entsteht ja auch kein "Ring". Das der "Ring" durch das Weglassen der Zeile unterbrochen wird, ist klar, weil kein Ereignis mehr ausgelöst wird. Wenn du EnableEvents an den richtigen Stellen setzt, entsteht auch kein "Ring" (siehe Code von Usreform2).
Application.EnableEvents = False/True funktioniert hier nicht.
Doch. Wie eben geschrieben, musst du es an die richtigen Stellen setzen.

Grüße und einen schönen Abend,
Andreas
 

Fritz50

Stammgast
Hallo Andreas und Mitleser,

Nochmal ein paar Gedanken zum Thema. Ich möchte mir die Möglichkeit offen lassen, auch Werte von der Tatsatur in die ComboBox zu schreiben. Wenn halt das Ereignis nach jedem Zeichen auftritt, ist das vielleicht unschön, aber schlussendlich steht der gewünschte Wert drin. Ziel ist schon immer eine Zahl (z.B. Startnummer).

Dann zu den UserForms: UserForm2 funktioniert wie gewollt. Dort ist die Event Enable/Disable Sache mit einer boolschen Variable gelöst (bEnableChangeEvents). Das Setzen der Eigenschaft "Application.EnableEvents" ist zwar nie auskommentiert, hat m.E. wahrscheinlich keinen Einfluss.

Denn in UserForm3 fehlt die Lösung mit der bool'schen Variable. Da verwende ich die Application.EnableEvents-Eigenschaft. Ich habe immer noch den Eindruck, dass diese Variante so nicht geht ( "dreht durch", bei mir entstehen Werte 93, 96 ..).

Freundliche Grüsse
Fritz
 

Fritz50

Stammgast
Dann habe ich noch ein anderes Problem: In einer Anwendung habe ich ein paar Commandbuttons (4). Nun reagiert Excel nicht mehr auf diese Buttonclicks resp. nicht immer. Ich habe das in dieser Anwendung schon hin und wieder beobachtet. Dann gehts wieder (nach schliessen und wieder öffnen), aber auch da nicht immer.
Die Zuordnung der Ereignisse scheint mir in Ordnung. In der Entwurfsansicht ist der Zusammenhang CommandButton / Ereigniscode vorhanden.
In der Entwurfsansicht funktionieren die Prozeduren (F8, F5).
Die Applikation hat noch zwei andere Sheets, die nicht stören sollten (History und Zuordnung_Koordinaten, einfach zwei Tabellen).
Wo könnte es klemmen?

Freundliche Grüsse
Fritz
 

nochEinAndreas

Stammgast
Hallo Fritz,

zu Posting #15: Bitte lade deinen aktuellen Code hoch. ich bin sicher, dass es in beiden UserForms mit Application.EnableEvents funktioniert, wenn es richtig gemacht wird. Die Lösung mit der Variablen geht sicher, du brauchst es aber nicht. ich werde es dir zeigen.

Gruß,
 

Fritz50

Stammgast
Hallo Andreas

Im Anhang der aktuelle Code.

Dann habe ich in einem Forum folgenden Satz gefunden:

@ein Name:
Ich bin begeistert! "If Not Application.EnableEvents Then Exit Sub" war meine Rettung Funktioniert einwandfrei! Vielen Dank!

Ich meine aber "Application.EnableEvents" ist implizit, d.h. verhindert den Aufruf eines Ereignisses (wenn False) und muss demnach darin gar nicht abgefragt werden.

Im Sinne OO-Programmierung muss doch jede "Beeinflussung" im Modul selbst stattfinden. Mit eine Variablen arbeiten, die in jedem betroffenen Ereignis/Codesequenz abgefragt werden muss, verletzt man diesen Grundsatz.

Gruss
Fritz
 

Anhänge

  • Test_Noten(2).zip
    44,1 KB · Aufrufe: 1
Zuletzt bearbeitet:

nochEinAndreas

Stammgast
Gaaaanz viel Asche auf mein Haupt und zurückruder!!!
Hallo Fritz, du hast Recht. Ich habe mich im Netz noch mal schlau gemacht. Dort gibt es etliche Aussagen, dass EnableEvents bei UserForm-Ereignissen wirkungslos ist. Warum das so ist, weiß wohl nur Bill Gates. D. h. aber, dein Ansatz mit der Variablen ist völlig richtig.
Tschuldigung!

Aber das bringt mich zu deiner weiteren Frage.
"If Not Application.EnableEvents Then Exit Sub"
Dieser Code ist gar nicht so dumm. Du kannst z.B. am Anfang der ComboBox1_Change Routine schreiben:
Application.EnableEvents = False
Dann erhöhst du ja in deinem Code in einer der folgenden Zeilen den Wert von ComboBox2 um 1.
Application.EnableEvents = False ist zwar innerhalb von UserForms prinzipiell ohne Wirkung. D.h. die ComboBox2_Change Routine wird trotzdem angesprungen.
Wenn du dort aber in der ersten Zeile den zitierten Code rein schreibst, dann wird die Routine sofort wieder verlassen, weil ja EnableEvents auf False steht.
Hier wird also praktisch der Status von EnableEvents als Variable "missbraucht". ich finde, das ist eine sehr clevere Idee. Damit umgeht man das Manko, dass EnableEvents in Userforms ohne Wirkung ist. Es ist zwar in dem Sinne wirkungslos, dass die Routine trotz False angesprungen wird. Der Wert/Status lässt sich aber trotzdem abfragen. Ich habe deinen Code von UserForm2 mal entsprechend umgeschrieben. Funktioniert einwandfrei.

Grüße und noch mal Sorry,
Andreas
 

Anhänge

  • Test_Noten(2).zip
    38,4 KB · Aufrufe: 2

Fritz50

Stammgast
Hallo Andreas, Guten Morgen,

Herzlichen Dank für deine geduldige Mithilfe. Aber nur mit einer gewissen Hartnäckigkeit kommt man schlussendlich zu guten und eleganten Lösungen. Vielleicht konnten auch Mitleser profitieren.
Hast du vielleicht noch eine Idee zum Posting #16? Ich habe keine Reaktionen mehr auf ButtonClicks oder DblClicks.

Gruss
Fritz
 
Oben