Allgemeine Klick-Events abfangen?

Liebe Leute,

Folgendes Problem: Ich habe eine userform mit mehreren Rahmen. In jedem Rahmen befinden sich jeweils mehrere Buttons. Die Anzahl der Rahmen wird im Programm ermitteln und die entsprechende Anzahl dynamisch zur Userform hinzugefuegt.

Wenn nun ein Button geklickt wird, wie kann ich das entsprechende Event auswerten? Es gibt ja keine statische Sub Button_click. Zwar kann ich den Buttons dynamisch erzeugte Namen zuweisen, aber dann weiss ich immer noch nicht, wie und wo ich auf die entsprechenden Klicks reagieren soll. Hat jemand einen Rat?

Gruss,

martin

Hallo martin,

das Klick-Ereignis gibt es ja nicht nur bei Buttons, mit Images oder Pictures … geht das auch. Erstellst Du ein Steuerelementefeld, hast Du für alle Elemente auch nur eine Prozedur und erfährst über den Index welches der Elemente geklickt wurde.

Wenn Du das nicht magst und nur wissen willst, ob überhaupt geklickt wurde, aber nicht wohin, dann geht auch …

Option Explicit
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Private Sub Form\_Load()
 Timer1.Interval = 100
 Timer1.Enabled = True
End Sub

Private Sub Timer1\_Timer()
 If GetAsyncKeyState(1) Then
 'Dein Code
 End If
End Sub

Das ist eher Geschmakssache und hängt vom Ziel ab.

Gruß, Rainer

Hallo Rainer,

vielen Dank fuer die Antwort. Leider bin ich in VBA noch nicht so erfahren und weiss daher nicht genau, was du mit dem Steuerelementfeld meinst. Wie erstelle ich dieses und wie genau hilft es mir bei meinem Problem?

Gruss,

Martin

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Martin,

wenn du postest so gebe bitte mit an ob du VB oder VBA meinst. Denn da gibt es maechtig gewaltig unterschiede :wink:
Aber nun zu deiner Frage. Ein Steuerelement sind die Elemente die du auf deine Form ziehst. Zum Bsp. Schatlflaechen, Labels etc.

Du schreibst das du sie Dynamisch erstellst. Das geht ergo nur mit der Load Anweisung. Willst du diese nutzen, so musste du Indexe benutzen und über das Click Event und des Indexes weisst du welches Steuerelement geklickt wurde.

MfG Alex

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Alex und Rainer,

auch auf die Gefahr hin, dass ich mich als Depp zu erkennen gebe, ich kapier’s immer noch nicht.
(es geht uebrigens um VBA, vielleicht liegts daran)

Machen wir es doch mal ganz konkret. Normalerweise, wenn ich einen Button auf eine Userform packe, dann habe ich eine Prozedur aehnlich dieser:

Private Sub CommandButton1_Click()
MsgBox(„Klickeriki“)
End Sub

Nun fuege ich meine Buttons wie folgt dynamisch hinzu:

Dim AddButton As MSForms.CommandButton

Set AddButton = CurrentFrame.Controls.Add(„Forms.CommandButton.1“, „AddButton“ & code, True)

With AddButton
.Caption = „Add“
.Height = 18
.Width = 40
.Left = 495
.Top = 20
End With

Der Schnippsel „Code“ im Namen des Buttons ist eindeutig und laesst mich den Button identifizieren - theoretisch. Wo aber bekomme ich jetzt meine Prozedur „AddButton_code_click“ her?

Das ist im Prinzip die Frage, um die sich alles dreht. Wenn ich allgemein alle Click events dieser Userform abfangen und die Quelle auswerten koennte, dann waere es ja kein problem. Nur, wie geht das? Oder welche andere Loesung gaebe es?

Gruss,

Martin

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo,

auch auf die Gefahr hin, dass ich mich als Depp zu erkennen
gebe, ich kapier’s immer noch nicht.

mir geht das bei Fragen immer so, bis ich die verstanden habe … :smile:

(es geht uebrigens um VBA, vielleicht liegts daran)

kann sein, ich kenne VBA gar nicht, aber hier genügen wohl die Gemeinsamkeiten.

Machen wir es doch mal ganz konkret. Normalerweise, wenn ich
einen Button auf eine Userform packe, dann habe ich eine
Prozedur aehnlich dieser:

Private Sub CommandButton1_Click()
MsgBox(„Klickeriki“)
End Sub

OK.

Nun fuege ich meine Buttons wie folgt dynamisch hinzu:

Dim AddButton As MSForms.CommandButton

Set AddButton =
CurrentFrame.Controls.Add(„Forms.CommandButton.1“, „AddButton“
& code, True)

