Rubrik: Controls · Sonstiges | VB-Versionen: VB5, VB6 | 06.11.05 |
Zentrale Auswertung der Control-Events Mit Hilfe eines Klassenmoduls werden die Events bestimmter oder aller Controls eines Formulars gekapselt und zentral ausgelöst. | ||
Autor: Roland Ortega | Bewertung: | Views: 19.888 |
ohne Homepage | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt auf CD |
Oft kommt es vor, dass man an einer zentralen Stelle auf die Ereignisse von verschiedenen Controls reagieren möchte. Beispielsweise habe ich mir angewöhnt, alle Interaktionen innerhalb eines Formulars in einer zentralen Prozedur zu sammeln. Je nach Listbox / Checkbox / Textbox Auswahl werden weitere Controls sichtbar / unsichtbar bzw enabled oder disabled.
Solange man nur mit Steuerelement-Feldern arbeitet ist das in VB ja gar kein Thema. Was ist aber, wenn man etliche unterschiedliche Textboxen hat. Immer wenn sich eine ändert, soll das ganze Formular zentral überprüft werden. Dann muss man für jede Textbox das Event "Change" programmieren. Das ist viel stupider Code.
Nachfolgend möchten wir Ihnen eine einfache Lösung mit Hilfe von Klassen vorstellen, in der man mit nur einer Event-Prozedur über etliche Events verschiedener Controls informiert wird.
Erstellen Sie ein neues Projekt und fügen ein neues Klassenmodul mit dem Namen "clsControlHandler" hinzu. Fügen Sie nachfolgenden Code in das Klassenmodul ein:
Option Explicit ' zusätzliche Control-Infos Private Type tpObjDaten Parent As clsMultiControlEvent InitOK As Boolean End Type Private m As tpObjDaten ' Hier alle Control-Objekte deklarieren, auf deren ' Ereignisse Sie zentral reagieren möchten Private WithEvents cTextbox As VB.TextBox Private WithEvents cListBox As VB.ListBox Private WithEvents cCommand As VB.CommandButton Private WithEvents cCheckBox As VB.CheckBox Private WithEvents cOptionButton As VB.OptionButton
' Initialisierung Public Sub Init(ByVal refCon As Object, Parent As clsMultiControlEvent) Set m.Parent = Parent m.InitOK = False ' keine Steuerelementfelder! Dim Index As Integer On Error Resume Next Index = refCon.Index If Err.Number <> 0 Then ' Objekt-Typ abfragen Select Case TypeName(refCon) Case "TextBox" Set cTextbox = refCon m.InitOK = True Case "ListBox" Set cListBox = refCon m.InitOK = True Case "CommandButton" Set cCommand = refCon m.InitOK = True Case "CheckBox" Set cCheckBox = refCon m.InitOK = True Case "OptionButton" Set cOptionButton = refCon m.InitOK = True End Select End If End Sub
' Rückgabe, ob Initialisierung erfolgreich war Public Property Get InitOK() As Boolean InitOK = m.InitOK End Property
' Referenz-Objkekte zerstören Public Sub Terminate() Set cTextbox = Nothing Set cListBox = Nothing Set cCommand = Nothing Set cCheckBox = Nothing Set cOptionButton = Nothing Set m.Parent = Nothing End Sub
' Klick-Event der CheckBox weiterleiten Private Sub cCheckbox_Click() m.Parent.Click cCheckBox End Sub ' GotFocus-Event der CheckBox weiterleiten Private Sub cCheckbox_GotFocus() m.Parent.GotFocus cCheckBox End Sub
' Klick-Event des CommandButton weiterleiten Private Sub cCommand_CLick() m.Parent.Click cCommand End Sub ' GotFocus-Event des CommandButton weiterleiten Private Sub cCommand_GotFocus() m.Parent.GotFocus cCommand End Sub
' Klick-Event des OptionButton weiterleiten Private Sub cOptionButton_Click() m.Parent.Click cOptionButton End Sub ' GotFocus-Event des OptionButton weiterleiten Private Sub cOptionButton_GotFocus() m.Parent.GotFocus cOptionButton End Sub
' Change-Event der TextBox weiterleiten Private Sub cTextbox_Change() m.Parent.Change cTextbox End Sub ' Click-Event der TextBox weiterleiten Private Sub cTextbox_Click() m.Parent.Click cTextbox End Sub ' GotFocus-Event der TextBox weiterleiten Private Sub cTextbox_GotFocus() m.Parent.GotFocus cTextbox End Sub
' Click-Event der ListBox weiterleiten Private Sub cListBox_Click() m.Parent.Click cListBox End Sub ' GotFocus-Event der ListBox weiterleiten Private Sub cListBox_GotFocus() m.Parent.GotFocus cListBox End Sub
Jetzt benötigen wir noch ein weiteres Klassenmodul mit dem Namen "clsMultiControlEvent" und folgendem Code:
Option Explicit ' Ereignisse Public Enum enEventtyp enClick = 1 ' Werte immer verdoppeln! enChange = 2 enGotFocus = 4 enLostFocus = 8 enAll = 15 ' Summe aus allen vorigen Werten End Enum Private Type tpObjDaten ContrClasses() As clsControlHandler Filter As enEventtyp End Type Private m As tpObjDaten ' zentrales Ereignis Public Event UniEvent(sourcename As String, sourceobj As Object, _ EventName As String, EventNr As enEventtyp)
Private Sub Class_Initialize() ' Initialisieren ReDim m.ContrClasses(0) m.Filter = enAll End Sub
' alle referenzierten Control-Objekte zerstören Public Sub Terminate() Dim i As Long For i = 1 To UBound(m.ContrClasses) m.ContrClasses(i).Terminate Next i ReDim m.ContrClasses(0) End Sub
Private Sub Class_Terminate() ' Klasse zerstören Terminate End Sub
' Ereignis-Filter setzen Public Sub Filter(OnlyRiseTheseEvents As enEventtyp) m.Filter = OnlyRiseTheseEvents End Sub
' Hinzufügen eines einzelnen ControlsA Public Sub Add(refCon As Control) Dim nCount As Long nCount = UBound(m.ContrClasses) + 1 ReDim Preserve m.ContrClasses(nCount) Set m.ContrClasses(nCount) = New clsControlHandler m.ContrClasses(nCount).Init refCon, Me If Not m.ContrClasses(nCount).InitOK Then m.ContrClasses(nCount).Terminate ReDim Preserve m.ContrClasses(nCount - 1) End If End Sub
' mehrere Controls auf einmal hinzufügen Public Sub AddMulti(ParamArray refControls() As Variant) Dim i As Long Dim nCount As Long nCount = UBound(refControls) ReDim m.ContrClasses(nCount + 1) For i = 0 To UBound(refControls) Set m.ContrClasses(i + 1) = New clsControlHandler m.ContrClasses(i + 1).Init refControls(i), Me Next i End Sub
' Alle Controls der übergebenen Form hinzufügen Public Sub AddFormComplete(refForm As Form) Dim oControl As Object Dim i As Long i = 0 For Each oControl In refForm.Controls i = i + 1 ReDim Preserve m.ContrClasses(i) Set m.ContrClasses(i) = New clsControlHandler m.ContrClasses(i).Init oControl, Me If m.ContrClasses(i).InitOK = False Then m.ContrClasses(i).Terminate i = i - 1 End If Next End Sub
' Click-Ereignis zentral auslösen, falls nicht ausgefiltert Friend Sub Click(sourceobj As Object) If (m.Filter And enClick) = 0 Then Exit Sub RaiseEvent UniEvent(sourceobj.Name, sourceobj, "Click", enClick) End Sub ' Change-Ereignis zentral auslösen, falls nicht ausgefiltert Friend Sub Change(sourceobj As Object) If (m.Filter And enChange) = 0 Then Exit Sub RaiseEvent UniEvent(sourceobj.Name, sourceobj, "Change", enChange) End Sub ' GotFocus-Ereignis zentral auslösen, falls nicht ausgefiltert Friend Sub GotFocus(sourceobj As Object) If (m.Filter And enGotFocus) = 0 Then Exit Sub RaiseEvent UniEvent(sourceobj.Name, sourceobj, "GotFocus", enGotFocus) End Sub
Anwendung der Klassen
Nachfolgend ein kleines Beispiel, das die Anwendung der Klasse verdeutlichen soll.
Platzieren Sie auf die Form1 folgende Controls:
- TextBox "Text1"
- TextBox "Text2"
- ListBox "List1"
- CommandButton "Command1"
- CheckBox "Check1"
- Label "Label1"
Fügen Sie in den Codeteil der Form1 folgenden Code ein:
Option Explicit ' Klassenobjekt der zentralen Event-Behandlung Private WithEvents MultiEvent As clsMultiControlEvent
Private Sub Form_Load() ' Klasse instanzieren Set MultiEvent = New clsMultiControlEvent ' Möglichkeit 1: Die Controls einzeln übergeben ' MultiEvent.Add Me.Text1 ' MultiEvent.Add Me.Text2 ' MultiEvent.Add Me.List1 ' ... ' Möglichkeit 2: alle auf einmal..... ' MultiEvent.AddMulti Me.Text1, Me.Text2, Me.List1, ... ' Möglichkeit 3: der ganz heftige Weg... MultiEvent.AddFormComplete Me ' Falls nur auf bestimmte Ereignisse reagiert werden soll ' MultiEvent.Filter enClick End Sub
Private Sub MultiEvent_UniEvent(sourcename As String, _ sourceobj As Object, EventName As String, EventNr As enEventtyp) ' Contorlname und Ereignis im Label-Control anzeigen Me.Label1.Caption = sourcename & " : " & EventName End Sub
Private Sub Form_Unload(Cancel As Integer) ' Klasse zerstören Set MultiEvent = Nothing End Sub
Hauptnutzen dieser Klasse ist für mich die Formularsteuerung.
Beispiel:
Ein kleines Rechenprogramm bestehend aus den Feldern: Beitrag, Laufzeit, Zinssatz, Anfangskapital und Dynamik weist am Ende das Guthaben aus. Natürlich soll nach Änderung eines beliebigen Wertes die Endsumme neu berechnet werden. Und da gibt es eben die Möglichkeit Steuerelementefeld (=> schlecht lesbarer Code) oder eben für jedes Feld die Click/Change Eventprozedur.