Herbers Excel-Forum - das Archiv

change-ereignis bei dynamischen Controls / Teil 2

Informationen und Beispiele zu den hier genannten Dialog-Elementen:
Bild

Betrifft: change-ereignis bei dynamischen Controls / Teil 2
von: Thomas

Geschrieben am: 20.03.2008 15:50:18

Hallo,
nachdem ich vor ein paar Tagen die bittere Erfahrung machen mußte, daß es bei meinem Problem ohne Klassenmodul nicht gelöst werden kann, habe ich mich damit beschäftigt und komme zu folgender Frage.
Sehe ich das richtig, daß zunächst meine Controls wie gehabt dynamisch erstellt und dann als Klassen-Objekte definiert werden müssen?
UserForm: Positionen
Option Explicit
Dim new_ctl As MSForms.Control
Dim ctl_Art(88) As Variant

Private Sub UserForm_Initialize()
For n = 0 To Anz_ctl
Set new_ctl = Positionen.Controls.Add("Forms.TextBox.1", ctl_Art( n), True)
new_ctl.Move Left:=Links_Box(n),Top:=Oben_Box(n),Width:=Breite_Box(n),Height:=Höhe_Box(n)
Call Klassen_Objekte_definieren
Next n
Sub Klassen_Objekte_definieren()
Dim ctl_txt As Object
Dim m As Integer
m = -1
For Each ctl_txt In Positionen.Controls
If TypeOf ctl_txt Is MSForms.TextBox Then
m = m + 1
ReDim Preserve Ftxt(m)
Set Ftxt(m) = New cls_txt
Ftxt(m).Create ctl_txt
End If
Next ctl_txt
End Sub


Meine Eingaben im Klassenmodul sind nun folgende:
Klassenmodul: cls_txt
Option Explicit
Dim WithEvents txt As MSForms.TextBox

Public Function Create(TextBox As MSForms.TextBox) As Boolean
Set txt = TextBox
If Not txt Is Nothing Then
Create = True
End If
End Function


Private Sub txt_Change()
On Error Resume Next
' MsgBox txt.Name
End Sub


Obwohl das ganze funktioniert, meine Frage an die Fachleute, ob ich so weiter wursteln kann, oder ob ihr irgendwelche Bedenken dabei habt.
Viele Grüße
Thomas

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: Rudi Maintaire

Geschrieben am: 20.03.2008 16:28:28
Hallo,
so:
in der UF (Positionen)

Option Explicit
Private Sub UserForm_Initialize()
Dim i As Integer
For i = 1 To 88
Set oClsPositionen(i).myTxt = Me.Controls.Add("forms.textbox.1")
With oClsPositionen(i).myTxt
.Left = 20
.Top = (i - 1) * 24 + 10
End With
Next
Me.Height = oClsPositionen(88).myTxt.Top + 30
End Sub


In einem Modul:

Option Explicit
Public oClsPositionen(1 To 88) As New clsPositionen


Klassenmodul (clsPositionen)

Option Explicit
Public WithEvents myTxt As MSForms.TextBox
Private Sub myTxt_Change()
myTxt = UCase(myTxt)
End Sub


Gruß
Rudi
Eine Kuh macht Muh, viele Kühe machen Mühe

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: Thomas

Geschrieben am: 21.03.2008 11:12:13
Hallo Rudi,
vielen Dank für Deine Antwort.
Natürlich funktioniert alles genau so wie Du es angegeben hast.
Nun wollte ich es für mich ein bisschen abändern und bin dabei kläglich gescheitert.
Dehalb meine Fragen:
1. Wie kann ich die Controls in Gruppen bestehend aus jeweils:
TextBox
TextBox
TextBox
TextBox
ComboBox
TextBox
ComboBox
TextBox
TextBox
zusammenfassen?
2. Wie kann ich dann diese Gruppen so durchnummerieren
Gruppe1 Controls 110 - 118
Gruppe2 Controls 120 - 128 usw.
3. Wie kann ich durch einen Button eine Gruppe hinzufügen?
4. Wie kann ich durch einen Button eine Gruppe löschen und dann neu durchnummerieren?
Du hast recht mit Muh und Mühe, aber ich befürchte auch alleine Mühe zu machen.
Viele Grüße
Thomas

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: Thomas

Geschrieben am: 21.03.2008 14:11:40
Hallo Rudi,
momentan überhole ich mich selbst.
Zu meiner Nachfrage habe ich für 1. und 2. folgende Lösung gefunden:

