ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 10.01.2000

Diese Seite wurde zuletzt aktualisiert am 10.01.2000
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Zurück...


Anzeige

(-hg) mailto:hg_findbuddy@aboutvb.de

Sicher haben auch Sie schon einmal einem vorhandenen Steuerelement zu neuen Fähigkeiten und Eigenschaften verholfen, indem Sie es auf einem UserControl platziert und so ein neues Steuerelement geschaffen haben. Sie kennen daher auch den notwendigen Aufwand und die sich oft ergebenden Probleme. Wenn das neue Steuerelement genauso flexibel wie das Original-Steuerelement sein soll, müssen Sie nahezu alle Eigenschaften, Methoden und Ereignisse über das UserControl an die Außenwelt weiterreichen - selbst mit Hilfe des Schnittstellen-Assistenten ist das meistens kein leichtes Unterfangen. Und die Probleme treten vor allem dann auf, wenn es um Eigenschaften geht, die Visual Basic stur als nur zur Entwicklungszeit änderbar behandelt.

Oftmals reicht es statt dessen, ein einfaches, zur Laufzeit selbst nicht sichtbares Zusatzsteuerelement zu schaffen, das die Funktionalität der gewünschten neuen Features aufnimmt und dem das Original lediglich als Partner zugewiesen wird (der Partner eines solchen Zusatzsteuerelements wird oft als "Buddy" bezeichnet). Die naheliegendste, wenn auch sehr unkomfortable Möglichkeit besteht darin, diese Zuweisung zur Laufzeit per Code vorzunehmen. Eleganter ist es da schon, das Form oder den Container von diesem Steuerelement selbst nach möglichen Partnern durchsuchen zu lassen und die Fundstücke auf einer Eigenschaftenseite (PropertyPage) zur Auswahl anzubieten.

Aber wäre es nicht der eleganteste Weg, wenn Sie die Partnerwahl ganz einfach im bequemen visuellen Design-Stil, sozusagen per Drag&Drop vornehmen könnten? Ganz einfach, indem Sie das Zusatzsteuerelement auf dem gewünschten Partner platzieren oder auf diesen darauf schieben? Es geht und ist gar nicht einmal sonderlich aufwändig.


Das kleine Zusatzsteuerelement mit dem "Fadenkreuz" findet automatisch ein darunter liegendes Partner-Steuerelement

Der Trick beruht darauf, dass nach dem Neuplatzieren eines Steuerelements auf einem Form und nach jedem Verschieben die Eigenschaften neu in das Eigenschaftenfenster eingelesen werden. Genauer gesagt bedeutet das, dass alle Property Get-Prozeduren derjenigen Eigenschaften ausgeführt werden, die im Eigenschaftenfenster erscheinen. Sie brauchen also lediglich eine Eigenschaft, deren Property Let-Prozedur zur Entwicklungszeit gar nichts tut und alles andere ihrem Gegenstück, der Property Get-Prozedur überlässt.

Dort bestimmen Sie (über die private Hilfsprozedur zFindListBox) zuerst die Position des Mittelpunkts des UserControls und ermitteln dann das Steuerelement des gewünschten Typs auf dem Elternformular, innerhalb dessen Fläche der zuvor bestimmte Mittelpunkt liegt, das sich im gleichen Container befindet und das nicht Element eines Control-Arrays ist (für Steuerelemente in Arrays funktioniert leider die Zuweisung zu einer mit WithEvents deklarierten Objekt-Variablen nicht).

Das folgende Beispiel zeigt, wie das Grundgerüst für ein solches Zusatzsteuerelement eine ListBox als Partner findet. Während der Laufzeit wird diese ListBox dann einer mit WithEvents als Ereignisempfänger deklarierten Objektvariablen zugewiesen. Ein ähnliches Verfahren des "Mithörens" von Ereignissen habe ich für Forms in Lausch-Eingriffe beschrieben.

Private WithEvents eListBox As ListBox
Private pListBox As String