With AddButton
.Caption = „Add“
.Height = 18
.Width = 40
.Left = 495
.Top = 20
End With

Brrr. Das sieht in VB völlig anders aus, übersichtlicher. Da liegt wohl auch Dein Problem …

Der Schnippsel „Code“ im Namen des Buttons ist eindeutig und
laesst mich den Button identifizieren - theoretisch.

Praktisch auch, „Code“ ist bei Dir der Index des Steuerelementefeldes.

Wo aber
bekomme ich jetzt meine Prozedur „AddButton_code_click“ her?

Gar nicht, brauchst Du nicht. In VB hieße die …

„AddButton_click (Index As Integer)“

Du mußt in den Eigenschaften des Buttons, den du ‚vervielfältigen‘ willst, die Eigenschaft ‚Index‘ auf Null setzen, dann hat auch die Prozedur für das Klickereignis den richtigen Namen und Du hast in der Prozedur den Index, der Dir übergeben wird … in VB jedenfalls. Ich hoffe, daß in VBA die Syntax an der Stelle nicht zu weit abweicht.

Gruß, Rainer

Hallo Rainer,

es it wohl in der Tat ein VBA vs. VB-Problem hier. Die von dir erwaehnte Funktion mit dem Index gibt’s in VBA nicht. Die Funktion zum Hinzufuegen eines Buttons hat folgende Signatur:

Set Control = object.Add( ProgID [, Name [, Visible]])

Einen Index gibt’s nur bei Tabs

In meiner Verzweiflung habe ich nun versucht, den Code zum Abfangen des jeweiligen Klick-Events dynamisch hinzuzufuegen.

Den Button fuege ich so hinzu:

Set AddButton = CurrentFrame.Controls.Add(„Forms.CommandButton.1“, „AddButton_“ & code, True)

Und das dazugehoerigen event:

Private Sub AddClickEventCode(langCode As String)
Dim VBCodeMod As Object
Dim lines As Long