For m = 0 To 88
Links = 6
For n = 0 To 8
Set ctl_txt(m, n).txt = Me.Controls.Add("forms.textbox.1", _
"TextBox" & ((100 + (m + 1) * 10) + n), True)
With ctl_txt(m, n).txt
.Left = Links
.Top = Oben
.Width = 60
End With
Links = Links + 80
Next n
Oben = Oben + 20
Next m


Nun mal nur am Beispiel der TextBoxen. Für die ComboBoxen will ich eine If-Abfrage machen für n=4 oder n=6.
Natürlich muß ich die ComboBoxen noch im Modul definieren und ein Klassenmodul für sie anlegen.
Was bleibt ist 3. und 4.
Viele Grüße
Thomas (Muh)

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: fcs

Geschrieben am: 21.03.2008 22:01:29
Hallo Thomas,
wie bist du nur auf die Idee verfallen hier bis zu 88 Steuerfeld-Gruppen anzulegen (Horror). Das muss doch auch anders in übersichtlicherer Form darstellbar sein.
Grundsätzlich kann man die Elemente über den Namen wieder löschen und dabei systematisch nach der Gruppennummer suchen. Zum Einfügen weiterer Gruppen muss die kleinste und die max. Gruppennummer in einer Modulweiten-Variablen gespeichert und jeweils bei Löschungen/Hinzufügen angepasst werden.
In der mit Excel97 erstellten Beispieldatei findest du auch den nachfolgenden Code im Userform.
https://www.herber.de/bbs/user/50911.xls
Gruß
Franz

Option Explicit
Private Gruppe1 As Integer ' niedrigste Gruppen-Zählnummer
Private GruppeMax As Integer 'höchste Gruppen-Zählnummer
Private Oben As Double, Links As Double
Private element As Control 'Steuerelement
Const Links1 As Double = 10 'Startposition für Steuerelemente
Const Oben1 As Double = 35 'Startposition für Steuerelemente
Const AbstandVertikal As Double = 20 'Abstand der Gruppen
Private Sub CB_GruppeHinzu_Click()
GruppeMax = GruppeMax + 1
Oben = Oben1 + (GruppeMax - Gruppe1) * AbstandVertikal
Call GruppeHinzu(GruppeMax, Oben)
End Sub
Private Sub CB_GruppeLoeschen_Click()
Dim iGruppe As Integer
iGruppe = Val(InputBox("Bitte die ersten beiden Ziffern der Gruppe eingeben", _
"Steuerelement-Gruppe löschen", Format(Gruppe1, "00")))
If iGruppe = 0 Then GoTo ende
'Gruppenelement löschen
For Each element In Me.Controls
If Left(Right(element.Name, 3), 2) = Format(iGruppe, "00") Then
Oben = element.Top
Me.Controls.Remove (element.Name)
End If
Next element
'Gruppen neu nummeriern und positionieren
If iGruppe < GruppeMax Then
For iGruppe = iGruppe + 1 To GruppeMax
For Each element In Me.Controls
If Left(Right(element.Name, 3), 2) = Format(iGruppe, "00") Then
element.Name = Left(element.Name, Len(element.Name) - 3) _
& Format(iGruppe - 1, "00") & Right(element.Name, 1)
element.Top = Oben
If element.Name = "LabelGr" & Format(iGruppe - 1, "00") & "1" Then
element.Object.Caption = Format(iGruppe - 1, "00")
End If
End If
Next element
Oben = Oben + AbstandVertikal
Next iGruppe
End If
GruppeMax = GruppeMax - 1
ende:
End Sub
Private Sub CB_Schliessen_Click()
Unload Me
End Sub
Private Sub UserForm_Activate()
Dim ii As Integer
Gruppe1 = 10: GruppeMax = 19
Oben = Oben1
For ii = Gruppe1 To GruppeMax Step 1
Call GruppeHinzu(ii, Oben)
Oben = Oben + AbstandVertikal
Next
End Sub
Private Sub GruppeHinzu(GruppeNr As Integer, iOben As Double)
'Elemente einer Gruppe erzeugen
Dim tbox As Integer
'Label mit GruppenNr
Links = Links1
Set element = Me.Controls.Add(bstrprogid:="Forms.Label.1", _
Name:="LabelGr" & Format(GruppeNr, "00") & "1")
element.Top = iOben
element.Left = Links
element.Width = 15
element.Caption = Format(GruppeNr, "00")
Links = Links + 20
'Textboxen 1 bis 3
For tbox = 1 To 3
Set element = Me.Controls.Add(bstrprogid:="Forms.TextBox.1", _
Name:="Textbox" & Format(GruppeNr, "00") & Format(tbox, "0"))
element.Top = iOben
element.Left = Links
element.Width = 25
element.Value = GruppeNr * 10 + tbox 'testwertzuweisung
Links = Links + 35
Next tbox
End Sub


Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: Thomas