Public Property Get ListBox() As String
  zFindListBox
  ListBox = pListBox
End Property

Private Sub zFindListBox()
  Dim nControl As Control
  Dim nLeft As Single
  Dim nTop As Single
  
  If Not Ambient.UserMode Then
    pListBox = ""
    With Extender
      nLeft = .Left + (.Width \ 2)
      nTop = .Top + (.Height \ 2)
    End With
    On Error Resume Next
    For Each nControl In UserControl.Parent.Controls
      If TypeOf nControl Is ListBox Then
        With nControl
          If .Container Is Extender.Container Then
            Select Case nLeft
              Case .Left To .Left + .Width
                Select Case nTop
                  Case .Top To .Top + .Height
                    If .Index < 0 Then
                      pListBox = .Name
                      If Ambient.UserMode Then
                        zSetListBoxControl
                      End If
                      Exit For
                    End If
                End Select
            End Select
          End If
        End With
      End If
    Next
    Extender.ZOrder 0
  End If
End Sub

Über die Methode FindListBox können Sie auch zur Laufzeit die ListBox ausfindig machen, über der sich das UserControl aktuell befindet:

Public Function FindListBox() As Object
  zFindListBox
  Set FindListBox = eListBox
End Function

Zur Entwicklungszeit passiert in den Prozeduren zum Setzen der Eigenschaft wirklich nichts, wie Sie hier sehen:

Public Property Let ListBox(ByVal New_ListBox As String)
  If Ambient.UserMode Then
    pListBox = New_ListBox
    zSetListBoxControl
  End If
End Property

Public Property Set ListBox(New_ListBox As Object)
  Dim nSuccess As Boolean
  
  If Ambient.UserMode Then
    pListBox = ""
    If TypeOf New_ListBox Is ListBox Then
      With New_ListBox
        If .Container Is Extender.Container Then
          On Error Resume Next
          Set eListBox = New_ListBox
          nSuccess = Not (eListBox Is Nothing)
          If nSuccess Then
            pListBox = .Name
          Else
            Set eListBox = Nothing
          End If
          RaiseEvent InitDone(nSuccess)
        Else
        End If
      End With
    End If
  End If
End Property

Private Sub zSetListBoxControl()
  Dim nControl As Control
  Dim nSuccess As Boolean
  
  Set eListBox = Nothing
  On Error Resume Next
  For Each nControl In UserControl.Parent.Controls
    With nControl
      If .Container Is Extender.Container Then
        If .Name = pListBox Then
          Set eListBox = nControl
          nSuccess = Not (eListBox Is Nothing)
          RaiseEvent InitDone(nSuccess)
          If nSuccess Then
            Exit For
          End If
        End If
      End If
    End With
  Next
  pListBox = ""
End Sub

Zur Laufzeit jedoch kann der Eigenschaft entweder der Name einer ListBox als String oder eine ListBox als Objekt-Referenz zugewiesen werden. In der Property Let-Prozedur wird die private Prozedur zSetListBoxControl aufgerufen. In dieser wird die Controls-Collection des UserControl.Parent nach einer ListBox anhand der gleichen Kriterien wie in der Prozedur zFindListBox durchsucht. Wird eine entsprechende ListBox gefunden, wird sie der Ereignisempfänger-Variablen eListBox zugewiesen. In der Property Set-Prozedur wird direct versucht, die übergebene ListBox der Ereignisempfänger-Variablen eListBox zuzuweisen, wenn sie sich im gleichen Container befindet. Konnte sie nicht zugewiesen werden, weil die ListBox aus einem Control-Array stammt, wird eine eventuell bereits vorhandene Referenz auf eine andere ListBox gelöscht. Sowohl in zSetListBoxControl als auch in der Property Set-Prozedur wird das Ereignis InitDone mit der entsprechenden Erfolgsmeldung ausgelöst.