Set VBCodeMod = ThisWorkbook.VBProject.VBComponents(„ComplexPOForm“).CodeModule
lines = VBCodeMod.CountOfLines + 1
VBCodeMod.InsertLines lines, „Private Sub AddButton_“ & langCode & „_Click()“
VBCodeMod.InsertLines lines + 1, „AddButtonClicked (“"" & langCode & „“")"
VBCodeMod.InsertLines lines + 2, „End Sub“
End Sub

Leider stuertzt mir Excel nun staendig ab, wenn der dynamisch zu erzeugende Code eingefuegt wird.

Ich sitze hier ganz schoen fest. Hast noch jemand einen Tipp?

Bis denne,

Martin

Machen wir es doch mal ganz konkret. Normalerweise, wenn ich
einen Button auf eine Userform packe, dann habe ich eine
Prozedur aehnlich dieser:

Private Sub CommandButton1_Click()
MsgBox(„Klickeriki“)
End Sub

OK.

Nun fuege ich meine Buttons wie folgt dynamisch hinzu:

Dim AddButton As MSForms.CommandButton

Set AddButton =
CurrentFrame.Controls.Add(„Forms.CommandButton.1“, „AddButton“
& code, True)

With AddButton
.Caption = „Add“
.Height = 18
.Width = 40
.Left = 495
.Top = 20
End With

Brrr. Das sieht in VB völlig anders aus, übersichtlicher. Da
liegt wohl auch Dein Problem …

Der Schnippsel „Code“ im Namen des Buttons ist eindeutig und
laesst mich den Button identifizieren - theoretisch.

Praktisch auch, „Code“ ist bei Dir der Index des
Steuerelementefeldes.

Wo aber
bekomme ich jetzt meine Prozedur „AddButton_code_click“ her?

Gar nicht, brauchst Du nicht. In VB hieße die …

„AddButton_click (Index As Integer)“

Du mußt in den Eigenschaften des Buttons, den du
‚vervielfältigen‘ willst, die Eigenschaft ‚Index‘ auf Null
setzen, dann hat auch die Prozedur für das Klickereignis den
richtigen Namen und Du hast in der Prozedur den Index, der Dir
übergeben wird … in VB jedenfalls. Ich hoffe, daß in VBA die
Syntax an der Stelle nicht zu weit abweicht.

Gruß, Rainer

Hallo Martin,

es it wohl in der Tat ein VBA vs. VB-Problem hier. Die von dir
erwaehnte Funktion mit dem Index gibt’s in VBA nicht. Die
Funktion zum Hinzufuegen eines Buttons hat folgende Signatur:

Set Control = object.Add( ProgID [, Name [, Visible]])

hast du die erste Version meiner Antwort per Mail bekommen? Vergiß die, ich war in Gedanken in einem anderen Tread. :smile:

Zurück zu Deinem Problem. Auf die Userform kannst Du doch mit der Maus einen Button legen. Wenn Du den anklickst, solltest Du ein Fenster mit den Eigenschaften bekommen. wenn nicht, dann Rechtsklick auf den Button und dann auf Eigenschaften klicken.
In den Eigenschaften solltest Du die Eigenschaft ‚Index‘ finden.

Anderer Ansatz:

Wenn Du den Button auf der Form hast, klick den mal mir rechts an und dann auf ‚kopieren‘. Dann klickst Du rechts auf die Form und dann auf ‚Einfügen‘. Auch VBA sollte Dich dann fragen, ob Du ein Steuerelementefeld erstellen willst.

Hmmm, aber wie geht es weiter? Ich muß mich wohl doch mal mit VBA beschäftigen … :smile: Bis dahin hoffen wir mal, daß noch ein VBA-Experte antwortet.

Gruß, Rainer

Hallo Martin,

es it wohl in der Tat ein VBA vs. VB-Problem hier. Die von dir
erwaehnte Funktion mit dem Index gibt’s in VBA nicht. Die
Funktion zum Hinzufuegen eines Buttons hat folgende Signatur:

Set Control = object.Add( ProgID [, Name [, Visible]])

hast du die erste Version meiner Antwort per Mail bekommen?
Vergiß die, ich war in Gedanken in einem anderen Tread. :smile:

Kann schon sein. Zuviele Threads verderben die Loesung. :smile:

Zurück zu Deinem Problem. Auf die Userform kannst Du doch mit
der Maus einen Button legen.

Hier geht’s schon los: Der Button wird vom Programm waehrend der Laufzeit dynamisch erzeugt und ist zur Compile-Zeit noch gar nicht da.

Tja, und nu?

Gruss,

Martin

Hallo Martin,

Hier geht’s schon los: Der Button wird vom Programm waehrend
der Laufzeit dynamisch erzeugt und ist zur Compile-Zeit noch
gar nicht da.

Tja, und nu?

seit dem ersten Beitrag sind schon fünf Tage vergangen. Bis jetzt konnte ich Dir ja nicht weiter helfen, Du hast in der Zwischenzeit auch keine Lösung gefunden.

Ich werde mich jatzt mal etwas intensiver mit Deinem Problem beschäftigen, wie es aussieht, mischt sich kein VBA-Experte ein.
Ich werde mich erst mal selbst mehr mit VBA befassen und auch einen Kollegen Fragen, der im Schwesterunternehmen intensiv mit VBA arbeitet. Mit Terminzusagen halte ich mich besser zurück, ich kenne meine Schwächen. :smile: Das Problem interessiert mich aber jetzt, ich werde es lösen. Ich hatte angenommen, der Tipp würde genügen.

Reicht es Dir, wenn ich Dir ein Beispiel mit ein paar Buttons schicke, die zur Laufzeit in einer Schleife erzeugt werden, die dann in einer gemeinsamen Prozedur reagieren und Dein Programm weiß, welcher Button geklickt wurde? Daß das geht weiß ich, nur noch nicht ganz genau, wie. :smile: Wenn Dir das hilft, habe ich sicher bald die Lösung, ich kümmere mich darum.

Gruß, Rainer

Hallo Martin,

Zwischenergebnis. Der Button wird zur Laufzeit hinzugefügt, die Ereignisprozedur ist aber im Code schon enthalten. Die willst Du ja aber auch zur Laufzeit hinzufügen, wenn ich Dich richtig verstanden habe.

Erst mal der Code so:

Option Explicit

Private WithEvents CommandButtonNeu As CommandButton

Private Sub CommandButtonNeu\_Click()
 MsgBox "Guten Tag ich bin's, der neue Button"
End Sub

Private Sub UserForm\_Activate()
 Set CommandButtonNeu = UserForm1.Controls.Add("Forms.CommandButton.1", "CommandButtonNeu", True)

 With CommandButtonNeu
 .Visible = True
 .Width = 90
 .Height = 30
 .Caption = "Hier klicken"
 .Top = 30
 .Left = 30
 End With
End Sub

Das läuft schon mal. Oder genügt Dir das so schon?

Gruß, Rainer

Hallo Martin,

ich konnte bisher keine Möglichkeit finden, zur Laufzeit Code einzufügen. Wenn ich mir deinen Satz betrachte …

Hier geht’s schon los: Der Button wird vom Programm waehrend
der Laufzeit dynamisch erzeugt und ist zur Compile-Zeit noch
gar nicht da.

… beschleichen mich auch Zweifel, daß das geht. Wann soll der neu hinzugefügte Code compiliert werden?

Ich habe einen Alternativvorschlag.

Du willst ja nur Buttons erzeugen.

Wenn Du vorher weißt, wie viele Buttons das werden und zu jedem Button einen anderen Code brauchst, kannst Du den ja schon schreiben.

Wenn aber beim Klicken immer die selbe Prozedur ausgeführt werden soll, ist es eventuell besser, gar nicht die vielen verschiedenen Klickereignisse auszuwerten, sondern Systemweit die Maus zu überwache und aus der lage der Form und der mausposition errechnen, welcher Button geklickt wurde. Das ist zwar etwas rechnerei, aber nur eine Prozedur, die immer funktioniert. Das würde dann so aussehen:

Option Explicit

Private Type POINTAPI
 X As Long
 Y As Long
End Type

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private WithEvents CommandButtonNeu As CommandButton
Dim Point As POINTAPI

Private Sub CommandButtonNeu\_Click()
 MsgBox "Guten Tag ich bin's, der neue Button"
End Sub

Private Sub UserForm\_Activate()
 Set CommandButtonNeu = UserForm1.Controls.Add("Forms.CommandButton.1", "CommandButtonNeu", True)
 With CommandButtonNeu
 .Visible = True
 .Width = 90
 .Height = 30
 .Caption = "Hier klicken"
 .Top = 30
 .Left = 30
 End With
 tm
End Sub

Private Sub tm()
 'Timernachbau
 Dim t As Double
 t = Timer
 While t \> 0
 t = Timer + 0.1
 While t \> Timer
 DoEvents
 Wend
 If GetAsyncKeyState(1) Then
 GetCursorPos Point
 UserForm1.Caption = Str(Point.X) & " " & Str(Point.Y)
 End If
 Wend
End Sub

Eine bessere Idee habe ich z.Z. nicht.

Gruß, Rainer

Hallo Rainer,

ich fuehle mich ja sehr geehrt, dass du dich so in mein Problem verbeissen willst. :smile:

Zu deinen vorherigen Mails: Die Anzahl der Buttons ist leider nicht vor Programmstart bekannt, da sie von Benutzereingaben abhaengt.
Die Loesung mit der Maus ware vielleicht machbar, aber erscheint mir etwas unelegant (also, die Denkweise ist sehr lateral und elegant, ich waere nicht draufgekommen, aber die eigentliche Loesung ist etwas messy).

Dein Beispiel wuerde wie beschrieben ziemlich genau das widergeben, was mein Problem ist. Die Button koennen sogar unterschiedliche Namen haben, was die Sache einfacher machen sollte. Allerdings braucht man dann fuer jeden Button eine Klick-Prozedur. Alternativ haben alle Buttons den gleichen Namen und eine einzige Klick-Prozedur, allerdings kann ich mir nicht vorstellen, woher man dann wissen soll, woher der Klick kam.
Wenn dein Kollege einen TIpp hat, das waer natuerlich klasse.

Bis denne,

Martin

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Martin,

Zu deinen vorherigen Mails: Die Anzahl der Buttons ist leider
nicht vor Programmstart bekannt, da sie von Benutzereingaben
abhaengt.

Das dachte ich mir.

Die Loesung mit der Maus ware vielleicht machbar, aber
erscheint mir etwas unelegant (also, die Denkweise ist sehr
lateral und elegant, ich waere nicht draufgekommen, aber die
eigentliche Loesung ist etwas messy).

Ja, völlig korrekt.

Dein Beispiel wuerde wie beschrieben ziemlich genau das
widergeben, was mein Problem ist. Die Button koennen sogar
unterschiedliche Namen haben, was die Sache einfacher machen
sollte.

So kannst Du die Buttons erstellen. Zwei mit dem gleichen Namen wird VB nicht zulassen, die müssen ja unterschieden werden.

Allerdings braucht man dann fuer jeden Button eine
Klick-Prozedur.

So ist es. Unter VB sind die Steuerelemente deshalb indizierbar. VBA bietet diese Möglichkeit leider nicht.

Alternativ haben alle Buttons den gleichen
Namen und eine einzige Klick-Prozedur, allerdings kann ich mir
nicht vorstellen, woher man dann wissen soll, woher der Klick
kam.

Nein, mehrere Buttons mit gleichem Namen kann es nicht geben, sonst hättest Du ja auch mehrere Prozeduren mit gleichem Namen, das funktioniert nicht.

Wenn dein Kollege einen TIpp hat, das waer natuerlich klasse.

Der hat zuerst gefragt, was die Buttons denn tun sollen, für die Anwendung sind Buttons bei VBA nicht vorgesehen. Für die Funktion, die Du suchst, sollst Du bei VBA Options-Schaltflächen oder Checkboxen nehmen. Mit Buttons geht das so, wie Du möchtest nur mit VB, mit VBA nicht.

Gruß, Rainer