Geschrieben am: 22.03.2008 15:51:37
Hallo liebe Experten,
vielleicht seid ihr bitte so nett, euch mein Beispiel anzusehen. Ihr seht bestimmt, wo bei mir der Wurm drin liegt.
https://www.herber.de/bbs/user/50934.zip
Auf Tabelle 'Rechnung' klicken,
in der ListBx die erste Zeile markieren
dann 'Wählen' klicken
und schließlich 'Positionen'
Bei vorhandenen Daten:
Besonderen Wert lege ich darauf, daß Änderungen der Menge, oder des Preises sofort in die Summen auf der UserForm u n d in der Tabelle übernommen werden.
Wenn eine Position hinzu gefügt wurde:
Das ist leider etwas holprig. Ich mußte die Feststellung machen, daß zunächst alle Wete auf '0' gesetz werden müssen, damit auch mit der neuen Position gerechnet wird.
Löschen einer Position:
Dabei scheitere ich schon am markieren des Frames. Am liebsten würde ich ihn rot umranden.
Wie kann man dann nach der Bestätigung des Löschens den ganzen Frame löschen?
Und wie kann ich dann die Controls wieder einlesen, daß die Positionen auf der UserForm wider mit denen in der Tabelle wieder übereinstimmen?
Liege ich denn völlig falsch, oder ist mein Ansatz wenigstens ein bisschen richtig?
Viele Grüße
Thomas

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: fcs

