|
Der Tag-Eigenschaft der "Mengen"-Elemente der Microsoft
Common Controls in Visual Basic 6 (Node beim TreeView,
ListItem beim ListView, Button bei der Toolbar usw.) können Sie
direkt ein Objekt zuweisen. Dies ist ganz praktisch, wenn Sie mit
diesen Steuerelementen Objekt-Sammlungen verwalten und etwa bei der
Auswahl eines der Elemente direkten Zugriff auf ein von diesem
repräsentierten Objekt haben möchten. Bei den Microsoft Common
Controls in Visual Basic 6 ist die Tag-Eigenschaft
nämlich vom Datentyp Variant. Bei den Vorgängerversionen der
Microsoft Common Controls (in Visual Basic 4 und
5) sind die Tag-Eigenschaften lediglich vom Datentyp String,
wie das auch bei allen übrigen Steuerelementen in Visual Basic
gewöhnlich der Fall ist. Genau so eingeschränkt ist die
ItemData-Eigenschaft der Elemente der ListBox und der ComboBox. Sie
ist vom DatenTyp Long, und somit können Sie dieser auch kein Objekt
direkt zuweisen.
Nun können Sie zwar in der gewöhnlichen Tag-Eigenschaft oder in
der ItemData-Eigenschaft indirekt einen Verweis auf ein Objekt
unterbringen, indem Sie den hinter einer Objekt-Variablen stehenden
Zeiger, die eigentliche Referenz auf ein Objekt, dort ablegen.
Diesen Zeiger (ein Long-Wert) ermitteln Sie mit der undokumentierten
VB-Funktion ObjPtr:
Zeiger = ObjPtr(Objekt)
und damit:
Command1.Tag = Zeiger
ListBox.ItemData(Index) = Zeiger
Das Problem ist nur, dass Ihnen dieser Zeiger selbst nicht viel
weiter hilft, wenn Sie wieder auf das dazugehörige Objekt zugreifen
wollen. Mit Hilfe der API-Funktion CopyMemory
(sie wird meistens unter diesem Namen deklariert, heißt aber
eigentlich RtlMoveMemory) können Sie wieder eine wie gewohnt zu
verwendende Objekt-Referenz in einer Objekt-Variablen erhalten. Sie
kopieren einfach den Zeiger in eine leere, uninitialisierte
Objekt-Variable. Da durch die Anwendung dieses Tricks die interne
Objekt-Verwaltung in Visual Basic durcheinander geraten ist, wäre
aber der normale Weg, die Objekt-Variable auf Nothing zu setzen,
oder die Objekt-Variable mit dem Verlassen des Gültigkeitsbereichs
"sterben" zu lassen, einfach tödlich - Ihre Anwendung
würde sich sang- und klanglos verabschieden. Sie müssen die auf
diese Weise erzeugten Objekt-Referenz nach der Verwendung selbst
wieder freigeben, indem Sie die Referenz abschließend mit einem
Nullzeiger (Wert 0) überschreiben.
Wenn Sie aber die so erzeugte Objekt-Referenz vor der Freigabe
einer anderen Objekt- Variablen zuweisen, erhalten Sie eine wie
gewohnt verwendbare Objekt-Referenz. Der hierfür zuständige
interne Mechanismus in Visual Basic ist nicht durcheinander geraten.
Der Einfachheit halber packen Sie die gesamte Aktion in eine
Hilfs-Funktion:
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (dest As Any, source As Any, _
ByVal bytes As Long)
Public Function PtrToObject(ByVal iObj As Variant) As Object
Dim nObj As Object
If VarType(iObj) = vbLong Then
CopyMemory nObj, CLng(iObj), 4
Else
Exit Function
End If
Set PtrToObject = nObj
CopyMemory nObj, 0&, 4
End Function
Den Einsatz dieser Technik im Zusammenhang mit Tag- und
ItemData-Eigenschaften zeigt das folgende kleine Beispiel. Hier
können Sie in einer ListBox auswählen, welches von vier
verschiedenen Icons, sichtbar sein soll. Zum Start des
Progrämmchens sind alle vier Icons, jeweils in einem
Image-Steuerelement untergebracht, zunächst noch unsichtbar.
Private Sub Form_Load()
With List1
.AddItem "CD-ROM"
.ItemData(.NewIndex) = ObjPtr(Image1)
.AddItem "Disk 5,25"""
.ItemData(.NewIndex) = ObjPtr(Image2)
.AddItem "Disk 3,5"""
.ItemData(.NewIndex) = ObjPtr(Image3)
.AddItem "Harddisk"
.ItemData(.NewIndex) = ObjPtr(Image4)
.ListIndex = 0
End With
End Sub
Private Sub List1_Click()
Dim nCmd As Image
Dim nTag As Long
With List1
nTag = Val(.Tag)
If nTag <> 0 Then
PtrToObject(nTag).Visible = False
End If
nTag = .ItemData(.ListIndex)
PtrToObject(nTag).Visible = True
.Tag = nTag
End With
End Sub
|