Samstag, 20. Oktober 2007

Buttons dynamisch zur Laufzeit hinzufügen ist in Excel leicht realisiert, aber ...

wie bringt man diese Buttons dazu dass ein Klick darauf etwas sinnvolles macht?

Eine Variante, die ich im Netz gefunden habe, ist entsprechende Ereignisprozeduren dynamisch zu erzeugen.
Eine weitere gefundene Variante die mir besser gefällt habe ich nachfolgend zusammengefasst.

[hinzugefügt am 2008-11-18 12:15]
Ein vollständiges lauffähiges Beispiel steht unter diesem Link zum Download bereit.
Die Codeteile sind im VBA-Editor unter "Diese Arbeitsmappe", "DynamicButtonSheet (Tabelle1)" und im Klassenmodul "ButtonObject" zu finden.

Nachfolgend die wichtigsten Codeteile mit einigen Anmerkungen:
[hinzugefügt bis hier]

Folgendes Klassen-Modul wird benötigt.

   1 Option Explicit
2
3 Public WithEvents ButtonObject As MSForms.CommandButton
4
5 Public btnName As String
6 Public btnId As Integer
7
8 Private Sub ButtonObject_Click()
9 Module1.MoveButton_Click btnId
10 End Sub

Der globalen Variable ButtonObject wird später der neu erstellt Button zugewiesen.
btnName und btnId sind Beispiele für zusätzliche Properties zur Identifikation welcher konkrete Butten gedrückt wurde.

ButtonObject_Click() ist die Ereignis-Prozedur die im Fall eines Button-Click aufgerufen wird.
Module1.MoveButton_Click btnId ist eine zentrale Prozedur in der die Button-Click-Ereignisse verarbeitet werden, an die der Aufruf weitergeleitet wird.

Es folgt ein Beispielcode wie die Buttons erstellt werden.

   1 Private Buttons As New Collection
2
3 Dim btnWidth as Integer
4 Dim btnHeight as Integer
5
6 btnWidth = 50
7 btnHeight = 25
8
9 For i = 0 To 10
10 Set btn = ws.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False, _
11 Left:= i * btnWidth, _
12 Top:= 200, Width:=btnWidth, Height:=btnHeight)
13 btn.Name = RT_PREFIX & "MoveButton" & i
14 btn.Object.Caption = "Button " & i
15 btn.Object.TakeFocusOnClick = False
16 Next i

Nach dem Erstellen der Buttons kommt ein kleiner Trick der Excel eine kurze Verschnaufpause verschafft damit es nicht außer Tritt kommt.

   1 Application.OnTime Time + TimeSerial(0, 0, 1), "Module1.prcAssign"

Damit wird die Prozedur prcAssign aus dem Module1 zeitversetzt aufgerufen.
prcAssign sieht folgendermaßen aus:

   1 Public Sub prcAssign()
2 Dim ws As Worksheet
3 Dim btn As OLEObject
4 Dim button As ButtonObject
5 Dim i As Integer
6
7 Set ws = ActiveWorkbook.Worksheets("Tabelle1")
8 i = 0
9
10 For Each btn In ws.OLEObjects
11 If Left(btn.Name, Len(RT_PREFIX)) = RT_PREFIX Then
12 Set button = New CButton
13 Set button.ButtonObject = btn.Object
14 button.Id = i
15 button.Name = RT_PREFIX & "Button" & i
16 Buttons.Add button
17
18 i = i + 1
19 End If
20 Next
21
22 End Sub

Beim Zuordnen eines Buttons in der beschriebenen Art an die ButtonObject Variable einer CButton Instanz wird automatisch die Ereignisprozedur ButtonObject_Click zugeordnet.

Kommentare:

Anonym hat gesagt…

Das Beispiel ist genial.
Ich bekomme es aber unter Excel VBA nciht zum Laufen, weil mir das
Objekt "CButton" fehlt.
Was ist das?
Fehlt mir ein Verweis?

Liebe Grüße

Rosi

Günter Zöchbauer hat gesagt…

Hallo Rosi,

vielen Dank für dein Lob und den Hinweis, dass offensichtlich nicht alle relevanten Informationen angeführt sind.

Im oberen Teil des Blogeintrages habe ich einen Link zu einer fertigen Implementierung eingefügt.

Ich hoffe, es hilft dir weiter.

Liebe Grüße
Günter

Anonym hat gesagt…

Hallo Günter,

das ist das, was ich suche. Leider kennt er bei mir ButtonObject aus
Dim button As ButtonObject
nicht und den CButton ebenfalls. Wenn ich Dein Beispiel runterlade, erhalte ich ein ZIP mit 0 Byte. Kannst Du mir weiterhelfen?

Gruß, Roland

Günter Zöchbauer hat gesagt…

Hallo Roland,

danke für den Hinweis auf den broken Link.

Ich habe die URL aktualisiert.
Der Download sollte daher wieder funktionieren.

Günter

Anonym hat gesagt…

Hallo Günter,

Dein Beispiel hört sich wirklich vielversprechend an und das habe ich lange gesucht. Leider funktioniert der Link nicht, wo ich das lauffähige Beispiel downloaden kann. Oder kannst Du mir das Beispiel schicken?

Gruß Tom

Günter Zöchbauer hat gesagt…

Hallo Tom,

vielen Dank für den Hinweis und bitte entschuldige den Ärger...

Es hat sich herausgestellt, dass das Microsoft Live Skydrive nicht dafür geeignet ist Dateien zum Blog bereitzustellen, da sich die URLs immer wieder ändern.
Ich habe die Datei auf einem anderen Share verschoben, jetzt sollte es dauerhaft funktionieren.

Die Mailadresse die beim Kommentieren abgefragt wird, wird von Blogger.com nicht weitergereicht, ich kann dir die Datei daher leider nicht mailen.

Anonym hat gesagt…

Hallo,

eine kurze Ergänzung von mir: Der Mechanismus funktioniert auch, wenn man zur Laufzeit Steuerelemente zu einem Formular hinzufügen möchte.

*Allerdings* (und das hat mich einen halben Tag gekostet, bis ich darauf gekommen bin) muss man das Formular erst ausblenden (UserForm1.Hide), dann die Elemente hinzufügen und dann das Formular wieder einblenden (UserForm1.Show), andernfalls funktionieren die Events nicht.

Der Timer-Aufruf wird in diesem Fall nicht benötigt.

Grüße,
Frank