Geschrieben am: 23.03.2008 03:52:59
Hallo Thomas,
ich hab mir deine Userformen mal angesehen.
Das Problem bei der Anzeige aller Positionen ist, dass während der Initialisierung des Userform bereits die Berechnungen gestartet werden obwohl noch nicht alle Steuerelemente einer Position angelegt sind. Dadurch kommt es zum Abbruch, wenn von diesen noch fehlenden Steuerelementen Werte ausgelesen werden sollen.
Abhilfe:
Steuere über eine Boolsche Variable, dass während der Formblattinitialisierung die Berechnungen nicht ausgeführt bzw. übersprungen werden.
In der Textdatei findest du den UF-Code entsprechend modiifziert. Die Zeilen hab ich mit '###fcs markiert.
Bei mir unter Excel97 hab ich dann mehrfach noch Probleme weil die Rechenfunktionen einen Text oder Leerstrings verarbeiten müssen. Das hab ich aber nicht bereinigt.
Ich hab in der zweiten Datei das UF Positionen mal komplett anders aufgebaut.
Die Positionen werden in einer Listbox angezeigt und nur die Daten der jeweils selektierte Position werden in einem Satz Steuerelemente angezeigt.
Mit dieser Methode ist es kein Problem Positionen einzufügen oder zu löschen.
Das ganze beruht darauf, dass alle Daten einer Rechnung in einem Range-Objekt (rngRechnung) verwaltet werden. Dieses Range-Objekt, das ja nicht anderes als ein Auszug aus der Gesamttabelle ist, wird dann benutzt um die Auswahlliste zu füllen und samtliche Summenberechnungen durchzuführen.
Das UF Rechnungen hab ich um etwas Funktionalität ergänzt. Per Schieberegler kann man durch die Positionen scrollen und Daten editieren. Die Löschfunktion funktioniert hier genau so wie im UF Positionen.
Im Moment werden die Eingaben/Änderungen nicht direkt in die Tabelle geschrieben sondern erst nach Klick auf den Button. Dies kann man aber relativ einfach ändern, wobei evtl. nicht das Change sondern das Exit-Ereignis für die Aktualisierung genutzt werden sollte. Für die Textboxen (Menge, Einzelpreis und EZ Einzelpreis wird beim Verlassen (Exit-Ereignis) geprüft, ob eine Zahl eingegeben ist. Dadurch gibt es bei der Weiterverarbeitung der Eingabe weniger Probleme.
Auf die Klassen-Module für die Text- bzw. Combobox hab ich verzichtet. Für die wenigen jetzt noch betroffenen Steuerelemente kann man den entsprechenden Code ggf. auch direkt im UF-Modul anlegen.
https://www.herber.de/bbs/user/50946.zip
Gruß
Franz

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: Thomas

Geschrieben am: 23.03.2008 14:21:51
Hallo Franz,
vielen Dank für Deine ausführliche Antwort!
Du hast mich wieder auf den Pfad der Tugend zurück gebracht.
Für mich war die einzige Lösung mehrere Positionen auf einer neuen UserForm einfach Stück für Stück untereinander zu "malen". Dadurch habe ich mich in den Bereich der Klassenmodule verirrt, von dem ich nun gar nichts verstehe und so geriet ich immer weiter in Probleme hinein.
Damit möchte ich mich bei allen anderen die mir in dieser Richtung geholfen haben entschuldigen, denn die wußten ja gar nicht was ich eigentlich wollte.
Deine Lösung ist viel besser! In einer ListBox hat man alle Positionen zusammen schön aufgeführt und die, welche man wirklich ändern möchte, gesondert im Fokus.
Nun muß ich mich Punkt für Punkt mit Deiner Lösung beschäftigen. Wenn ich dazu noch weitere Fragen haben sollte, was ich stark vermute, soll ich dann diese hinter diesen Thread schreiben, oder wie mache ich das?
Nochmals vielen Dank für Deine Mühe
und Viele Grüße
Thomas

Bild

Betrifft: AW: change-ereignis bei dynamischen Controls / Tei
von: fcs

Geschrieben am: 23.03.2008 22:00:17
Hallo Thomas,
solange der Thread noch in der Forums-Liste angezeigt wird solltes du weitere Fragen anhängen.
Später dann neuen Thread anlegen mit Link auf den ursprünglichen Thread.
Ein Tip noch: Falls die Zahl der Datenspalten in der Datentabelle noch nicht endgültig feststeht, dann solltest du die Nr. der letzten Spalte im Modul Basis in einer Public Konstanten festlegen und in allen Anweisungen
Set rngRechnung = Range(Cells(...,1),Cells(...,42))
die 42 durch die Konstante ersetzen. Dann wird die Pflege des Codes ggf. einfacher.
Gruß
Franz

Bild

Betrifft: Change-Ereignis Teil 3
von: Thomas

Geschrieben am: 30.03.2008 15:55:42
Hallo im Forum,
inzwischen bin ich von den dynamischen Controls wieder abgekommen, aber trotzdem etwas weiter.
Geblieben sind die Probleme mit den Change-Ereignissen.
Am anschaulichsten ist es sicher mit einem Beispiel.
https://www.herber.de/bbs/user/51150.zip
Wird eine vorhandene Rechnung geändert/ergänzt/gedruckt, genügt ein klick auf die ListBox1.
Alle Änderungen werden sofort berechnet, in der UserForm dargestellt und in die Tabelle geschrieben. Beendet wird dieser Vorgang durch den CommandButton "BEENDEN", welcher später das Speichern der Daten beinhalten soll, oder durch die Eingabe einer neuen Rechnung.
Bei der Eingabe einer neuen Rechnung wird der Kunde über die ComboBox0 gewählt, wobei unterschieden wird, ob es sich um einen Kunden mit eigener Konto-Nr. handelt, oder einen "Diversen", für welchen durch klicken des CommandButton "i" die Daten eingegeben werden.
Danach wird sofort eine Daten-Zeile mit der Anschrift des Kunden in die Tabelle geschrieben.
Nun sollen wie oben die Daten Position für Position eingegeben werden können und während der Eingabe fortlaufend berechnet werden.
Beendet soll dieser Vorgang wie bei der vorhandenen Rechnung werden. Wobei die neue Rechnung ohnehin nach Eingabe der KundenDaten, wie eine vorhandene behandelt werden soll.
Woran mir besonders liegt, ist das Problem ohne weitere CommandButtons, wie etwa "Änderung berechnen" und/oder "Eingabe beenden" o.ä. zu lösen.
Bei der Berechnung ist wichtig zu wissen, daß nicht nur die Variante Menge * Stückpreis = Gesamtpreis, sondern auch nur ein Gesamtpreis möglich sein sollte. In diesem Fall sollte die Stelle des Stückpreises leer bleiben.
Was meint Ihr zu meinem Ansatz, bin ich auf dem richtigen Weg?
Viele Grüße
Thomas

 Bild
Excel-Beispiele zum Thema "change-ereignis bei dynamischen Controls / Teil 2"
Im Change-Ereignis Eingabe in oder Leeren von Zellen erkennen Makroverzweigung im Change-Ereignis
Beispiele zum Einsatz des SelectionChange-Ereignisses Dynamischen Dialog erstellen
Summe über dynamischen Bereich bilden