Den Namen des gefundenen Partner-Steuerelements (hier: der ListBox) speichern wir auf für Eigenschaften übliche Weise:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  pListBox = PropBag.ReadProperty("ListBox", "")
  ' ...
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  PropBag.WriteProperty "ListBox", pListBox, ""
End Sub

Da so ein Zusatzsteuerelement oftmals zur Laufzeit nicht sichtbar zu sein braucht, steht der normalerweise ideale Platz für eine Zuweisung des Partner-Steuerelements zur Laufzeit nicht zur Verfügung - die Ereignisprozedur UserControl_Show. Das Problem besteht nämlich darin, dass die Reihenfolge, in der Steuerelemente vom Container (Form) geladen werden, prinzipiell nicht vorhersehbar ist (auch wenn es anders scheinen mag!). Beim ersten greifbaren Ereignis, UserControl_ReadProperties, ist noch niocht gewährleistet, dass das gewünschte Partner-Steuerelement bereits geladen ist und somit zugewiesen werden könnte. Beim Eintreffen des Ereignisses UserControl-Show eines sichtbaren Steuerelements wäre die Sicherheit gegeben - nur wie gesagt, in diesem Beispiel wird das Ereignis wegen der Unsichtbarkeit des Zusatzsteuerelements gar nicht ausgelöst. Wir behelfen uns daher mit einem Timer, der nur zur Laufzeit (Ambient-UserMode = True) im Ereignis ReadProperties aktiviert wird und nach Abschluss aller Ladevorgänge das erste Mal ausgelöst wird. In dessen Timer-Ereignis rufen wir nun die Hilfsprozedur zSetListBox auf, um die zum während der Entwicklungszeit gefundenen Namen passende ListBox zu finden. Die vollständige Ereignis-Prozedur UserControl_ReadProperties und die Timer-Ereignis-Prozedur sehen wie folgt aus:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  pListBox = PropBag.ReadProperty("ListBox", "")
  If Ambient.UserMode Then
    Extender.Visible = False
    If Len(pListBox) Then
      tmrSetListBox.Enabled = True
    End If
  End If
End Sub

Private Sub tmrSetListBox_Timer()
  tmrSetListBox.Enabled = False
  zSetListBoxControl
End Sub

Das weitere ist nur noch "Kosmetik" in diesem Beispiel zur Darstellung einer Art "Fadenkreuz" und zur Fixierung der Größe während der Entwicklungszeit. Ob wie Sie das bei Ihren eigenen Zusatzsteuerelementen ausgestalten, bleibt völlig Ihnen selbst überlassen.

Private Sub UserControl_Paint()
  If Not Ambient.UserMode Then
    With UserControl
      UserControl.Line (.ScaleWidth \ 2, 0)-Step(0, .ScaleHeight), _
       vbBlue
      UserControl.Line (0, .ScaleHeight \ 2)-Step(.ScaleWidth, 0), _
       vbBlue
      UserControl.Line (0, 0)-(.ScaleWidth - 1, .ScaleHeight - 1), _
       vbInfoText, B
    End With
  End If
End Sub

Private Sub UserControl_Resize()
  Static sInProc As Boolean
  
  If sInProc Then
    Exit Sub
  Else
    sInProc = True
  End If
  If Not Ambient.UserMode Then
    With UserControl
      .Size 1.5 * .TextHeight("A") * Screen.TwipsPerPixelX, _
       1.5 * .TextHeight("A") * Screen.TwipsPerPixelY
    End With
  End If
  sInProc = False
End Sub

Während der Laufzeit können Sie die gefundene Partner-ListBox beispielsweise folgendermaßen nutzen:

Private Sub eListBox_MouseUp(Button As Integer, Shift As Integer, _
 X As Single, Y As Single)

  MsgBox "MouseUp: " & eListBox.Name
End Sub

Korrekturen und Ergänzungen

09.11.1999

Ergänzung: Änderung

Erweiterung zum Setzen der Partner-ListBox zur Laufzeit


Beispiel-Projekt FindBuddyTest (findbuddy.zip - ca. 3,8 KB)






Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche



Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer