ich habe eine verwirrende Entdeckung gemacht:
im folgenden Code steckt eine Endlosschleife.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim RG As Range
Set RG = Application.Intersect(Range("A1").CurrentRegion, _
Range("A:A"), Selection)
If RG Is Nothing Then
Exit Sub
Else
If MsgBox(RG.Address & " abfragen", vbApplicationModal + _
vbDefaultButton2 + vbOKCancel + vbQuestion, _
"Kursabfrage") = vbOK Then
Exit Sub
End If
End If
Set RG = Nothing
Exit Sub
End Sub
und zwar in der Zeile mit Application.intersect
Wenn man Application.EnableEvents = False davor
und Application.EnableEvents = True dahinter setzt,
gibts keine Endlosschleife.
Daraus folgt doch wohl, die Methode löst ein Worksheet_SelectionChange
aus.
Was ist das? Bug oder Feature? Wahrscheinlich letzteres ;-)
Ich bin neugierig auf Theorien. Ich hab keine.
mfG
--
E-Mail von Martin Worm, Karlsruhe, Deutschland
benutze Excel2000(9.0.2812) Win ME
Antworten bitte nur in die Newsgroup
Martin Worm schrieb:
Würd ich auch sagen ;-)
Meine Frage dazu ist; was willst Du überprüfen?
Für welchen Bereich soll die Prüfung in Intersect gelten?
Weshalb verwendest Du 'Selection', wenn Du als Übergabeparameter 'Target' hast?
Wenn Du auf Eingaben im befüllten Bereich von Spalte A prüfen willst, würde
ich es in etwa folgendermassen tun:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set Target = Application.Intersect(Range("A:A"), Target)
If Target Is Nothing Or IsEmpty(Target) Then Exit Sub
If MsgBox(Target.Address & " abfragen", vbApplicationModal + _
vbDefaultButton2 + vbOKCancel + vbQuestion, _
"Kursabfrage") = vbOK Then
Exit Sub
End If
End Sub
IMHO ist das aber nicht das vollständige Makro, da meines Erachtens beim
Bestätigen der MsgBox eine Aktion ausgelöst wird.
Das Problem scheint mir die Kombination von Range("A:A") und
Range("A1").CurrentRegion zu sein.
--
Mit freundlichen Grüssen
Thomas Ramel
- MVP für Microsoft-Excel -
[Win 2000Pro SP-4 / xl2000 SP-3]
"Martin Worm" schrieb:
das scheint tatsächlich ein Bug der 'CurrentRegion-Eigenschaft' unter XL97 und XL2000 zu sein.
In XL02 und XL03 funzt der Befehl einwandfrei.
Bei folgendem Szenario wird das SelectionChange des
Worksheet und Workbook je zwei mal aufgerufen:
' Modul
Public i As Integer
'Tabelle
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
i = i + 1
Debug.Print i
End Sub
'DieseArbeitsmappe
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
MsgBox i
End Sub
' Im Direktfenster mit Enter aufrufen:
i=0:?Activecell.CurrentRegion.Address
Wenn CurrentRegion aus einer einzelnen Zelle besteht wird das SelectionChange nicht ausgelöst.
Warum setzt du CurrentRegion in der Intersect-Methode ein?
Die Überprüfung einer Schnittmenge würde ich wie Thomas bereits geschrieben hat durchführen.
Auf jeden Fall bist du mal wieder einem heißen Phänomen auf die Spur gekommen ;-)
--
Mit freundlichen Grüßen
Melanie Breden
_____________________
[Microsoft MVP für Excel]
Sieht ganz danach aus, denn mit
Set RG = Application.Intersect(Range("A:A"), Target)
funktioniert es ebenfalls einwandfrei.
>
>Bei folgendem Szenario wird das SelectionChange des
>Worksheet und Workbook je zwei mal aufgerufen:
>' Modul
>Public i As Integer
>
>'Tabelle
>Private Sub Worksheet_SelectionChange(ByVal Target As Range)
>i = i + 1
>Debug.Print i
>End Sub
>
>'DieseArbeitsmappe
>Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
>MsgBox i
>End Sub
[....]
Hierzu habe ich zwei Fragen:
1. Public i As Integer im Modul des Tabelenblatts (in dem Private Sub
Worksheet.... steht), wirkt sich nicht auf das Modul in Diese
Arbeitsmappe aus. Fehleranzeige: Variable nicht deklariert. Wie public
ist Public?
Es läuft erst, wenn ich in diesem letztgenannten Modul ein "Dim i as
Integer" einfüge. Dann wird allerdings i=0 ausgegeben.
2. Den zweimaligen Aufruf desWorksheet und Workbook konnte ich nicht
beobachten. Wenn ich das richtig verstehe, dann sollte Debug.Print
hintereinander 1 und 2 ausgeben? (Und beim nächsten Auslösen von
Worksheet --> 3 und 4 usw) Außerdem sollte doch die MsgBox zweimal
erscheinen?
>
>' Im Direktfenster mit Enter aufrufen:
>i=0:?Activecell.CurrentRegion.Address
>
Das funktioniert einwandfrei.
--
Als XL-Lehrling grüsst
Eberhard mit XL 2000
"Eberhard Funke" schrieb:
> >das scheint tatsächlich ein Bug der 'CurrentRegion-Eigenschaft' unter XL97 und XL2000 zu sein.
> >In XL02 und XL03 funzt der Befehl einwandfrei.
>
> Sieht ganz danach aus, denn mit
> Set RG = Application.Intersect(Range("A:A"), Target)
> funktioniert es ebenfalls einwandfrei.
> >
> >[...]>
> [....]
> Hierzu habe ich zwei Fragen:
>
> 1. Public i As Integer im Modul des Tabelenblatts (in dem Private Sub
> Worksheet.... steht), wirkt sich nicht auf das Modul in Diese
> Arbeitsmappe aus. Fehleranzeige: Variable nicht deklariert. Wie public
> ist Public?
> Es läuft erst, wenn ich in diesem letztgenannten Modul ein "Dim i as
> Integer" einfüge. Dann wird allerdings i=0 ausgegeben.
Die Variablendeklarierung 'i' gehört - wie geschrieben- in ein Standardmodul,
nicht ins Codemodul der Tabelle und auch nicht in DieseArbeitsmappe!
Dann ist sie öffentlich und wird bei jedem Durchlauf des Worksheet_SelctionChange-
Ereignisses um einen Zähler erhöht.
Deswegen setzte ich für den Test im Direktfenster die Variable vorher auf 0 zurück.
> 2. Den zweimaligen Aufruf desWorksheet und Workbook konnte ich nicht
> beobachten. Wenn ich das richtig verstehe, dann sollte Debug.Print
> hintereinander 1 und 2 ausgeben? (Und beim nächsten Auslösen von
> Worksheet --> 3 und 4 usw) Außerdem sollte doch die MsgBox zweimal
> erscheinen?
>
> >
> >' Im Direktfenster mit Enter aufrufen:
> >i=0:?Activecell.CurrentRegion.Address
> >
> Das funktioniert einwandfrei.
Was wird denn bei dir als Ergebnis im Direktfenster ausgegeben?
Wenn der Bezug auf eine einzelne Zelle hat Excel auch keine Probleme damit.
Markiere im Tabellenblatt mehrere Zellen und brich die ausgelösten Ereignisse ab.
(die durch das Markieren ausgelöst wurden)
Rufe dann die Befehlszeile im Direktfenster auf.
Bei mir wird zwei mal die MsgBox aufgerufen und im Direktfenster steht
i=0:?Activecell.CurrentRegion.Address
1
2
$C$5:$D$7
Kannst du das bei dir nachvollziehen?
"Melanie Breden" schrieb:
> "Eberhard Funke" schrieb:
> > >' Im Direktfenster mit Enter aufrufen:
> > >i=0:?Activecell.CurrentRegion.Address
> > >
> > Das funktioniert einwandfrei.
>
> Was wird denn bei dir als Ergebnis im Direktfenster ausgegeben?
> Wenn der Bezug auf eine einzelne Zelle hat Excel auch keine Probleme damit.
> Markiere im Tabellenblatt mehrere Zellen und brich die ausgelösten Ereignisse ab.
> (die durch das Markieren ausgelöst wurden)
> Rufe dann die Befehlszeile im Direktfenster auf.
>
> Bei mir wird zwei mal die MsgBox aufgerufen und im Direktfenster steht
> i=0:?Activecell.CurrentRegion.Address
> 1
> 2
> $C$5:$D$7
>
> Kannst du das bei dir nachvollziehen?
Nachtrag:
für den Test im Direktfenster ist es unwichtig, wie viele Zellen markiert sind,
sondern stelle den Cursor in eine Zelle, inmitten eines Bereichs nicht_leerer Zellen
so dass CurrentRegion einen Bereich aus mehreren Zellen zurückgeben muss.
"Melanie Breden" <Melanie...@mvps.org> schrieb:
[....]
>
>Die Variablendeklarierung 'i' gehört - wie geschrieben- in ein Standardmodul,
>nicht ins Codemodul der Tabelle und auch nicht in DieseArbeitsmappe!
Ich hatte zuvor schon so lange an Martin's Code rumgewurstelt, daß ich
Deine eigentlich klare Anweisung nicht mehr richtig aufgenommen habe.
>
[.....]
>
>Bei mir wird zwei mal die MsgBox aufgerufen und im Direktfenster steht
>i=0:?Activecell.CurrentRegion.Address
>1
>2
>$C$5:$D$7
>
>Kannst du das bei dir nachvollziehen?
Ja, aber auch nach vielen Versuchen immer noch ohne genaues
Verständnis des Ablaufs.
Jetzt "Flasche leer", ich dreh mich im Kreis.
Ich muß mal 'ne Nacht drüber schlafen und komme dann nochmals darauf
zurück.
Das Wichtigste wurde zwar schon gesagt, möchte aber trotzdem
noch ein paar Bemerkungen anbringen.
Ich bin wie ihr zum Schluss gekommen, dass CurrentRange die Ursache
des Problems ist. Dass jegliche Verwendung von CurrentRange das
SelectionChange-Ereignis auslöst, also auch ohne die Select-Methode,
ist schon ein ziemlich übler Bug. Wenn man über Gehe zu/Aktueller
Bereich bzw. Strg+Umschalt+* (entspricht CurrentRange) die Mar-
kierung vornimmt, und der aktuelle Bereich nicht bereits markiert ist,
wird SelectionChange ebenfalls zwei Mal ausgelöst; was allerdings
nachvollziehbar ist. Ist der aktuelle Bereich schon markiert, wird kein
SelectionChange ausgelöst. Bei CurrentRange dagegen wird das
Ereignis immer zwei Mal ausgelöst, egal welche Zellen markiert
sind. Ich tendiere daher zur etwas unschönen VBA-Alternative
SendKeys "+^*" (anstelle von CurrentRange.Select), die bei bereits
selektiertem aktuellen Bereich besser funktioniert.
Übrigens verhält sich die Endlosschleife - wenn CurrentRange in
SelectionChange benutzt wird - sehr interessant. Auf meinem Rechner
wird nach ca. 213 bis 217 Rekursionen das SelectionChange-Ereignis
nicht mehr aufgerufen sondern die Codezeile mit dem CurrentRange
einfach übergangen. Ich nehme an, dass der Procedure Call Stack
überläuft und daher die Ereignisprozedur kein weiteres Mal von sich
selbst aufgerufen werden kann.
Ich habe die MSKB durchforstet, aber keinen einzigen Hinweis
auf das CurrentRange-Verhalten gefunden. Melanie erwähnte, dass
das Problem ab XL2002 nicht mehr auftritt. Da es in XL97 und
XL2000 kaum mehr behoben wird, wäre es doch wünschenswert,
wenn MS einen entsprechenden KB-Artikel verfasst. Falls man
nämlich in XL2002 VBA-Code mit CurrentRange im Selection-
Change-Ereignis schreibt, so funktioniert er wunderbar. In XL97/
XL2000 aber tritt die Endlosschleife auf, was den Programmierer
ohne einen MSKB-Artikel doch ziemlich im Regen stehen lässt.
Ist nicht als Auftrag gemeint, aber vielleicht könnte Melanie oder
Thomas als MVPs eine Info bei MS deponieren (ihr kennt sicher
eine geeignete Anlaufstelle).
Besten Dank und Gruss
Philipp
Philipp schrieb:
>
> Ich bin wie ihr zum Schluss gekommen, dass CurrentRange die Ursache
> des Problems ist. Dass jegliche Verwendung von CurrentRange das
> SelectionChange-Ereignis auslöst, also auch ohne die Select-Methode,
> ist schon ein ziemlich übler Bug.
>
> Ich habe die MSKB durchforstet, aber keinen einzigen Hinweis
> auf das CurrentRange-Verhalten gefunden. Melanie erwähnte, dass
> das Problem ab XL2002 nicht mehr auftritt. Da es in XL97 und
> XL2000 kaum mehr behoben wird, wäre es doch wünschenswert,
> wenn MS einen entsprechenden KB-Artikel verfasst. Falls man
> nämlich in XL2002 VBA-Code mit CurrentRange im Selection-
> Change-Ereignis schreibt, so funktioniert er wunderbar. In XL97/
> XL2000 aber tritt die Endlosschleife auf, was den Programmierer
> ohne einen MSKB-Artikel doch ziemlich im Regen stehen lässt.
>
> Ist nicht als Auftrag gemeint, aber vielleicht könnte Melanie oder
> Thomas als MVPs eine Info bei MS deponieren (ihr kennt sicher
> eine geeignete Anlaufstelle).
Ich hab mal eine entsprechende Anfrage nach den Kontaktmöglichkeiten
abgesetzt - mal sehen, was daraus wird. Dnke dir für die Anregung, Philipp.
hallo Thomas, Melanie und Eberhard,
>> Was ist das? Bug oder Feature? Wahrscheinlich letzteres ;-)
>Würd ich auch sagen ;-)
>Meine Frage dazu ist; was willst Du überprüfen?
>Für welchen Bereich soll die Prüfung in Intersect gelten?
>Weshalb verwendest Du 'Selection', wenn Du als Übergabeparameter 'Target' hast?
ja, das ist die Frage ;-). Ich hab vergessen, daß ich in einem
Tabellenmodul bin(und sollte nach 22.00 Uhr keine Makros mehr
"verbösern"). Ersetz ich Selection durch Target, gehts leider auch
nicht. Es geht nur mit Ereignisabschaltung :-(, das mach ich nur in
Notfällen und das ist keiner. ;-)
Ich habe eine Aufstellung meiner Depotbestände und wollte durch
selektieren allein Xl dazu bringen, die markierten Zeilen zu
aktualisieren. Aber das krieg ich auch anders hin.
>IMHO ist das aber nicht das vollständige Makro, da meines Erachtens beim
>Bestätigen der MsgBox eine Aktion ausgelöst wird.
das stimmt, aber der Code war imho irrelevant
>Das Problem scheint mir die Kombination von Range("A:A") und
>Range("A1").CurrentRegion zu sein.
Ich hab diverses ausprobiert, es geht alles nicht, macht aber nix.
Danke für eure Bemühungen, es geht wohl nicht
danke
Martin Worm schrieb:
>
>>Meine Frage dazu ist; was willst Du überprüfen?
>>Für welchen Bereich soll die Prüfung in Intersect gelten?
>>Weshalb verwendest Du 'Selection', wenn Du als Übergabeparameter 'Target' hast?
>
> ja, das ist die Frage ;-). Ich hab vergessen, daß ich in einem
> Tabellenmodul bin(und sollte nach 22.00 Uhr keine Makros mehr
> "verbösern"). Ersetz ich Selection durch Target, gehts leider auch
> nicht. Es geht nur mit Ereignisabschaltung :-(, das mach ich nur in
> Notfällen und das ist keiner. ;-)
Mit Target 'allein' klappt es auch nicht, das stimmt - es liegt eben an der
Verwendung von .CurrentRegion.
> Ich habe eine Aufstellung meiner Depotbestände und wollte durch
> selektieren allein Xl dazu bringen, die markierten Zeilen zu
> aktualisieren. Aber das krieg ich auch anders hin.
Einen Ansatz hatte ich ja geliefert - er berücksichtigt allerdings noch
nicht, dass Du auch mehrere Zellen selektieren kannst.
In Intersect() prüfst Du eine èberschneidung von:
- Selection (=Target)
- Range("A1").CurrentRegion (=die Region um Zelle A1 herum)
- Range("A:A") (=Spalte A)
Dies lässt sich IMHO zusammenfassen in eine Prüfung auf Spalte A und ob die
jeweilige Zelle nicht leer ist.
>>IMHO ist das aber nicht das vollständige Makro, da meines Erachtens beim
>>Bestätigen der MsgBox eine Aktion ausgelöst wird.
>
> das stimmt, aber der Code war imho irrelevant
Radio Eriwan würde sagen:
"Im Prinzip habn Sie recht..."
Denn meist ist es mehr als sinnvoll zu wissen, an welcher Stelle
zusätzlihcer Code ausgeführt oder aufgerufen wird, um eine Prozedur zu
verstehen. Diese Info hatte hier gefehlt (es war aber nicht sonderlich
schwierig, dies heruazufinden ;-) )
> Ich hab diverses ausprobiert, es geht alles nicht, macht aber nix.
> Danke für eure Bemühungen, es geht wohl nicht
Doch; das geht bestimmt, versuche es mal folgendermassen oder beschreibe
das gewünschte Verhalten noch etwas genauer:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Set Target = Application.Intersect(Range("A:A"), Target)
If Target Is Nothing Then Exit Sub
Dim rngZelle As Range
For Each rngZelle In Target
If IsEmpty(rngZelle) Then Exit Sub
If MsgBox(rngZelle.Address & " abfragen", vbApplicationModal + _
vbDefaultButton2 + vbOKCancel + vbQuestion, _
"Kursabfrage") = vbOK Then
Exit Sub 'IMHO hier der Aufruf der weitern Aktion
End If
Next rngZelle
End Sub
"Martin Worm" schrieb:
> >Weshalb verwendest Du 'Selection', wenn Du als Übergabeparameter 'Target' hast?
>
> ja, das ist die Frage ;-). Ich hab vergessen, daß ich in einem
> Tabellenmodul bin(und sollte nach 22.00 Uhr keine Makros mehr
> "verbösern"). Ersetz ich Selection durch Target, gehts leider auch
> nicht. Es geht nur mit Ereignisabschaltung :-(, das mach ich nur in
> Notfällen und das ist keiner. ;-)
was ist so schlimm beim deaktivieren der Ereignisprozeduren?
Zur Ermittlung der CurrentRegion wird durch die Abschaltung doch Nichts anderes beeinflusst.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Application.EnableEvents = False
Set Target = Application.Intersect(Target, _
Columns("A"), _
Range("A1").CurrentRegion)
Application.EnableEvents = True
If Target Is Nothing Then Exit Sub
MsgBox "Zelle ist im benutzten Bereich A1 und in Spalte A"
' weiterer Code
End Sub
--
der Ablauf Deiner Prozeduren ist mir noch nicht klar.
--------------------
Um ein Rückblättern zu erübrigen, hier noch mal Dein Vorschlag:
' Modul
Public i As Integer
'Tabelle
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
i = i + 1 '<==VOR DIESER ZEILE EIN STOP EINGEFÜGT
Debug.Print i
End Sub
'DieseArbeitsmappe
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal
Target As Range)
MsgBox i
End Sub
' Im Direktfenster mit Enter aufrufen:
i=0:?Activecell.CurrentRegion.Address
------------------------
Bei der zuletzt aufgeführten Zeile habe ich das "i=0" weggelassen,
weil ich dann anhand der fortlaufenden Zahlen den Vorgang besser
verfolgen kann, also:
?Activecell.CurrentRegion.Address
Nach dem eingefügten Stop in Worksheet habe ich mich mit F8
durchgeklickt. Ich beschreibe mal, was ich beobachte, wie ich das
interpretiere:
1. Klick auf die Tabellenzelle löst sowohl Worksheet als auch
Workbook aus.
2. Zuerst läuft Worksheet ab:
Debug.Print i --> 1
3. Danach Workbook:
--> MsgBox "1"
-- > Fertig.
4. Entertaste auf CurrentRegion im Direktfenster löst wiederum sowohl
Worksheet als auch Workbook aus:
5. Zuerst Worksheet:
Debug.Print i --> 2
6. Danach Workbook:
Anders als oben 3, wird jetzt das Codefenster Sub Workbook...
eingeblendet und die Zeile
...Sub Workbook... ist gegilbt.
--> MsgBox "2"
Analog zum obigen Ablauf 1 bis 3 hatte ich jetzt nach "ok" erwartet:
Fertig.
7. Aber: Es wird erneut Worksheet angesprungen (das Codefenster wird
eingeblendet, Zeile ... Sub Worksheet... = gelb)
Debug.Print --> 3
8. Zurück in Worksheet (Sub Worksheet... = gelb)
--> MsgBox "3"
--> Fertig.
Mein Direktfenster:
?Activecell.CurrentRegion.Address
2
3
$A$1:$A$10
1
Wieso läuft das Ganze nach 6. weiter?
Das Klick-Ereignis(1.) läßt die Prozeduren nur einmal durchlaufen.
Das CurrentRegion "Ereignis" (4.) *scheint* zweimal auszulösen.
P.S. Entschuldigung für die Länge. Hoffentlich habe ich damit aber
wenigstens klarmachen können, was mir unklar ist.
hallo Melanie und Thomas,
>was ist so schlimm beim deaktivieren der Ereignisprozeduren?
>Zur Ermittlung der CurrentRegion wird durch die Abschaltung doch Nichts anderes beeinflusst.
>
>Private Sub Worksheet_SelectionChange(ByVal Target As Range)
> Application.EnableEvents = False
> Set Target = Application.Intersect(Target, _
> Columns("A"), _
> Range("A1").CurrentRegion)
> Application.EnableEvents = True
>
> If Target Is Nothing Then Exit Sub
> MsgBox "Zelle ist im benutzten Bereich A1 und in Spalte A"
> ' weiterer Code
>End Sub
wahrscheinlich werd ichs so machen. Hast eigentlich recht. Da ich im
Büro für "Nur"Anwender Makros schreibe, bin ich bemüht, narrensichere
Makros zu schreiben. Aber dieses ist nur für mich ;-).
Ich wollte halt aus 3 Teilbereichen eine Spalte rauskriegen :-)
Aber die Ausmaße einer Selection bestimmen kann ich.
Ich wollte was anderes probieren.
Übrigens, wenn die Ereignisse nicht abgeschaltet werden, kommt, wenn man
Spalte A nicht selektiert, der Bereich A1:A14 heraus(CurrentRegion hat
gegenwärtig 14 Zeilen)
danke an euch, ich weiß jetzt wieder mehr
mfG
"Martin Worm" schrieb:
> hallo Melanie und Thomas,
>
> >was ist so schlimm beim deaktivieren der Ereignisprozeduren?
> >Zur Ermittlung der CurrentRegion wird durch die Abschaltung doch Nichts anderes beeinflusst.
[...]
> wahrscheinlich werd ichs so machen. Hast eigentlich recht. Da ich im
> Büro für "Nur"Anwender Makros schreibe, bin ich bemüht, narrensichere
> Makros zu schreiben. Aber dieses ist nur für mich ;-).
[...]
> danke an euch, ich weiß jetzt wieder mehr
wir haben zu danken, denn durch deinen Hinweis wissen wir auch wieder mehr :-)
Martin Worm schrieb:
>
> hallo Melanie und Thomas,
>
>>was ist so schlimm beim deaktivieren der Ereignisprozeduren?
>>Zur Ermittlung der CurrentRegion wird durch die Abschaltung doch Nichts anderes beeinflusst.
>
> wahrscheinlich werd ichs so machen. Hast eigentlich recht. Da ich im
> Büro für "Nur"Anwender Makros schreibe, bin ich bemüht, narrensichere
> Makros zu schreiben. Aber dieses ist nur für mich ;-).
>
> Ich wollte halt aus 3 Teilbereichen eine Spalte rauskriegen :-)
> Aber die Ausmaße einer Selection bestimmen kann ich.
> Ich wollte was anderes probieren.
>
> Übrigens, wenn die Ereignisse nicht abgeschaltet werden, kommt, wenn man
> Spalte A nicht selektiert, der Bereich A1:A14 heraus(CurrentRegion hat
> gegenwärtig 14 Zeilen)
Es klappt auch ohne das Ausschalten der Events, wenn Du eine übergeordnerte
Steuervarible verwendest. Der Vorteil ist dann, dass Du mehrere Regionen in
derselben Prozedur 'bedienen' kannst:
Dim blnHandler As Boolean
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not blnHandler Then
blnHandler = True
Dim RG As Range
Set RG = Application.Intersect(Range("A1").CurrentRegion, _
Range("A:A"), Selection)
If Not RG Is Nothing Then
If MsgBox(RG.Address & " abfragen", vbApplicationModal + _
vbDefaultButton2 + vbOKCancel + vbQuestion, _
"Kursabfrage") = vbOK Then
End If
End If
Set RG = Nothing
blnHandler = False
End If
End Sub
--
"Thomas Ramel" schrieb:
[...]
> Es klappt auch ohne das Ausschalten der Events, wenn Du eine übergeordnerte
> Steuervarible verwendest. Der Vorteil ist dann, dass Du mehrere Regionen in
> derselben Prozedur 'bedienen' kannst:
>
> Dim blnHandler As Boolean
>
> Private Sub Worksheet_SelectionChange(ByVal Target As Range)
> If Not blnHandler Then
> blnHandler = True
> Dim RG As Range
> Set RG = Application.Intersect(Range("A1").CurrentRegion, _
> Range("A:A"), Selection)
> If Not RG Is Nothing Then
> If MsgBox(RG.Address & " abfragen", vbApplicationModal + _
> vbDefaultButton2 + vbOKCancel + vbQuestion, _
> "Kursabfrage") = vbOK Then
> End If
> End If
>
> Set RG = Nothing
> blnHandler = False
> End If
> End Sub
eine schöne Idee, damit wird wie bei normalen Subs das Ereignis nur zweimal zusätzlich aufgerufen.
Bei EnableEvents hingegen kein weiteres Mal.
Eine Frage habe ich zum Codeablauf:
Mir ist klar, warum blnHandler am Schluß auf False gesetzt werden muss.
Durch die modulare Deklarierung behält die Variable Ihren Wert auch nach Beendigung der Prozedur.
Das würde bei weiteren Ereignisaufrufen dazu führen, dass der relevante Code nicht erreicht würde.
Aber RG ist nur auf Prozedurebene deklariert und wird nach Beendigung der Prozedur gelöscht.
Warum setzt du diesen Verweis zurück?
Melanie Breden schrieb:
>>
>>Dim blnHandler As Boolean
>>
>>Private Sub Worksheet_SelectionChange(ByVal Target As Range)
>> If Not blnHandler Then
>> blnHandler = True
>> Dim RG As Range
>> Set RG = Application.Intersect(Range("A1").CurrentRegion, _
>> Range("A:A"), Selection)
>> If Not RG Is Nothing Then
>> If MsgBox(RG.Address & " abfragen", vbApplicationModal + _
>> vbDefaultButton2 + vbOKCancel + vbQuestion, _
>> "Kursabfrage") = vbOK Then
>> End If
>> End If
>>
>> Set RG = Nothing
>> blnHandler = False
>> End If
>>End Sub
>
> eine schöne Idee, damit wird wie bei normalen Subs das Ereignis nur zweimal zusätzlich aufgerufen.
> Bei EnableEvents hingegen kein weiteres Mal.
Das ist soweit korrekt - es sollte halt eine Variante aufzeigen, ohne die
Events 'anzutasten'. Ich machs üblicherweise auch mit aus-/einschalten der
Events; meist dann mit einem Errorhandler, damit auch im Falle eines
Fehlers die Events wieder 'scharf' sind.
> Eine Frage habe ich zum Codeablauf:
> Mir ist klar, warum blnHandler am Schluß auf False gesetzt werden muss.
> Durch die modulare Deklarierung behält die Variable Ihren Wert auch nach Beendigung der Prozedur.
> Das würde bei weiteren Ereignisaufrufen dazu führen, dass der relevante Code nicht erreicht würde.
Richtig...
> Aber RG ist nur auf Prozedurebene deklariert und wird nach Beendigung der Prozedur gelöscht.
> Warum setzt du diesen Verweis zurück?
...dies ist nicht auf 'meinem Mist gewachsen'. ;-)
Ich habe in Martins ursprünglichem Code nur die Steuervariable eingebaut
und einige If-Abfragen etwas umgebaut, um nicht mehrere Ausstigespunkte aus
der Sub zu haben. Der Rest entspricht dem Code von Martin, der vermutlich
seine Gründe hat, die Objekt-Vatiable zurückzusetzen.
Vielleicht teilt er sie und und der NG ja mit?
@ Martin
Weshalb setzt Du die Variable mit "Set RG = Nothing" explizit zurück?
Welche fundierten Argumente gibt es, ies zu tun?
hallo Thomas,
>Weshalb setzt Du die Variable mit "Set RG = Nothing" explizit zurück?
>Welche fundierten Argumente gibt es, ies zu tun?
ich kenn das so von Delphi(Pascal). Wer sich ein Objekt deklariert und
Speicher belegt, gibt diesen am Ende auch wieder frei.
Ich hab aber auch gelesen, daß auf existierende Objekte wie ein
Tabellenblatt nur ein Zeiger auf die schon existierende Struktur
angelegt wird, aber so ne Zeile wie set RG=nothing tut ja nicht weh und
hält auch die Programmiererdisziplin hoch. ;-)
Allerdings ist ein beliebiger Range aus einem Tabellenblatt bestimmt
nicht von XL definiert.
Martin Worm schrieb:
>
>>Weshalb setzt Du die Variable mit "Set RG = Nothing" explizit zurück?
>>Welche fundierten Argumente gibt es, ies zu tun?
>
> ich kenn das so von Delphi(Pascal). Wer sich ein Objekt deklariert und
> Speicher belegt, gibt diesen am Ende auch wieder frei.
Aha; eine Anwendung von anderweitig angeeigenten Gewohneiten also.
Es gibt teilweise 'militante' Verfechter dieser Gewohnheit - mich
interessierten halt die fundierten Gründe dafür; speziell in Verbindung mit
Excel-VBA.
> Ich hab aber auch gelesen, daß auf existierende Objekte wie ein
> Tabellenblatt nur ein Zeiger auf die schon existierende Struktur
> angelegt wird, aber so ne Zeile wie set RG=nothing tut ja nicht weh und
> hält auch die Programmiererdisziplin hoch. ;-)
Dass es 'ethische' und emotionale Gründe darür gibt ist mir sehr wohl klar;
auch dass Gewohnhieten hier mit im Spiel sind. Ich denke auch, dass jeder
seinen eigenen Stil pflegen sollte - solange er/sie nicht den Anspruch auf
alleinige Richtigkeit erhebt.
Danke für deine Offenheit.
hallo Thomas,
>Es klappt auch ohne das Ausschalten der Events, wenn Du eine übergeordnerte
>Steuervarible verwendest. Der Vorteil ist dann, dass Du mehrere Regionen in
>derselben Prozedur 'bedienen' kannst:
Ich werds mir merken. Die Methode mit .EnableEvents erscheint mir
"übersichtlicher".
Denn das "Problem" bei Makros ist nicht, sie zu verstehen, wenn man sie
geschrieben hat, sondern 4 Wochen später. ;-). Die Erfahrung hab ich
zumindest gemacht. Deshalb sind meine Variablennamen meistens auch
länger und beschreibend. Und Kommentieren hilft auch(manchmal) ;-)
"Martin Worm" schrieb:
> >Es klappt auch ohne das Ausschalten der Events, wenn Du eine übergeordnerte
> >Steuervarible verwendest. Der Vorteil ist dann, dass Du mehrere Regionen in
> >derselben Prozedur 'bedienen' kannst:
>
> Ich werds mir merken. Die Methode mit .EnableEvents erscheint mir
> "übersichtlicher".
> Denn das "Problem" bei Makros ist nicht, sie zu verstehen, wenn man sie
> geschrieben hat, sondern 4 Wochen später. ;-). Die Erfahrung hab ich
> zumindest gemacht. Deshalb sind meine Variablennamen meistens auch
> länger und beschreibend. Und Kommentieren hilft auch(manchmal) ;-)
allgemein schließe ich mich der Meinung von Thomas an.
Für mich ist es allerdings verwirrend, bzw. auch unübersichtlich, wenn ich in einem Code die
Zurücksetzung einer Objektvariablen lese.
Normalerweise setzt man in VBA Objekt-Variablen zurück, wenn diese global deklariert sind.
Dadurch kann man in weiteren Code- oder Prozedurbaläufen diese Objektvariable mit 'Is Nothing' überprüfen.
Bsp:
Public gwksNew As Worksheet
Sub NeuesBlatt()
If gwksNew Is Nothing Then Set gwksNew = Worksheets.Add
End Sub
Über diese Prozedur wird nur ein einziges Blatt der Arbeitsmappe hinzufügefügt,
egal wie oft sie aufgerufen wird. will, da die Variable gwksNew öffentlich deklariert wurde.
Sobald sie in irgendeiner anderen Prozedur der Anwendung zurückgesetzt wurde,
kann ein weiteres Blatt über die Prozedur NeuesBlatt eingefügt werden.
Der Vorteil von sprechenden Variablennamen ist hier deutlich zu erkennen:
g=global, wks=worksheet, New=Beschreibung
Innerhalb umfangreicher Prozeduren sehe ich das Zurücksetzten von Objektvariablen,
die auf Prozedurebene deklariert wurden als sinnvoll an,
wenn durch verschiedene Verschachtelungen (If...Then...Else) explizit ein
Objekt mit 'Is Nothing' überprüft werden soll.
Wenn hingegen am Ende einer Prozedur eine Zurücksetzung erfolgt,
ist das für mich ein Anzeichen, dass diese Variable öffentlich ist.
Es schadet wohl nicht, in VBA modulare Objektvariablen grundlos vor Beendigung
einer Prozedur zurückzusetzen.
Müsste man dann aber der Vollständigkeithalber nicht alle Variablen zurück-,
bzw. je nach Deklarierung auf 0 oder "" setzen?
hallo Melanie,
>Für mich ist es allerdings verwirrend, bzw. auch unübersichtlich, wenn ich in einem Code die
>Zurücksetzung einer Objektvariablen lese.
das ist wohl eine Frage der Gewohnheit. In Delphi(Pascal) muss man
Variablen deklarieren und auch wieder freigeben, sonst verschwendet man
Speicher. Ein weiterer gewöhnungsbedürftiger Unterschied besteht darin,
daß Variablenübergaben an Unterprogramme byRef erfolgen.
>Der Vorteil von sprechenden Variablennamen ist hier deutlich zu erkennen:
>g=global, wks=worksheet, New=Beschreibung
dazu gibt es übrigens eine Beschreibung zur Namenskonvention
http://mypage.bluewin.ch/access/access/reddick.htm
>Müsste man dann aber der Vollständigkeithalber nicht alle Variablen zurück-,
>bzw. je nach Deklarierung auf 0 oder "" setzen?
hab ich mal überlegt, aber da Longs und Strings nicht allzuviel Platz
wegnehmen, der längste String, den ich verwende, ist ca 2000 bytes lang,
und ich Variablen initialisiere, mach ichs noch nicht. In einem Fall
aber schon, ich stell eine DDE-Verbindung her und wnn ich sie wieder
schließe, setz ich die Variable auf 0.
(Hatte ich schon einmal gepostet, war wohl irgendwie untergegangen,
jedenfalls bisher ohne Antwort geblieben)
"Melanie Breden" <Melanie...@mvps.org> schrieb:
[..............]
>Bei folgendem Szenario wird das SelectionChange des
>Worksheet und Workbook je zwei mal aufgerufen:
>' Modul
>Public i As Integer
>
>'Tabelle
>Private Sub Worksheet_SelectionChange(ByVal Target As Range)
STOP '<=== eingefügt, um mit F8 schrittweise zu verfolgen
>i = i + 1
>Debug.Print i
>End Sub
>
>'DieseArbeitsmappe
>Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
>MsgBox i
>End Sub
>
>' Im Direktfenster mit Enter aufrufen:
>i=0:?Activecell.CurrentRegion.Address
>
[.....................]
Bei der vorstehend zuletzt aufgeführten Zeile habe ich das "i=0"
-- > Fertig.
--> Fertig.