Sie sind auf Seite 1von 680

visual basic 6

referenz
visual basic 6
referenz

rudolf huttary

new technology

Markt+Technik Verlag
Die Deutsche Bibliothek – CIP-Einheitsaufnahme

Ein Titeldatensatz für diese Publikation ist bei


Der Deutschen Bibliothek erhältlich.

Die Informationen in diesem Produkt werden ohne Rücksicht auf einen


eventuellen Patentschutz veröffentlicht.
Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt.
Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter
Sorgfalt vorgegangen.
Trotzdem können Fehler nicht vollständig ausgeschlossen werden.
Verlag, Herausgeber und Autoren können für fehlerhafte Angaben
und deren Folgen weder eine juristische Verantwortung noch
irgendeine Haftung übernehmen.
Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und
Herausgeber dankbar.

Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der
Speicherung in elektronischen Medien.
Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten
ist nicht zulässig.

Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden,
sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet
werden.

Umwelthinweis:
Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt.
Die Einschrumpffolie – zum Schmutz vor Verschmutzung – ist aus
umweltverträglichem und recyclingfähigem PE-Material.

10 9 8 7 6 5 4 3 2 1

03 02 01 00

ISBN 3-8272-5588-0

© 2000 by Markt+Technik Verlag,


ein Imprint der Pearson Education Deutschland GmbH,
Martin-Kollar-Straße 10–12, D 81829 München/Germany
Alle Rechte vorbehalten
Lektorat: Erik Franz, efranz@pearson.de
Herstellung: Claudia Bäurle, cbaeurle@pearson.de
Satz: reemers publishing services gmbh, Krefeld
Druck und Verarbeitung: Media Print, Paderborn
Printed in Germany
Inhaltsverzeichnis
Vorwort 15
Lesebuch und Nachschlagewerk 15
Gut verwurzelt: traditionelles Basic vs. Visual Basic 16
Zielgruppe 18

Teil I: Referenzteil 21
Grundlegendes 23
Programme und Module in Visual Basic 23
Programm 23
Modul 24
Projekt 24
Arten von Modulen in einem Projekt 25
Literale und Konstanten 27
Anweisungen 33
Bezeichner und Namensraum 34
Kontrollstrukturen 36
Unbedingte und bedingte Verzweigung, Subroutinen 36
Fallunterscheidung 38
Schleifen 40
Fehlerbehandlung 43

Datentypen und ihre Operationen 49


Elementare Datentypen 49
Der Datentyp Variant 50
Die Datentypen Integer, Long, Single und Double 51
Die Datentypen Boolean und Byte 52
Die Datentypen Currency und Date 52
Der Datentyp Decimal 53
Operatoren für elementare Datentypen und logische Bedingungen 54
Arrays 55
Typumwandlung 57
Benutzerdefinierte Datentypen 60
Type-Datentypen 61
Enum-Aufzählungen 62
Funktionen und Anweisungen für Zeichenfolgen 63
Asc-, AscB- und AscW-Funktion 66
Chr-, ChrB- und ChrW-Funktion 67
Filter-Funktion 68
Format-Funktion 69
FormatCurrency-Funktion 73
FormatDateTime-Funktion 74
FormatNumber-Funktion 75

5
Inhaltsverzeichnis

FormatPercent-Funktion 75
Hex-Funktion 76
InStr- und InStrB-Funktion 76
InStrRev-Funktion 77
Join-Funktion 78
LCase-Funktion 79
Left- und LeftB-Funktion 79
Len- und LenB-Funktion 79
LSet-Anweisung 80
LTrim-Funktion 81
Mid- und MidB-Funktion 81
Mid- und MidB-Anweisung 82
MonthName-Funktion 82
Oct-Funktion 82
Option Compare-Anweisung 83
Replace-Funktion 84
Partion-Funktion 85
Right- und RightB-Funktion 85
RSet-Anweisung 86
RTrim-Funktion 86
Space-Funktion 86
Split-Funktion 87
Str-Funktion 87
StrComp-Funktion 88
StrConv-Funktion 89
String-Funktion 90
StrReverse-Funktion 90
Trim-Funktion 90
UCase-Funktion 91
Val-Funktion 91
WeekdayName-Funktion 92
Mathematische und finanzmathematische Funktionen und Anweisungen 92
Abs-Funktion 94
Atn-Funktion 95
Cos-Funktion 95
DDB-Funktion 96
Exp-Funktion 97
Fix-Funktion 97
FV-Funktion 98
Int-Funktion 99
IPmt-Funktion 99
IRR-Funktion 100
Log-Funktion 101
MIRR-Funktion 102
NPer-Funktion 103
NPV-Funktion 104

6
Inhaltsverzeichnis

Pmt-Funktion 105
PPmt-Funktion 106
PV-Funktion 106
Randomize-Anweisung 107
Rate-Funktion 108
Rnd-Funktion und Rnd-Anweisung 109
Round-Funktion 110
Sgn-Funktion 110
Sin-Funktion 112
SLN-Funktion 112
Sqr-Funktion 113
SYD-Funktion 113
Tan-Funktion 114
Funktionen und Anweisungen für Datums-/Zeitwerte 114
CDate-Funktion 116
Date-Funktion und Date-Anweisung 116
DateAdd-Funktion 116
DateDiff-Funktion 117
DatePart-Funktion 118
DateSerial-Funktion 119
DateValue-Funktion 120
Day-Funktion 121
FileDateTime-Funktion 121
FormatDateTime-Funktion 121
Hour-Funktion 121
Minute-Funktion 121
Month-Funktion 122
MonthName-Funktion 122
Now-Funktion 122
Second-Funktion 122
Time-Funktion und Time-Anweisung 123
Timer-Funktion 124
TimeSerial-Funktion 124
TimeValue-Funktion 125
Weekday-Funktion 125
WeekdayName-Funktion 126
Year-Funktion 126
Dateiorientierte Funktionen und Anweisungen 126
ChDir-Anweisung 131
ChDrive-Anweisung 132
Close-Anweisung 133
CurDir-Funktion 134
Dir-Funktion 135
Environ-Funktion 136
EOF-Funktion 137
FileAttr-Funktion 138

7
Inhaltsverzeichnis

FileCopy-Anweisung 138
FileDateTime-Funktion 139
FileLen-Funktion 139
FreeFile-Funktion 139
Get-Anweisung 140
GetAttr-Funktion 142
Input- und InputB-Funktion 142
Input #-Anweisung 143
Kill-Anweisung 144
Line Input #-Anweisung 145
Loc-Funktion 146
Lock-Anweisung 146
LOF-Funktion 147
LSet-Anweisung 148
MkDir-Anweisung 148
Name-Anweisung 148
Open-Anweisung 149
Print #-Anweisung 151
Put-Anweisung 153
Reset-Anweisung 154
RmDir-Anweisung 155
Seek-Anweisung und Seek-Funktion 156
SetAttr-Anweisung 157
Shell-Anweisung 158
Unlock-Anweisung 159
Write #-Anweisung 159

Variablen 161
Variablendeklaration 162
Typkennzeichen und Bezeichnerbereiche für Typen 167
Variableninitialisierung 168
Geltungsbereiche von Variablen 173

Funktionen und Prozeduren 175


Parameterübergabe an Funktionen und Prozeduren 178
Funktionen selbst definieren 181
Prozeduren selbst definieren 183
Routinen aus DLLs und der Windows-API einsetzen 185

Objekte und Klassen 195


Klassen als Datentypen für Objektvariablen 196
Ereignisroutinen 204
Standardereignisse 207
Activate-Ereignis und Deactivate-Ereignis 212
Change-Ereignis 214
Click-Ereignis 215
DblClick-Ereignis 217

8
Inhaltsverzeichnis

DragDrop-Ereignis 218
DragOver-Ereignis 221
GotFocus-Ereignis und LostFocus-Ereignis 222
Initialize-Ereignis 224
KeyDown-Ereignis und KeyUp-Ereignis 225
KeyPress-Ereignis 228
LinkClose-Ereignis 230
LinkError-Ereignis 231
LinkExecute-Ereignis 232
LinkNotify-Ereignis 233
LinkOpen-Ereignis 233
Load-Ereignis 236
MouseDown-Ereignis und MouseUp-Ereignis 237
MouseMove-Ereignis 239
OLECompleteDrag-Ereignis 241
OLEDragDrop-Ereignis 242
OLEDragOver-Ereignis 245
OLEGiveFeedback-Ereignis 247
OLESetData-Ereignis 248
OLEStartDrag-Ereignis 250
Paint-Ereignis 253
QueryUnload-Ereignis 256
Resize-Ereignis 257
Terminate-Ereignis 258
Unload-Ereignis 259
Validate-Ereignis 260
Global-Objekt 261
App-Objekt 264
CallByName-Methode 269
Clipboard-Objekt 270
Command-Methode 273
CreateObject-Methode 273
DeleteSetting-Methode 275
DoEvents-Methode 276
Err-Objekt 277
Forms-Auflistung 279
GetAllSettings-Methode 279
GetObject-Methode 280
GetSetting-Methode 281
InputBox-Methode 281
Load-Methode 282
LoadPicture-Methode 283
LoadResData-Methode, LoadResPicture-Methode,
LoadResString-Methode 284
Printer-Objekt 284
Printers-Auflistung 297

9
Inhaltsverzeichnis

QBColor-Methode 298
RGB-Methode 299
SavePicture-Methode 299
SaveSetting-Methode 300
Screen-Objekt 300
Sendkeys-Methode 302
Unload-Methode 303
Auflistungen und Collection-Objekte 304
Formulare 306
Form-Objekt (Basisobjekt für Formulare) 307
MDIForm-Objekt 313
Selbst definierte Klassen 318
ClassModul-Schnittstelle 320

Steuerelemente 321
Gemeinsame Eigenschaften 323
Alignment-Eigenschaft 327
Appearance-Eigenschaft 328
AutoSize-Eigenschaft 329
BackColor-Eigenschaft und ForeColor-Eigenschaft 330
BackStyle-Eigenschaft 331
BorderStyle-Eigenschaft 332
Caption-Eigenschaft 334
Container-Eigenschaft 335
CausesValidation-Eigenschaft 335
DataChanged-Eigenschaft 336
DataField-Eigenschaft 336
DataFormat-Eigenschaft 338
DataMember-Eigenschaft 339
DataSource-Eigenschaft 339
DisabledPicture-Eigenschaft 341
DownPicture-Eigenschaft 341
DragIcon-Eigenschaft 342
DragMode-Eigenschaft 343
DrawMode-Eigenschaft 344
DrawStyle-Eigenschaft 346
Enabled-Eigenschaft 347
FillColor-Eigenschaft 348
FillStyle-Eigenschaft 349
Font-Eigenschaft 349
ForeColor-Eigenschaft 350
HasDC-Eigenschaft 350
hDC-Eigenschaft 351
Height-Eigenschaft und Width-Eigenschaft 351
HelpContextID-Eigenschaft und WhatsThisHelpID-Eigenschaft 353
hWnd-Eigenschaft 354
Image-Eigenschaft 354

10
Inhaltsverzeichnis

Index-Eigenschaft 356
Left-Eigenschaft und Top-Eigenschaft 357
MaskColor-Eigenschaft 358
MouseIcon-Eigenschaft 359
MousePointer-Eigenschaft 360
MultiLine-Eigenschaft 361
Name-Eigenschaft 361
OLEDropAllowed- und OLETypeAllowed-Eigenschaften 362
OLEDropMode-Eigenschaft 363
Parent-Eigenschaft 364
Picture-Eigenschaft 365
RightToLeft-Eigenschaft 366
ScaleLeft-Eigenschaft und ScaleTop-Eigenschaft 366
ScaleHeight-Eigenschaft und ScaleWidth-Eigenschaft 368
ScaleMode-Eigenschaft 369
ShowTips-Eigenschaft 371
Style-Eigenschaft 372
TabIndex-Eigenschaft 375
TabStop-Eigenschaft 376
Tag-Eigenschaft 376
ToolTipText-Eigenschaft 377
UseMaskColor-Eigenschaft 377
Visible-Eigenschaft 378
WhatsThisHelp-Eigenschaft 378
WhatsThisHelpID-Eigenschaft 378
Width-Eigenschaft 379
Gemeinsame Methoden 379
Drag-Methode 379
LinkExecute-Methode 380
LinkPoke-Methode 381
LinkRequest-Methode 382
LinkSend-Methode 382
Move-Methode 383
OLEDrag-Methode 383
Refresh-Methode 384
SetFocus-Methode 385
ShowWhatsThis-Methode 386
ZOrder-Methode 386
Standardsteuerelemente 387
Anzeige-Steuerelement (Image) 390
Befehlsschaltfläche-Steuerelement (CommandButton) 392
Bezeichnungsfeld-Steuerelement (Label) 393
Bildfeld-Steuerelement (PictureBox) 395
Bildlaufleisten-Steuerelemente (HScrollBar, VScrollBar) 398
Dateilistenfeld-Steuerelement (FileListBox) 400
Data-Datensteuerelement (Data) 402

11
Inhaltsverzeichnis

Figur-Steuerelement (Shape) 406


Kombinationsfeld-Steuerelement (ComboBox) 407
Kontrollkästchen-Steuerelement (CheckBox) 409
Laufwerklistenfeld-Steuerelement (DriveListBox) 410
Linie-Steuerelement (Line) 411
Listenfeld-Steuerelement (ListBox) 412
OLE-Container-Steuerelement (OLE) 415
Optionsfeld-Steuerelement (OptionButton) 424
Rahmen-Steuerelement (Frame) 426
Textfeld-Steuerelement (TextBox) 427
Verzeichnislistenfeld-Steuerelement (DirListBox) 431
Zeitgeber-Steuerelement (Timer) 432
ActiveX-Steuerelemente (OCX) – Windows-Standardsteuerelemente 433
Abbildungsliste-Steuerelement (ImageList) 436
Weitere ActiveX-Steuerelemente 439
Bildausschnitt-Steuerelement (PictureClip) 442
Standarddialoge-Steuerelement (CommonDialog) 444

Teil II: Praxisteil 451


Ältere Basic-Programme nach Visual Basic portieren 453
Wie importiert man den Quelltext? 454
Einfache Programme 454
Implementation einer eigenen Input-Routine 456
Anspruchsvollere Programme 457
Implementation von Inkey$ 459
Implementation von LOCATE, POS, CSRLIN und COLOR 460
Koordinatensystem und Grafikmodus 461
Zusammenfassung der Emulation als Standardmodul 463
Von WANKEL.BAS zur WankelAnimation 468
Die portierte Fassung 472

Mathematik und Algorithmen 477


ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge 478
Implementation des Apfelmännchen-Algorithmus 484
Optimierung 485
Ereignisbehandlung mit DoEvents, ein komplexes Problemfeld 485
Benutzerschnittstelle 487
Der Stack 488
Einzelbilder speichern 489

Formulare und Ansichten 491


Ereignisbehandlung 491
Gummiband – Bereiche interaktiv auswählen 492
DDE-Verbindungen 495
OLE-Drag&Drop 501

12
Inhaltsverzeichnis

DiaProjektor – SDI-Formulare synchronisieren 511


Das Programmdesign 514
Info-Dialog als gebundenes Formular aufrufen 525
Ereignisse delegieren und Instanziierung durch One-Shot-Logik 525
Programmstart und Auswahl der Bilddateien im
Standarddialog Öffnen 527
Das Anzeigesystem 530
Bilder einlesen und in maximaler Größe zeichnen 535
Vollbildanzeige 536
Menü und Kontextmenü 538
Benutzerschnittstelle 542
Bildlaufleisten für Ansichten einsetzen und auf
Größenänderungen reagieren 544
Bildlauf – ein kleiner Betrachter für große Bilder 545
HexView – eine schnelle Textansicht für große Dateien 551
Registrierung 561
RegTest – Sitzungen wieder aufnehmen 562

Objektorientiertes Basic 567


Klassen selbst definieren 567
Ring – eine einfache Klasse demonstriert Grundlegendes 568
3DAnimation – Drahtgittermodelle frei im Raum gedreht 577
Point3D – ein Punkt im Raum 582
Line3D – eine Linie aus zwei Punkten 586
ActiveX-Steuerelemente und Benutzersteuerelemente 599
LongTimer – der Timer mit Ausdauer 599
Transparenz und Drag&Drop 606
MemoryEdit – das Textfeld mit Gedächtnis 615
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic 642

Tabellenindex 659

13
Vorwort
Wer heute nicht täglich mit einem bestimmten Produkt, etwa einem Entwicklungssystem wie
Visual Basic, einer Tabellenkalkulation oder einer Textverarbeitung arbeitet, sondern eher spo-
radisch, dem bleibt nichts anderes übrig, als erst einmal erhebliche Mengen an wertvoller Zeit
schlicht damit zu vergeuden, sich und sein System immer wieder auf den neuesten Stand des
jeweiligen Produkts zu bringen. Der Effizienzvorsprung, den der neueste Stand des Produkts
verspricht, muss oft sehr teuer mit Lernaufwand und der Umgestaltung bestehender Lösungen
erkauft werden. Die Hersteller wollen nicht nur, dass ein Produkt in der neuen Version äußer-
lich anders erscheint, die zusätzlichen Features sowie die Anpassung an eine sich ständig
ändernde Umgebung (Benutzeroberfläche, Betriebssystem, Entwicklungsplattform, Vernetzung,
verwandte Produkte) erzwingen in den meisten Fällen auch Änderungen des inneren Aufbaus,
eingeführter Daten- und Kommunikationsstrukturen und nicht zuletzt auch erhebliche Ände-
rungen in der Dokumentation. Damit wären wir bereits beim Thema.

Lesebuch und Nachschlagewerk


Dieses Buch reiht sich mit seinem Titel in die 1999 neu ins Leben gerufene Referenzreihe des
Markt+Technik-Verlags ein. Maßgeblich für das Erscheinen dieser neuen Reihe war der
Wunsch vieler semi- wie professioneller Programmierer nach verdichteten Referenzinformatio-
nen mit ineinander greifender theoretischer und praktischer Aufarbeitung, mit anderen Worten,
der schnelle und gleichzeitig kompetente Überblick über ein Sprachprodukt mit nichttrivialen
praktischen Anregungen – als Nachschlagewerk für den Einstieg, Umstieg sowie die Auffri-
schung für die konkrete Arbeit mit dem Produkt.
Die Titel in dieser Reihe geben Antwort auf die Fragen »Was ist das?« und »Wie geht das?« –
und dies in einer für den Einzelnen noch überschaubaren Weise. Das Buch soll dem Käufer als
Lesebuch und als Nachschlagewerk dienen, es soll ihm also das nötige Know-how für seine Pro-
grammiertätigkeit vermitteln und ihm gleichzeitig Anregungen und Lösungen anbieten, die er in
seine Programmierarbeit einfließen lassen kann. Schaltstelle und Garant für die gute gegensei-
tige Durchdringung der Themen im Referenz- und Praxisteil ist der zentrale Tabellenindex im
Anhang, dessen themen- und sachbezogene Einträge überwiegend in beiden Teilen Fundstellen
ausweisen.
Heutige Online-Hilfen zu Produkten können dies aus verschiedenen Gründen eher schlecht als
recht bzw. immer häufiger gar nicht mehr leisten. So, weil sie sich über die Versionen hinweg
immer weiter aufgeblasen haben, ohne strukturell überarbeitet worden zu sein, weil sie auf-
grund schlechter und unvollständiger Aufarbeitungen teilweise bereits in sich widersprüchlich
geworden sind, weil sie aufgrund erbärmlicher Indizes nur sehr zeitraubend zu handhaben sind
und nicht zuletzt, weil sie in ihrem enzyklopädischen Charakter keinerlei Gewichtung der
Informationen nach Kriterien der Brauchbarkeit und dem Wissensstand des Lesers mehr enthal-
ten. Ein wirklich pathologisches Beispiel einer solchen Online-Hilfe ist die MSDN Library für
Visual Studio 6.0. Der monumentale Fundus dieses in seinem Format inzwischen auf den Inter-
net Explorer zugeschnittenen Hilfesystems ist auf zwei CDs verteilt und stellt einen Rundschlag
an Informationen über die wichtigeren Sprachprodukte von Microsoft dar – darunter zu Visual
Basic, Visual C++, Visual J++, Visual FoxPro sowie die SDK- und die DDK-Dokumentation.
Die Benutzbarkeit des Systems lässt jedoch extrem zu wünschen übrig. Erstens wurden Text
und Index teilweise eingedeutscht, was für den Index eine echte Katastrophe darstellt, teilweise
im amerikanischen Original belassen, und zweitens wurde bei der indexikalischen Suche
schlicht vergessen, die Produktzugehörigkeit der einzelnen Themen mit anzugeben. Die Voll-
textsuche leistet dies zwar, erschlägt einen aber schier mit der Fülle der Fundstellen. Wer dieser
Hilfe in annehmbarer Zeit etwas halbwegs Vernünftiges über Visual Basic entlocken will, tut

15
Gut verwurzelt: traditionelles Bas ic vs. Visual Basic

gut daran, sich über das Menü ANSICHT/UNTERMENGE DEFINIEREN als Erstes eine Quellenaus-
wahl in Form einer Untermenge zusammenzustellen und diese für die weitere Arbeit als Filter zu
benutzen.
Eine gedruckte Referenz zu Visual Basic im Umfang des vorliegenden Buches kann es sich nicht
leisten, ausgiebigst auf allen Hochzeiten zu tanzen – das sei der Online-Hilfe vorbehalten. Viel-
mehr stellt sich die gedruckte Referenz der Aufgabe, die Ecken und Kanten abzuschleifen, die
ein Verständnis der Sprache oder spezifische Problemlösungen erschweren, indem sie Zusam-
menhängendes als solches aufzeigt, begreiflich darstellt und in seinen relevanten Dimensionen
exemplarisch erläutert. Entscheidend ist dabei die Auswahl und Verdichtung der behandelten
Thematiken, die zwar nicht in jedem Fall, so doch aber in der Mehrzahl der Fälle eine Vertie-
fung der eher lax gehaltenen Online-Hilfe zu Visual Basic erreicht.
Gut verwurzelt: traditionelles Basic vs. Visual Basic

Der vorliegende Band enthält eine umfassende Darstellung der Konzepte, Funktionen und
Objekte von Visual Basic als Programmiersprache und Entwicklungsplattform, beschränkt sich
aber in seiner Themenauswahl auf die »Innensicht der Sprache«, ohne sich allzu weit in der
Welt des ActiveX, der Automatisierung, der Datenbankprogrammierung sowie generell des
COM (bzw. DCOM) zu verlieren. Grob gesehen deckt der Band das gesamte Instrumentarium
von Visual Basic inklusive aller Standardsteuerelemente sowie ausgewählter Windows-Stan-
dardsteuerelemente und die Programmierung eigener Benutzersteuerelemente ab.

Gut verwurzelt: traditionelles Basic vs. Visual Basic


Keiner anderen Programmiersprache haftet so stark das Etikett an, in Hunderte verschiedener
Dialekte zerfallen zu sein, wie Basic. Das liegt zum einen daran, dass Basic über lange Zeit hin-
weg, insbesondere für die ersten in ihren Möglichkeiten massiv beschränkten Mikrocomputer
und später für den PC die mit dem Betriebssystem ausgelieferte Standardsprache darstellte –
wenn es nicht gar, wie etwa für den Commodore C64 zur Kommandosprache für das Betriebs-
system selbst avanciert war. Zum anderen liegt es aber auch daran, dass die Sprache in ihrer
Entwicklung einer weniger rigiden Kontrolle durch Standardisierungskomitees und -gremien
ausgesetzt war als die anderen – vielleicht wegen des Buchstabens »B« im Akronym, der ja
bekanntlich für »Beginners« steht. Unterschwellig mag dabei freilich auch noch das Vorurteil
mitgeschwungen haben, Basic werde aufgrund seiner Begrenztheit als Entwicklungssprache für
ernst zu nehmende Anwendungen sowieso nie taugen.
Ein großes Veränderungspotential geht aber auch mit einem großen Entwicklungspotential und
der Fähigkeit zur schnellen Adaption einher. In der Tat haben im letzten Jahrzehnt die Philoso-
phien für Benutzeroberflächen und Betriebssysteme einen massiven Wandel durchgemacht. Das
gilt in besonders krasser Weise für den PC. Da ist es nicht verwunderlich, wenn sich auch die
Anforderungen verlagert haben, denen eine Programmiersprache bei der Anwendungsentwick-
lung für moderne Benutzeroberflächen genügen muss. Eine wichtige Rolle spielen heute Objekt-
orientierung, Modularisierung und Prozesskommunikation. Mit anderen Worten, das monoli-
thische Programm, das isoliert von anderen Anwendungen den ihm zugedachten Aufgaben
nachkommt, indem es seine eigenen Datenformate und Algorithmen strickt, seine eigene Benut-
zerschnittstelle parat hält und vielleicht noch so tut, als gehöre ihm die Maschine alleine, hat
unwiderruflich ausgedient. Gefragt sind überschaubare, möglichst allgemein einsetzbare Kom-
ponenten, die im Dienste der Allgemeinheit das Ihre zum Großen Ganzen beitragen. Dieser
neue Zeitgeist hört auf den Namen COM (Component Object Model), eine sprachübergrei-
fende Spezifikation, die die Implementation und das Miteinander von Objekten in dieser Welt
regelt. Microsoft hat seinen Beitrag an der technologischen Umsetzung dieser Konzeption (mit
Blick auf die Internet-Programmierung) unter der Bezeichnung ActiveX zusammengefasst. Einer
Anwendung, gleich in welcher Sprache sie realisiert wird, stehen damit vonseiten des Betriebs-
systems komplexe, allgemein gehaltene Bausteine in Form von Komponenten (Steuerelemente,

16
Gut verwurzelt: traditionelles Basic vs. Visual Basic

Schnittstellen, Player, Filter etc.) mit verkapselter Funktionalität und Implementation zur Ver-
fügung, derer sie sich nach Belieben und ohne großes Brimborium bedienen kann.
Angesichts dieser Entwicklungen scheint es etwa bei Betrachtung der Linie von BasicA über
QuickBasic/QBasic nach Visual Basic beinahe schon verblüffend, wie treu sich die Sprache in
ihren Wurzeln doch geblieben ist und wie viel sie von ihren ursprünglichen Konzepten in die
neue Objekt-dominierte Welt retten konnte. Mehr noch, die Adaption ist so erstaunlich gut
gelungen, dass sich der mit Visual Basic vorliegende Basic-Dialekt mit Fug und Recht inzwi-
schen zu den ernst zu nehmenden Sprachen für die Anwendungsentwicklung zählen darf. Aber
auch damit noch nicht genug. Microsoft hat Visual Basic vielmehr die Rolle des Flagschiffs
zugedacht: In Form von VBA (Visual Basic für Anwendungen) stellt das neue Basic zudem die
Automatisierungssprache für die wichtigsten Anwendungen der Microsoft Office Suite, und in

Gut verwurzelt: traditionelles Basic vs. Visual Basic


der stark eingeschränkten Form von VBScript ist das neue Basic auch gleich noch zur neuen
Kommandosprache des Betriebssystems Windows avanciert.
Wer nun darauf beharrt, Visual Basic habe nicht mehr viel mit dem traditionellen Basic zu tun,
dem kann natürlich genauso wenig widersprochen werden. Die objektorientierte Fassung von C
ist C++ und von Pascal ist Modula oder Delphi, und keiner wird Letztere als Dialekte Ersterer
bezeichnen wollen, obwohl die Kenntnis von C bzw. Pascal doch sehr beim Verständnis ihrer
objektorientierten Nachfolger von Vorteil ist. Nehmen Sie es so: Basic war schon immer mehr
ein Oberbegriff, denn ein kohärentes Gebilde, und als Oberbegriff ist es durchaus in der Lage,
auch den Übergang in die objektorientierte Programmierung unter sich zu subsumieren.
Die wesentlichen in Visual Basic zu findenden Neuerungen sind:
● Module – der Modulbegriff deckt sich nicht mehr mit dem Programmbegriff, sondern
erweitert die Strukturierungsfähigkeit der Sprache nach oben hin. Die Sprache vermag
damit insbesondere Bibliotheken (Klassen- und Komponentenbibliotheken) konzeptuell
zu integrieren
● Objekte – der Objektbegriff ist inzwischen sprachlich-syntaktisch verwurzelt. Neben
den einfachen Datentypen stehen nun auch komplexe, verkapselte Datentypen samt
zugehöriger Operationen zur Disposition. Der Sprache eröffnet sich damit unter ande-
rem die vollständige Anbindung an alle Dienste des Betriebsystems inklusive der gra-
fisch orientierten Benutzerschnittstelle, des gesamten Dateiwesens, der Kommunikati-
onseinrichtungen und der Datenbankschnittstellen.
● Ereignisse – die Sprache adaptiert das Modell der ereignisgesteuerten Anwendungspro-
grammierung von Windows über den Objektbegriff. So gestatten vordefinierte Klassen
und interaktiv definierte Objekte dieser Klassen eine umfassende Repräsentation der
Benutzerschnittstelle mit all ihren Elementen (Fenster, Menüs, Symbol- und Statusleis-
ten, Steuerelemente, Komponenten) und Aktionen.
● ActiveX – die vom COM geforderte Codeabstraktion ermöglicht es der Sprache nicht
nur, von existierenden Komponenten zu profitieren, sondern auch selbst Komponenten
beizusteuern, von denen wiederum andere Anwendungen profitieren können.
Erst mit Integration dieser Konzepte besitzt Visual Basic das nötige Rüstzeug, um in der Welt
der modernen Windows-Programmierung Schritt halten zu können. Das gilt mit gleichem Vor-
zeichen für den Programmierer: Wer auch nur halbwegs ernst zu nehmende Anwendungen mit
Visual Basic zu Stande bringen will, dem bleibt nichts anderes übrig, als sein Basic-Repertoire
(und sein Denken) auf den Stand dieser Neuerungen zu bringen. Dabei spielt in erster Linie der
Objektbegriff eine zentrale Rolle. Wer den Objektbegriff einmal soweit verinnerlicht hat, dass
er nicht mehr über die Nahtstelle zwischen dem »alten Basic« und dem »Basic mit Objekten«
stolpert, dem wird auch die modulare Programmierung mit Code- und Klassenbibliotheken,
ActiveX-Komponenten keine allzu großen Rätsel mehr aufgeben. Damit wären wir bereits bei
der Zielgruppe dieses Buchs.

17
Zielgruppe

Zielgruppe
Was das Vorwissen des Lesers betrifft, so wurde bei der Gestaltung der einzelnen Themen größ-
ter Wert auf eine Steigerung vom Einfachen zum Komplexen und vom Allgemeinen zum Spezi-
ellen gelegt. Der Eine liest so weit, wie er kommt, der Andere beginnt da zu lesen, wo es für ihn
interessant wird. Damit ist, wie für eine Referenz üblich, die Zielgruppe dieses Buchs naturge-
mäß recht breit anzusetzen. Sie umfasst:
● den unerfahrenen Programmierer, der die ersten Schritte und Hürden der Visual-Basic-
Programmierung zwar hinter sich gebracht hat, aber weder den inneren Zusammenhang
der Sprache so recht durchdrungen hat, noch eine Vorstellung von der Fülle ihrer Mög-
Zielgruppe

lichkeiten bei der Bewältigung praktischer Problemfelder besitzt. Programmierer dieser


Gruppe finden in diesem Buch nicht nur einen übersichtlichen Grundlagenteil, der auf
die Elemente und Konzepte der Sprache genauer eingeht und gleichermaßen eine Vertie-
fung des Objektbegriffs vermittelt, sondern auch Anregungen für die eigene Program-
miertätigkeit in Form einfacher Programmbeispiele, die Lösungen zu typischen Frage-
stellungen vorstellen.
● den Alten Hasen, der Basic seit langem kennt, die Sprache aber vernachlässigt hat und
mit Visual Basic den schnellen Wiedereinstieg in die heutige objektorientierte Basic-Pro-
grammierung sucht. Programmierer dieser Gruppe werden in der Referenz nützliche
Gegenüberstellungen und Anmerkungen finden, die gerade auf die Veränderung der
Sprache im Vergleich zu QBasic abzielen.
● den ambitionierten Anwendungsentwickler, der sein Repertoire erweitern will, nach
Ansätzen für neue Lösungen sucht und sich vom Griff zur Referenz nicht nur Auskunft,
sondern auch Inspiration erwartet. Als Referenz bemüht sich das Buch, Licht in mög-
lichst viele Winkel der Visual-Basic-Programmierung zu bringen. Programmierer dieser
Gruppe werden daher in der Fülle der vorgestellten Programmiertechniken und Pro-
blemlösungen schnell Ansatzpunkte für die Lösung der eigenen Fragestellungen finden.
● den versierten Programmierer, der in vielen Programmiersprachen zu Hause ist und
gezielte Hilfestellung in der einen oder anderen Fragestellung sucht. Die problemrele-
vante Auswahl der Einzelthemen und die Anwendungen unterschiedlicher Schwierig-
keitsgrade und Komplexität umfassende Beispielsammlung dürfte das Buch für diesen
Programmierertyp zu einer Fundgrube bei der Suche nach speziellen Lösungen werden
lassen.
● den Entwickler spezifischer Datenbanklösungen, der Visual Basic unter anderem als
Plattform für die Front-End-Programmierung benutzt
Auch wenn im Text vielfach nur »Visual Basic« zu lesen ist, ist der Inhalt des Buches vor dem
Hintergrund der bei Drucklegung aktuellsten Version von Visual Basic zu interpretieren. Die in
diesem Buch aufgeführten Thematiken und Beispiele wurden daher unter Visual Basic 6.0 (SP3)
sowie der dazu von Microsoft bereitgestellten Dokumentation sorgfältig ausgearbeitet und
auch getestet. Da Microsoft die Entwicklungszyklen seiner Produkte inzwischen scheinbar
zunehmend auf Release-Versionen ausdehnt und eine weitgehende Fehlerfreiheit meist erst mit
dem zweiten oder dritten Service-Pack erreicht wird, bietet diese Version eine hinreichend sta-
bile Plattform für die Anwendungsentwicklung.

Die CD zum Buch


Dem Buch ist eine CD beigelegt, auf der Sie die im Text explizit als Projekte bezeichneten Bei-
spiele in je eigenen Unterverzeichnissen der Verzeichnisse Referenz und Praxis vorfinden. Zur
einfacheren Orientierung tragen die Unterverzeichnisse die Namen der Projekte. Um die nicht

18
Zielgruppe

kompilierten Programme auszuführen, öffnen Sie die jeweilige VBP-Projektdatei oder VBG-Pro-
jektgruppendatei in der Visual-Basic-Entwicklungsumgebung und starten die Ausführung mit-
tels der Taste (F5).
Für Kommentare, Verbesserungen und Anregungen mit Bezug auf den Inhalt dieses Buchs bin
ich jederzeit dankbar. Richten Sie Zuschriften bitte an:
R.Huttary@digitaldocument.de

München im August, 2000 Rudolf Huttary

Zielgruppe

19
Teil 1:
Referenzteil

21
Grundlegendes
Bei der prozeduralen Programmierung erfolgt die Strukturierung des Quellcodes traditionell
durch Kontrollstrukturen, Funktionen/Prozeduren und Module. Während Kontrollstrukturen
als Muss für jede Programmiersprache schon immer zum Kern von Basic zählten, hielten der
Funktions- und Prozedurbegriff und das damit verbundene Konzept des Namensraums nur sehr
zögerlich Einzug in die Sprache. Der Modulbegriff war als solcher zwar schon immer vorhan-
den, er implizierte bis zur Entwicklung von Visual Basic jedoch nicht mehr als die schiere Mög-
lichkeit, von einem ersten Programm aus die Kontrolle zusammen mit gegebenenfalls speziell
für den Export deklarierten Werten an ein zweites Programm abzugeben. Da das erste Pro-
gramm dadurch beendet wurde und seine gesamte Umgebung verlorenging, war dieses Konzept
als zusätzliche Strukturebene wenig geeignet. Brauchbare Adaptionen für Funktionen/Prozedu-
ren gibt es seit QuickBasic und QBasic, wenngleich die etwas seltsam anmutenden Regeln für
den Namensraum aus heutiger Sicht den Eindruck erwecken, als seien den Funktionen/Prozedu-
ren Teile eines Modulkonzepts untergemischt worden. Erst die mit Visual Basic vollzogene Öff-
nung zur objektorientierten Programmierung brachte der Sprache ein ausgewogenes Verhältnis
dieser drei Strukturebenen, wie es heute in allen modernen Programmiersprachen zu finden ist:
Kontrollstrukturen sind (unverändert) bedingte Verzweigungen und Schleifen, die eine Steue-
rung der Programmausführung ermöglichen. Prozeduren/Funktionen fassen als Unterpro-
gramme umfangreiche Anweisungsfolgen zu kompakten Einheiten zusammen, wobei Funktio-
nen aufgrund des Funktionswerts, den sie verkörpern, noch der spezielle Aspekt der
Auswertung komplexer Ausdrücke zufällt. Module haben Bibliothekscharakter und kombinie-
ren Code und Datenstrukturen zu eigenständigen Programmeinheiten. Damit erfüllen sie die
strukturelle Voraussetzung für die Implementation von Objektdatentypen (Klassen).

Programme und Module in Visual Basic


Dieser Abschnitt diskutiert den Programm- und Modulbegriff von Visual Basic und stellt die
verschiedenen Ausprägungen vor.

Programm
Ein Programm ist eine Folge von Befehlen, die auf einem Computer ausführbar ist und im wei-
testen Sinne eine spezifische Anleitung für die spezifische Verarbeitung spezifischer Daten dar-
stellt. Das hier etwas strapazierte Wort »spezifisch« soll deutlich machen, dass bei der Daten-
verarbeitung die Repräsentation eine enorme Rolle spielt und Programm nicht gleich Programm
ist, selbst wenn es das Gleiche tut. Basic war ursprünglich als Interpretersprache konzipiert, was
nichts anderes heißt, als dass zur Ausführung eines Basic-Programms ein Interpreter (also ein
weiteres Programm) erforderlich war, das vergleichbar einem Dolmetscher die Basic-Befehle
nacheinander in Maschinenbefehle übersetzte. Darüber hinaus musste der Interpreter während
des Übersetzens auch noch darauf achten, dass der Programmtext keine Fehler syntaktischer
oder sonstiger Natur enthielt. Das hatte zwar den Vorteil, dass die Programmentwicklung sehr
einfach – weil vollständig interaktiv – vonstatten gehen konnte, aber auch den Nachteil, dass
die Ausführungsgeschwindigkeit zu wünschen übrig ließ. Basic hatte daher immer schon den
Ruf, »nicht gerade der schnellsten einer« zu sein. Im Gegensatz zu Basic sind andere Sprachen
wie C oder Pascal von vornherein als Compilersprachen konzipiert, das heißt, Programmtexte
werden einmalig (sowie nach jeder Änderung) von einem Compiler (Übersetzungsprogramm)
auf syntaktische und sonstige Fehler hin untersucht und dann in eine ausführbare Version über-
setzt, die aus nichts weiter als aus Maschinenbefehlen besteht und vom Prozessor direkt verar-
beitet werden kann. (In der Praxis muss der vom Compiler gelieferte Code allerdings zur Auflö-

23
Programme und Module in Visual Basic

sung von Bibliotheksverweisen noch einem Bindevorgang unterzogen werden – dafür ist der so
genannte Linker zuständig). Der Geschwindigkeitsvorteil liegt dabei natürlich auf der Hand.
Visual Basic vereint heute die Vorteile einer Interpretersprache mit der einer Compilersprache.
Für die interaktive Programmentwicklung stellt die Entwicklungsumgebung von Visual Basic
einen Interpreter (genau genommen handelt es sich dabei um einen inkrementellen Compiler)
mit integriertem Debugger bereit, und zur Fertigstellung einen Compiler, der direkt ausführba-
ren Code erzeugen kann. Dieser Code ist allerdings noch auf eine oder mehrere zu Visual Basic
gehörende Laufzeitbibliotheken angewiesen, die in Form von DLLs bereitstehen. Neben der
Übersetzung in Maschinencode bietet Visual Basic auch die Übersetzung in den so genannten P-
Code an, ein im Schnitt etwa um 40 Prozent kompakterer und syntaktisch fehlerfreier Zwi-
schencode. In P-Code vorliegende Programme besitzen einen kleinen ca. 9 KB umfassenden
Programme und Module in Visual Basic

Maschinencode-Anteil, den so genannten P-Code-Interpreter, der ein primitives Laufzeitsystem


darstellt und den P-Code (mit weitaus geringeren Geschwindigkeitsverlusten als ein Basic-Inter-
preter) in Maschinencode entfaltet.

Modul
Ein Blick auf die Entwicklung von Basic zeigt weiterhin, dass sich die Sprache von einer
schwach strukturierenden Sprache, deren einzige Strukturelemente Kontrollstrukturen und
(inzwischen völlig verpönte) Subroutinen bildeten, zu einer stark strukturierenden Sprache
gemausert hat, die sich dem Vorwurf, sie würde Spagetti-Code fördern, nicht mehr gefallen las-
sen muss. So baut sich die Funktionseinheit Programm heute nicht mehr als schlichte Folge von
Anweisungen, Verzweigungen und Sprüngen auf, sondern als Sammelsurium sich gegenseitig in
streng hierarchischer Organisation aufrufender Funktionen und Prozeduren, also in sich abge-
schlossener und gekapselter Untereinheiten mit eng begrenzten und überschaubaren Funktiona-
litäten. Damit aber nicht genug. Um als Programmiersprache in einer zunehmend objektorien-
tiert gestalteten Systemumgebung noch mitmischen zu können, muss auch die Möglichkeit einer
Strukturierung »nach oben hin« gegeben sein. Dies bringt den Begriff des Moduls ins Spiel. Ein
Modul vereinigt im Wesentlichen das unter sich, was traditionell als Basic-Programm begriffen
wurde: einen als Datei vorliegenden Programmtext, der vom Basic-Laufzeitsystem als eigenstän-
dige Programmeinheit behandelt wird. Charakteristikum des Moduls ist, dass es einen eigenen
Namensraum darstellt, mithin also Variablen bereitstellen kann, die global in allen Prozeduren
des Moduls bekannt sind (Deklaration mit Dim oder Private). Darüber hinaus ist auch ein
Export globaler Variablen und Prozeduren an andere Module (Deklaration mit Public) mög-
lich. Auf diese Weise lässt sich in Visual Basic die Gesamtfunktionalität eines Programms als
Ansammlung kleinerer »Programme« bzw. Module mit definierten Schnittstellen begreifen. Das
einzelne Modul kann im Zusammenspiel mit anderen Modulen einem höheren Zwecke dienen,
aber auch für sich genommen ein vollständiges Programm sein. Mit Blick auf die Objektorien-
tierung hat das Modul in Visual Basic eine noch weitere sehr wichtige Funktion: Es kann als
eigenständiger komplexer Datentyp (Klasse) auftreten und stellt dafür die Implementation. Eine
ausführliche Diskussion dieses Aspekts finden Sie im Teil »Objekte und Klassen« (S. 195).

Projekt
Der Visual-Basic-Programmierer legt für jedes neue Programm ein Projekt an, welches als orga-
nisatorischer Rahmen für die verschiedenen Module seines Programms fungiert. Damit das Pro-
gramm für sich lauffähig ist, muss eines (und nur eines) dieser Module ein Startobjekt bereit-
stellen, das unter PROJEKTEIGENSCHAFTEN auf der Seite ALLGEMEIN anzugeben ist. Der Name
»Objekt« ist hier ein wenig unglücklich gewählt, weil nicht nur Objekte mit eigenständiger
Nachrichtenbehandlung (wie Formulare), sondern auch eine Prozedur mit dem speziellen
Bezeichner Main zur Auswahl stehen. Ist für ein Projekt kein Startobjekt definiert, kann der
resultierende Code nur als Bibliothek für andere Programme oder Bibliotheken fungieren. (Eine

24
Arten von Modulen in einem Projekt

Bibliothek kann allerdings gleichfalls ein Startobjekt benötigen, wenn noch vor dem Aufruf der
ersten Bibliotheksroutine gegebenenfalls notwendige Initialisierungen durchzuführen sind.)
So ergibt sich, dass in Visual Basic geschriebene Programme aus unterschiedlichen Teilen
zusammengesetzt sind, die jeweils unterschiedliche Gestalten haben bzw. annehmen können:
● Quelltext oder Interpretercode – liegt im ASCII-Format vor und kann die Dateierweite-
rungen .frm (Formular und MDI-Formular), .bas (Programmmodul), .ctl (ActiveX-
Steuerelement) oder .cls (Klassenmodul, ActiveX-Komponente) haben. Zur Ausführung
des Quelltextes im Visual-Basic-Interpreter sind darüber hinaus je Quelltext eine Pro-
jektdatei (.vbp) und bei Gruppierung mehrerer Projekte zu einem Ganzen eine Gruppie-
rungsdatei (.vbg) vonnöten.

Programme und Module in Visual Basic


● Compilercode – liegt als ausführbarer Maschinencode oder P-Code vor und kann die
Dateierweiterungen .exe (Ausführbare Datei oder prozessexterne ActiveX-Kompo-
nente), .dll (dynamische Bibliothek oder prozessinterne ActiveX-Komponente) oder
.ocx (ActiveX-Steuerelement) tragen.

Arten von Modulen in einem Projekt


Visual Basic unterscheidet mehrere Arten von Modulen. Um einem bestehenden Projekt ein
weiteres Modul hinzuzufügen, finden sich im Menü PROJEKT der Entwicklungsumgebung ent-
sprechende Einträge. Mit Ausnahme von Standardmodulen des Typs Modul sowie allgemeinen
Klassenmodulen setzt sich ein Modul aus einer Codekomponente und einer Objektkomponente
(lies: sichtbare Repräsentation) zusammen. Die Bearbeitung der Codekomponente erfolgt im
ASCII-Editor und die Bearbeitung der Objektkomponente im Designerfenster der integrierten
Entwicklungsumgebung Visual Studio.
Standardmäßiges Modul für die Programmierung kleiner Anwendungen mit Ein- und Ausgabe-
funktionalität ist das Formular. Sein Charakteristikum ist, dass seine Funktionalität im Wesent-
lichen auf ein einzelnes Fenster ausgerichtet ist, das ihm als Eingabe- und Ausgabemedium
dient. Nachdem ein Formularmodul zur Laufzeit durch ein Formularobjekt mit eigenständiger
Nachrichtenbehandlung repräsentiert wird, kann jedes Formularmodul formal zum Startobjekt
erklärt werden. (Natürlich muss dann auch das Design sowie die Logik des Formulars auf diese
Eigenschaft zugeschnitten sein.) Somit kann ein aus einem einzelnen Formularmodul bestehen-
des Projekt bereits als vollständiges, interaktives Visual-Basic-Programm auftreten. Sie erhalten
ein solches Minimalprojekt (mit geeignet definiertem Startobjekt), wenn Sie ein Projekt des
Typs »Standard-EXE« anlegen. Mit dieser Konstellation kommt das Formularmodul dem tra-
ditionellen Basic-Programm am weitesten entgegen, auch wenn die Programmiertechniken für
die Ein- und Ausgabe unter Windows doch erheblich anders aussehen als vergleichsweise noch
unter DOS. Eine Anleitung, wie ältere, noch mit QBasic geschriebene Basic-Programme unter
Visual Basic zum Laufen gebracht werden, findet sich zu Anfang des Praxisteils.
Eine andere, gleichfalls auf die Arbeit mit Fenstern ausgerichtete Modulart ist das MDI-Formu-
lar. Es unterscheidet sich vom gewöhnlichen Formularmodul darin, dass es das Rüstzeug für die
Programmierung mit einem Hauptfenster und beliebig vielen weiteren, ersterem untergeordne-
ten Fenstern sozusagen bereits mitbringt. MDI-Formularmodule kommen dementsprechend
dann zum Einsatz, wenn es um die Darstellung und Verwaltung mehrerer Dokumente (Formu-
larmodule) »unter einem gemeinsamen Dach« (MDI-Formularmodul) geht. Weitere Informa-
tionen hierzu im Abschnitt »Selbst definierte Klassen« auf Seite 318.
Die schlichte Bezeichnung Modul für die dritte Modulart verrät bereits, dass es sich hierbei um
ein unspezifisches Standardmodul handelt. Ein solches Modul kann beispielsweise die Logik für
die Koordination weiterer Module enthalten oder schlicht als Bibliothek für von allen Modulen
eines Projekts gemeinsam genutzte Funktionen, Prozeduren, Variablen, Typen und Konstanten
fungieren.

25
Programme und Module in Visual Basic

Geheimnisvoller ist die Bezeichnung Klasse für die vierte Modulart. Sie ist dafür gedacht, die neu
mit Visual Basic hinzugekommene Seite der objektorientierten Programmierung aktiv zu bedie-
nen, sprich, eigene Objekte zu implementieren. Sieht man ein Objekt als Kombination aus einem
benutzerdefinierten Datentyp und den zugehörigen Operationen über diesem Datentyp an, wird
die Rolle des Klassenmoduls schnell deutlich. Es beherbergt die Beschreibung des Objektdaten-
typs hinsichtlich seiner Repräsentation und seiner Methoden (lies: Funktionen und Prozeduren).
Weitere Informationen hierzu im Abschnitt »Selbst definierte Klassen« auf Seite 318.
Die Modulart Benutzersteuerelement ist dem Bereich der ActiveX-Programmierung zuzurech-
nen. Sie erlaubt die Bereitstellung eigener Steuerelemente im OCX-Format, deren Funktionalität
im (allerdings recht reichhaltigen) Angebot der unter Windows allgemein verfügbaren Steuer-
elemente nicht enthalten ist. Anders als ein Formular ist ein Benutzersteuerelement im Allgemei-
Programme und Module in Visual Basic

nen nicht dazu da, ein komplettes Fenster darzustellen, sondern – wie der Name schon sagt –
nur ein Steuerelement, das sich auf einem Formular platzieren lässt. Aus diesem Grund besitzt
ein Benutzersteuerelement für gewöhnlich weder Menüleisten, Symbolleisten und andere Dinge,
die bei Formularen anzutreffen sind, noch ein feste Größe. Vergleichbar mit den Standard-
steuerelementen, werden die sichtbaren Abmessungen eines Benutzersteuerelements erst bei
Platzierung des fertigen Steuerelements im Verlauf des Formularentwurfs oder programmge-
steuert festgelegt. Das Benutzersteuerelementmodul enthält die gesamte Logik eines Benutzer-
steuerelements sowie die Schnittstellendefinition für den Datenaustausch (Eigenschaften). Wie
das Formular Minimalbestandteil des Projekttyps »Standard-EXE« ist, so ist das Benutzer-
steuerelement Minimalbestandteil des Projekttyps »ActiveX-Steuerelement«.
Auch die Modulart Eigenschaftsseite fällt in den Bereich der ActiveX-Programmierung. Acti-
veX-Steuerelemente haben oft komplexe Eigenschaften (so etwa zusammengesetzte Datentypen
oder Objekte), deren Darstellung im standardmäßigen Fenster Eigenschaften der Entwicklungs-
oberfläche nicht mehr erfolgen kann. Für diesen Fall besteht die Möglichkeit, eine oder mehrere
Eigenschaftsseiten für die Eingabe der Eigenschaften bereitzustellen. Da ein ActiveX-Steuerele-
ment, das beim Entwurf eines Formulars, eines anderen Steuerelements oder einer anderen
Komponente in den Entwurfbereich gezogen wird, standardmäßig (als Entwurfsinstanz) zur
Ausführung kommt, steht insbesondere auch der hinter einer Eigenschaftsseite steckende Code
zur Verfügung. Eine Eigenschaftsseite lässt sich wie ein Formular unter Verwendung von
Steuerelementen im Designerfenster der Entwicklungsumgebung zusammenstellen und im
Code-Editor mit der entsprechenden Logik für den Datenaustausch mit einem ActiveX-Steuer-
element, aber auch mit mehreren ActiveX-Steuerelementen (bei Mehrfachauswahl von ActiveX-
Steuerelementen im Designerfenster, denen die gleiche Eigenschaftsseite zugeordnet ist) verse-
hen.
Die letzte Modulart, Designer, ist mehr oder weniger ein Sammelbecken für die verschiedensten
Objekte. Visual Basic hält für jedes dieser Objekte ein Designer-Werkzeug bereit, das ähnlich
dem Formulardesigner die interaktive visuelle Gestaltung der Objektkomponente ermöglicht.
Wie beim Formular wird in der Codekomponente eines solchen Objekts seine spezifische Reak-
tion auf bestimmte Ereignisse festgelegt. Unter den Werkzeugen finden sich der DHTML-Desi-
gner für den Entwurf und die Programmierung dynamischer HTML-Seiten, der Data-Report-
Designer für den Entwurf und die Programmierung von Datenberichten, der Data-Environ-
ment-Designer für die interaktive Gestaltung und das Management der Datenumgebung für
Datenbankverbindungen mit programmgesteuerten Datenzugriffen sowie der WebClass-Desig-
ner für die Bereitstellung von Active Server Pages (.asp-Dateien) im Zusammenhang mit verteil-
ten Anwendungen im Internet oder Intranet und dem Internet Information Server.
Tipp

...................................................
Tipp
Module sind ein sehr geeignetes Mittel für die Strukturierung von Programmcode hinsichtlich
seiner Wiederverwendbarkeit. Die Vielfalt der unter Visual Basic vorhandenen Modularten för-

26
Literale und Konstanten

dert zwar bereits von sich aus die modulare Programmierung, ersetzt aber verständlicherweise
nicht die bewusste Aufteilung des Codes in spezifische und allgemein verwendbare Programm-
texte. Wer sich beizeiten vernünftige Bibliotheken anlegt, kann später um so mehr davon profi-
tieren.
Beispiele

Beis piele
...................................................
Das einfache Projekt Modultest besteht aus zwei Modulen, einem gewöhnlichen Modul Module1
und einem Formularmodul Form1. Module1 enthält eine Startprozedur namens Main, die im Dia-
log PROJEKTEIGENSCHAFTEN als Startobjekt spezifiziert ist. Form1 enthält dagegen nichts weiter
als eine Schaltfläche Beenden zum Beenden des Formulars. In diesem Programm ruft Main als

Literale und Konstanten


Startobjekt Form1 zweimal hintereinander als gebundenes Formular auf und passt dazu den
Fenstertitel entsprechend an. Wählt man Form1 als Startobjekt, erfolgt nur ein Aufruf des For-
mulars, während das Modul Module1 gar nicht erst zur Ausführung kommt:
' Projekt: Modultest

' vollständiger Code von Module1


Sub Main() ' Main ist Startobjekt des Projekts
Dim f As New Form1
f.Caption = "Erster Aufruf" ' Lädt Formular Form1 in Hauptspeicher
f.Show 1 ' Zeigt Formular an und wartet, bis dieses endet

f.Caption = "Zweiter Aufruf"


f.Show 1 ' Zeigt Formular an und wartet, bis dieses endet
End Sub

' vollständiger Code von Form1


' Formular enthält Schaltfläche "Beenden"
Private Sub Beenden_Click()
Unload Me
End Sub

Das in den folgenden beiden Abbildungen gezeigte Projekt EuroDMTestprojekt besteht aus
zwei Modulen, einem einfachen Formularmodul und einem Benutzersteuerelementmodul. Das
Programm testet ein Benutzersteuerelement namens EuroDM, welches die Ein- und Ausgabe
von Geldbeträgen wahlweise in DM oder Euro gestattet. Der Einfachheit halber wurde auf eine
Rundung und eine Korrektur der Punkt-/Komma-Problematik verzichtet. Das aus zwei Text-
und zwei Bezeichnungsfeldern bestehende Benutzersteuerelement rechnet Eingaben in der einen
Währung automatisch in die andere um und erlaubt die Definition und Abfrage seiner beiden
Textfelder über die Eigenschaften Euro und DM. Da die Textfelder eine gegenseitige Wertände-
rung im Rahmen ihrer Change-Behandlung vornehmen, sind ein wenig Logik und die globale
Zustandsvariable Changing nötig, um eine Endlosschleife zu verhindern.

Literale und Konstanten


[Public | Private] Const ConstName [As Typ] = Literal
[Public | Private] Const ConstName [As Typ] = LiteralerAusdruck

27
Literale und Konstanten
Literale und Konstanten

Testprojekt für das Benutzersteuerelement EuroDM im Entwurfsmodus

Das Benutzersteuerelement EuroDM im Einsatz


Beschreibung

Bes c hreibung
...................................................
Die elementarste Unterscheidung bei der Datenverarbeitung, an der selbst einfachste Taschen-
rechner nicht vorbeikommen, ist die zwischen Daten und Befehlen. Als Datum bezeichnet man
die Repräsentation eines Werts in einem spezifischen Datenformat (Datentyp). Ein Datum kann
als Literal, als Konstante oder als Variable vorliegen. Im Falle des Literals steht der Wert für
sich selbst, etwa wie 42 für die Zahl Zweiundvierzig oder »Rudolf« für den Vornamen des
Autors dieses Buches. Im Falle der Konstanten hat man es genau genommen gleichfalls mit
einem Literal zu tun, da der Interpreter bzw. Compiler jedes Vorkommen einer Konstanten im
Quelltext automatisch durch ihren literalen Wert ersetzt. Variablen sind dagegen auf ein
bestimmtes Datenformat (Datentyp) zugeschnittene Behälter, die einen Bezeichner (lies: einen
Namen) tragen und einen (in dem bestimmten Datenformat gehaltenen) Wert enthalten. Wäh-
rend sich der Wert eines Literals oder einer Konstanten im Programmverlauf nicht ändern
kann, weil – wenn man so will – Bezeichner und Wert identisch sind, kann eine Variable (im

28
Literale und Konstanten

Rahmen ihres Datenformats) unter Beibehaltung ihres Namens jederzeit ihren Wert ändern.
Anders gesagt: Ein Literal ist ein Wert, eine Konstante steht für einen Wert und eine Variable
enthält einen Wert.
Ein Befehl ist eine allgemeine Vorschrift für die Manipulation von Daten im weitesten Sinne
und wird in Visual Basic häufig mit der so genannten Anweisung gleichgesetzt (vgl. »Anweisun-
gen«, S. 33). So ist beispielsweise die Zuweisung eines Werts an eine Variable, die so genannte
Zuweisungsoperation mit »=« ebenso ein Befehl wie die Ausgabe einer Grafik mit automati-
scher Größenanpassung in ein Bildfeld, das auf einem Formular gelegen ist. Als Operationen
bezeichnet man dagegen eine besondere Art von Befehlen, bei der ein Operator (lies: Rechen-
vorschrift) auf einen oder mehrere Operanden (lies: Werte einer bestimmten Art) angewendet
wird und einen neuen Wert (gleicher Art) produziert – so etwa die Bildung der Summe zweier

Literale und Konstanten


Zahlen, die Verkettung von Zeichenfolgen, die Restwertdivision (Modulo-Rechnung) oder, wie
gesagt, die Zuweisung eines Werts an eine Variable. Ist ein Wert so notiert, dass er erst durch
Anwendung von Operatoren auf Operanden berechnet werden muss, spricht man von einem
Ausdruck. Sind die Operanden als Literale notiert, spricht man genauer von einem literalen
Ausdruck.
Anwendung

Anwendung
...................................................
Ein Literal kann überall dort stehen, wo ein Wert erforderlich ist – so bei Zuweisungen als
Rechtswert (lies: rechts von Gleichheitszeichen), in Ausdrücken als Operand, bei Funktions-
und Prozeduraufrufen als Argument für einen Parameter.
Für die Notation literaler Größen gibt es feste Regeln, die sich auch von Datentyp zu Datentyp
unterscheiden können.
So sind Zeichenfolgenliterale in doppelte Anführungszeichen einzuschließen, und damit es zu
keiner Verwechslung zwischen dem doppelten Anführungszeichen als Zeichen und dem Zei-
chenfolgenende kommt, muss das Anführungszeichen doppelt notiert werden, wenn es als Zei-
chen auftritt.

strMyName = "Rudolf Huttary"


Position$ = "Das Schiff liegt 2° 3' und 42"" Ost"

Zahlenliterale können Sie in dezimaler Schreibweise, wie gewohnt:

Const cMaxSize = 255

in hexadezimaler Schreibweise durch Voranstellen von &H:

Const cMaxSize = &HFF ' dezimaler Wert 255

oder in oktaler Schreibweise durch Voranstellen von &O notieren:

Const cMaxSize = &O377 ' dezimaler Wert 255

Die dezimale Notation von Zahlenliteralen mit Nachkommastellen erfolgt mit Dezimalpunkt.
(Achtung: In Zeichenfolgen, die später implizit oder mittels einer Funktion wie Val umgewan-
delt werden, gelten jedoch die Ländereinstellungen, so dass hier auf einem deutschen System ein
Komma zu notieren ist.) Etwaige Zehnerpotenzen sind, durch ein »E« abgetrennt, an die Dezi-
maldarstellung anzuhängen. Positive Vorzeichen können Sie weglassen; negative Vorzeichen
stellen Sie jeweils dem Wert voran, für den sie gelten.

Const delta = -2.14E-27 ' Minus 2 Komma 14 mal 10 hoch Minus 27

29
Literale und Konstanten

Der standardmäßige Datentyp von Zahlenliteralen ist Integer bzw. – bei vorhandenen Nach-
kommastellen – Single. Um einen anderen Datentyp zu erzwingen, können Sie dem literalen
Wert ein Typkennzeichen anhängen.
Const cAlpha = 100& ' cAlpha ist vom Typ Long
Const cBeta = 100! ' cBeta ist vom Typ Single
Const cGamma = 100# ' cGamma ist vom Typ Double

Nicht ganz so eingängig sind die Regeln für die Notation von Datumsliteralen.
Werte dieses Typs repräsentiert Visual Basic als 64-Bit-Gleitkommazahlen (8 Bytes) nach IEEE
und kann somit Datumsangaben im Bereich zwischen dem 1. Januar 100 und dem 31. Dezem-
Literale und Konstanten

ber 9999 sowie Uhrzeiten im Bereich von 0:00:00 bis 23:59:59 unterscheiden. Datumsliterale
können Datumsangaben und Zeitangaben kombinieren, aber auch je einzeln ausdrücken. Der
Notation literaler Datums- und Zeitangaben liegt das amerikanische Format zugrunde, das
heißt, in Datumsangaben wird der Monat vor dem Tag notiert und die Abtrennung erfolgt
durch das Zeichen »/«, und Zeitangaben sind in 12-Stunden-Darstellung gefolgt von »PM«
oder »AM« zu treffen. Zudem ist die Darstellung durch ein führendes und abschließendes Zei-
chen »#« einzuschließen. (Der Editor erkennt übrigens auch andere Darstellungen, so etwa
#1 Feb 99#, und korrigiert diese beflissen in das erwünschte Format.)
Dim a As Date, b As Date, c As Date
a = #2/1/1996 1:12:01 PM#
b = #12:01:00 PM#
c = #2/1/1996#

Konstanten lassen sich – wie Literale – überall dort einsetzen, wo ein Wert erforderlich ist.
Gegenüber Literalen bieten sie den Vorteil, dass der Wert, für den sie stehen, an zentraler Stelle
definiert und fortan formal durch Angabe des Konstantenbezeichners notiert werden kann. Die
Definition einer Konstanten erfolgt zur Entwurfszeit im Rahmen einer Const-Anweisung durch
Zuweisung eines Literals oder eines literalen Ausdrucks an einen Konstantenbezeichner. Bei der
Wahl des Konstantenbezeichners gelten die üblichen Vorschriften für die Bezeichnerwahl (vgl.
»Bezeichner und Namensraum«, S. 34). Es ist legitim, bei der Definition von Konstanten,
andere, bereits definierte Konstanten als Rechtswerte oder als Operanden in Ausdrücken zu
verwenden.
Const MinSize = 8 ' MinSize steht für den Wert 8
Const MaxSize = MinSize + 2741 ' MaxSize steht für den Wert 2749

Warnung
Warnung

...................................................
Wer denkt, dass die Konstantendeklarationen
Const a = 65535

und
Const b = &HFFFF

identisch sind, der irrt. a steht für die Zahl 65535 (wie notiert), b jedoch für -1. Das liegt daran,
dass Visual Basic a implizit den Datentyp Long und b den Datentyp Integer zuordnet und der
Wert -1 aufgrund der Repräsentation negativer Zahlen durch Zweierkomplementbildung die
hexadezimale Darstellung &HFFFF hat. Damit beide Konstanten den gleichen Wert erhalten, ist
die hexadezimale Darstellung so zu notieren:
Const b = &H0FFFF

30
Literale und Konstanten

In Basic existiert nur formal ein Unterschied zwischen der bitweisen Operation und der logi-
schen Operation, da die Repräsentation logischer Werte genau so gewählt ist, dass eine bitweise
Operation die jeweilige logische Operation hervorbringt.
Const a = Not 2 ' a steht für -3 (Zweierkomplement)

und
s% = -3 And 42 Or 1 ' s% erhält den Wert 41

Die von Visual Basic verwendete interne Repräsentation für Datumswerte kann mit folgender
Kapriole aufwarten: Der 30. Dezember 1899 ist nicht darstellbar. Visual Basic interpretiert die-
sen Tag vielmehr als reine Zeitangabe #12:00:00 AM#.

Literale und Konstanten


Tipps

Tipps
...................................................
Vermeiden Sie im Programmtext nach Möglichkeit die Verwendung von Literalen und arbeiten
Sie mit Konstanten, die Sie jeweils zu Anfang des Moduls im Bereich ALLGEMEIN (seltener: zu
Anfang einer Prozedur) definieren. Auf diese Weise können Sie den Wert eines Literals an zen-
traler Stelle mit globaler Wirkung für den gesamten Programmtext ändern.
Const cMaxSize = 255
...
For x = 0 to cMaxSize

Um für Konstanten einen bestimmten Typ zu erzwingen, erklären Sie diesen entweder durch die
Angabe eines Typkennzeichens oder durch eine explizite Typdeklaration.
Const cMaxSize As Integer = 255

Bildet ein literaler Wert die Grundlage für einen weiteren literalen Wert, so empfiehlt es sich,
den zweiten Wert als Ausdruck zu schreiben, der auf den ersten aufbaut, oder anstelle des zwei-
ten Literals eine Variable einzusetzen und deren Wert rechnerisch aus dem ersten Literal zu
ermitteln.
Const cMinSize = 100
' Const cMaxSize = 199 ' falsch
Const cMaxSize = 2 * cMinSize – 1 ' richtig

Const cVerschlüsseltesKennWort = "2XVf5uhf"


' Const KennwortLänge = 8 ' falsch
...
Dim KennwortLänge As Integer
KennwortLänge = Len(cVerschlüsseltesKennwort) ' richtig

Visual Basic besitzt eine sehr reichhaltige Fülle an vordefinierten Konstanten (auch Objektkon-
stanten), deren Einsatz nicht nur ein Garant für Kompatibilität ist, sondern auch (gerade im
Zusammenhang mit Objektkonstanten) zu Laufzeitverbesserungen führt. Einen Überblick über
diese Konstanten gibt der Objektkatalog (aufzurufen über ANSICHT/OBJEKTKATALOG oder (F2)).
Beispiel

Beis piel
...................................................
Das folgende vollständige Programm Apfelmann, eine stark vereinfachte Version des mehrfach
in diesem Buch diskutierten Apfelmännchens, demonstriert den Umgang mit literalen Werten.
Da das Programm während der Berechnung keine Aktualisierung der Anzeige vornimmt,
erscheint das Bild erst nach Abschluss aller Berechnungen – es sei denn, man fügt einen Show-
Aufruf in die Load-Routine ein und setzt die AutoRedraw-Eigenschaft des Formulars auf False.

31
Literale und Konstanten

' Bereich Allgemein


Const cx1 As Double = -2.1 ' Bildausschnitt des Apfelmännchens
Const cy1 As Double = -1.2
Const cx2 As Double = 0.7
Const cy2 As Double = 1.2
Const cFenster_x = 4000 ' Fensterabmessungen nicht zu groß
Const cFenster_y = 3600 ' sonst dauert es zu lange
Const cMaxIterat As Integer = 200
Const cGrenze As Double = 100

Private Sub Apfel(m_x1, m_x2, m_y1, m_y2, step_x, step_y)


Literale und Konstanten

Dim r1 As Double, re As Double, im As Double


Dim zr As Double, zi As Double, it As Integer

For zr = m_x1 To m_x2 Step step_x ' alle Spalten in x-Richtung


For zi = m_y1 To m_y2 Step step_y ' alle Punkte in Spalte zr
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
For it = 0 To cMaxIterat ' Iteration für Punkt
r1 = re * re – im * im + zr
im = 2 * re * im + zi
re = r1
If re < -cGrenze Or re > cGrenze Or _
im < -cGrenze Or im > cGrenze Then
PSet (zr, zi), it * 16 ' Punkt ausgeben
Exit For
End If
Next it
Next zi
Next zr
End Sub

Private Sub Form_Load()


Dim step_x As Double, step_y As Double
Width = cFenster_x ' Fensterabmessungen anpassen
Height = cFenster_y
' AutoRedraw = False
' Show
ScaleMode = vbPixels ' Ab jetzt Bildpunkte als Einheit
step_x = (cx2 – cx1) / ScaleWidth ' Breite eines Bildpunkts
step_y = (cy2 – cy1) / ScaleHeight ' Höhe eines Bildpunkts
Scale (cx1, cy1)-(cx2, cy2) ' Koordinatensystem vorgeben
Apfel cx1, cx2, cy1, cy2, step_x, step_y ' Apfelmännchen berechnen
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Dim, Public, Private, ReDim
Verwandte Themen

Verwandte Them en
...................................................
Datentypen und ihre Operationen (S. 49); Operatoren für elementare Datentypen und logi-
sche Bedingungen (S. 54); Anweisungen (S. 33); Bezeichner und Namensraum (S. 34)

32
Anweisungen

Anweisungen
_ (Operator für Übertrag in nächste Zeile)
: (Operator für Aneinanderreihung von Anweisungen)
[Let] Var = Wert
Rem Kommentar
' Kommentar
#If Ausdruck Then
Anweisungsfolge1

Anweisungen
[#Else | ElseIf AusdruckN
AnweisungsfolgeN
#End If
Beschreibung

Bes c hreibung
...................................................
Der Quelltext eines Visual-Basic-Moduls setzt sich aus einer Folge von Anweisungen zusam-
men.
Unter einer Anweisung versteht man in Visual Basic alles, was einen Befehl darstellt, ohne selbst
einen Wert zu verkörpern. Man unterscheidet zwischen einfachen Anweisungen, die in einer
einzelnen Zeile stehen können, und Kontrollstrukturen, die als zusammengesetzte Anweisungen
ihrerseits Anweisungsfolgen strukturieren und auf höherer Ebene zu einer logischen Einheit
zusammenfassen.
Eine besondere Anweisungsform stellen Compileranweisungen dar, denen das Zeichen # voran-
geht (#If Then...#Else...#End If). Sie werden nicht erst zur Laufzeit, sondern bereits zur
Übersetzungszeit interpretiert und führen dazu, dass bestimmte Teile des Codes gar nicht erst
übersetzt werden. Ausdrücke in solchen Anweisungen dürfen nur aus Literalen und Konstanten
zusammengesetzt sein. Visual Basic definiert in diesem Zusammenhang die Boolean-Konstanten
Win16 und Win32, deren (jeweils gegensätzlicher) Wahrheitswert ausdrückt, ob die Übersetzung
auf einer 16-Bit- oder 32-Bit-Plattform erfolgt.
Anwendung

Anwendung
...................................................
Zu den einfachen Anweisungen zählen Zuweisungsoperationen (Let, Set, LSet, RSet Mid), Pro-
zeduren (vordefinierte und benutzerdefinierte), Deklarationen (Const, Dim, Private, Public,
Declare) und Definitionen (Function, Sub) aller Art. Alles, was Visual Basic als einfache Anwei-
sungen betrachtet, kann als eigenständige Programmzeile stehen. Überlange einfache Anweisun-
gen lassen sich mittels des Übertragsoperators _ (Unterstrich) in zwei oder mehrere Zeilen auf-
teilen. Dabei muss der Übertragsoperator durch ein Leerzeichen getrennt als letztes Zeichen in
der Zeile notiert sein – und darf insbesondere keine Zeichenfolgenliterale trennen. Mehrere
Anweisungen lassen sich in eine Zeile stellen, wenn zwischen den Anweisungen der Aneinan-
derreihungsoperator : (Doppelpunkt) notiert ist.
Eine Kontrollstruktur ist eine zusammengesetzte Anweisung, die sich über mehrere Zeilen hin-
weg erstrecken kann und eine Rahmung untergeordneter Anweisungsfolgen mittels Schlüssel-
wörtern vorsieht, entsprechend den die Kontrollstruktur geltenden syntaktischen Regeln. Im
Falle der If-Anweisung akzeptiert Visual Basic sowohl die kompakte Zeilenform als auch eine
mehrzeilige Form.
Rem-Anweisungen sind nur aus formaler Sicht Anweisungen. Eigentlich stellen sie Kommentare
dar, da sie der Compiler bei der Übersetzung ebenso ignoriert wie Kommentare, die durch ein
Hochkomma ' eingeleitet sind.

33
Bezeichner und Namensraum

Bezeichner und Namensraum


Bezeichner, Namensraum, Schlüsselwörter
Private, Public, Dim
Beschreibung

Bes c hreibung
...................................................
Bezeichner fungieren in Visual Basic als formale Namen für verschiedenen Größen: Konstanten,
Variablen und Objekte, Funktionen und Prozeduren (Methoden) sowie Module. Bei der Wahl
eines Bezeichners für eine bestimmte Größe genießt der Programmierer weitestgehende Freihei-
ten. Er muss lediglich die formalen Regeln zur Bezeichnerbildung einhalten und auf Eindeutig-
Bezeichner und Namensraum

keit im jeweiligen Namensraum achten. Zudem verbietet sich die Verwendung der von Visual
Basic reservierten Schlüsselwörter, die von der Sprache selbst mit einer festen Bedeutung belegt
sind.
Die formalen Regeln für die Bezeichnerbildung in Visual Basic sind:
● Bezeichner dürfen zwischen ein und 255 Zeichen lang sein
● Bezeichner müssen mit einem Buchstaben beginnen, wobei auch deutsche Umlaute und
Sonderzeichen (genau genommen sogar alle ANSI-Zeichen mit einem Code zwischen
128 und 255) erlaubt sind.
● Für alle weiteren Zeichen sind darüber hinaus auch die Ziffern »0« bis »9« und der
Unterstrich »_« erlaubt.
● Visual Basic unterscheidet in der Notation von Bezeichnern nicht zwischen Groß- und
Kleinschreibung. MyVar und Myvar bezeichnen somit dasselbe. (Der Editor der integrier-
ten Entwicklungsumgebung setzt allerdings auf Modulebene eine konsistente Schreib-
weise durch, indem er jeweils die bei der Deklaration eines Bezeichners verwendete
Schreibweise erzwingt und bei implizit deklarierten Bezeichnern jeweils die zuletzt ver-
wendete Schreibweise für alle Vorkommen des Bezeichners übernimmt.)
Als Namensraum eines Bezeichners wird der Bereich bezeichnet, innerhalb dessen ein Bezeich-
ner bekannt ist. Der größte Namensraum ist der so genannte globale Namensraum oder die
Programmebene. Bezeichner, die diesem Namensraum angehören, sind in allen Modulen eines
Programms bekannt und somit global ansprechbar. Jeweils kleinere Namensräume sind die
Modulebene und Prozedurebene. Bezeichner, deren Namensraum auf die Modulebene
beschränkt ist, sind nur innerhalb des Moduls bekannt, in dem sie deklariert wurden, und
Bezeichner, deren Namensraum auf die Prozedurebene beschränkt ist, sind nur innerhalb der
Prozedur (bzw. Funktion) bekannt, in dem sie deklariert wurden.
Bei Bezeichnerkonflikten, die durch die Wahl gleicher Bezeichner für unterschiedliche Größen
in überlappenden Namensräumen unterschiedlicher Stufe entstehen, ist im kleineren Namens-
raum immer nur der in diesem Namensraum deklarierte Bezeichner sichtbar.
Anwendung

Anwendung
...................................................
Während Modulbezeichner von vornherein dem globalen Namensraum angehören, müssen
Prozeduren, Funktionen und Methoden explizit mit dem Zusatz Public deklariert werden,
damit ihr Bezeichner im globalen Namensraum sichtbar wird. Geschieht die Deklaration dage-
gen mit dem Zusatz Private oder ohne Zusatz, ist ihr Bezeichner jeweils immer nur innerhalb
des Moduls bekannt, das den Quelltext enthält. Die vielfältigsten Möglichkeiten für die Gestal-
tung des Namensraums bieten Konstanten, Variablen und Objekte. Bei impliziter oder explizi-
ter Deklaration in einem Prozedur- oder Funktionskörper erstreckt sich der Namensraum des
Bezeichners ab Deklaration bis zum Endes des Körpers. Findet die Deklaration dagegen auf
Modulebene (im Bereich ALLGEMEIN) ohne Zusatz oder unter Angabe von Dim oder Private
statt, ist der Bezeichner fortan im restlichen Teil des Modulkörpers bekannt und insbesondere

34
Bezeichner und Namensraum

auch in allen Funktionen und Prozeduren (bzw. Methoden) sichtbar. Während sich der
Namensraum einer Konstanten grundsätzlich nicht über mehrere Module erstrecken kann, son-
dern maximal auf die Modulebene beschränkt bleibt, unterliegen Variablen und Objekte dieser
Einschränkung nicht. Damit eine Variable oder ein Objekt im globalen Namensraum bekannt
wird, muss eine Public-Deklaration auf Modulebene erfolgen.
Warnung

...................................................
Wa rnung
Visual Basic betrachtet es nicht als Fehler, wenn Sie ein und denselben Bezeichner in verschiede-
nen Namensräumen vergeben. Solange die Namensräume nichts miteinander zu tun haben,
wird dies keine allzu große Verwirrung stiften, ja, vielfach sogar Vorteile bringen. Problema-

Bezeichner und Namensraum


tisch wird es allerdings, wenn ein Namensraum den anderen umfasst, wie etwa die Modulebene
eine Prozedurebene. In diesem Fall wird die auf Modulebene deklarierte Variable in der Proze-
durebene unsichtbar, weil ihr Bezeichner durch die lokal in der Prozedur deklarierte Variable
»verdeckt« ist. Dies ist meist zu verschmerzen, oft sogar auch gewollt. Fehlerträchtig wird es
allerdings, wenn der Programmierer auf eine implizite Deklaration auf Prozedurebene setzt und
unwissentlich oder fahrlässig den Bezeichner einer global deklarierten Variable erwischt. So
führt beispielsweise der folgende Code zu unangenehmen Nebeneffekten:
Dim x As Single, y As Single
...
Sub BerechneMatrix(a(), b())
...
For x = 1 To 100
For y = 1 To 200
...
Next x, y
End Sub

Die Variablen x und y werden hier leichtfertig und im Vertrauen auf die implizite Deklaration
als Zählvariablen eingesetzt. Eine solche findet aber nicht statt, da unter diesen Bezeichnern
globale Variablen bekannt sind. Diese verlieren durch die Schleifen leider ihren Wert, was an
völlig anderer Stelle seltsame Nebeneffekte hervorbringen kann. Deshalb immer fleißig dekla-
rieren und auf globaler Ebene keine nichtssagenden 08/15-Bezeichner vergeben.
Tipp

...................................................
Tipp
Wer die Wahl hat, hat die Qual. Dieser Spruch bewahrheitet sich insbesondere, wenn es darum
geht, sich immer wieder neue Bezeichner auszudenken. Eine gute Hilfe ist es, sich dabei von for-
malen Kriterien leiten zu lassen und bei der Auswahl darauf zu achten, dass ein Bezeichner
möglichst viel über die Größe aussagt, für die er steht. Um Konstanten, Variablen und Prozedu-
ren besser auseinander halten zu können, folgen viele Programmierer daher bei der Bildung von
Bezeichnern bestimmten Konventionen. So hat es sich beispielsweise bewährt, Konstanten
immer in Großschreibung zu notieren, Variablen mit einem Kleinbuchstaben beginnen zu lassen
und Prozeduren mit einem Großbuchstaben. Sehr verbreitet ist zudem die so genannte ungari-
sche Notation, die durch Bezeichnerpräfixe den zu einem Bezeichner gehörigen Datentyp zum
Ausdruck bringt. Variablen vom Typ Integer würden mit einem »i« beginnen, Variablen vom
Typ String mit einem »s« oder »str« usw. Der restliche Teil des Bezeichners kann dann noch in
gemischter Groß- und Kleinschreibung notiert werden, um seine Funktion mnemonisch besser
zum Ausdruck zu bringen. (Diese Schreibweise wird inzwischen der früher weit verbreiteten
Zusammensetzung mit Unterstrichen »_« vorgezogen.) Bei sehr enger Verwandtschaft zweier
Größen leistet oft auch die Abzählung durch Anhängen von Ziffern als Suffix gute Dienste.

35
Kontrollstrukturen

Beispiel

Beis piel
...................................................
' Unterscheidung der Notation durch Klein und Großschreibung
Const MAXSIZE = 10 ' Konstanten in Großschreibung
Private anzahl As Integer ' Variable in Kleinschreibung
Private ergebnis As Single, werte(MAXSIZE) As Single
Function StandardAbweichung(a() As Single) As Single
' Ungarische Notation
Const cMaxSize = 10 ' Präfix "c" für Konstante
Private iElemAnzahl As Integer ' Präfix "i" für Integer
Kontrollstrukturen

Private bChanging As Boolean ' Präfix "b" für Boolean


Private frmAnmeldung As Form1 ' Präfix "frm" für Formular
Private sErgebnis1 As Single ' Präfix "s" für Single, Abzählung
Private sErgebnis2 As Single ' Präfix "s" für Single, Abzählung
Function sStandardAbweichung(a() As Single) As Single
Verwandte Befehle

Verwa ndte Befehle


...................................................
DefType
Verwandte Themen

Verwandte Them en
...................................................
Datentypen und ihre Operationen (S. 49); Typkennzeichen und Bezeichnerbereiche für
Typen (S. 167); Geltungsbereiche von Variablen (S. 173)

Kontrollstrukturen
Aufgabe einer Kontrollstruktur ist die Steuerung der Programmausführung in Abweichung von
der im Quelltext notierten Anweisungsfolge.

Unbedingte und bedingte Verzweigung, Subroutinen


GoTo {Marke | Zeile}
...
Marke:
GoSub SubRoutine
...
SubRoutine:
...
Return
If Bedingung Then Anweisung [Else Anweisung]
If Bedingung Then
[ThenAnweisungsBlock]
[ElseIf Bedingung1
[ElseIfAnweisungsBlock]]
...
[Else
[ElseAnweisungsBlock]]
End If

36
Unbedingte und bedingte Verzweigung, Subroutinen

Beschreibung

Bes c hreibung
...................................................
Die einfachste (inzwischen aber verpönte) Möglichkeit, die Kontrolle einem anderen Pro-
grammteil weiterzugeben, ist der unbedingte Sprung mittels GoTo zu einer Sprungmarke oder
Zeilennummer. Die Anweisung GoSub ermöglicht den Aufruf eines Unterprogramms (auch ver-
schachtelt), das an der Sprungmarke oder Zeilennummer SubRoutine beginnt und bis zur nächs-
ten Return-Anweisung (auf gleicher Ebene) reicht. Sprungmarken und Zeilennummern müssen
jeweils innerhalb der gleichen Funktion/Prozedur liegen und am Zeilenanfang stehen. Eine
Sprungmarke ist ein beliebiger Bezeichner gefolgt von einem Doppelpunkt.
Die wichtigste Kontrollstruktur zur Steuerung des Programmablaufs ist die bedingte Verzwei-
gung in Form der If-Anweisung, für die zwei unterschiedliche Notationen zulässig sind. In der

Kontrollstrukturen
kürzeren Schreibweise (Zeilenform) muss die Anweisung – gegebenenfalls samt Else-Teil – in
einer Zeile und ohne abschließendes End If notiert sein. In der mehrzeiligen Schreibweise ist
dagegen das abschließende End If unerlässlich. Die Syntax erlaubt in dieser Form zudem
ElseIf-Fallunterscheidungen. Die If-Anweisung führt den im Then-Zweig gelegenen ThenAnwei-
sungsblock aus, wenn die – meist als logischer Ausdruck formulierte – Bedingung Bedingung
einen Wert ungleich 0 ergibt. Ist der Wert 0, kommt der ElseAnweisungsblock des Else-Zweiges
zur Ausführung. Der Else-Zweig kann durch Einfügung von ElseIf-Zweigen weiter aufge-
spreizt sein, wobei ein ElseIf-Zweig nichts anderes als die optimierte Form einer verschachtel-
ten If-Anweisung im Else-Zweig ist. Ergibt sich für die Bedingung eines ElseIf-Zweiges ein
Wert ungleich 0, kommt der ElseIfAnweisungsblock zur Ausführung. Bei vorhandenen ElseIf-
Zweigen kommt ein ElseAnweisungsblock nur zur Ausführung, wenn alle bis dahin geprüften
Bedingungen den Wert 0 ergeben haben.
Anwendung

Anwendung
...................................................
Der unbedingte Sprung mit GoTo, aber auch die GoSub-Unterprogramme, zählen zu den Erblas-
ten von Basic, denen die Sprache in ihrer Anfangszeit das Attribut »Spagetti-Code« zu verdan-
ken hatte. In der modernen, strukturierten Programmierung findet in seltenen Fällen nur noch
die GoTo-Anweisung Anwendung, nämlich im Zusammenhang mit der Fehlerbehandlung, wo
der Befehl im Zusammenspiel mit On Error gezielte Sprünge zu Fehlerbehandlungsroutinen
ermöglicht. Anstelle von GoSub-Unterprogrammen benutzt man heute ausschließlich benutzer-
definierte Funktionen und Prozeduren.
Anders die If-Anweisung. Sie hat an Wichtigkeit im Laufe der Zeit nichts eingebüßt. In der
mehrzeiligen Form eignet sie sich bei Verwendung von ElseIf-Zweigen für umfangreichere
Fallunterscheidungen, auch wenn die Select-Anweisung hier oft die bessere Wahl darstellt. If-
Anweisungen können natürlich auch vollständig verschachtelt werden, von der Laufzeit her
sind ElseIf-Formulierungen jedoch überlegen.
Warnung

Wa rnung
...................................................
Aufrufe parameterloser Prozeduren und schlichte Sprungmarken kann Visual Basic von der
Notation her nicht unterscheiden, wenn der Doppelpunkt-Operator zur Anreihung mehrerer
Anweisungen in einer Programmzeile ins Spiel kommt. Visual Basic zieht in diesem Fall die
Interpretation »Sprungmarke« der anderen vor. Setzen Sie parameterlose Prozeduraufrufe
daher besser in eigene Zeilen (ohne nachfolgenden Doppelpunkt) oder benutzen Sie die Call-
Anweisung für den Aufruf.
Beispiel

Beis piel
...................................................
Die folgenden Zeilen zeigen, wie die Logik für die Berechnung der Sgn-Funktion aussieht:

37
Kontrollstrukturen

If a > 0 Then
a = 1
ElseIf a < 0 Then
a = -1
End If ' für den Fall a = 0 hat a bereits den richtigen Wert!
Verwandte Befehle

Verwa ndte Befehle


...................................................
On Error, Select, On ... GoSub
Verwandte Themen

Verwandte Them en
...................................................
Kontrollstrukturen

Operatoren für elementare Datentypen und logische Bedingungen (S. 54); Fallunterschei-
dung (S. 38); Fehlerbehandlung (S. 43)

Fallunterscheidung
Select Case TestAusdruck
[Case Fall1
[AnweisungsBlock1]]
...
[Case FallN
[AnweisungsBlockN]]
[Case Else
[ElseAnweisungsBlock]]
End Select
Function Switch(Ausdruck1, Wert1,[Ausdruck2, Wert2[, ...]]) As Variant
Function Choose(Index As Integer, Wert1[, Wert2[,... WertN]]) As Variant
On Ausdruck GoSub SprungzielListe
On Ausdruck GoTo Sprungzielliste
Function IIf(Kriterium As Boolean, ThenWert, ElseWert) As Variant
Beschreibung

Bes c hreibung
...................................................
Die Select Case-Kontrollstruktur führt eine Fallunterscheidung auf Basis des Werts von Test-
Ausdruck durch. Für jeden zu unterscheidenden Fall ist ein Case-Zweig mit der Anweisungsfolge
AnweisungsblockN zuständig. Der Case-Ausdruck Fall kann als Konstante/Literal, Is-Vergleich
(offener Bereich), To-Bereich (geschlossener Bereich) oder als Fall-Aufzählung formuliert sein:
Fall = Zahl | Zeichenfolge
Fall = Is VglOperator VglWert
Fall = Fall1 To FallN
Fall = Fall1, ..., FallN
In einer Select-Struktur kommt maximal ein, bei vorhandenem Else-Zweig genau ein Zweig
zur Ausführung.
Die Switch-Funktion führt eine Fallunterscheidung auf Basis ihrer in Paaren zu je einem Aus-
druck und einem potentiellen Funktionswert organisierten Parameterliste durch. Den Funkti-
onswert WertN eines solchen Paares gibt die Funktion zurück, wenn der Ausdruck AusdruckN
von links beginnend der erste Ausdruck ist, der einen von 0 verschiedenen Wert hat, also den
Wahrheitswert True besitzt. Falls keiner der Ausdrücke ungleich 0 ist, liefert die Funktion den
Wert Null.

38
Fallunterscheidung

Die Choose-Funktion liefert den an der Position Index in der Werteliste stehenden Wert – der
Wert 1 wählt Wert1, der Wert 2 wählt Wert2 usw.
Die On-Kontrollstruktur ermöglicht eine Fallunterscheidung durch Auswahl eines Sprungziels
aus der Liste SprungzielListe in Abhängigkeit von Ausdruck. Der Wert von Ausdruck darf zwi-
schen 0 und 255 liegen. Ist er 0 oder größer als die Anzahl der Sprungziele in der Liste, findet
kein Sprung bzw. Unterprogrammaufruf statt, ansonsten benennt er die Listenposition des
anzusteuernden Sprungziels. Als Sprungziele können wahlweise Zeilennummern oder Sprung-
marken genannt sein, die in der gleichen Funktion/Prozedur definiert sind.
Eine Fallunterscheidung der besonderen Art stellt die Funktion IIf dar. Sie wird mit drei Para-
metern aufgerufen und liefert in Abhängigkeit vom Wahrheitswert des ersten Parameters den
zweiten Parameter (erster Parameter ist True) oder dritten Parameter (erster Parameter ist False)

Kontrollstrukturen
als Funktionsergebnis.
Anwendung

Anwendung
...................................................
Obwohl sich Fallunterscheidungen prinzipiell gesehen genauso gut über If-Anweisungen (ver-
schachtelt oder mit ElseIf-Zweigen) formulieren lassen, sind Select Case-Formulierungen im
Allgemeinen eleganter und übersichtlicher – vor allem, wenn viele Fälle zu unterscheiden sind.
Die Syntax für die Formulierung der einzelnen Fälle ist reichhaltig. Der Compiler nimmt aller-
dings keine Überprüfung auf Überlappung vor, so dass auf eine disjunkte Formulierung der
Fall-Ausdrücke geachtet werden sollte.
In einfachen Fällen, wenn sich die Fallunterscheidung (wie bei Arrays) auf die indexorientierte
Auswahl eines Werts aus einer Werteliste zurückführen lässt, sollte die Choose-Funktion das
Mittel der Wahl sein. Dieselbe Funktionalität lässt sich allerdings mittels der Array-Funktion
erzielen, wie das Beispiel am Ende des Abschnitts zeigt.
Für Fallunterscheidungen, die auf die Auswahl eines Werts in Abhängigkeit verschiedener
Bedingungen hinauslaufen, ist die Switch-Funktion meist das eleganteste Mittel. Die Anwen-
dung der Funktion widerspricht aber in gewisser Hinsicht der Intuition, da es grundsätzlich zur
Auswertung aller Ausdrücke kommt. In der Praxis hat das zwei Auswirkungen: Erstens muss
jeder Ausdruck für jeden Fall wohldefiniert sein (kein Überlauf, keine Division durch 0 etc.),
sonst kommt es zu einem Laufzeitfehler, und zweitens hat die Funktion unabhängig vom unter-
schiedenen Fall immer die gleichen Seiteneffekte.
Von einem Gebrauch der On-Anweisung (jenseits von On Error) ist abzuraten, weil GoTo-Sprünge
und GoSub-Unterprogramme angesichts der reichhaltigen Ausstattung von Visual Basic für die
strukturierte Programmierung nicht mehr zeitgemäß sind. Diese Befehle werden nur noch für
die Abwärtskompatibilität unterstützt.
Warnung

Wa rnung
...................................................
Da in Select-Strukturen immer nur ein Case-Zweig zur Ausführung kommt, ist im Falle der
Überlappung von Case-Ausdrücken die Reihenfolge der Case-Aufzählung relevant.
Visual Basic wertet bei Abarbeitung der Switch-Funktion immer alle Ausdrücke aus, so dass
eventuelle Seiteneffekte vom Funktionswert unabhängig bleiben.
Beispiel

Beis piel
...................................................
Der folgende Code zeigt die eine Select-Fallunterscheidung für den von einem Textfeld gemel-
deten Tastaturcode:
Private Sub Text1_KeyUp(KeyCode As Integer, Shift As Integer)
Select Case KeyCode
Case vbKeyDelete, vbKeyBack ' wg. Überschreibmodus
Case vbKeyUp, vbKeyDown ' Nächste Zeile in Textfeld
AktualisiereZeile(sZeile) ' Änderungen zurückschreiben

39
Kontrollstrukturen

Case vbKeyEscape
List1_Click ' Ursprüngliche Fassung holen
Case vbKeyEnd
Start = LineLen – 1
Case vbKeyLeft
Start = LinePos – 1
Case vbKeyRight
Start = LinePos + 1
Case vbKeyHome
Start = 0
Kontrollstrukturen

Case Else ' Sonstige Tasten


VerarbeiteTaste(KeyCode, sZeile)
End Select
Text1.SelStart = Start ' Position in Puffer aktualisieren
Text1.SelLength = 1 ' Überschreibmodus
End Sub
Hier verschiedene Formulierungen für die Zuordnung eines numerischen Werts zu einer Zei-
chenfolge:
sZahl = Choose(a + 1, "Null", "Eins", "Zwei", "Drei", "Vier", "Fünf")
sZahl = Switch(a = 0, "Null", a = 1, "Eins", a = 2, "Zwei", a = 3, _
"Drei", a = 4, "Vier", a = 5, "Fünf")
sZahl = Array("Null", "Eins", "Zwei", "Drei", "Vier", "Fünf")(a)

IIf macht die Min-/Max-Berechnung leicht:


Min = IIF(a < b, a, b)
Max = IIF(a > b, a, b)
Verwandte Befehle

Verwa ndte Befehle


...................................................
If, GoTo, GoSub
Verwandte Themen

Verwandte Them en
...................................................
Unbedingte und bedingte Verzweigung, Subroutinen (S. 36)

Schleifen
For CountVar = StartVal To EndVal [Step StepVal]
[Anweisungsfolge]
[Exit For]
[Anweisungsfolge]
Next [CountVar[, CountVar1]]
For Each IteratVar In Liste
[Anweisungsfolge]
[Exit For]
[Anweisungsfolge]
Next [IteratVar[, IteratVar1 ...]]
While Bedingung
[Anweisungsfolge]
[Exit While]

40
Schleifen

[Anweisungsfolge]
Wend
Do [{While | Until} Bedingung]
[Anweisungsfolge]
[Exit Do]
[Anweisungsfolge]
Loop
Do
[Anweisungsfolge]

Kontrollstrukturen
[Exit Do]
[Anweisungsfolge]
Loop [{While | Until} Bedingung]
Beschreibung

Bes c hreibung
...................................................
Schleifen sind Kontrollstrukturen, die es gestatten, einen Anweisungsblock oder Schleifenkör-
per in Abhängigkeit eines Kriteriums – einer logischen Bedingung oder dem Wert einer Zählva-
riablen – mehrmals zu durchlaufen. Das klassische Programmiermodell unterscheidet zwischen
abweisenden Schleifen, die das Schleifenkriterium im Schleifenkopf vor dem ersten Durchlaufen
des Schleifenkörpers prüfen (und selbst die einmalige Ausführung des Schleifenkörpers unter-
binden können), und nicht abweisenden Schleifen, die ihr Kriterium nach Abarbeitung des
Schleifenkörpers prüfen. Visual Basic weicht diese Unterscheidung allerdings auf, indem es
sprachliche Mittel für den Schleifenabbruch an beliebiger Stelle vorsieht. Darüber hinaus lässt
sich zwischen Schleifen unterscheiden, bei denen eine Berechnung der benötigten Schleifen-
durchläufe noch vor dem ersten Eintritt in die Schleife möglich ist (Zählschleifen), und solchen,
bei denen diese Berechnung nicht möglich ist (Schleifen mit implizitem Abbruchkriterium).
Schleifen, deren Kriterium sich nie erfüllt, heißen Endlosschleifen. Falls der Schleifenkörper
einer Schleife eine weitere Schleife enthält, spricht man von verschachtelten Schleifen.
Anwendung

Anwendung
...................................................
Der Einsatzbereich von Schleifen ist derartig breit, dass es wohl nur wenige auch nur halbwegs
anspruchsvolle Programme geben wird, die ohne dieses Mittel auskommen. Abweisende Schlei-
fen werden in Visual Basic als For-, While- oder Do-Schleifen und nicht abweisende Schleifen
ausschließlich als Do-Schleifen formuliert. Als Zählschleife ist die starre Form der For-Schleife
am besten geeignet. Schleifen lassen sich beliebig verschachteln, solange gewährleistet ist, dass
eine äußere Schleife den Schleifenkörper einer inneren Schleife jeweils vollständig enthält.

Die For...Next- Schleife


Eine For-Schleife kann in einer von zwei Formen benutzt werden. In der ersten Form verlangt
sie die Bekanntgabe einer Zählvariablen (CountVar) eines beliebigen numerischen Typs, eines
Startwerts (StarVal), eines Endwerts (EndVal) und gegebenenfalls einer Schrittweite, wenn diese
von der standardmäßigen Schrittweite 1 abweicht. Der Ablauf ist:
1. Beim ersten Eintritt der Programmausführung in den Schleifenkopf initialisiert die For-
Schleife die Zählvariable mit dem Startwert.
2. Unmittelbar vor jedem Durchlaufen des Schleifenkörpers prüft die Schleife, ob die Zählvari-
able den Endwert bereits überschritten hat. Falls ja, endet die Schleife, und die Ausführung
überspringt den Schleifenkörper.
3. Nach jedem Durchlaufen des Schleifenkörpers erfolgt automatisch die Aktualisierung der
Zählvariablen unter Beachtung der geltenden Schrittweite.

41
Kontrollstrukturen

Beachten Sie, dass Sie zwar den Wert der Zählvariablen jederzeit ändern und somit das Verhal-
ten der Schleife von innerhalb des Schleifenkörpers manipulieren können, nicht jedoch den gel-
tenden Endwert oder die Schrittweite. Von einer solchen Manipulation ist aber generell eher
abzuraten, da der Code dann nicht mehr übersichtlich ist. Um eine For-Schleife verfrüht abzu-
brechen, bedienen Sie sich besser des Befehls Exit For. Als Datentyp für die Zählvariable kom-
men ganzzahlige Typen wie Integer oder Long in Betracht, ebenso aber auch Fließkommatypen
wie Single oder Double. Das beste Laufzeitverhalten hat eine Schleife, wenn die Zählvariable
vom Typ Long ist. Um eine Schleife zum Rückwärtszählen zu bewegen, geben Sie StepVal mit
einer negativen Schrittweite an sowie einen Endwert, der kleiner als der Startwert ist.
Dim i As Long
Kontrollstrukturen

For i = 10 to 2 Step -2
Print i, i+1
Next i

In Form der For Each-Schleife ermöglicht die For-Schleife das Durchlaufen aller Elemente einer
Auflistung Liste. An die Stelle der Zählvariable tritt die Aufzählvariable IterateVar, die bei
jedem Schleifendurchlauf den Wert des jeweils nächsten Elements von Liste annimmt, bis das
Ende der Auflistung erreicht ist. Eine Modifikation der Aufzählvariable innerhalb des Schleifen-
körpers hat keine Auswirkung auf die Aufzählung. Einzig der vorzeitige Abbruch mittels Exit
For ist möglich. Als Voraussetzungen für die Anwendung dieser Form sind zu beachten: Liste
muss eine Auflistung (Collection-Objekt) oder ein Array sein, und IterateVar muss den Daten-
typ Variant oder einen Objektdatentyp tragen.
Dim a(20) As Integer
Dim i As Variant
For Each i In a ' Array elementweise initialisieren
i = 2
Next i

Die Nennung der Zähl- bzw. Aufzählvariablen nach dem Schlüsselwort Next ist optional. Als
Abschluss verschachtelter For-Schleifen ist auch die Nennung mehrerer Zähl- bzw. Aufzählvari-
ablen nach dem Schlüsselwort Next zulässig.

Die While...Wend- Schleife


Als Standardlösung für abweisende Schleifen bietet sich die While-Schleife an. Schleifen dieser
Art prüfen unmittelbar vor jedem Eintritt in den Schleifenkörper, ob das Kriterium Bedingung
einen Wert ungleich 0 hat. Falls dem so ist, bricht die Schleife ab und die Ausführung über-
springt den Schleifenkörper. While-Schleifen lassen sich jederzeit auch von innerhalb des Schlei-
fenkörpers mittels einer Exit While-Anweisung abbrechen.
While Not EOF(1) ' Zeilen aus Datei in Auflistung einlesen
Line Input #1, a
MyList.AddItem a
Wend

Die Do...Loop- Schleife


Am meisten Flexibilität bietet die Do-Schleife. Sie lässt sich als abweisende, als nicht abweisende
Schleife und als Endlosschleife formulieren. In der abweisenden Form wird das Schleifenkrite-
rium mit einem While- oder Until-Zusatz hinter das Schlüsselwort Do, in der nicht abweisenden
Form hinter das Schlüsselwort Loop gesetzt. Ein While-Kriterium bricht die Schleife ab, wenn es
den Wert 0 hat, während ein Until-Kriterium mit einem Wert ungleich 0 den Abbruch bedingt.
Wie die anderen Schleifen lässt sich auch die Do-Schleife jederzeit von innerhalb des Schleifen-

42
Fehlerbehandlung

körpers mittels einer Exit Do-Anweisung abbrechen. Endlosschleifen sind in Wirklichkeit


halbabweisende Schleifen, da sie mittels Exit Do irgendwo mitten im Schleifenkörper abgebro-
chen werden müssen.
Do ' Leerzeilen überlesen
Line Input #1, a
Loop While a = ""
MyList.AddItem a ' Zeile in Auflistung einfügen
Warnung

Wa rnung
...................................................
Da Schleifen die Reaktionen eines Windows-Programms auf Benutzereingaben sehr beeinträch-

Kontrollstrukturen
tigen können, empfiehlt es sich, in Schleifen mit zeitaufwändigen Berechnungen etwa jede
Zehntelsekunde die Anweisung DoEvents aufzurufen. Beachten Sie jedoch, dass es zur Rekur-
sion kommt, wenn bei der Ereignisverarbeitung die so unterbrochene Funktion/Prozedur erneut
aufgerufen wird.
Achtung! Endlosschleifen entstehen häufig auch ungewollt durch Ereignisse, die sich gegenseitig
oder selbst auslösen. Ereignisfluten dieser Art können das System destabilisieren.
Tipps

Tipps
...................................................
Als Faustregel lässt sich sagen, dass Schleifen in einem Programm ca. zwischen 80 und 99 Pro-
zent der Ausführungszeit absorbieren. Es lohnt sich daher, wenn es um die Einsparung von
Laufzeit geht, insbesondere innere Schleifen zu optimieren, die besonders oft durchlaufen wer-
den.
Rekursive Aufrufe von Funktionen/Prozeduren lassen sich in der Regel ohne große Schwierig-
keiten mittels Schleifen in iterative Aufrufe überführen. Iterative Fassungen dienen insbesondere
der Vermeidung des Fehlers 28, »Nicht genügend Stapelspeicher« und sind von der Laufzeit her
meist überlegen.
Endlosschleifen nicht kompilierter Programme lassen sich innerhalb der Entwicklungsumge-
bung mittels (Strg)+(Untbr) abbrechen. Schwieriger ist der Abbruch von endlosen Ereignis-
schleifen unter Windows 9x. Aber auch hierzu gibt es einen Trick, den unter Windows 9x all-
fälligen Reset zu vermeiden. Das Problem ist, dass der Task-Scheduler von Windows 9x der aus
dem Rahmen fallenden Anwendung nach gewisser Zeit nahezu die gesamte Rechenzeit zur Ver-
fügung stellt, weil die Nachrichtenflut die Priorität so weit hochschraubt, dass keine Hinter-
grundanwendung mehr Nachrichten zugestellt bekommt (noch nicht einmal der Task-Swit-
cher). Der Trick: Man muss die Visual-Basic-Anwendung durch den impliziten Start einer
Vordergrundanwendung in den Hintergrund verbannen. Für einen solchen impliziten Start
reicht bereits das Einlegen einer CD (gegebenenfalls mit Autorun-Anwendung) oder der Emp-
fang eines Faxes. Windows NT ist gegen endlose Ereignisschleifen unempfindlich, da die Ereig-
niswarteschlange in diesem Betriebssystem anders implementiert ist.
Beispiele

Beis piele
...................................................
Für die For-Anweisung vgl. das Beispiel zu »Literale und Konstanten« (S. 23).
Für die Do-Anweisung vgl. das Beispiel zu »InStrRev-Funktion« (S. 79).
Für die While-Anweisung vgl. die Beispiele zu »Dir-Funktion« (S. 148).
Komplexer ist das Beispiel des Bubble-Sort-Algorithmus im Abschnitt »Prozeduren selbst defi-
nieren« (S. 204).

Fehlerbehandlung
Sub Error(lFehlerNr As Long)

43
Kontrollstrukturen

Sub Err.Raise(Number As Long[, Source As String, _


Description As String, Helpfile As String, _
Helpcontext As String])
Function Error(lFehlerNr As Long) As String
On Error Resume Next
On Error GoTo Marke
...
[On Error GoTo 0]
...
Kontrollstrukturen

Exit {Function | Sub}


Marke:
...
Resume [Next]
Function CVErr(FehlerNummer As Long) As Error
Funktion IsError(VarWert) As Boolean
Beschreibung

Bes c hreibung
...................................................
Die Vielfalt der möglichen Ursachen für das Fehlverhalten eines Systems steigt mit der Komple-
xität des Systems. Es ist nicht nur aus theoretischen Gründen unmöglich, die Logik eines Pro-
gramms so zu gestalten, dass dieses vor jedem Schritt jede Fehlermöglichkeit ausschließt –
schließlich könnte sich eine Fehlerbedingung im zeitlichen Verlauf auch erst unmittelbar nach
der Prüfung einstellen –, auch aus praktischen Erwägungen heraus ist es unsinnig, Laufzeit für
die Überprüfung selbst halbwegs wahrscheinlicher Fehlerbedingungen aufzuwenden. Anstatt
umfangreicher und letztlich doch unzulänglicher Fehlerprüfungen setzt sich daher in den Pro-
grammiersprachen zunehmend das Konzept der Ausnahmebehandlung bzw. der Behandlung
von Laufzeitfehlern durch.
Zu einem Laufzeitfehler kommt es, wenn eine Routine ihrer Aufgabe aufgrund einer Fehlerbe-
dingung nicht nachkommen kann und dies als Laufzeitfehler mit einer bestimmten Nummer
signalisiert. Das Signal für einen Laufzeitfehler kann von einer Routine des Betriebssystems,
einer Komponente oder einem sonstigen Objekt gesetzt werden (die entsprechenden Fehlernum-
mern sind im Hilfesystem dokumentiert), aber auch von einer Visual-Basic-Routine selbst,
wenn diese die Anweisung Error unter Angabe einer Fehlernummer, lFehlerNr, oder die Raise-
Methode des vordefinierten Err-Objekts ausführt. Die Funktion Error liefert die zu einer Feh-
lernummer gehörige textuelle Fehlermeldung.
Zur Behandlung eines Laufzeitfehlers – gleich welcher Natur dieser ist – lässt sich mittels einer
On Error GoTo-Anweisung eine vorbereitete Fehlerbehandlungsroutine auf Funktions-/Prozedur-
ebene installieren. Die Anweisung On Error Resume Next installiert dagegen eine standardmä-
ßige Fehlerbehandlungsroutine für die Inline-Fehlerbehandlung, deren Strategie darin besteht,
den für den Laufzeitfehler verantwortlichen Befehl zu überspringen und die Fehlerbehandlung
unmittelbar im Anschluss an den Befehl durch Auswertung der Fehlernummer durchzuführen.
Für die De-installation einer Fehlerbehandlungsroutine sorgt On Error GoTo 0.
Ein anderes Konzept für die Signalisierung von Fehlern eröffnet die Funktion CVErr. Sie liefert
einen Wert von Typ Variant mit dem Untertyp Error zurück und ermöglicht die Implementa-
tion von Funktionen/Prozeduren, die als Ergebniswert auch eine Fehlernummer zurückgeben
können. Ob ein Variant-Wert den Untertyp Error hat, lässt sich mittels der IsError-Funktion in
Erfahrung bringen. Aufgerufen mit einem Variant-Wert, liefert Sie den Wert True, wenn dieser
eine Fehlernummer repräsentiert.

44
Fehlerbehandlung

Anwendung

Anwendung
...................................................
Die Anweisungen Error bzw. Err.Raise werden im Allgemeinen zur Simulation von Fehlern
eingesetzt, um den Code für die Behandlung von Laufzeitfehlern zu testen. Darüber hinaus eig-
nen sich die Befehle auch für die Realisierung programminterner Fehlerbehandlungsmechanis-
men. (Einzelheiten über den Einsatz des Fehlerobjekts für die Signalisierung von Laufzeitfehlern
finden Sie im Abschnitt »Err-Objekt«, S. 277). Die Fehlernummer 0 sowie Fehlernummern grö-
ßer als 65535 sind nicht zulässig, sondern führen ihrerseits zu einem Laufzeitfehler 5, »Ungülti-
ger Prozeduraufruf oder ungültiges Argument«. Die Fehlernummern zwischen 1 und 1000 sind
für das Laufzeitsystem von Visual Basic reserviert, wenn auch derzeit noch nicht alle mit einer
Bedeutung versehen sind. Die anderen Fehlernummern sind frei verfügbar und lassen sich für

Kontrollstrukturen
programmspezifische Zwecke nutzen. Für die reservierten Fehlernummern von Visual Basic ste-
hen textuelle Fehlermeldungen zur Verfügung, die sich mittels der Funktion Error – jeweils auf
den letzten Fehler bezogen – abfragen lassen. Bei Einsatz des Err-Objekts lässt sich diese Fehler-
meldung für jede Fehlernummer Number frei gestalten, da Error nichts weiter als den Wert der
Description-Eigenschaft dieses Objekts liefert. Wenn der Vorgabetext des Systems für die Sig-
nalisierung programmspezifischer Fehler nicht angemessen ist, ist nur der Wert dieser Eigen-
schaft anzupassen – bzw. der Text als Wert bei Aufruf der Raise-Methode für den zweiten Para-
meter anzugeben.
Um Laufzeitfehler abzufangen und darauf reagieren zu können, installiert man mittels On Error
GoTo Marke eine Fehlerbehandlungsroutine, wobei Marke (am Zeilenanfang gefolgt von einem
Doppelpunkt zu notieren) eine innerhalb derselben Routine befindliche Sprungmarke darstellt,
die den Beginn des Fehlerbehandlungscodes kennzeichnet. Die für die genauere Analyse des
Fehlers erforderliche Fehlernummer liefert die Eigenschaft Err.Number des vordefinierten Fehler-
objekts. Nachdem es sich dabei um die Standardeigenschaft des Objekts handelt, ergibt sich der
Wert bereits durch schlichte Nennung des Objektbezeichners – was insbesondere die Kompati-
bilität mit älterem Basic-Code sicherstellt. Der zur Fehlernummer gehörige Fehlertext liefert die
Error-Funktion oder die Eigenschaft Err.Description. Der Befehl Resume beendet die Fehlerrou-
tine nach erfolgreicher Behandlung des Fehlers mit einem Rücksprung und bewirkt die erneute
Ausführung jenes Befehls, der den Laufzeitfehler ausgelöst hatte. Falls eine Wiederholung dieses
Befehls nicht in Frage kommt, lässt sich die Ausführung mit Resume Next beim nächstfolgenden
Befehl wieder aufnehmen. Bei Fehlern, die sich nicht erfolgreich behandeln lassen oder für die
die Fehlerroutine nicht ausgelegt ist, bleibt der Routine nur der Ausweg, ihrerseits einen Fehler
auszulösen, der dann auf der Ebene des Aufrufers behandelt wird – und somit den gleichen Weg
nimmt wie ein Fehler, für den keine Fehlerbehandlung auf aktueller Aufrufebene eingerichtet
ist. Anders herum: Kommt während der Behandlung eines Fehlers eine Funktion/Prozedur zum
Aufruf, die eine eigene Fehlerbehandlung vornimmt, ist deren Fehlerbehandlungsroutine für
alle auf dieser Ebene ausgelösten Fehler zuständig. Hat die Funktion/Prozedur keine eigene Feh-
lerbehandlung, fällt die Fehlerbehandlung der Fehlerbehandlungsroutine des Aufrufers zu.
Damit besteht die Möglichkeit, dass eine Fehlerbehandlungsroutine während der Behandlung
eines Fehlers erneut zum Aufruf kommt, was von der Sache her nicht unbedingt mit Schwierig-
keiten verbunden sein wird, logisch aber ein wenig verzwickt sein kann.
Wenn ein Laufzeitfehler bereits durch Überspringen des jeweiligen Befehls behoben ist, kann
die Fehlerbehandlungsroutine auch inline mittels On Error Resume Next installiert werden. In die-
sem Fall ist kein weiterer Code erforderlich.
Die Zuständigkeit der jeweils aktuellen Fehlerbehandlungsroutine in einer Funktion/Prozedur
erlischt mit dem Befehl On Error GoTo 0. Fehlt dieser Befehl, endet Zuständigkeit mit der Rück-
gabe der Kontrolle an den Aufrufer.

45
Kontrollstrukturen

Bei Signalisierung eines Fehlers ermittelt das Laufzeitsystem jeweils die nächste zuständige Feh-
lerbehandlungsroutine. Eine auf gleicher Ebene (Prozedurebene) gelegene Fehlerbehandlungs-
routine kommt als Erstes zum Zuge, ansonsten wandert der Fehler in umgekehrter Aufruffolge
von Aufrufer zu Aufrufer, bis sich eine zuständige Fehlerbehandlungsroutine findet oder das
Laufzeitsystem schließlich eine standardmäßige Behandlung vornimmt.
Warnung

Wa rnung
...................................................
Die Logik von Fehlerbehandlungsroutinen ist meist komplizierter als man denkt. So ist erstens
davon auszugehen, dass jeder zwischen einer On Error GoTo Marke-Anweisung und einer On
Error GoTo 0-Anweisung auftretende Laufzeitfehler zum Aufruf der Routine führen kann: fal-
Kontrollstrukturen

sche Argumente bei Prozedur-/Funktionsaufrufen ebenso wie Laufzeitfehler, die von einer auf-
gerufenen Prozedur oder Funktion signalisiert werden, weil sie dort keine Behandlung erfahren
oder eine Behandlung nicht möglich ist. Zweitens ist aber auch davon auszugehen, dass ein Feh-
ler immer wieder auftritt, weil er nicht korrekt behoben ist. Der unbedachte Einsatz von Resume
ohne den Zusatz Next kann dann zu lästigen Endlosschleifen führen, die sich in der Entwick-
lungsumgebung nur noch mittels (Strg)+(Untbr) oder in der kompilierten Fassung des Pro-
gramms nur noch über den Task-Manager abbrechen lassen.
Ein häufiger Fehler im Zusammenhang mit Fehlerbehandlungsroutinen ergibt sich aus einer
Nachlässigkeit: Die Ausführung durchläuft die Routine auch ohne Vorliegen eines Laufzeitfeh-
lers, weil diese nicht durch den Befehl Exit Sub oder Exit Function vom gewöhnlichen Code
abgesetzt ist.
Tipp

Tipp
...................................................
Testen Sie jede Fehlerbehandlungsroutine auf Herz und Nieren, indem Sie Testcode einsetzen,
der alle Fehler – also auch solche, die die Routine nicht behandeln kann – mittels Error-Anwei-
sungen oder Aufrufen der Methode Err.Raise simuliert.
Beispiel

Beis piel
...................................................
Das folgende Codebeispiel demonstriert die Fehlerbehandlung, wenn das Öffnen einer Datei
mit vorangehender Abfrage des Dateinamens fehlschlägt. Da es keinen Sinn macht, die Open-
Anweisung ohne erneute Eingabe des Dateinamens (hier über ein Standarddialoge-Objekt
CommonDialog1 gelöst) zu wiederholen, ist der betreffende Code in einer eigenen Funktion
zusammengefasst, der die Dateinummer zurückliefert. Die in der aufrufenden Routine instal-
lierte Fehlerbehandlungsroutine bietet dem Benutzer die Wahl zwischen der Wiederholung des
gesamten Funktionsaufrufs oder einem Abbruch der aktuellen Routine. Der Abbruch wird sei-
nerseits durch Auslösung eines Laufzeitfehlers bewerkstelligt. (Hinweis: Der FreeFile-Aufruf
liefert nach einem Fehlschlag wieder die gleiche Dateinummer, da Open keine Reservierung der
angebotenen Dateinummer vornimmt.)
...
Dim Handle As Integer
Dim Meldung As String
...
On Error GoTo OpenFehler ' Routine installieren
Handle = OpenBinary ' Funktion aufrufen
On Error GoTo 0 ' Routine de-installieren
...
Exit Sub ' Hier nicht weiter!
OpenFehler:
Meldung = "Fehler" + Str(Err) + ": " + Error(Err)

46
Fehlerbehandlung

If MsgBox(Meldung, vbRetryCancel) = vbRetry Then


Resume ' Funktionsaufruf wiederholen
Else ' Fehler an Aufrufer weitermelden
Err.Raise(1001, "Binärdatei lässt sich nicht öffnen")
End If
...

Function OpenBinary() As Integer


OpenBinary = FreeFile ' freie Dateinummer ermitteln
CommonDialog1.ShowOpen

Kontrollstrukturen
Open CommonDialog1.FileName For Binary As FreeFile
End Function

Vgl. auch das Beispiel zu »Open-Anweisung« (S. 166).


Verwandte Themen

...................................................
Verwa ndte Them en
Dateiorientierte Funktionen und Anweisungen (S. 126); Err-Objekt (S. 277); Standarddia-
loge-Steuerelement (CommonDialog) (S. 444)

47
Datentypen und ihre Operationen
Wie alle Programmiersprachen, deren Wurzeln in der prozeduralen Programmierung liegen,
verfügt Basic über ein Typkonzept, das im Laufe der Sprachentwicklung zunehmend reichhalti-
ger geworden ist. Das ursprüngliche Typsystem von Basic war geschlossen. Es gab vier numeri-
sche Datentypen mit unterschiedlichen Wertebereichen, über denen sich Ganzzahl- und Fließ-
kommaarithmetik und ein wenig Boolsche Algebra betreiben ließ, sowie einen
Zeichenfolgendatentyp mit vielen komfortablen Funktionen. QuickBasic und QBasic brachten
der Sprache eine »Pascalisierung«, die sich nicht nur in einem verallgemeinerten Prozedur- und
Funktionsbegriff bemerkbar machte, sondern auch in der Öffnung des Typsystems für benut-
zerdefinierte Datentypen. Darüber hinaus erhielt die Sprache auch einen flexiblen Datentyp, der
jeden elementaren Datentyp (nicht jedoch benutzerdefinierte Datentypen) vertreten konnte und
aufgrund impliziter Typumwandlungen eine gewisse Typtoleranz mit sich brachte. Seit die
Sprache mit Visual Basic in den Bereich der objektorientierten Programmierung vorgedrungen
ist, hat das Typsystem der Sprache in Form der in Typbibliotheken vorliegenden Objektdaten-
typen eine explosive Verbreiterung erfahren.

Elementare Datentypen
Byte, Boolean, Integer, Long, Single, Double, Currency, Decimal, Date, Object, String,
Variant
True, False, Empty, Nothing, Null, Error
Function IsEmpty(Var) As Boolean
Function IsError(Var) As Boolean
Function IsNull(Var) As Boolean
Function IsNumeric(Var) As Boolean
Function IsObject(Var) As Boolean
Beschreibung

Bes c hreibung
...................................................
Elementare Datentypen sind die Grundelemente einer Sprache für die Darstellung und Interpre-
tation von Informationen. Die einzelnen Datentypen unterscheiden sich hinsichtlich ihrer Dar-
stellung, ihrer Wertebereiche und der für sie definierten grundlegenden Operationen. Visual
Basic kennt elementare Datentypen für die Repräsentation logischer Werte (Boolean), binärer
Werte (Byte), numerischer Ganzzahlwerte (Integer und Long), numerischer Fließkommawerte
(Single und Double), Datumsgaben (Date), Zeichenfolgen (String) und die Referenz auf Objekte
(Object).
Anwendung

Anwendung
...................................................
Mit Hilfe der elementaren Datentypen lassen sich Konstanten und Variablen für die Handha-
bung der in Programmen anfallenden Daten deklarieren. Jeder dieser Datentypen mit Aus-
nahme von Variant steht für eine ganz bestimmte Art der Repräsentation und Interpretation
von Information. Die folgende Tabelle gibt einen Überblick über ihre Wertebereiche.

49
Elementare Datentypen

Datentyp Bytes Beschreibung und Wertebereich


Byte 1 Kurze vorzeichenlose Ganzzahl zwischen 0 bis 255
Boolean 2 Logischer Wert, True oder False
Integer 2 Ganzzahl zwischen –32.768 bis 32.767
Long 4 Lange Ganzzahl zwischen –2.147.483.648 und 2.147.483.647
Single 4 Gleitkommazahl einfacher Genauigkeit von –3,402823E38 bis
–1,401298E–45 für negative Werte und von 1,401298E-45 bis
3,402823E38 für positive Werte
Elementare Datentypen

Double 8 Gleitkommazahl mit doppelter Genauigkeit:


–1,79769313486232E308 bis –4,94065645841247E-324
für negative Werte und
4,94065645841247E–324 bis 1,79769313486232E308
für positive Werte
Currency 8 Ganzzahl mit Skalierung in 10.000stel zwischen
–922.337.203.685.477,5808 und 922.337.203.685.477,5807
Decimal 14 29stellige Dezimalzahl ohne Exponent, als Ganzzahl zwischen
±79.228.162.514.264.337.593.543.950.335 mit Abstand 1, als Zahl
mit 28 Nachkommastellen zwischen
±7,9228162514264337593543950335 mit Abstand
±0,0000000000000000000000000001
Date 8 Datum zwischen 1. Januar 100 und 31. Dezember 9999
Object 4 Referenz auf ein Objekt, eine gültige Adresse oder Nothing
String 10 + Länge Zeichenfolge mit variabler Länge. 0 bis theoretisch 231-1 Zeichen. In
der Praxis ist je nach Speicherausbau des Systems aber bereits bei
einer Länge von ca. 100 Millionen Zeichen Schluss, wegen »Überlauf
des Zeichenfolgenspeichers»
String * Länge Zeichenfolge mit fester Länge zwischen 1 und 65.535 (216-1)
Variant 16 Standardtyp, bei numerischem Untertyp wie der Datentyp Double
Variant 22 + Länge Standardtyp, bei Zeichenfolge als Untertyp, wie Datentyp String mit
variabler Länge
Die elementaren Datentypen von Visual Basic

Der Datentyp Variant


Der Typ Variant bildet eine Hülle für alle anderen Datentypen und kann alle durch elementare
Datentypen darstellbaren Werte repräsentieren (außer Zeichenfolgen fester Länge) sowie die
Werte Empty, Nothing, Null und Error. Variablen vom Typ Variant müssen nicht eigens dekla-
riert werden, da Visual Basic diesen Datentyp als Standardtyp für alle nicht explizit oder via
Typkennzeichen deklarierten Variablen einsetzt. Es ist aber kein Fehler (ja sogar guter Pro-
grammierstil), Variablen vom Typ Variant explizit zu deklarieren. In diesem Fall erhält die
Variable Empty als Initialisierungswert. Man kann einer Variant-Variablen auch den Wert Null
zuweisen, was üblicherweise signalisiert, dass die Variable absichtlich keinen gültigen Wert ent-
hält. Bei Zuweisung eines typgebundenen Werts speichert die Variable nicht nur den Wert an
sich, sondern auch seinen Typ. Man spricht in diesem Zusammenhang vom Untertyp eines

50
Die Datentypen Integer, Long, Single und Double

Variant-Werts. Um die Sonderwerte abzufragen, lassen sich die eigens dafür definierten
Boolean-Funktionen IsEmpty, IsError und IsNull verwenden – ein expliziter Vergleich mit den
Werten Empty, Nothing, Null und Error tut es natürlich auch.
Bei der Operation mit typgebundenen Werten kann es passieren, dass der Wertebereich des
aktuellen Untertyps einer Variant-Variablen für die Darstellung eines Wert nicht mehr aus-
reicht. In diesem Fall nimmt Visual Basic eine implizite Typumwandlung im Sinne einer Werte-
bereichserweiterung vor. Implizite Typumwandlungen finden auch statt, wenn ein Variant-
Wert mit numerischem Untertyp einer String-Variable oder ein Variant-Wert mit Untertyp
String einer Variable mit numerischem Typ zugewiesen werden soll. Im ersten Fall wandelt
Visual Basic den Variant-Wert in eine adäquate Zeichendarstellung um und im zweiten Fall in
eine adäquate numerische Darstellung.

Elementare Datentypen
Der Sonderwert Error in einer Variablen vom Datentyp Variant ist dafür vorgesehen, in Proze-
duren erkannte Fehlerbedingungen anzuzeigen, wenn keine On Error-Fehlerbehandlung durch
die Anwendung stattfindet. In diesem Fall muss die rufende Prozedur selbst den Fehler auswer-
ten und nötige Maßnahmen ergreifen. Gesetzt wird der Sonderwert gewöhnlich mittels der
Funktion CVErr, die eine Fehlernummer entgegennimmt und einen entsprechenden Error-Wert
vom Typ Variant liefert.
Trägt ein Variant-Wert den Untertyp Object, drückt der Wert Nothing aus, dass auf kein Objekt
referiert wird. Um in Erfahrung zu bringen, ob ein Variant-Wert den Untertyp Object trägt,
lässt sich die Boolean-Funktion IsObject verwenden.
Nach all dem dürfte offensichtlich sein, welch enorme Flexibilität der Datentyp Variant mit sich
bringt und wie sehr er die Programmierung vereinfachen kann, indem er die Typenvielfalt auf
einen einzigen Datentyp zurückführt. Allerdings verhält es sich bei der Programmierung mit
diesem Datentyp anders als im richtigen Leben: Hier sollten die einfachen Dinge eher den Profis
vorbehalten bleiben. Ungeübten Programmierern mit einem noch nicht vollständig ausgepräg-
ten Verständnis für die elementaren Datentypen spielt das verborgene Wirken von Visual Basic
gerne mal den einen oder anderen Streich.

Die Datentypen Integer, Long, Single und Double


Die Datentypen Integer und Long setzt man üblicherweise für Zählvariablen, Indizierungen
oder Berechnungen im Bereich der Ganzzahlarithmetik ein. Sie unterscheiden sich von einander
allein durch ihren Wertebereich. Single und Double eignen sich dagegen speziell für die Darstel-
lung gebrochen-rationaler Werte (lies: Dezimalzahlen mit Nachkommaanteil). Die zugehörige
Gleitkommaarithmetik entspricht der üblichen Dezimalrechnung mit Rundung auf eine feste
Anzahl von Dezimalstellen. Das bedingt, dass benachbarte Werte in den jeweiligen Werteberei-
chen keinen festen Abstand zueinander aufweisen (der bei den Datentypen Integer und Long ja
1 ist), sondern ihren Abstand mit wachsendem Betrag vergrößern (bzw. gegen 0 hin verklei-
nern). Double weist gegenüber Single die doppelte Genauigkeit sowie einen erheblich größeren
Wertebereich auf. Visual Basic initialisiert diese Datentypen mit dem Wert 0 bzw. 0,0.
' Vollständige Deklaration
Const cDelta As Double = 2.71364234E-123
Dim iGanzzahl As Integer
Dim lGanzzahl As Long
Dim sFlKommazahl As Single
Dim dFlKommazahl As Double
' Deklaration mit Typkennzeichen
Const ci# = 1.2
Dim i%
Dim l&

51
Elementare Datentypen

Dim s!
Dim d#
For n% = 1 to 100 ' Deklaration mit Typkennzeichen durch Nennung

Die Datentypen Boolean und Byte


Der mit Visual Basic neu zu Basic hinzugekommene Datentyp Boolean weist einen sehr kleinen
Wertebereich auf, nämlich nur die als Konstanten vordefinierten Wahrheitswerte True und
False. In Basic entspricht der Wahrheitswert True traditionell dem Wert -1 und False dem Wert
0. Bei Typumwandlungen in den Datentyp Boolean wird jeder Wert ungleich 0 als True interpre-
tiert und nur der Wert 0 als False. Boolean leistet vornehmlich in Kontrollstrukturen für die
Elementare Datentypen

Programmsteuerung sowie bei der Berechnung logischer Funktionen auf Grundlage der Boole-
schen Algebra gute Dienste. Visual Basic initialisiert Variablen vom Typ Boolean mit False.
Dim bLogValue As Boolean
bLogValue = True
...
If bLogValue Then
...
End If

Gleichfalls ein neues Mitglied im Club ist der Datentyp Byte. Er dient insbesondere dem
Umgang mit binären Inhalten, denen keine feste Interpretation zukommt. (Traditionell wurden
für Inhalte dieser Art Zeichenfolgen benutzt.) Dieser Datentyp wird zwar noch als numerischer
Datentyp gehandelt, das heißt, er wird mit 0 initialisiert, und man kann mit ihm ganz normal
rechnen, solange der Wertebereich nicht überschritten wird. Er ist aber als einziger vorzeichen-
los.
Dim MyByte(256) As Byte
...
For i = 0 to 255
Print #1, MyByte(i);
Next i

Die Datentypen Currency und Date


Der eng mit den ganzzahligen Typen Integer und Long verwandte Datentyp Currency wurde
speziell zur Erleichterung finanzmathematischer Berechnungen mit in die elementaren Datenty-
pen aufgenommen. Die Werte in seinem Wertebereich sind ein ganzzahliges Vielfaches von
0,0001. Damit stellt der Datentyp noch vier Stellen hinter dem Komma dar und seine Arithme-
tik entspricht der üblichen Dezimalrechnung mit Kaufmannsrundung an der vierten Stelle hin-
ter dem Komma. Visual Basic initialisiert Currency-Variablen mit 0,0000.
Interessanter ist der gleichfalls neue Datentyp Date, der nicht zuletzt im Schatten des Jahr-2000-
Problems eine ebenso zweifelhafte wie steile Karriere hinter sich hat. Visual Basic repräsentiert
Werte dieses Typs als 64-Bit-Gleitkommazahlen (8 Bytes) nach IEEE und kann somit Datums-
angaben im Bereich zwischen dem 1. Januar 100 und dem 31. Dezember 9999 sowie Uhrzeiten
im Bereich von 0:00:00 bis 23:59:59 unterscheiden. Sie können mit diesem Datentyp Datums-
angaben und Zeitangaben in Kombination, aber auch einzeln als Werte darstellen. Der Nota-
tion literaler Datums- und Zeitangaben liegt das amerikanische Format zugrunde, das heißt, in
Datumsangaben wird der Monat vor dem Tag notiert und die Abtrennung erfolgt durch das
Zeichen »/«, während Zeitangaben in 12-Stunden-Darstellung gefolgt von »PM« oder »AM«
zu treffen sind. Zudem ist die Darstellung durch ein führendes und abschließendes Zeichen »#«
einzuschließen. (Der Editor erkennt übrigens auch andere Darstellungen, so etwa #1 Feb 99#,
und korrigiert diese beflissen in das erwünschte Format.)

52
Der Datentyp Decimal

Dim a As Date, b As Date, c As Date


a = #2/1/1996 1:12:01 PM#
b = #12:01:00 PM#
c = #2/1/1996#

Beim Umwandeln anderer numerischer Datentypen in Werte des Datentyps Date repräsentieren
die Vorkommastellen das Datum und die Nachkommastellen die Uhrzeit. Mitternacht ent-
spricht dem Wert 0,0 und 12 Uhr Mittags dem Wert 0,5. Negative ganze Zahlen repräsentieren
ein Datum vor dem 30. Dezember 1899, positive ein Datum nach dem 30. Dezember 1899.
Den 30. Dezember 1899 selbst kennt Visual Basic dagegen überhaupt nicht, sondern interpre-
tiert ihn als #12:00:00 AM#.

Elementare Datentypen
Der Datentyp Decimal
Der gleichfalls neue Datentyp Decimal ist kein eigenständiger Datentyp, sondern kann nur als
Untertyp eines Variant-Werts auftreten. Um einen Wert dieses Typs zu erzeugen, bedarf es der
Typumwandlungsfunktion CDec.
Dim vDez1
vDez1 = CDec(100.00000021) ' aus Double erzeugt

Werte vom Typ Decimal haben eine 29-stellige dezimale Repräsentation mit Komma ohne
Exponent im BCD-Code. Den Typen Single und Double liegt dagegen eine binäre Repräsenta-
tion zugrunde, die nicht mehr als 8 bzw. 15 dezimale Stellen erfasst. Um Decimal-Werte mit
mehr als 15 Stellen (mehr erlaubt der Datentyp Double nicht) noch direkt definieren zu können,
ist der Funktion CDec eine entsprechende Zeichenfolgendarstellung des Werts zu übergeben.
Beachten Sie, dass dabei die auf dem jeweiligen System geltenden Ländereinstellungen eine
Rolle spielen. So legt die Einstellung Deutsch (Standard) als Dezimalzeichen ein Komma fest.
Dim vDez2
vDez2 = CDec("100,000000000000000021") ' aus String erzeugt
Warnung

Wa rnung
...................................................
Visual Basic vereinbart jede Variable standardmäßig als Variant, wenn sie nicht explizit im
Rahmen einer Variablendeklaration oder implizit durch eine DefType-Anweisung bzw. durch
eines der traditionellen Typkennzeichen von Basic ($, %, &, !, #) eine feste Typzuweisung
erfährt.
Tipp

Tipp
...................................................
Beobachten Sie bei der Fehlersuche in Programmen besonders Werte vom Typ Variant, insbe-
sondere wenn Seltsames und Absurdes mit im Spiel zu sein scheint. Entlaufene Variant-Werte
waren schon Ursache so manchen Übels. Vereinbaren Sie Variablen besser explizit, um einen
bestimmten Datentypen zu erzwingen, das verbessert die Übersicht. Wenn Sie das Tippen läng-
licher Typdeklarationen scheuen, verwenden Sie doch DefType oder die Typkennzeichen ($, %, &,
!, #). Oft entlarvt eine Option Explicit-Anweisung den Übeltäter bereits.
Verwandte Befehle

Verwa ndte Befehle


...................................................
Dim, Public, Private, Function, DefType
Verwandte Themen

Verwandte Them en
...................................................
Literale und Konstanten (S. 27); Typumwandlung (S. 57); Typkennzeichen und Bezeichner-
bereiche für Typen (S. 167); Variablendeklaration (S. 162)

53
Operatoren für elementare Datentypen und logische Bedingungen

Operatoren für elementare Datentypen und logische


Bedingungen
+, –, *, /, \, MOD, ^, Not, And, Or, Xor, Eqv, Imp, <, >, =, >=, <=, <>, Is, TypeOf
Beschreibung

Bes c hreibung
...................................................
Operatoren dienen der Bildung von Ausdrücken. Die Menge der Operatoren, die Visual Basic
für die elementaren Datentypen kennt, unterteilt sich in die Gruppe der logischen Operatoren
(And, Or, Xor, Eqv, Imp, Not) – die in Visual Basic aufgrund der besonderen Wahl der Repräsenta-
tion der Wahrheitswerte mit den bitweisen Operatoren übereinstimmen –, die Gruppe der
Operatoren für elementare Datentypen und logische Bedingungen

arithmetischen Operatoren (+, –, *, /. \, Mod, ^), die Gruppe der Vergleichsoperatoren (<, >, =,
<=, >=, <>, Is) und die Gruppe der Zeichenfolgenoperatoren (die derzeit nur die Verkettungs-
operatoren »+« und »&« umfasst).
Eine Art Doppelrolle spielt traditionell der Zuweisungsoperator »=«, der für alle elementaren
Datentypen definiert ist und gegebenenfalls auch für die implizite Typumwandlung zwischen
verwandten Typen sorgt. Er darf nicht mit dem gleich notierten Vergleichsoperator verwechselt
werden.
Ein Vergleichsoperator der besonderen Art ist der Is-Operator für den Vergleich zweier Objekt-
variablen. Er liefert den Wert True, wenn die beiden Operanden auf dasselbe Objekt verweisen,
ansonsten False. Er kommt insbesondere häufig im Zusammenhang mit dem TypeOf-Schlüssel-
wort zur Anwendung, wenn abgefragt werden soll, ob eine Objektvariable auf einen bestimm-
ten Objekttyp verweist.
If TypeOf MeineVar Is Form1
Anwendung

Anwendung
...................................................

Operator Notation Operation Operanden


+ a + b Verkettung Zeichenfolgen
& a & b
+ a + b Summenbildung Numerische Werte
- a – b Differenzbildung Numerische Werte
- -a Vorzeichenumkehr Numerische Werte
* a * b Multiplikation Numerische Werte
/ a / b Division Numerische Werte
\ a \ b Division mit ganzzahligem Numerische Werte
Ergebnis
Mod a Mod b Restwertdivision Numerische Werte
(Modulo-Operation)
^ a ^ b Potenz Numerische Werte
And a And b Logisches und bitweises UND Numerische Werte, logische Werte
Or a Or b Logisches und bitweises ODER Numerische Werte, logische Werte
Not Not a Logische und bitweise Numerische Werte, logische Werte
Negation
Operationen der elementaren Datentypen

54
Arrays

Operator Notation Operation Operanden


Xor a Xor b Logisches und bitweises Exklu- Numerische Werte, logische Werte
siv-ODER
Eqv a Eqv b Logische und bitweise Äquiva- Numerische Werte, logische Werte
lenz
Imp a Imp b Logische und bitweise Implika- Numerische Werte, logische Werte
tion
= a = b Logische Bedingung: »Gleich- Numerische Werte, logische Werte,

Arrays
heit« (vgl. auch Eqv) Zeichenfolgen, Datums-/Zeitwerte
< a < b Logische Bedingung: »kleiner Numerische Werte, logische Werte,
als« (bei Zeichenfolgen von Zeichenfolgen, Datums-/Zeitwerte
Option Compare abhängig)
> a > b Logische Bedingung: »größer Numerische Werte, logische Werte,
als« (bei Zeichenfolgen von Zeichenfolgen, Datums-/Zeitwerte
Option Compare abhängig)
<= a <= b Logische Bedingung: »kleiner Numerische Werte, logische Werte,
gleich« (bei Zeichenfolgen: von Zeichenfolgen, Datums-/Zeitwerte
Option Compare abhängig)
>= a >= b Logische Bedingung: »größer Numerische Werte, logische Werte,
gleich« (bei Zeichenfolgen: von Zeichenfolgen, Datums-/Zeitwerte
Option Compare abhängig)
<> a <> b Logische Bedingung: Numerische Werte, logische Werte,
»ungleich« Zeichenfolgen, Datums-/Zeitwerte
Is a Is b Testet, ob Operanden auf glei- Objektvariablen
TypeOf TypeOf a ches Objekt verweisen bzw.
Is b gleichen Objekttyp tragen
Operationen der elementaren Datentypen

Arrays
Dim StatArray({iDimension1 | Untergrenze1 To Obergrenze1}[, _
{Dimension2 | Untergrenze2 To Obergrenze2}[, _
...
{DimensionN | Untergrenze2 To Obergrenze2}]]) _
[As Typ]
Dim DynArray() [As Typ]
ReDim [Preserve] DynArray [As Typ]
Function Array([Wert1[, Wert2[, ... WertN]]]) As Variant
Function UBound(Array[, iDimension As Integer = 1]) As Long
Function LBound(Array[, iDimension As Integer = 1]) As Long
Function IsArray(Var) As Boolean
Option Base {0 | 1}

55
Arrays

Beschreibung

Bes c hreibung
...................................................
Ein Array stellt eine ein- oder mehrdimensionale Struktur dar, die eine Menge von Werten glei-
chen Typs unter einem gemeinsamen Variablenbezeichner zusammenfasst. Visual Basic unter-
scheidet zwischen statischen und dynamischen Arrays.
Die (endgültige) Deklaration statischer Arrays erfolgt im Rahmen einer Dim-Anweisung. Für die
Deklaration sind neben dem Array-Bezeichner StatArray auch ein oder mehrere Indexbereiche
anzugeben – je nachdem, wie viele Dimensionen das Array besitzt – sowie optional ein Element-
typ Typ. Wird ein Indexbereich durch Nennung einer Obergrenze iDimensionN angegeben,
beginnt die Zählung der Array-Elemente standardmäßig bei 0 (Option Base 0 ist die Voreinstel-
lung von Visual Basic), es sei denn, das betreffende Modul enthält die Anweisung Option Base
Arrays

1. Es lassen sich aber auch Indexbereiche mit beliebigen Grenzen durch explizite Nennung unte-
rer und oberer Grenzen (UntergrenzeN To ObergrenzeN) vereinbaren.
Die formale Deklaration eines dynamischen Arrays kann durch Vereinbarung einer Array-Vari-
ablen im Rahmen einer Dim-Anweisung geschehen, muss aber nicht. Dabei notiert man den
Bezeichner DynArray gefolgt von einem leeren Klammerpaar und vereinbart optional einen Ele-
mentdatentyp. Die konkrete Definition kann dann an passender Stelle vermittels der ReDim-
Anweisung unter Angabe von Dimensionen und Array-Grenzen geschehen – auch mehrmals
mit unterschiedlichen Grenzen und Dimensionen, aber gleichem Datentyp. ReDim eignet sich
auch zur Vergrößerung eines bereits definierten dynamischen Arrays unter Beibehaltung der
Dimensionen und Elementwerte. In diesem Fall muss das Schlüsselwort Preserve angegeben
werden.
Der Zugriff auf den Wert eines Array-Elements erfolgt durch Angabe des Array-Bezeichners
gefolgt von einem Index oder einer Indexliste (bei mehrdimensionalen) Arrays in Klammern).
Anwendung

Anwendung
...................................................
Arrays eignen sich hervorragend zur Verwaltung großer Mengen von gleichartigen, aber auch
ungleichartigen (wenn als Datentyp Variant vereinbart wird) Daten, auf die ein effizienter
indexsequenzieller Zugriff erfolgen soll. Seien es Matrixelemente bei der numerischen Vektor-
rechnung, Messwerte, Adressenstämme, Datensätze oder auch Ansammlungen gleichartiger
Steuerelemente, die Array-Struktur bietet sich hervorragend für die einfache und schnelle Hand-
habung von variablen Werten an. Als Elementtyp für Arrays sind alle elementaren und komple-
xen Datentypen erlaubt, insbesondere auch benutzerdefinierte Datentypen, Objekte und der
Typ Variant. Da ein Wert vom Typ Variant seinerseits ein Array sein kann, sind also auch impl-
izit verschachtelte Arrays mit individueller Tiefe je Element möglich.
Eine Array-Variable lässt sich wie eine gewöhnliche Variable verwenden – sie erhält ihren
»Wert« durch Zuweisung oder durch (partielle) Initialisierung im Zuge einer ReDim-Anweisung.
Im Gegensatz zu anderen Programmiersprachen (vgl. C/C++) beschränkt sich Visual Basic bei
der Zuweisung eines Arrays an eine Array-Variable nicht auf eine reine Adresszuweisung, son-
dern erstellt eine physikalische Kopie des gesamten Arrays, wie folgender Code beweist:
Dim a(0), b()
a(0) = 10
b = a
a(0) = 11
Print b(0), a(0) ' Ausgabe: 10 11

Diese Aussage ist allerdings mit Vorsicht zu genießen, sie gilt nämlich nur, wenn die Elemente
einfache Datentypen tragen. Von Objekten fertigt Visual Basic keine Kopien an. Das liegt
daran, dass der Wert einer Objektvariablen einen Verweis auf das tatsächliche Objekt darstellt
und die einfache Zuweisungsoperation (im Gegensatz zur Set-Anweisung) sich auf eine Kopie
des Verweises beschränkt, wie folgender Code zeigt:

56
Typumwandlung

Dim a(0) As Object, b() As Object


Set a(0) = Me ' Formular wird zugewiesen
b = a
b(0).Caption = "Dieser "
a(0).Caption = "oder jener?"
Print b(0).Caption ' Ausgabe: "oder jener?"

Array- Funktionen
Visual Basic unterstützt Array-Konstanten ebenso wenig wie literale Arrays. Während bei stati-
schen Arrays die Wertzuweisung elementweise erfolgen muss, kann im Falle von dynamischen

Typumwandlung
Arrays eine Zuweisung auch auf Array-Ebene erfolgen. Das macht ein kompakte Initialisierung
mittels der Array-Funktion möglich, die ihre als Aufrufparameter übergebene Werteliste als
Array zurückliefert. Um die obere bzw. untere Indexgrenze eines Arrays in Erfahrung zu brin-
gen, gibt es die Funktionen UBound bzw. LBound. Falls das Array mehr als eine Dimension
besitzt, lässt sich die Dimension als Wert iDimension spezifizieren (die Zählung beginnt bei 1).
Variablen des Typs Variant können bekanntlich Werte verschiedenster Datentypen annehmen,
darunter auch Arrays. Die Funktion IsArray liefert eine Aussage in Form eines Wahrheitswerts
darüber, ob es sich bei einer Variablen um eine Array-Variable handelt oder nicht.
Leider kennt Visual Basic keine Funktion, die den kompletten Speicherbedarf für das Speichern
eines Arrays ermittelt. Dieser Wert muss vielmehr aus dem Elementdatentyp, der Dimensionen-
zahl, der Dimensionsgrenzen und gegebenenfalls mitzuspeichernder Deskriptoren »zu Fuß«
errechnet werden (vgl. »Get-Anweisung«, S. 140), da Arrays in den unterschiedlichen Datei-
modi unterschiedlich repräsentiert werden.
Beispiel

Beis piel
...................................................
Dim StatArray(-10 To 10, -10 To 10) As Integer ' statisch, zweidim.
Dim DynArray() As String ' dynam. deklarieren
...
Redim DynArray(10) As String ' dynam. definieren
...
Redim Preserve DynArray(UBound(DynArray) + 1) As String 'erweitern
Verwandte Themen

Verwandte Them en
...................................................
Auflistungen und Collection-Objekte (S. 304); Get-Anweisung (S. 140); Elementare Datenty-
pen (S. 49)

Typumwandlung
Function CBool(Ausdruck) As Boolean
Function CByte(Ausdruck) As Byte
Function CCur(Ausdruck) As Currency
Function CDate(Ausdruck) As Date
Function CDbl(Ausdruck) As Double
Function CDec(Ausdruck) As Decimal
Function CInt(Ausdruck) As Integer

57
Typumwandlung

Function CLng(Ausdruck) As Long


Function CSng(Ausdruck) As Single
Function CVar(Ausdruck) As Variant
Function CVDate(Ausdruck) As Variant
Function CStr(Ausdruck) As String
Function IsDate(Ausdruck) As Variant
Function IsNumeric (Ausdruck) As Boolean
Typumwandlung

Beschreibung

Bes c hreibung
...................................................
Die explizite Typumwandlung wird bei Visual Basic zwar nicht so groß geschrieben wie bei
manch anderer Programmiersprache, da der Visual Basic Compiler von sich aus implizite
Typanpassungen nach Bedarf vornimmt, vermeidbar ist sie aber nicht in allen Fällen. Die fol-
gende Tabelle gibt einen Überblick über die auf die einzelnen Datentypen zugeschnittenen Kon-
vertierungs- und Typumwandlungsfunktionen.

Funktion Beschreibung
CBool Konvertiert Ausdruck nach Möglichkeit (bei Zeichenfolgen ohne Unterscheidung
der Großschreibung) in einen Wert vom Typ Boolean; Interpretiert die Zeichen-
folgen "Wahr", "True" sowie numerische Werte ungleich 0 als True und die Zei-
chenfolgen "Falsch", "False" sowie den Wert 0 als False. Bei anderen
Zeichenfolgen liefert die Funktion einen Laufzeitfehler.
CByte Liefert Ausdruck als Wert vom Typ Byte. Fließkommawerte mit einem Nachkom-
maanteil von exakt 0,5 werden zur nächsten geraden Zahl hin gerundet (0,5 wird
zu 0 und 1,5 zu 2), ansonsten gilt die Kaufmannsrundung. Liegt der Wert von
Ausdruck nicht im Bereich zwischen 0 und 255 oder ist Ausdruck von Typ String,
löst die Funktion einen Laufzeitfehler aus.
CCur Liefert Ausdruck als Wert vom Typ Currency. Rundet numerische Werte auf vier
Stellen hinter dem Komma und interpretiert Zeichenfolgen im gebietsspezifischen
Währungsformat. Für das Gebietsschema »Deutsch (Standard)« gilt: Komma ist
Dezimalzeichen, Punkt ist Tausendertrennzeichen, »DM« als führendes oder
nachgestelltes Währungssymbol ist erlaubt, sonstige nicht zur Notation von Zah-
lenliteralen gehörende Zeichen führen zu einem Laufzeitfehler. Der zulässige
Wertebereich für Ausdruck geht von -922.337.203.685.477,5808 bis
922.337.203.685.477,5807.
CDate Liefert Ausdruck als Wert vom Typ Date. Interpretiert numerische Werte und Zei-
chenfolgen als Zeit-/Datumswert. Bei numerischen Werten ist ein Vorkommaan-
teil zwischen -657.434 und 2.958.465 zulässig – er wird als Tage-Offset bezogen
auf das Datum 1.1.1899 interpretiert – und ein Nachkommaanteil von nicht
mehr als sechs Stellen – er wird als Sekunden-Offset bezogen auf das Datum
interpretiert. Bei der Interpretation von Zeichenfolgen erkennt die Funktion das
kurze, mittlere oder lange gebietsspezifische Datumsformat (das lange Datums-
format jedoch nur, wenn kein Wochentag notiert ist). Die Funktion IsDate
erlaubt eine Vorabprüfung, ob ein gegebener Wert in einen Zeit-/Datumswert
wandelbar ist.
Konvertierungs- und Typumwandlungsfunktionen

58
Typumwandlung

Funktion Beschreibung
CDbl Liefert Ausdruck als Wert vom Typ Double. Bei der Konvertierung aus Decimal
und Currency werden nicht darstellbare Stellen gegebenenfalls gerundet, alle
anderen numerischen Datentypen lassen sich ohne Genauigkeitsverlust überfüh-
ren. Bei der Konvertierung von Zeichenfolgen erwartet die Funktion das gebiets-
spezifische Zahlenformat. Für das Gebietsschema »Deutsch (Standard)« gilt:
Komma ist Dezimalzeichen, Punkt ist Tausendertrennzeichen. Der Wertebereich
geht von -1,79769313486232E308 bis -4,94065645841247E-324 für negative
Werte und von 4,94065645841247E-324 bis 1,79769313486232E308 für posi-
tive Werte.

Typumwandlung
CDec Liefert Ausdruck als Wert vom Typ Decimal, der jedoch (ohne erneute Typum-
wandlung) nur Variablen des Typs Variant zugewiesen werden kann. Bei der
Konvertierung von Zeichenfolgen erwartet die Funktion das gebietsspezifische
Zahlenformat. Für das Gebietsschema »Deutsch (Standard)« gilt: Komma ist
Dezimalzeichen, Punkt ist Tausendertrennzeichen. Der Wert selbst darf im
Bereich ±79.228.162.514.264.337.593.543.950.335 liegen, wobei das Komma
fließen darf.
CInt Liefert Ausdruck als Ganzzahlwert vom Typ Integer. Fließkommawerte mit
einem Nachkommaanteil von exakt 0,5 werden zur nächsten geraden Zahl hin
gerundet (0,5 wird zu 0 und 1,5 zu 2) ansonsten gilt die Kaufmannsrundung. Der
Wertebereich geht von -32.768 bis 32.767.
CLng Liefert Ausdruck als Ganzzahlwert vom Typ Long. Fließkommawerte mit einem
Nachkommaanteil von exakt 0,5 werden zur nächsten geraden Zahl hin gerun-
det (0,5 wird zu 0 und 1,5 zu 2), ansonsten gilt die Kaufmannsrundung. Der
Wertebereich geht von -2.147.483.648 bis 2.147.483.647.
CSng Liefert Ausdruck als Wert vom Typ Single. Bei der Konvertierung aus Double,
Decimal und Currency werden nicht darstellbare Stellen gegebenenfalls gerundet,
alle anderen numerischen Datentypen lassen sich ohne Genauigkeitsverlust über-
führen. Bei der Konvertierung von Zeichenfolgen erwartet die Funktion das
gebietsspezifische Zahlenformat. Für das Gebietsschema »Deutsch (Standard)«
gilt: Komma ist Dezimalzeichen, Punkt ist Tausendertrennzeichen. Der Wertebe-
reich geht von -1,79769313486232E308 bis -4,94065645841247E-324 für
negative Werte und von 4,94065645841247E-324 bis 1,79769313486232E308
für positive Werte.
CVar Konvertiert numerische Werte in den Untertyp Double (vgl. CDbl) und alle ande-
ren in den Untertyp String
CVDate Konvertiert einen numerischen Wert oder eine Zeichenfolge Ausdruck in das von
älteren Visual-Basic-Versionen benutzte Datumsformat Variant mit Untertyp
Date. Da Date inzwischen als elementarer Datentyp verfügbar ist, dient diese
Funktion nur noch dem Erhalt der Kompatibilität mit älteren Programmen. Die-
selbe Funktionalität ergibt sich auch implizit, wenn der Funktionswert eines
CDate-Aufrufs einer Variablen vom Typ Variant zugewiesen wird. Umgekehrt
lässt sich aufgrund der impliziten Typanpassung des Compilers auch der Funkti-
onswert eines CVDate-Aufrufs einer Variablen vom Typ Date zuweisen, so dass
zwischen CDate und CVDate praktisch gesehen kein Unterschied besteht.
Konvertierungs- und Typumwandlungsfunktionen

59
Benutzerdefinierte Datentypen

Funktion Beschreibung
CStr Liefert literale Darstellung von Ausdruck als Zeichenfolge im gebietsspezifischen
Format. Wahrheitswerte erscheinen als "Wahr" und "Falsch", numerische Werte
ohne Tausendertrennzeichen jedoch mit Komma als Dezimalzeichen und erfor-
derlichenfalls in Fließkommanotation mit Exponentenanteil. Der Wert Empty ent-
spricht der leeren Zeichenfolge, während Null einen Laufzeitfehler auslöst.
Datumswerte erhalten das für das Gebietsschema geltende kurze Datumsformat.
Die literale Darstellung eines Objekts ist die seiner Standardeigenschaft – so lie-
fert CStr(Err) die zuletzt gesetzte Fehlernummer Err.Number.
Benutzerdefinierte Datentypen

Konvertierungs- und Typumwandlungsfunktionen


Anwendung

Anwendung
...................................................
Wer viel mit dem flexiblen Datentyp Variant arbeitet oder von einer streng typisierenden Pro-
grammiersprache her kommt, wird in so manchem Fall die Typumwandlungsfunktionen von
Visual Basic zu schätzen wissen. Obwohl der Visual-Basic-Compiler weitgehend tolerant ist,
was die implizite Typanpassung bei der Zuweisung, der Parameterübergabe und der Aus-
drucksberechnung betrifft, lässt sich die Flexibilität im Miteinander von Datentypen durch
explizite Typumwandlungen noch weiter verbessern, insbesondere wenn die länderspezifische
Darstellung entlang des in der Systemsteuerung eingestellten Gebietsschemas bei der Umwand-
lung aus Zeichenfolgen ins Spiel kommt. So ist beispielsweise die explizite Typumwandlung in
Visual Basic 6.0 der einzige Weg, um Werte des nur als Untertyp von Variant existierenden
Datentyps Decimal zu generieren, denn eine Deklaration mit diesem vergleichsweise neuen
Datentyp ist in der Version 6.0 noch nicht möglich. Auch greift der Compiler nur dann zum
Mittel der impliziten Typumwandlung, wenn eine Verengung oder Erweiterung des gegebenen
Typs unvermeidbar ist.
Tipps

Tipps
...................................................
Um festzustellen, ob ein Wert als Zahl ausgewertet werden kann, steht die Boolean-Funktion
IsNumeric zur Verfügung.
Die Typumwandlung von einem benutzerdefinierten Typ in einen elementaren Typ ist nicht so
ohne Weiteres möglich. Einen Schleichweg eröffnet jedoch die LSet-Anweisung (vgl. S. 80).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Asc, Chr, ChrB, Date, DateSerial, Fix, Format, FormatCurrency, FormatDateTime, Format-
Number, FormatPercent, Int, Round, Str, StrConv Time, TimeSerial, Val
Verwandte Themen

Verwandte Them en
...................................................
Elementare Datentypen (S. 49)

Benutzerdefinierte Datentypen
Visual Basic kennt drei verschiedene Arten von benutzerdefinierten Datentypen: in Type-
Konstrukten vereinbarte Datenstrukturen; in Enum-Konstrukten vereinbarte Aufzählungsdaten-
typen; in Klassenmodulen definierte Klassen (Objektdatentypen). Letztere werden ausführlicher
im objektorientierten Teil vorgestellt, wenn es um »Selbst definierte Klassen« (S. 318) geht. Ein
Vergleich zwischen Type-Datentypen und Objektdatentypen findet sich in der Tabelle auf
Seite 197.

60
Type- Datentypen

Type- Datentypen
{Private | [Public]} Type BDT
ElementName [([Indizes])] As Typ
[ElementName1 [([Indizes])] As Typ]
...
End Type
With bdtVar
.ElementName = Wert
End With

Benutzerdefinierte Datentypen
Beschreibung

Bes c hreibung
...................................................
Die Type-Struktur ermöglicht die Definition eines eigenen Datentyps BDT, der aus Elementen
ElementName bereits bekannter Datentypen zusammengesetzt ist. Die Private-Vereinbarung des
Datentyps ist für beliebige Modularten auf Modulebene möglich und beschränkt den Geltungs-
bereich der Definition auf das jeweilige Modul. Fehlt der Spezifizierer Private, behandelt der
Compiler die Definition als Public-Vereinbarung, die jedoch nur in einem Standardmodul
zulässig ist. Ein Public-Datentyp ist in allen Modulen des gegebenen Projekts sowie in allen
Projekten einer gegebenenfalls existierenden Projektgruppierung bekannt.
Anwendung

Anwendung
...................................................
Im Gegensatz zu älteren Basic-Versionen sind in Visual Basic statische und dynamische Arrays
als Feldelemente für benutzerdefinierte Datentypen ebenso zulässig wie Objektvariablen. Auch
einer Verschachtelung benutzerdefinierter Datentypen durch Verwendung bereits definierter
Datentypen als Feldtyp steht nichts im Wege.
Die Vereinbarung eines benutzerdefinierten Datentyps BDT für eine Variable weist formal keine
Besonderheiten gegenüber der Vereinbarung eines elementaren Datentyps auf. Der einzige
Unterschied zu den vordefinierten Datentypen von Visual Basic besteht darin, dass die Public-
Vereinbarung von Variablen benutzerdefinierter Typen nur in einem Standardmodul erfolgen
darf, während in allen anderen Modularten eine Private-Deklaration erforderlich ist.
An Operationen für benutzerdefinierte Datentypen gibt es nur den Punktoperator und den
Zuweisungsoperator. Der Punktoperator ermöglicht den Zugriff auf die einzelnen Felder des
benutzerdefinierten Datentyps für die Arbeit mit einzelnen Feldwerten nach dem Schema
Var.Feld. Der Zuweisungsoperator ermöglicht die Zuweisung eines Werts mit einem benutzer-
definierten Datentyp an eine Variable gleichen Typs. Dabei kopiert Visual Basic alle Feldwerte
en bloc, selbst wenn Arrays mit im Spiel sind.
Zur Vereinfachung der Notation beim Zugriff auf Elementwerte eines benutzerdefinierten
Datentyps (aber auch auf Eigenschaften und Methoden von Objekten, mit Ausnahme von
Print, Circle und Line) kann die With-Struktur benutzt werden. Dabei führt die With-Anwei-
sung den genannten Bezeichner als Qualifizierungskontext ein. Innerhalb eines Moduls benutzt
Visual Basic von sich den Modulbezeichner als Qualifizierungskontext. Mit jeder With-Anwei-
sung (Verschachtelung ist erlaubt) verengt sich der bestehende Qualifizierungskontext.
Warnung

Wa rnung
...................................................
Vom Prinzip her besteht zwar die Möglichkeit, LSet-Zuweisungen zwischen benutzerdefinierten
Datentypen mit unterschiedlichen Strukturen vorzunehmen, von einem Gebrauch dieses Hinter-
türchens ist aber generell eher abzuraten, da dabei unvorhergesehene Effekte auftreten können
(vgl. »LSet-Anweisung«, S. 80).

61
Benutzerdefinierte Datentypen

Tipp

Tipp
...................................................
Anstelle benutzerdefinierter Datentypen können Sie eigene Datentypen auch über Klassenmo-
dule implementieren. Der dahinter stehende objektorientierte Ansatz verschmilzt das Konzept
des benutzerdefinierten Datentyps mit den zu dem Datentyp gehörigen Manipulationsoperatio-
nen und bietet somit den Vorteil der Datenabstraktion.
Beispiel

Beis piel
...................................................
' Bereich (Allgemein) eines Moduls
Private Type BDT
Benutzerdefinierte Datentypen

lFeld As Long
sFeld As String
lDynArray() As Long
sStatArray(10) As String
End Type
...
Dim bdtVar1 As BDT, bdtVar1 As BDT
...
bdtVar1.lFeld = 10 ' numerischen Wert zuweisen
bdtVar1.sFeld = "Wert des String-Feldes" ' Zeichenfolge zuweisen
ReDim bdtVar1.lDynArray(10) As Long ' dyn. Array dimensionieren
bdtVar2 = bdtVar1 ' Struktur en bloc zuweisen

' Schreibweise bei Qualifizierung mit With


With bdtVar1
.lFeld = 10 ' numerischen Wert zuweisen
.sFeld = "Wert des String-Feldes" ' Zeichenfolge zuweisen
ReDim .lDynArray(10) As Long ' dyn. Array dimensionieren
End With
bdtVar2 = bdtVar1 ' Struktur en bloc zuweisen
Verwandte Befehle

Verwa ndte Befehle


...................................................
LSet
Verwandte Themen

Verwandte Them en
...................................................
Elementare Datentypen (S. 49); Routinen aus DLLs und der Windows-API einsetzen
(S. 185); Objekte und Klassen (S. 195); Klassen als Datentypen für Objektvariablen (S. 196)

Enum- Aufzählungen
{Private | [Public]} Enum MeineAufzählung
Element1 = LiteralerWert1
[Element2 = LiteralerWert2]
...
End Enum
Beschreibung

Bes c hreibung
...................................................
Eine Enum-Aufzählung ist eine Sammlung von Konstanten des Typs Long, die formal in einem
Aufzählungsdatentyp zusammengefasst sind. Die einzelnen Konstanten sind jedoch auch jede
für sich im Rahmen des jeweiligen Geltungsbereichs bekannt. Ein Aufzählungsdatentyp lässt

62
Funktionen und Anweisungen für Zeichenfolgen

sich wie jeder andere Datentyp für die Vereinbarung von Variablen, Parametern und Funkti-
onswerten heranziehen, eine Überprüfung auf Einhaltung des über die Aufzählung definierten
Wertebereichs findet jedoch nicht statt; auch unterscheidet der Compiler nicht zwischen unter-
schiedlichen Aufzählungsdatentypen, vielmehr behandelt er jeden Aufzählungsdatentyp als
Long.
Anwendung

Anwendung
...................................................
Obwohl es möglich ist, Variablen zu vereinbaren, die einen Aufzählungsdatentyp tragen, und
der Editor der Entwicklungsumgebung bei der Notation von Rechtswerten dieses Typs eine
Liste mit den vereinbarten Konstanten einblendet, sind Aufzählungsdatentypen faktisch nichts

Funktionen und Anweisungen für Zeichenfolgen


weiter als eine Umbenennung des Datentyps Long und somit reine Fassade.
Sie verwenden Aufzählungsdatentypen, um Konstanten zu gruppieren und Symbolvorräte for-
mal als endliche Wertebereiche ausdrücken zu können. Ein Blick in den Objektkatalog (Taste
(F2)) zeigt, dass Visual Basic in seinen Bibliotheken massiv von diesem Konzept Gebrauch
macht.
Beispiel

Beis piel
...................................................
Public Enum VbTest
vbA1 = &H11111111
vbA2 = 101
vbA3 = 105
vbA4 = 103
vbA5 = 104
End Enum
...
' innerhalb einer Prozedur/Funktion
Dim a As VbTest
a = vbA3
Print TypeName(a) ' Ausgabe: "Long"

Funktionen und Anweisungen für Zeichenfolgen


Der unkomplizierte Umgang mit Zeichenfolgen war schon immer die ureigenste Domäne der
Programmiersprache Basic. Darüber hinaus hat sich die Ausstattung für die Manipulation von
Zeichenfolgen mit jeder Neuauflage von Basic noch einmal verbessert, so dass dem Program-
mierer unter Visual Basic 6.0 ein ausgesprochen reichhaltiges Angebot an vordefinierten Funk-
tionen und Anweisungen für die Arbeit mit Zeichenfolgen zur Verfügung steht. Während in frü-
heren Versionen von Visual Basic so manche Zeichenfolgenfunktion in zwei Varianten
implementiert war – eine mit $-Suffix und eine ohne –, von denen diejenige mit $-Suffix »echte«
Zeichenfolgen lieferte und diejenige ohne $-Suffix Werte des Typs Variant, unterstützt Visual
Basic 6.0 die Varianten mit $-Suffix zwar noch zur Wahrung der Kompatibilität, kommt aber
grundsätzlich ohne sie aus.
Beschreibung

Bes c hreibung
...................................................
Seit Einführung der 32-Bit-Version mit Visual Basic 4.0 legt Visual Basic intern allen Zeichen-
folgen die Unicode-Darstellung zugrunde. Im Gegensatz zu dem bis dahin verwendeten ANSI-
Code, der zur Repräsentation eines Zeichens gerade mal ein Byte vorsieht (und somit nicht
mehr als 256 Zeichen unterscheiden kann), umfasst die Repräsentation eines Zeichens im Uni-
code zwei Bytes. In Unicode gibt es daher bis zu 65.535 unterschiedliche Zeichen, die von der

63
Funktionen und Anweisungen für Zeichenfolgen

ISO international festgelegt wurden. Zeichen mit Unicode kleiner als 256 entsprechen den Zei-
chen des ANSI-Codes, so dass beispielsweise das Zeichen »A« mit dem ANSI-Code 65 (oder
&H40) in Unicode die Darstellung »0, 65« (oder &H0040) hat. Neben Unicode gibt es noch
einen weiteren Zeichencode namens DBCS (Double-Byte Character Set), dessen Darstellung
zwei Bytes je Zeichen vorsieht. Dieser Code ist in erster Linie im asiatischen Sprachraum ver-
breitet und dazu gedacht, die Vielfalt der in diesen Sprachen verwendeten Schriftzeichen aus-
drücken zu können. Er hat weder etwas mit ANSI-Code noch mit Unicode gemeinsam, stellt
also einen völlig eigenständigen Zeichensatz dar.
All dies heißt für den Visual-Basic-Programmierer, dass er es potenziell mit allen drei, sicherlich
jedoch mit zwei unterschiedlichen Repräsentationsarten für Zeichenfolgen zu tun bekommen
Funktionen und Anweisungen für Zeichenfolgen

kann – so etwa beim Lesen von Datensätzen aus Dateien mit älteren und neueren Datenforma-
ten. Damit aber nicht genug: Es gilt auch systembedingte Unterschiede zu beachten, die sich
aufgrund unterschiedlicher Versionen für Objektbibliotheken und Windows selbst einschlei-
chen. Die folgende Tabelle zeigt eine Aufstellung, welche Umgebung mit welcher Zeichendar-
stellung einhergeht.

Umgebung Verwendete Zeichensätze


Windows-9x-API ANSI und DBCS
16-Bit-Objektbibliotheken ANSI und DBCS
Visual Basic Unicode
32-Bit-Objektbibliotheken Unicode
Windows-NT-API Unicode
Automatisierung in Windows NT Unicode
Automatisierung in Windows 9x Unicode
Zeichendarstellung in verschiedenen Windows- Komponenten

Um den Programmierer gegen alle Fälle zu wappnen, unterhält Visual Basic daher für die tradi-
tionellen Zeichenfolgenfunktionen Asc, Chr, Len, InStr, Left, Right und Mid unterschiedliche
Varianten, deren Funktionsweise spezifisch auf die eine oder andere Repräsentation ausgerich-
tet ist. Varianten mit Suffix B (so etwa AscB) gehen von einer ANSI-Darstellung und Varianten
mit Suffix W (so etwa ChrW) von einer Unicode- oder DBCS-Darstellung aus.
Die folgende Tabelle gibt eine Übersicht über die unter Visual Basic 6.0 verfügbaren Funktio-
nen und Prozeduren, die im engeren oder weiteren Sinne etwas mit der Manipulation von Zei-
chenfolgen zu tun haben.

Bezeichner Kurzbeschreibung
Asc Liefert den ANSI-Code des ersten Zeichens einer Zeichenfolge (auf DBCS-
Systemen DBCS-Code)
AscB Liefert den ANSI-Code des ersten Bytes einer Zeichenfolge
AscW Liefert den Unicode des ersten Doppel-Bytes einer Zeichenfolge
Chr Liefert das zu einem ANSI-Code gehörige Unicode-Zeichen
ChrB Liefert das zu einem ANSI-Code gehörige ANSI-Zeichen
ChrW Liefert das zu einem Unicode gehörige Unicode-Zeichen
Zeichenfolgenfunktionen und - prozeduren von Visual Basic

64
Funktionen und Anweisungen für Zeichenfolgen

Bezeichner Kurzbeschreibung
Filter Durchsucht alle Elemente eines Zeichenfolgen-Arrays nach einer bestimm-
ten Zeichenfolge und liefert die Array-Elemente, in denen diese enthalten
ist
Format Liefert Zeichenfolgendarstellung eines Werts im spezifizierten Format
FormatCurreny Liefert die Darstellung eines Währungswerts im spezifizierten Format
FormatDateTime Liefert die Darstellung eines Datumswerts im spezifizierten Format
FormatNumber Liefert die Darstellung eines Zahlenwerts im spezifizierten Format

Funktionen und Anweisungen für Zeichenfolgen


FormatPercent Liefert die Darstellung eines Prozentwerts im spezifizierten Format
Hex Liefert die hexadezimale Notation eines Werts
InStr Liefert die Startposition einer Zeichenfolge in einer anderen Zeichenfolge
InStrB Liefert die Startposition einer ANSI-Zeichenfolge in einer anderen ANSI-
Zeichenfolge
InStrRev Wie InStr, beginnt die Suche aber von hinten
Join Umkehrfunktion zu Split, setzt die Zeichenfolgen eines String-Arrays zu
einer einzigen Zeichenfolge zusammen (Trennzeichen optional)
LCase Liefert die Kopie einer Zeichenfolge in Kleinschreibung
Left Liefert den linken Teil einer Zeichenfolge
LeftB Liefert den linken Teil einer ANSI-Zeichenfolge
Len Liefert die Anzahl der Zeichen in Zeichenfolge – trägt der im Parameter
übergebene Wert nicht den Typ String, liefert die Funktion die Anzahl der
zum Speichern dieses Werts erforderlichen Bytes.
LenB Liefert die Anzahl der Bytes, die für die Darstellung des Werts (zum Bei-
spiel bei Speichern) erforderlich sind; liefert damit auch die Länge einer
ANSI-Zeichenfolge
LSet Byteorientierte, linksbündige Zuweisungsoperation für beliebige Datenty-
pen, ohne Längenanpassung des Linkswerts. Elementare Datentypen
unterliegen einer Typüberprüfung, benutzerdefinierte nicht.
LTrim Liefert eine Kopie der Zeichenfolge ohne führende Leerzeichen zurück
Mid Liefert den mittleren Teil einer Zeichenfolge
Mid Zuweisungsoperation für den mittleren Teil einer Zeichenfolge
MidB Liefert den mittleren Teil einer Zeichenfolge als ANSI-Zeichenfolge
MidB Zuweisungsoperation für mittleren Teil einer ANSI-Zeichenfolge
MonthName Liefert für eine Zahl zwischen 1 und 12 den Monatsname als Zeichenfolge
Oct Liefert die oktale Notation eines Werts
Option Compare Standardvorgabe für Zeichenfolgenvergleiche auf binären Vergleich oder
Textvergleich (ohne Beachtung der Großschreibung) setzen
Zeichenfolgenfunktionen und - prozeduren von Visual Basic

65
Funktionen und Anweisungen für Zeichenfolgen

Bezeichner Kurzbeschreibung
Partition Liefert das Intervall, in das eine Zahl fällt, als Zahlenbereich der Form
»IntervallAnf: IntervallEnde«. Der Aufruf der Funktion erfolgt unter
Angabe eines Startwerts für das erste Intervall, eines Endwerts für das
letzte Intervall und einer Intervallbreite.
Replace Sucht Vorkommen einer Suchzeichenfolge in Zeichenfolge, ersetzt dieses
gegen Ersatzzeichenfolge und liefert resultierende Zeichenfolge
Right Liefert den rechten Teil einer Zeichenfolge
Funktionen und Anweisungen für Zeichenfolgen

RightB Liefert den rechten Teil einer ANSI-Zeichenfolge


RSet Rechtsbündige Zuweisungsoperation für Zeichenfolgen ohne Längenände-
rung des Linkswerts; füllt mit Leerzeichen auf oder schneidet ab
RTrim Liefert die Kopie einer Zeichenfolge ohne abschließende Leerzeichen
Space Liefert eine Zeichenfolge mit der gewünschten Anzahl von Leerzeichen
Split Umkehrfunktion zu Join, durchsucht eine Zeichenfolge nach Trennzeichen
und liefert die Zeichenfolgenabschnitte als Array
Str Liefert standardmäßige Repräsentation eines Zahlenwerts als Zeichenfolge
StrComp Führt alphanumerischen Zeichenfolgenvergleich durch und unterscheidet
dabei vier Fälle
StrConv Konvertiert eine Zeichenfolge nach einem von sieben möglichen Konvertie-
rungsschemata und liefert die konvertierte Version als Kopie
String Liefert Zeichenfolge mit der gewünschten Anzahl eines einzelnen Zeichen-
codes
StrReverse Liefert die Kopie einer Zeichenfolge mit verkehrter Reihenfolge der
Zeichen
Trim Liefert Zeichenfolge ohne führende und abschließende Leerzeichen
UCase Liefert die Kopie einer Zeichenfolge in Großschreibung
Val Liefert den Zahlenwert einer Zeichenfolge
WeekdayName Liefert für eine Zahl zwischen 1 und 7 den Wochentag als Zeichenfolge
Zeichenfolgenfunktionen und - prozeduren von Visual Basic

Warnung
Warnung

...................................................
Eine notorische Ursache für Ungereimtheiten im Programmverhalten ist die auf die länderspezi-
fische Zahlendarstellung (Gebietseinstellungen des Systems) zurückzuführende Punkt-/Komma-
Problematik im Zusammenhang mit Zeichenfolgen. Wer mit Ländereinstellung »Deutsch (Stan-
dard)« auf seinem System einen Zahlenwert als literale Zeichenfolge spezifiziert, muss darauf
achten, das Komma als echtes Komma zu schreiben, während in »echten« numerischen Litera-
len der Punkt als Dezimalsymbol notiert werden muss.

Asc- , AscB- und AscW- Funktion


Function Asc (s As String) As Integer
Function AscB (s As String) As Integer
Function AscW (s As String) As Integer

66
Chr- , ChrB- und ChrW- Funktion

Beschreibung

Bes c hreibung
...................................................
Die Funktion Asc liefert den Code des ersten Zeichens der Zeichenfolge s entsprechend dem auf
dem System geltenden Zeichensatz als Ganzzahl. Die beiden anderen Varianten der Funktion
liefern (ohne Rücksicht auf den geltenden Zeichensatz) den ANSI-Code des ersten Bytes der
Zeichenfolge (AscB) bzw. den Unicode des ersten Doppel-Bytes der Zeichenfolge (AscW).
Beispiel

Beis piel
...................................................
Die Funktion StrToHex wandelt eine Zeichenfolge beliebiger Länge byteweise in eine hexadezi-
male Repräsentation der Form "hh hh ..." um.

Funktionen und Anweisungen für Zeichenfolgen


' Funktion wandelt beliebig lange Byte-Strings in Hex-String um
Function StrToHex(sByteString As String) As String
Dim i As Integer, iByte As Integer
Dim sLow As String, sHigh As String
For i = 1 To LenB(sByteString) ' byteweise analysieren
iByte = AscB(MidB(sByteString, i, 1))
If iByte \ 16 > 9 Then ' Ziffer oder Buchstabe?
sHigh = Chr(iByte \ 16 + 55) ' Buchstabe
Else
sHigh = Chr(iByte \ 16 + 48) ' Ziffer
End If
If iByte Mod 16 > 9 Then
sLow = Chr(iByte Mod 16 + 55)
Else
sLow = Chr(iByte Mod 16 + 48)
End If
StrToHex = StrToHex + sHigh + sLow + " " ' Zusammensetzen
Next i
End Function
Verwandte Befehle

Verwa ndte Befehle


...................................................
Chr, Str
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

Chr- , ChrB- und ChrW- Funktion


Function Chr (iANSICode As Integer) As String
Function ChrB (iANSICode As Integer) As String
Function ChrW (iUnicode As Integer) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Chr liefert das Unicode-Zeichen zu einem ANSI-Code als Unicode-Zeichenfolge
der Länge 1. ChrB liefert dagegen zu einem ANSI-Code das ANSI-Zeichen als ANSI-Zeichen-
folge der Länge 1 und ChrW das Unicode-Zeichen zu einem Unicode als Unicode-Zeichenfolge
der Länge 1.

67
Funktionen und Anweisungen für Zeichenfolgen

Beispiel

Beis piel
...................................................
Die Funktion HexToStr ist die Umkehrfunktion zu der Funktion StrToHex (vgl. Beispiel zu Asc).
Sie wandelt beliebig lange Hexadezimaldarstellungen der Form "hh hh ..." in Bytefolgen des
Typs String um.
Public Function HexToStr(sHexString As String) As String
Dim i As Integer, iHigh As Integer, iLow As Integer
Dim sHexChar As String
Dim sLow As String, sHigh As String
If LenB(" ") = Len(" ") Then ' Unicode-System?
Funktionen und Anweisungen für Zeichenfolgen

HexToStr = Space(Len(sHexString) / 3)
Else
HexToStr = Space(Len(sHexString) / 6)
End If

For i = 1 To Len(sHexString) Step 3 ' aus 3 Zeichen wird 1 Byte!


iHigh = Asc(Mid(sHexString, i, 1)) – 48 ' Annahme: Ziffer
If iHigh > 15 Then iHigh = iHigh – 7 ' War es etwa ein Buchstabe?
iLow = Asc(Mid(sHexString, i + 1, 1)) – 48
If iLow > 15 Then iLow = iLow – 7
MidB(HexToStr, (i + 2) \ 3) = ChrB(iHigh * 16 + iLow) ' Zusammensetzen
Next i
End Function
Verwandte Befehle

Verwa ndte Befehle


...................................................
Asc, Str
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

Filter- Funktion
Function Filter( _
StringPool() As String, _
SuchString As String, _
[bVorkommenLiefern As Boolean = True], _
[vgl As vbCompareMethod = vbBinaryCompare]) _
As String()
Beschreibung

Bes c hreibung
...................................................
Die Funktion Filter durchsucht die Elemente des Zeichenfolgenarrays StringPool nach dem
Vorkommen der Zeichenfolge SuchString und liefert die entsprechenden Array-Elemente als
Zeichenfolgenarray. Hat der optionale Parameter VorkommenLiefern den Wert True oder fehlt
er, enthält das Ergebnisarray alle Elemente, die SuchString enthalten, andernfalls (False) alle
Elemente, die SuchString nicht enthalten. Hat der optionale Parameter vgl den Wert vbBinary-
Compare oder fehlt er, ist die Vergleichsoperation ein zeichenweiser Unicode-Vergleich; hat vgl
den Wert vbTextCompare, legt die Funktion der Vergleichsoperation die standardmäßige Sortier-
ordnung der für die auf dem System geltenden Landessprache zugrunde – ohne Unterscheidung
der Groß- und Kleinschreibung.

68
Format- Funktion

Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.
Beispiel

Beis piel
...................................................
Das Programm benutzt die Funktion Filter, um herauszufinden, welche Wochentage (hierfür
gilt die Ländereinstellung) ohne Unterscheidung der Großschreibung die Zeichenfolge "TAG"
nicht enthalten.
Private Sub Form_Load()

Funktionen und Anweisungen für Zeichenfolgen


Dim sWochenTage(7) As String, sErgebnis() As String
AutoRedraw = True
For i = 0 To 6 ' Wochentage generieren
sWochenTage(i) = WeekdayName(i + 1)
Next i
sErgebnis = Filter(sWochenTage, "TAG", False, vbTextCompare)
For i = 0 To UBound(sErgebnis) – 1 ' es kommt nur der Mittwoch
Print sErgebnis(i)
Next i
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Join, Split

Format- Funktion
Function Format( _
vData, _
sFormat As String], _
[FirstDayOfWeek As VbFirstDayOfWeek = vbSunday], _
[FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1]) _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Format liefert für den Wert vData eine formatierte Darstellung als Zeichenfolge.
Fehlt der optionale Parameter sFormat, folgt die Darstellung den auf dem jeweiligen System gel-
tenden Ländereinstellungen, und das Ergebnis entspricht bis auf das fehlende führende Leerzei-
chen bei der Darstellung positiver Zahlen dem von Str. Ansonsten drückt sFormat unter Beach-
tung der Syntax für Formatausdrücke ein benutzerdefiniertes Darstellungsformat aus. Die
optionalen Parameter FirstDayOfWeek und FirstWeekOfYear beziehen sich auf exotische Formen
der Datumsdarstellung und können im Allgemeinen getrost weggelassen werden.
Anwendung

Anwendung
...................................................
Für den Formatausdruck sFormat gelten folgende Regeln:
1. Der Formatausdruck kann den Namen eines benannten Formats enthalten. Die folgenden
drei Tabellen geben einen Überblick über die benannten Formate.

69
Funktionen und Anweisungen für Zeichenfolgen

Formatname Beschreibung
"General Date" Übliche Datums-/Zeitdarstellung mit zweistelliger Jahreszahl – bei
Angabe von Datum und Zeit: 01.01.00 13:00:00; bei Angabe von Zeit:
13:00:00; bei Angabe von Datum: 01.01.00
"Long Date" Ausgeschriebenes Datum, entsprechend der Systemeinstellungen:
Samstag, 1. Januar 2000
"Medium Date" Mittleres Datumsformat (von Host-Anwendung definierbar): 1. Jan. 00
"Short Date" Kurzes Datum, entsprechend der Systemeinstellungen: 01.01.00
Funktionen und Anweisungen für Zeichenfolgen

Benannte Datumsformate

Formatname Beschreibung
"Long Time" Zeitangabe enthält auch Sekunden: 13:00:00
"Medium Time" Zeitangabe im 12-Stunden-Format, ohne Sekunden: 1:00
"Short Time" Zeitangabe im 24-Stunden-Format, ohne Sekunden: 13:00
Benannte Zeitformate

Formatname Beschreibung
"General Number" Zahlen werden ohne Tausendertrennzeichen notiert.
"Currency" Zahlen werden mit Tausendertrennzeichen und zwei Nachkomma-
stellen sowie unter Beachtung der auf dem System geltenden Gebiets-
schema-Einstellungen notiert.
"Fixed" Festkommadarstellung unter Beachtung der auf dem System gelten-
den Gebietsschema-Einstellungen, ohne Tausendertrennzeichen und
gerundet auf zwei Stellen hinter dem Komma: 10001,34
"Standard" Wie "Fixed", jedoch mit Tausendertrennzeichen: 10.001,34
"Percent" Wie "Fixed", jedoch mit Faktor 100 multipliziert und angehängtem
Prozentzeichen %
"Scientific" Wissenschaftliches Standardformat mit einer Stelle vor dem Komma,
zwei Stellen nach dem Komma und Zehnerpotenz: 1,00E34
"Yes/No" Ausgabe von »Nein« anstatt 0, »Ja« für jeden anderen Wert
"True/False" Ausgabe von »False« anstatt 0, »True« für jeden anderen Wert
"On/Off" Ausgabe von »Aus« anstatt 0, »Ein« für jeden anderen Wert
Benannte Zahlenformate

2. Der Formatausdruck kann ein benutzerdefiniertes Format enthalten. Die folgende Tabelle
gibt einen Überblick über die Bedeutung der Symbole, die für die Zusammenstellung benut-
zerdefinierter Formate eine feste Interpretation haben.

70
Format- Funktion

Symbol Bedeutung
0 Platzhalter für Ziffer (vor und nach dem Dezimalzeichen). Auch Platzhalter
für Ganzzahlanteil vor dem Dezimalzeichen. Platzhalterpositionen, die die
Dezimaldarstellung nicht bedient, erhalten das Füllzeichen 0. Das Format
"0.000" für 1234,12 ergibt "1234,120" und das Format "000000" für 1234,12
ergibt "001234".
# Wie Symbol 0, es gibt jedoch kein Füllzeichen
. Platzhalter für Dezimalzeichen

Funktionen und Anweisungen für Zeichenfolgen


% Zahlenwert wird mit 100 multipliziert und als Prozentwert mit anhängen-
dem Prozentzeichen % dargestellt. Das Format "0.000%" für 1234,12 ist
"123412,000%".
, Die Position dieses Zeichens im Formatausdruck ist ausschlaggebend für
seine Bedeutung. Steht es zwischen zwei Ziffernplatzhaltern links vom Dezi-
malzeichenplatzhalter erfolgt die Darstellung mit Tausendertrennzeichen.
Steht es dagegen links vom ersten Ziffernplatzhalter in einer Zahlendarstel-
lung, erscheint es als gewöhnliches Komma. Steht es bei fehlendem Dezimal-
zeichenplatzhalter rechts vom letzten Ziffernplatzhalter oder unmittelbar
links neben dem Dezimalzeichenplatzhalter, wird der Zahlenwert durch
1000 dividiert. So bewirkt "#," für 123.4123.456 die Darstellung "1234123"
und "#,,.0" für 1234.887.654 die Darstellung "1234,9".
E- oder e- Wissenschaftliche Darstellung ohne Ausgabe des Pluszeichens im Exponenten
E+ oder e+ Wissenschaftliche Darstellung mit Ausgabe des Pluszeichens im Exponenten
- + $ ( ) Diese Symbole stehen für sich selbst. Sie erscheinen als Zeichen. Alle anderen
bedeutungsbeladenen Symbole müssen einen umgekehrten Schrägstrich
vorangestellt bekommen, um sie als einfaches Zeichen darzustellen.
\ Dieses Symbol kann einem anderen bedeutungsbeladenen Symbol vorange-
stellt werden, um dieses als Zeichen darzustellen. "\\" bewirkt die Ausgabe
des Symbols selbst als Zeichen. Um ein Anführungszeichen auszugeben,
muss es doppelt und in Kombination mit diesem Symbol notiert werden. Die
Zahl 30405 wird mit "#0\°##\'##\"" \N\o\r\d" zu "3°04'05"" Nord".
"Nord" Zeigt die Zeichenfolge in Anführungszeichen an. Die Regeln für Zeichenfol-
genliterale fordern die doppelte Notation von Anführungszeichen. Die Zahl
30405 wird mit "#0\°##\'##\"" ""Nord""" gleichfalls zu "3°04'05"" Nord".
Symbole für benutzerdefinierte Zahlenformate

Symbol Bedeutung
: Platzhalter für Zeittrennzeichen zwischen Stunden, Minuten und Sekunden
/ Platzhalter für Datumstrennzeichen zwischen Tagen, Monaten und Jahren
C Zeigt Datumsanteil in der Form ddddd und Zeitanteil in der Form ttttt an
d Tag erscheint als Zahl ohne führende Null (1 bis 31)
dd Tag erscheint als Zahl mit führender Null (01 bis 31)
ddd Tag erscheint als abgekürzter Wochentag (Mo bis So)
Symbole für benutzerdefinierte Datums- und Zeitformate

71
Funktionen und Anweisungen für Zeichenfolgen

Symbol Bedeutung
dddd Tag erscheint als ausgeschriebener Wochentag (Montag bis Sonntag)
ddddd Datum erscheint vollständig im kurzen Datumsformat (vgl. benanntes For-
mat "Short Date")
dddddd Datum erscheint vollständig im langen Datumsformat (vgl. benanntes For-
mat "Long Date")
w Wochentag erscheint als Zahl ohne führende Null (1 bis 7)
ww Woche erscheint als Kalenderwoche (1 bis 54)
Funktionen und Anweisungen für Zeichenfolgen

m Monat erscheint als Zahl ohne führende Null (1 bis 12)


mm Monat erscheint als Zahl mit führender Null (01 bis 12)
mmm Monat erscheint als abgekürzter Monatsname (Jan bis Dez)
mmmm Monat erscheint als ausgeschriebener Monatsname (Januar bis Dezember)
q Quartal erscheint als Zahl (1 bis 4)
y Kalendertag erscheint als Zahl (1 bis 366)
yy Jahr erscheint als zweistellige Zahl (00 bis 99)
yyyy Jahr erscheint als vierstellige Zahl (100 bis 9999)
h Stunde erscheint als Zahl ohne führende Null (0 bis 23)
hh Stunde erscheint als Zahl mit führender Null (00 bis 23)
n Minute erscheint als Zahl ohne führende Null (0 bis 59)
nn Minute erscheint als Zahl mit führender Null (00 bis 59)
s Sekunde erscheint als Zahl ohne führende Null (0 bis 59)
ss Sekunde erscheint als Zahl mit führender Null (00 bis 59)
ttttt Zeit erscheint als vollständiges langes Zeitformat mit Stunden, Minuten und
Sekunden (vgl. benanntes Format "Long Time")
AM/PM Zeit erscheint im 12-Stunden-Format mit Anhang »AM« für Stunden zwi-
schen 0 und 12 und mit Anhang »PM« für Stunden zwischen 13 und 23. Das
amerikanische Zeitformat ist somit "hh.nn.ss AM/PM".
am/pm Wie AM/PM, jedoch mit kleingeschriebenem Anhang »am« bzw. »pm»
Symbole für benutzerdefinierte Datums- und Zeitformate

Symbol Bedeutung
@ Platzhalter für alphanumerisches Zeichen; Füllzeichen ist das Leerzeichen
& Platzhalter für alphanumerisches Zeichen; kein Füllzeichen
< Erzwingt Kleinschreibung
> Erzwingt Großschreibung
! Erzwingt Auswertung der Platzhalter von links nach rechts (standardmäßig
werden Platzhalter von rechts nach links ausgewertet)
Symbole für benutzerdefinierte Zeichenfolgenformate

72
FormatCurrency- Funktion

Warnung

Wa rnung
...................................................
Leider ist die Format-Funktion von Visual Basic 6.0 nicht fehlersicher implementiert, und liefert
im Zusammenhang mit der Print-Anweisung gerne mal den obskuren Fehler 480, »Anwen-
dungs- oder objektdefinierter Fehler«, wenn der Formatausdruck syntaktisch nicht korrekt ist
oder einfach nicht zum Typ oder Wert von vData passt. Da dieser Fehler danach selbst bei
Angabe korrekter Argumente nicht mehr weg zu bekommen ist, hilft in diesem Fall nur ein
Neustart von Visual Basic.
Beispiel

Beis piel
...................................................

Funktionen und Anweisungen für Zeichenfolgen


Das Projekt FormatDemo gibt einen Halbjahreskalender auf einem gewöhnlichen Formular aus:
' Projekt FormatDemo
Private Sub Form_Load()
Const cJahr = 2001 ' Jahr
Const cHalbjahr = 2
AutoRedraw = True
For iMonat = 1 To 6 ' erstes Halbjahr
Dat = DateSerial(cJahr, iMonat + (cHalbjahr – 1) * 6, 1)
Print Format(Dat, "mmmm yyyy")
Print "Kal.-Woche",
For i = 0 To 6 ' Wochentage ausgeben
Print Format(Dat + i, "dddd"),
Next
Print
' Anzahl der Tage in Monat berechnen
Tage = Day(DateSerial(Year(Dat), Month(Dat) + 1, Day(Dat) – 1))
For i = 1 To Tage ' Kalenderwoche und Tage ausgeben
If (i – 1) Mod 7 = 0 Then Print Format(Dat + i – 1, "ww"),
Print Format(i, "00"),
If i Mod 7 = 0 Then Print
Next
Print
Next
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
FormatCurrency, FormatDateTime, FormatNumber, FormatPercent, Str
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

FormatCurrency- Funktion
Function FormatCurrency( _
vData, _
[NachkommaStellen As Long = -1], _
[NullVorKommaErgänzen As VbTriState = vbUseDefault], _
[WennNegativKlammernSetzen As VbTriState = vbUseDefault], _
[TausenderTrennzVerwenden As VbTriState = vbUseDefault]) _
As String

73
Funktionen und Anweisungen für Zeichenfolgen

Beschreibung

Bes c hreibung
...................................................
Die Funktion FormatCurrency ist eine spezialisierte Variante der Funktion Format. Sie liefert
unter Verwendung der in der Systemsteuerung definierten Währung eine als Währungswert for-
matierte Zeichenfolge. Mittels der vier optionalen Parameter lassen sich Vorgaben für die
Anzahl der Nachkommastellen, die Ergänzung einer führenden Null bei Werten kleiner eins,
die Klammerung negativer Zahlen sowie die Ergänzung eines Tausendertrennzeichens treffen.
Beispiel

Beis piel
...................................................
' Ausgabe: "(-14.345,13 DM)"
Funktionen und Anweisungen für Zeichenfolgen

Print FormatCurrency(-14345.1253, , , vbTrue)


' Ausgabe: "-14345,125 DM"
Print FormatCurrency(-14345.1253, 3, vbFalse, vbFalse, vbFalse)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Format, FormatDateTime, FormatNumber, FormatPercent, Str, CStr
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

FormatDateTime- Funktion
Function FormatDateTime( _
vData, _
BenanntesFormat As VbDateTimeFormat = vbGeneralDate]) _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion FormatDateTime ist eine spezialisierte Variante der Funktion Format. Sie liefert
unter Verwendung des in der Systemsteuerung definierten Datums- und Zeitformats eine als
Datums- und/oder Zeitangabe formatierte Zeichenfolge. Mittels des optionalen Parameters
BenanntesFormat lässt sich das zu verwendende Format vorgeben. Zur Auswahl stehen je ein
kurzes und ein langes Format für Zeitangaben und Datumsangaben.
Beispiel

Beis piel
...................................................
Print FormatDateTime(14345.1223, vbShortTime) ' Ausgabe: "02:56"
Print FormatDateTime(14345.1223, vbLongTime) ' Ausgabe: "02:56:07"

Print FormatDateTime(14345.1223, vbShortDate) ' Ausgabe: "10.4.39"


' Ausgabe: "Montag, 10 April 1939"
Print FormatDateTime(14345.1223, vbLongDate)

' Ausgabe: "10.4.39 02:56:07"


Print FormatDateTime(14345.1223, vbGeneralDate)
Print FormatDateTime(14345.1223) ' Ausgabe: "10.4.39 02:56:07"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Format, FormatCurrency, FormatNumber, FormatPercent, Str

74
FormatNumber- Funktion

Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

FormatNumber- Funktion
Function FormatNumber( _
vData, _
[NachkommaStellen As Long = -1], _
[NullVorKommaErgänzen As VbTriState = vbUseDefault], _
[WennNegativKlammernSetzen As VbTriState = vbUseDefault], _

Funktionen und Anweisungen für Zeichenfolgen


[TausenderTrennzVerwenden As VbTriState = vbUseDefault]) _
[ZiffernGruppieren As VbTriState = vbUseDefault)] _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion FormatNumber ist eine spezialisierte Variante der Funktion Format. Sie liefert eine
Zahlendarstellung in Form einer Zeichenfolge. Der einzige Unterschied zu FormatCurrency
besteht darin, dass die Funktion ihre Darstellung ohne Währungssymbol vornimmt. Mittels der
fünf optionalen Parameter lassen sich Vorgaben für die Anzahl der Nachkommastellen, die
Ergänzung einer führenden Null bei Werten kleiner eins, die Klammerung negativer Zahlen
sowie die Ergänzung eines Tausendertrennzeichens treffen.
Beispiel

Beis piel
...................................................
Print FormatNumber(-143.1253) ' Ausgabe:"-143,13"
Print FormatNumber(-143.1253, 3, , vbTrue) ' Ausgabe:"(143,125)"
Print FormatNumber(-143.1253, 0, vbFalse, vbFalse) ' Ausgabe:"-143)"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Format, FormatCurrency, FormatDateTime, FormatNumber, Str
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

FormatPercent- Funktion
Function FormatPercent( _
vData, _
[NachkommaStellen As Long = -1], _
[NullVorKommaErgänzen As VbTriState = vbUseDefault], _
[WennNegativKlammernSetzen As VbTriState = vbUseDefault], _
[TausenderTrennzVerwenden As VbTriState = vbUseDefault], _
[ZiffernGruppieren As VbTriState = vbUseDefault)] _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion FormatPercent ist eine spezialisierte Variante der Funktion Format. Sie multipli-
ziert vData mit 100 und liefert das Ergebnis als Prozentangabe mit Prozentzeichen in Form einer
Zeichenfolge. Mittels der fünf optionalen Parameter lassen sich Vorgaben für die Anzahl der
Nachkommastellen, die Ergänzung einer führenden Null bei Werten kleiner eins, die Klamme-
rung negativer Zahlen sowie die Ergänzung eines Tausendertrennzeichens treffen.

75
Funktionen und Anweisungen für Zeichenfolgen

Beispiel

Beis piel
...................................................
Print FormatPercent(-143.1253) ' Ausgabe: "-14.312,53%"
Print FormatPercent(-143.1253, , , vbTrue) ' Ausgabe: "(14.312,53%)"
Print FormatPercent(-143.1253, 0, vbFalse, vbFalse) 'Ausgabe:"-14.313%)"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Format, FormatCurrency, FormatDateTime, FormatNumber, Str
Verwandte Themen

Verwandte Them en
...................................................
Funktionen und Anweisungen für Zeichenfolgen

Typumwandlung (S. 57)

Hex- Funktion
Function Hex(vZahl) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Hex interpretiert den Wert vZahl als Ganzzahl und liefert deren hexadezimale
Repräsentation als Zeichenfolge. Die Darstellung enthält nicht mehr Stellen als nötig, mithin
also keine führenden Nullen oder Leerzeichen.
Beispiel

Beis piel
...................................................
Print Hex(255) ' Ausgabe: "FF"
lWert = 10
Print "&H" Right("0000000"+Hex(lWert) , 8) ' Ausgabe: "&H0000000A"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Oct

InStr- und InStrB- Funktion


Function InStr(
[lStart As Long = 1,] _
sDurchsuchterString As String, _
sSuchString As String,_
[vgl As VbCompareMethode = vbBinaryCompare]) _
As Long
Function InStrB(
[lStart As Long = 1,] _
sDurchsuchterANSIString As String, _
sANSISuchString As String,_
[vgl As VbCompareMethode = vbBinaryCompare]) _
As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion InStr durchsucht die Zeichenfolge sDurchsuchterString ab der Zeichenposition
lStart (optional mit Vorgabewert 1) nach dem nächsten Vorkommen der Zeichenfolge
sSuchString. Ist die Suche erfolgreich, liefert die Funktion ihre Startposition in der durchsuch-
ten Zeichenfolge, ansonsten den Wert 0. Hat der optionale Parameter vgl den Wert vbBinary-

76
InStrRev- Funktion

Compare oder fehlt er, ist die Vergleichsoperation ein zeichenweiser Unicode-Vergleich; hat vgl
den Wert vbTextCompare, legt die Funktion der Vergleichsoperation die standardmäßige Sortier-
ordnung der für die auf dem System geltenden Landessprache zugrunde – ohne Unterscheidung
der Groß- und Kleinschreibung. Die Variante InStrB dieser Funktion ist für Zeichenfolgen im
ANSI-Code zuständig.
Hinweis

Hinweis
...................................................
Die mit Visual Basic 6.0 vorliegende Implementation dieser Funktion hat kein Problem damit,
wenn Start größer ist als die Länge der durchsuchten Zeichenfolge. Negative Werte sowie ein
Wert von 0 führen dagegen zu einem Laufzeitfehler.

Funktionen und Anweisungen für Zeichenfolgen


Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.
Beispiel

Beis piel
...................................................
Der folgende Code zählt mittels der Zählvariablen iCount, wie oft die Zeichenfolge s1 innerhalb
der Zeichenfolge s2 vorkommt.
iCount = 0
lPos = 0
Do
lPos = InStr(lPos + 1, s1, s2)
If lPos Then iCount = iCount +1
Loop While lPos
... ' iCount enthält nun die Anzahl der Vorkommen
Verwandte Befehle

Verwa ndte Befehle


...................................................
Filter, InStrRev, StrComp

InStrRev- Funktion
Function InStrRev(
sDurchsuchterString As String, _
sSuchString As String,_
[lStart As Long = -1,] _
[vgl As VbCompareMethod = vbBinaryCompare]) _
As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion InStrRev vollbringt die gleiche Aufgabe wie InStr, mit dem feinen Unterschied,
dass sie die Zeichenfolge sDurchsuchterString ab der Zeichenposition lStart (optional, mit
Vorgabewert -1) rückwärts, also von rechts nach links, durchsucht. Hat der optionale Parame-
ter vgl den Wert vbBinaryCompare oder fehlt er, ist die Vergleichsoperation ein zeichenweiser
Unicode-Vergleich; hat vgl den Wert vbTextCompare, legt die Funktion der Vergleichsoperation
die standardmäßige Sortierordnung der für die auf dem System geltenden Landessprache
zugrunde – ohne Unterscheidung der Groß- und Kleinschreibung.

77
Funktionen und Anweisungen für Zeichenfolgen

Hinweis

Hinweis
...................................................
Die mit Visual Basic 6.0 vorliegende Implementation dieser Funktion hat kein Problem damit,
wenn lStart größer ist als die Länge der durchsuchten Zeichenfolge. Werte kleiner gleich 0
(außer dem Sonderwert -1) führen dagegen zu einem Laufzeitfehler.
Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.
Beispiel

Beis piel
...................................................
Funktionen und Anweisungen für Zeichenfolgen

Der folgende Code zählt mittels der Zählvariablen iCount, wie oft die Zeichenfolge s1 innerhalb
der Zeichenfolge s2 vorkommt.
iCount = 0
lPos = -1
Do
lPos = InStrRev(s1, s2, lPos) – 1
If lPos >= 0 Then iCount = iCount + 1
Loop While lPos > 0
... ' iCount enthält nun die Anzahl der Vorkommen
Verwandte Befehle

Verwa ndte Befehle


...................................................
Filter, InStr, StrComp

J oin- Funktion
Function Join( _
StringArray() As String, _
[TrennZeichen As String] = " ") _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Join ist die Umkehrfunktion zu Split. Sie verkettet die Elemente des Zeichenfol-
genarrays StringArray zu einer einzelnen Zeichenfolge und liefert diese zurück. Fehlt der
optionale Parameter TrennZeichen, fügt die Funktion zwischen den Elementen ein Leerzeichen
ein. Durch Angabe eines Werts lassen sich auch andere Trennzeichenfolgen vorgeben, so etwa
die leere Zeichenfolge "", das Tabulatorzeichen vbTab oder Zeilenvorschübe vbCrLf.
Beispiel

Beis piel
...................................................
Das Projekt JoinDemo initialisiert ein Zeichenfolgenarray mit den Namen der Wochentage und
gibt das Ergebnis des nachfolgenden Join-Aufrufs aus:
' Projekt: JoinDemo
Private Sub Form_Load()
Dim sWochenTage(7) As String, sErgebnis() As String
AutoRedraw = True
For i = 0 To 6 ' Wochentage generieren
sWochenTage(i) = WeekdayName(i + 1)
Next i
Print Join(sWochenTage, vbCrLf)
End Sub

78
LCase- Funktion

Verwandte Befehle

Verwa ndte Befehle


...................................................
Filter, Split

LCase- Funktion
Function LCase(s As String) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion LCase liefert eine Kopie der im Parameter s übergebenen Zeichenfolge in Klein-
schreibung zurück. Null wird wieder als Null zurückgegeben.

Funktionen und Anweisungen für Zeichenfolgen


Beispiel

Beis piel
...................................................
if LCase(sTest1) = LCase(sTest2) Then ' Schreibweise egal
Verwandte Befehle

Verwa ndte Befehle


...................................................
UCase

Left- und LeftB- Funktion


Function Left(sUnicode As String, lZeichenAnz As Long) As String
Function LeftB(sANSI As String, lZeichenAnz As Long) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Left liefert die ersten lZeichenAnz Zeichen der Zeichenfolge sUnicode als Uni-
code-Zeichenfolge und die Funktion LeftB die ersten lZeichenAnz Bytes der Zeichenfolge sANSI
als ANSI-Zeichenfolge. Ist der Wert von lZeichenAnz größer oder gleich der Länge der Zeichen-
folge, gibt die Funktion die vollständige Zeichenfolge zurück. Mit 0 als Wert für lZeichenAnz
gibt die Funktion die leere Zeichenfolge zurück.
Beispiel

Beis piel
...................................................
Die folgende Ausgabeanweisung gibt die Zeichenfolge s linksbündig in einem Feld aus. Ist die
Länge der Zeichenfolge s kleiner als 8, werden von rechts her Leerzeichen ergänzt (linksbün-
dige Prokrustes-Zuweisung, vgl. auch »LSet-Anweisung«, S. 80).
Const cFeldBreite = 8
Print Left(s + Space(cFeldBreite), cFeldBreite)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Right, RightB, Mid, MidB, LTrim, RTrim, Trim

Len- und LenB- Funktion


Function Len(sUnicode As String) As Long
Function LenB(Var As Type) As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion Len liefert die Anzahl der Zeichen in der Zeichenfolge sUnicode. Die leere Zei-
chenfolge Null hat die Länge 0. Die Funktion LenB gibt die Anzahl der Bytes zurück, die zum
Speichern des Werts von Var benötigt werden.

79
Funktionen und Anweisungen für Zeichenfolgen

Anwendung

Anwendung
...................................................
Wie es die Beschreibung bereits vermuten lässt, verbirgt sich hinter der Funktion LenB so etwas
wie der »Längenoperator« der Sprache Visual Basic, den Sie benutzen können, wann immer Sie
wissen wollen, wie viele Bytes für die Repräsentation eines bestimmten Werts von einem
bestimmten Datentyp erforderlich sind. Achtung jedoch, die Längenangaben von Zeichenfolgen
enthalten nicht den Längenbedarf des Deskriptors (vgl. auch »Get-Anweisung«, S. 140). Auf
Arrays lässt sich diese Funktion gar nicht anwenden.
Beispiel

Beis piel
...................................................
Funktionen und Anweisungen für Zeichenfolgen

Siehe Beispiel zu »Chr-, ChrB- und ChrW-Funktion« (S. 67)


Verwandte Befehle

Verwa ndte Befehle


...................................................
VarType

LSet- Anweisung
LSet sString1 = sString2
LSet bdtVar = bdtWert
Beschreibung

Bes c hreibung
...................................................
Die Anweisung LSet nimmt eine linksbündige Prokrustes-Zuweisung für Zeichenfolgen und
benutzerdefinierte Datentypen vor.
Auf Zeichenfolgen angewendet, überträgt sie den Wert von sString2 linksbündig in die Vari-
able sString1, ohne deren Länge anzupassen. Dabei wird der Wert von sString2 gegebenenfalls
zurechtgestutzt oder um Leerzeichen ergänzt (vgl. Beispiel in »Left- und LeftB-Funktion«,
S. 79).
Auf benutzerdefinierte Datentypen angewendet, überträgt LSet den Wert bdtWert Byte-weise
und linksbündig in die Variable bdtVar, ohne deren Länge anzupassen. Ist bdtWert kürzer als
der Wert, den bdtVar erwartet, ergänzt die Anweisung Nullbytes, ist er länger, wird zurechtge-
stutzt.
Anwendung

Anwendung
...................................................
Der ursprüngliche Sinn dieser Anweisung war die Bereitstellung einer blockorientierten Zuwei-
sungsoperation für zusammengesetzte bzw. benutzerdefinierte Datentypen. Solche Werte lassen
sich im Rahmen einer gewöhnlichen Let-Zuweisung en bloc nämlich nicht mehr übertragen.
Ein sehr wichtiger Einsatzbereich von LSet ist daher die Überführung traditionell via Get oder
Input gelesener Datensätze in Datensatzvariablen mit benutzerdefinierter Struktur bzw. die
Vorbereitung von Datensatzvariablen für die Put-Operation. Aus diesem Grund ist die Typ-
überprüfung, die Visual Basic LSet angedeihen lässt, nicht sehr rigide.
Warnung und Tipp

Wa rnung
...................................................
»Nachtigall, ick hör dir trapsen«. Ja, mit LSet lassen sich auf dem Umweg über benutzerdefi-
nierte Datentypen implizite Typumwandlungen ausführen, wie das Beispiel zu diesem Befehl
zeigt. Von einer ernsthaften Anwendung im Zusammenhang mit disparaten Datentypen, die
über eine Analyse von Repräsentationen bestimmter Datentypen oder Werte hinausgeht, ist
jedoch abzuraten, da für gewöhnlich nicht klar ist, welche Speicherausrichtung die Felder
benutzerdefinierter Datentypen vom Compiler erhalten.

80
LTrim- Funktion

Beispiel

Beis piel
...................................................
Wer die Speicherdarstellung eines spezifischen Werts zu Gesicht bekommen will, muss schon
ein wenig tricksen, um der rigiden Typkontrolle von Visual Basic zu entrinnen. Der folgende
Code benutzt die als Beispiel zu Chr vorgestellte Funktion StrToHex, um die hexadezimale
Repräsentation eines Double-Werts nach einer LSet-Zuweisung zu erhalten. Beachten Sie bei der
Interpretation der Hexadezimaldarstellung, dass Intel-Prozessoren mit verkehrter Bytereihen-
folge arbeiten und in einem aus mehreren Bytes bestehenden Wert das erste Byte das niederwer-
tige Byte ist.
Private Type bdt1 ' erster benutzerdefinierter Typ

Funktionen und Anweisungen für Zeichenfolgen


f As Double
End Type
Private Type bdt2 ' zweiter benutzerdefinierter Typ
s As String * 4
End Type
Private Sub Form_Load()
AutoRedraw = True
Dim bt1 As bdt1, bt2 As bdt2
bt1.f = 2.234E-23 ' wie sieht die Repräsentation dieses Werts aus?
LSet bt2 = bt1 ' Zuweisung unter Umgehung der Typprüfung
Print StrToHex(bt2.s) ' Ausgabe der hexadezimalen Darstellung
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Get, Let, Put, RSet
Verwandte Themen

Verwandte Them en
...................................................
Typumwandlung (S. 57)

LTrim- Funktion
Function LTrim(s As String) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion liefert eine Kopie der Zeichenfolge s zurück, die keine führenden Leerzeichen
mehr enthält.
Beispiel

Beis piel
...................................................
Dim i As Integer
i = 121
Print LTrim(Str(i)) ' schneidet Leerstelle für Vorzeichen ab
Verwandte Befehle

Verwa ndte Befehle


...................................................
RTrim, Trim

Mid- und MidB- Funktion


Function Mid(sUnicode As String, lStart As Long _
[, lAnz As Long]) As String
Function MidB(sANSI As String, lStart As Long _
[, lAnz As Long]) As String

81
Funktionen und Anweisungen für Zeichenfolgen

Beschreibung

Bes c hreibung
...................................................
Die Funktion Mid liefert lAnz Zeichen der Zeichenfolge sUnicode ab der Position lStart als Uni-
code-Zeichenfolge zurück. In gleicher Weise liefert die MidB-Funktion lAnz Bytes der Zeichen-
folge sANSI ab der Byteposition lStart als Zeichenfolge. Fehlt der optionale Parameter lAnz, lie-
fern beide Funktionen den gesamten Rest der Zeichenfolge ab der Position lStart.
Beispiel

Beis piel
...................................................
Vgl. die Beispiele in »Chr-, ChrB- und ChrW-Funktion« (S. 67) und »Asc-, AscB- und AscW-Funk-
tion« (S. 66).
Funktionen und Anweisungen für Zeichenfolgen

Mid- und MidB- Anweisung


Mid s, lStart [, lAnz] = sErsatz
MidB s, lStart [, lAnz] = sErsatz
Beschreibung

Bes c hreibung
...................................................
Die Mid-Zuweisung kopiert die ersten lAnz Zeichen der Zeichenfolge sErsatz in die Zeichen-
folge s ab Position lStart. Ist lAnz größer als die Länge von sErsatz oder fehlt lAnz, wird die
gesamte Zeichenfolge sErsatz kopiert. MidB unterscheidet sich von Mid nur darin, dass sie lAnz
als Byteanzahl interpretiert und Byte-weise kopiert.
Beispiel

Beis piel
...................................................
Siehe Beispiel zu »Chr-, ChrB- und ChrW-Funktion« (S. 67)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Left, LeftB, Right, RightB, LTrim, RTrim, Trim

MonthName- Funktion
Function MonthName(lMonat As Long[, bAbk As Boolean = False]) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion MonthName liefert den zur Monatszahl lMonat gehörigen Monatsnamen als Zei-
chenfolge. Hat der optionale Parameter bAbk den Wert False oder fehlt er, gibt die Funktion
den vollen Namen zurück, ansonsten seine Abkürzung (drei Buchstaben). Monatszahlen, die
nicht zwischen 1 und 12 liegen, führen zu einem Laufzeitfehler.
Beispiel

Beis piel
...................................................
Print MonthName(Month(Date)) ' Name aktueller Monat, ausgeschrieben
Verwandte Befehle

Verwa ndte Befehle


...................................................
WeekdayName

Oct- Funktion
Function Oct(vOctWert) As Double

82
Option Compare- Anweisung

Beschreibung

Bes c hreibung
...................................................
Die Funktion Oct zählt wie Hex nur mittelbar zu den Typumwandlungsfunktionen. Während
Hex die hexadezimale Notation seines als Ganzzahl interpretierten Arguments als Zeichenfolge
liefert, liefert Oct dessen oktale Notation.
Anwendung

Anwendung
...................................................
Die Umwandlung in das oktale Zahlensystem mittels Oct findet heutzutage eher selten Anwen-
dung. Sie ist ein Relikt aus vergangenen Zeiten, als das hexadezimale Zahlensystem im Compu-
terbereich noch nicht die alles dominierende Rolle spielte.

Funktionen und Anweisungen für Zeichenfolgen


Beispiel

Beis piel
...................................................
Print Oct(77) ' 64+8+5 = "115"
Print Oct(&o1234) ' Oktales Literal: "1234"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Hex

Option Compare- Anweisung


Option Compare Binary
Option Compare Text
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Option Compare legt fest, welche Art von Zeichenfolgenvergleich bestimmte Zei-
chenfolgenfunktionen laut Vorgabe (das heißt ohne Angabe des jeweiligen optionalen Parame-
ters) durchführen. Der Vergleichsart Binary liegt ein schlichter Vergleich der binären Repräsen-
tation (zeichenweiser Unicode-Vergleich), der Vergleichsart Text dagegen die standardmäßige
Sortierordnung der für die auf dem System geltende Landessprache zugrunde – ohne Unter-
scheidung der Groß- und Kleinschreibung. Diese Anweisung darf in einem Modul nicht mehr-
fach gegeben werden, das heißt, sie gilt immer für das gesamte Modul und muss auf Modul-
ebene stehen. Fehlt die Anweisung, gilt für das jeweilige Modul die Voreinstellung Binary.
Eine Option Compare-Anweisung wirkt sich auf die Zeichenfolgenoperatoren <, >, <=, >=, = und
<> aus. Weiterhin kann sie sich bei Fehlen des entsprechenden optionalen Parameters auch auf
die Funktionen: Filter, InStr, InStrB, InStrRev, Replace, Split, StrComp auswirken.
Beispiel

Beis piel
...................................................
Option Compare Text
...
Print (StrComp("ö", "u", vbBinaryCompare) = -1) = ("ö" < "ü")
' Ausgabe: Falsch

aber
Option Compare Binary ' Standardvergleichsart
...
Print (StrComp("ö", "u", vbBinaryCompare) = -1) = ("ö" < "ü")
' Ausgabe: Wahr

83
Funktionen und Anweisungen für Zeichenfolgen

Verwandte Befehle

Verwa ndte Befehle


...................................................
Option Base, Option Explicit, Option Private

Replace- Funktion
Function Replace( _
sDurchsuchterString As String, _
sSuchString As String,_
sErsatzString As String,_
[lStart As Long = 1], _
Funktionen und Anweisungen für Zeichenfolgen

[lAnz As Long = -1],


[vgl As VbCompareMethode = vbBinaryCompare]) _
As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion Replace durchsucht die Zeichenfolge sDurchsuchterString ab der Zeichenposition
lStart nach maximal lAnz Vorkommen der Zeichenfolge sSuchString und liefert eine Kopie
von sDurchsuchterString ab der Zeichenposition lStart, in der all diese Vorkommen gegen die
Zeichenfolge sErsatzString ersetzt sind. Fehlt der optionale Parameter lStart, beginnt die
Kopie beim ersten Zeichen. Fehlt der Parameter lAnz, ersetzt die Funktion beliebig viele Vor-
kommen von sSuchString. Hat der optionale Parameter vgl den Wert vbBinaryCompare oder
fehlt er, ist die Vergleichsoperation ein zeichenweiser Unicode-Vergleich; hat vgl den Wert
vbTextCompare, legt die Funktion der Vergleichsoperation die standardmäßige Sortierordnung
der für die auf dem System geltenden Landessprache zugrunde – ohne Unterscheidung der
Groß- und Kleinschreibung.
Hinweis

Hinweis
...................................................
Die mit Visual Basic 6.0 vorliegende Implementation dieser Funktion hat kein Problem damit,
wenn Start größer ist als die Länge der durchsuchten Zeichenfolge; negative Werte sowie ein
Wert von 0 führen dagegen zu einem Laufzeitfehler.
Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.
Beispiel

Beis piel
...................................................
Dim s As String
Print Replace("12222223", "22", "3") ' "13333"
Print Replace("12222223", "22", "3", 2, 2) ' "33223"
Print Replace("12222223", "22", "3", 2 ,0) ' "2222223"
Print Replace("abbbbbbc", "BB", "C", 2, , vbTextCompare) ' "CCCc"
Vergleiche auch das Beispiel zu »Print #« (S. 151).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Filter, InStr, StrComp

84
Partion- Funktion

Partion- Funktion
Function Partition(Number As Long, Start As Long, Stop As Long, _
Interval As Long) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Partition ordnet eine gegebene Zahl Number in das zugehörige Intervall einer
Intervallfolge ein und liefert dann eine Beschreibung des Intervalls in der Form
»UntereGrenze: ObereGrenze«. Die Intervallfolge ist über Start (untere Grenze des ersten
Intervalls), Stop (obere Grenze des letzten Intervall) und Interval (Breite der einzelnen Inter-
valle in der Folge) definiert und enthält die halboffenen (nach oben offen) Intervalle, die sich

Funktionen und Anweisungen für Zeichenfolgen


durch wiederholte Addition der Intervalllänge zum Startwert ergeben.
Ist Number kleiner als Start, beschreibt die Funktion das Intervall in der Form: »: UntereGrenze
», ist Number größer als Stop, in der Form: »ObereGrenze: «.
Anwendung

Anwendung
...................................................
Der Einsatzbereich dieser ziemlich spezialisierten Funktion liegt hauptsächlich im Bereich der
Datenbankprogrammierung, wo sie für die Berechnung der Datensatzgruppierung verwendbar
ist.
Beispiel

Beis piel
...................................................
Print Partition(1, 2, 100, 23) ' Ausgabe: ": 2"
Print Partition(24, 2, 100, 23) ' Ausgabe: "2: 24"
Print Partition(25, 2, 100, 23) ' Ausgabe: "25: 47"
Print Partition(101, 2, 100, 23) ' Ausgabe: "101: "

Right- und RightB- Funktion


Function Right(sUnicode As String, lZeichenAnz As Long) As String
Function RightB(sANSI As String, lZeichenAnz As Long) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Right liefert die letzten lZeichenAnz Zeichen der Zeichenfolge sUnicode als Uni-
code-Zeichenfolge und die Funktion RightB die letzten lZeichenAnz Bytes der Zeichenfolge
sANSI als ANSI-Zeichenfolge. Ist der Wert von lZeichenAnz größer oder gleich der Länge der
Zeichenfolge, gibt die Funktion die vollständige Zeichenfolge zurück. Mit 0 als Wert für lZei-
chenAnz gibt die Funktion die leere Zeichenfolge Null zurück.
Beispiel

Beis piel
...................................................
Die folgende Ausgabeanweisung gibt die Zeichenfolge s rechtsbündig in einem Feld aus. Ist die
Länge der Zeichenfolge s kleiner als 8, werden von links her Leerzeichen ergänzt (rechtsbün-
dige Prokrustes-Zuweisung, vgl. auch »RSet-Anweisung«, S. 86).
Const cFeldBreite = 8
Print Right(Space(cFeldBreite) + s , cFeldBreite)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Right, RightB, Mid, MidB, LTrim, RTrim, Trim

85
Funktionen und Anweisungen für Zeichenfolgen

RSet- Anweisung
RSet sString1 = sString2
Beschreibung

Bes c hreibung
...................................................
Die Anweisung RSet nimmt eine rechtsbündige Prokrustes-Zuweisung für Zeichenfolgen vor,
das heißt, sie kopiert den Wert von sString2 rechtsbündig in die Variable sString1, ohne deren
Länge anzupassen. Dabei wird der Wert von sString2 gegebenenfalls vorne zurechtgestutzt
oder um Leerzeichen ergänzt.
Beispiel

Beis piel
...................................................
Funktionen und Anweisungen für Zeichenfolgen

Dim s As String * 20
RSet s = FormatCurrency(vWert, 2)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Get, Let, LSet, Put

RTrim- Funktion
Function RTrim(s As String) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion liefert eine Kopie der Zeichenfolge s zurück, die keine Leerzeichen am Ende ent-
hält.
Beispiel

Beis piel
...................................................
Dim sFix As String * 100
Dim sVariable As String
sFix = "Literaler Wert" ' Prokrustes-Zuweisung
sVariable = sFix
Print RTrim(sVariable)
Verwandte Befehle

Verwa ndte Befehle


...................................................
LTrim, Trim

Space- Funktion
Function Space(lAnz As Long) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Space liefert eine Unicode-Zeichenfolge der Länge lAnz, die mit Leerzeichen
gefüllt ist.
Beispiel

Beis piel
...................................................
Siehe die Beispiele zu »Chr-, ChrB- und ChrW-Funktion« (S. 67), »Left- und LeftB-Funktion«
(S. 79 ) und »Right- und RightB-Funktion« (S. 85).
Verwandte Befehle

Verwa ndte Befehle


...................................................
LTrim, RTrim

86
Split- Funktion

Split- Funktion
Function Split(_
sKombination As String, _
[sTrennzeichen As String = " "], _
[lAnz As Long = -1], _
[vgl As vbCompareMethod = vbBinaryCompare]) _
As String()
Beschreibung

Bes c hreibung
...................................................
Als Umkehrfunktion zu Join unterteilt die Funktion Split die Zeichenfolge sKombination in

Funktionen und Anweisungen für Zeichenfolgen


mehrere Zeichenfolgen und gibt diese als Zeichenfolgenarray zurück. Fehlt der optionale Para-
meter sTrennzeichen, wertet die Funktion standardmäßig jedes erscheinende Leerzeichen als
Trennzeichen zwischen zwei Zeichenfolgen, ansonsten den Wert von sTrennzeichen. Fehlt der
optionale Parameter lAnz, nimmt die Funktion so viele Unterteilungen vor, wie sie Trennzei-
chen findet, ansonsten nicht mehr als lAnz. Hat der optionale Parameter vgl den Wert vbBina-
ryCompare oder fehlt er, ist die Vergleichsoperation ein zeichenweiser Unicode-Vergleich; hat
vgl den Wert vbTextCompare, legt die Funktion der Vergleichsoperation die standardmäßige Sor-
tierordnung der für die auf dem System geltenden Landessprache zugrunde – ohne Unterschei-
dung der Groß- und Kleinschreibung.
Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.
Beispiel

Beis piel
...................................................
cVornamen = "Audra, Petra, Jennifer, Maria, Magdalena"
Dim sVornamen() As String
sVornamen = Split(cVornamen, ", ")
For i = 0 To UBound(sVornamen) ' zeilenweise ausgeben
Print sVornamen(i)
Next i
Print cVornamen = Join(sVornamen, ", ") ' Ausgabe: Wahr
Verwandte Befehle

Verwa ndte Befehle


...................................................
Filter, Join

Str- Funktion
Function Str(lZahl As Long) As String
Function Str(dZahl As Double) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Str liefert den Wert von lZahl bzw. dZahl als Unicode-Zeichenfolge im standard-
mäßigen amerikanischen Zahlenformat.
Warnung

Wa rnung
...................................................
Leider ist die Str-Funktion von Visual Basic 6.0 nicht fehlersicher implementiert und liefert im
Zusammenhang mit der Print-Anweisung gerne mal den Fehler 480, wenn dZahl als literaler
Wert angegeben wird. Da dieser Fehler danach selbst bei Angabe korrekter Argumente nicht
mehr weg zu bekommen ist, hilft in diesem Fall nur ein Neustart von Visual Basic.

87
Funktionen und Anweisungen für Zeichenfolgen

Wird die Funktion mit einer literalen Zeichenfolge bzw. einer Konstante als Argument aufgeru-
fen, verwandelt Visual Basic die Zeichenfolge zunächst implizit in eine Zahl vom Typ Long oder
Double, um mit Str daraus wieder eine Zeichenfolge zu machen. In Systemen mit deutschem
Zahlenformat (Ländereinstellungen) passiert dabei dummerweise Folgendes:
Print Str("1234,1234") ' Ausgabe: 1234,1234
Print Str(Str("1234,1234")) ' Ausgabe: 12341234

Fehler, die aus dieser Ungereimtheit heraus entstehen, sind meist recht schwer zu finden (vgl.
auch Variableninitialisierung, S. 168).
Beispiel

Beis piel
...................................................
Funktionen und Anweisungen für Zeichenfolgen

Der folgende Code geht von einem Formular mit zwei Textfeldern namens Text1 und Text2 aus
und übersetzt Eingaben in die Standardnotation.
Private Sub Text1_Change()
Text2 = Str(Val(Text1))
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Val, Round

StrComp- Funktion
Function StrComp( _
s1 As String, _
s2 As String, _
[vgl As vbCompareMethod = vbBinaryCompare]) _
As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion StrComp unterzieht die beiden Zeichenfolgen s1 und s2 einer Vergleichsoperation
und unterscheidet dabei die vier in der folgenden Tabelle aufgelisteten Fälle. Hat der optionale
Parameter vgl den Wert vbBinaryCompare oder fehlt er, ist die Vergleichsoperation ein zeichen-
weiser Unicode-Vergleich; hat vgl den Wert vbTextCompare, legt die Funktion der Vergleichs-
operation die standardmäßige Sortierordnung der für die auf dem System geltenden Landes-
sprache zugrunde – ohne Unterscheidung der Groß- und Kleinschreibung.

Funktionswert Ergebnis des Vergleichs (hängt von Vergleichsoperation ab)


-1 s1 ist »kleiner als« s2
1 s1 ist »größer als« s2
0 s1 ist »gleich« s2
Null Einer der beiden Vergleichswerte ist Null

Warnung

Wa rnung
...................................................
Das Standardverhalten der Funktion bei fehlendem Parameter vgl kann sich durch eine Option
Compare-Anweisung ändern.

88
StrConv- Funktion

Beispiel

Beis piel
...................................................
Print StrComp("Blöd", "Blut") ' Ausgabe: 1
Print StrComp("Blöd", "Blut", vbTextCompare) ' Ausgabe: -1
Print StrComp("BlOnD", "blond", vbTextCompare) ' Ausgabe: 0
Verwandte Befehle

Verwa ndte Befehle


...................................................
Option Compare, <, > =

StrConv- Funktion

Funktionen und Anweisungen für Zeichenfolgen


Function StrConv( _
s As String, _
KonvSchema As VbStrConv, _
[lGebietsschemaID As Long) _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion StrComp liefert eine konvertierte Variante der Zeichenfolge s. Der Wert von Konv-
Schema (siehe Tabelle) bestimmt, welches Konversionsschema die Funktion der Konversion
zugrunde legt. Bestimmte Konversionen sind allerdings nur möglich, wenn im System ein ent-
sprechendes Gebietsschema eingestellt oder im optionalen Parameter lGebietsschemaID spezifi-
ziert ist.

Wert für KonvSchema Verwendetes Konversionsschema


vbUpperCase (1) Umwandlung in Großschreibung
vbLowerCase (2) Umwandlung in Kleinschreibung
vbProperCase (3) Umwandlung in gemischte Groß-/Kleinschreibung, Wortanfang groß,
Rest klein
vbWide (4) Umwandlung von Ein-Byte-Zeichen in Zwei-Byte-Zeichen (DBCS)
vbNarrow (8) Umwandlung von Zwei-Byte-Zeichen (DBCS) in Ein-Byte-Zeichen
vbKatakana (16) Umwandlung Hiragana-Zeichen in Katagana-Zeichen
vbHiragana (32) Umwandlung Katagana-Zeichen in Hiragana-Zeichen
vbUnicode (64) Umwandlung von systemspezifischem ANSI-Zeichensatz in Unicode
unter Verwendung der Zeichenumsetzungstabelle des Systems
vbFromUnicode (128) Umwandlung von Unicode in systemspezifischen ANSI-Zeichensatz
unter Verwendung der Zeichenumsetzungstabelle des Systems

Hinweis

Hinweis
...................................................
Sie können die in der Tabelle genannten Konstanten für KonvSchema auch kombinieren. Aller-
dings hängen die sinnvollen Kombinationsmöglichkeiten stark vom geltenden Gebietsschema
ab. Der Wert vbUnicode + vbProperCase bewirkt beispielsweise die Umwandlung einer ANSI-
Zeichenfolge in Unicode mit gemischter Groß-/Kleinschreibung. Folgende Zeichen wertet die
Funktion als Trennzeichen zwischen Wörtern: Chr(0), Chr(9), Chr(10), Chr(11), Chr(12),
Chr(13), Chr(32) – das gilt aber nicht für alle Gebietsschemata.

89
Funktionen und Anweisungen für Zeichenfolgen

Beispiel

Beis piel
...................................................
LSET s = StrConv(s, vbFromUnicode) ' ANSI-String für Ausgabe vorbereiten
Print StrConv(s1, vbUnicode + vbProperCase)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Chr, CStr

String- Funktion
Function String(lAnz As Long, iANSI As Integer) As String
Funktionen und Anweisungen für Zeichenfolgen

Function String(lAnz As Long, sVorgabe As String) As String


Beschreibung

Bes c hreibung
...................................................
Die Funktion String gibt es in zwei unterschiedlichen Varianten. Beide Varianten liefern eine
Unicode-Zeichenfolge der Länge lAnz, die mit einem einzelnen Zeichen aufgefüllt ist. Für die
erste Variante wird das Zeichen als ANSI-Code iANSI spezifiziert. Ist iANSI größer als 255, bil-
det die Funktion den Wert mittels einer Restwertdivision in das Intervall zwischen 0 und 255
ab.
Die zweite Variante von String arbeitet mit beliebigen Unicode-Zeichen. In dieser Syntax ver-
wendet die Funktion das erste Unicode-Zeichen der Zeichenfolge sVorgabe.
Beispiel

Beis piel
...................................................
Print StrToHex(String(2, 300)) ' Ausgabe: "2C 00 2C 00"
Print StrToHex(String(2, ChrW(300))) ' Ausgabe: "2C 01 2C 01"
Verwandte Befehle

Verwa ndte Befehle


...................................................
LTrim, RTrim

StrReverse- Funktion
Function StrReverse(s As String) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion StrReverse liefert eine Zeichenfolge, in der alle Zeichen der Zeichenfolge s in
umgekehrter Reihenfolge enthalten sind. Bei Aufruf mit einer leeren Zeichenfolge ist das Ergeb-
nis des Funktionsaufrufs gleichfalls eine leere Zeichenfolge. Ein Aufruf der Funktion mit Null
führt dagegen zu einem Laufzeitfehler.
Beispiel

Beis piel
...................................................
Print StrReverse("ABCD") ' Ausgabe: "DCBA"

Trim- Funktion
Function Trim(s As String) As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion liefert eine Kopie der Zeichenfolge s zurück, die weder am Anfang noch am Ende
Leerzeichen enthält.

90
UCase- Funktion

Beispiel

Beis piel
...................................................
Print RTrim(LTrim(" Test ")) = Trim(" Test ") ' Gibt "Wahr" aus
Verwandte Befehle

Verwa ndte Befehle


...................................................
LTrim, RTrim

UCase- Funktion
Function UCase(s As String) As String

Funktionen und Anweisungen für Zeichenfolgen


Beschreibung

Bes c hreibung
...................................................
Die Funktion UCase liefert eine Kopie der im Parameter s übergebenen Zeichenfolge in Groß-
schreibung zurück. Die leere Zeichenfolge Null wird wieder als Null zurückgegeben.
Beispiel

Beis piel
...................................................
If UCase(sTest1) = UCase(sTest2) Then ' Schreibweise egal
Verwandte Befehle

Verwa ndte Befehle


...................................................
LCase

Val- Funktion
Function Val(sZahl As String) As Double
Beschreibung

Bes c hreibung
...................................................
Die Funktion Val ist die Umkehrfunktion zu Str. Sie interpretiert die Zeichenfolge sZahl als
Zahl in Standardnotation (mit Dezimalpunkt, nicht mit Dezimalkomma, da die Funktion keine
Ländereinstellungen berücksichtigt) und liefert den Wert dieser Zahl.
Anwendung

Anwendung
...................................................
Val liefert auch einen Zahlenwert als Ergebnis, wenn sZahl mit einer Ziffernfolge beginnt und
danach Zeichen folgen, die nichts mehr mit der Zahlendarstellung zu tun haben – so macht Val
aus »12.34 Abfahrt Hamburg HBF« den Wert 12.34, aus »12,34 Abfahrt Hamburg HBF«
jedoch 12. Um festzustellen, ob ein Wert vollständig als Zahl ausgewertet werden kann, steht
die Boolean-Funktion IsNumeric zur Verfügung – sie liefert für beide Beispielzeichenfolgen
False.
Warnung

Wa rnung
...................................................
Anders als die anderen Zeichenfolgenfunktionen arbeitet Val nicht mit der länderspezifischen
Zahlendarstellung und will einen Punkt als Dezimalsymbol sehen. Dennoch ergeben sich im
Zusammenspiel mit Str »seltsame Effekte«:
Print Val("10,1") ' Ausgabe: 10
Print Val("10.1") ' Ausgabe: 10,1
Print Str(10.1) ' Ausgabe: "10,1"
Print Val(Str(10.1)) ' Ausgabe: 10,1 (seltsam,nicht?)

91
Mathematische und finanzmathematische Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Private Sub Text1_Change()
Text2.Text = Sqr(Val(Text1.Text))
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
LCase

WeekdayName- Funktion
Mathematische und finanzmathematische Funktionen und Anweisungen

Function WeekdayName( _
lTag As Long, _
[bAbk As Boolean = False], _
[FirstDayOfWeek As VbFirstDayOfWeek = vbUseSystemDayOfWeek]) _
As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion WeekdayName liefert den zur Tageszahl lTag gehörigen Wochentag als Zeichen-
folge. Hat der optionale Parameter bAbk den Wert False oder fehlt er, gibt die Funktion den vol-
len Namen zurück, ansonsten seine Abkürzung (zwei Buchstaben). Über den optionalen Para-
meter FirstDayOfWeek lässt sich zudem vorgeben, mit welchem Wochentag die Zählung
beginnen soll. Fehlt er, beginnt die Zählung mit dem im System festgelegten Tag, und das ist der
Montag. Tageszahlen, die nicht zwischen 1 und 7 liegen, führen zu einem Laufzeitfehler.
Beispiel

Beis piel
...................................................
Print WeekdayName(Weekday(Date)) ' aktueller Wochentag ausgeschrieben
Verwandte Befehle

Verwa ndte Befehle


...................................................
MonthName

Mathematische und finanzmathematische Funktionen und


Anweisungen
Wenn bei den Zeichenfolgen zuvor die Rede davon war, dass die Manipulation derselben schon
immer eine der ureigensten Domänen der Programmiersprache Basic war, dann sollte das nicht
etwa heißen, dass die Sprache in puncto Mathematik wenig zu bieten habe. Auch für die For-
mulierung mathematischer und numerischer Problematiken war die Sprache für sich genommen
immer schon recht reichhaltig ausgestattet. Insbesondere bot die weitgehend interaktive Pro-
grammentwicklung eine enorme Flexibilität bei der Programmierung von On-the-fly-Anwen-
dungen für die Lösung minder komplexer Problematiken, die nicht auf das überlegene Laufzeit-
verhalten von Compilersprachen angewiesen waren. Als problematisch erwiesen sich allerdings
die fehlenden Mittel für eine geeignete Modularisierung und eine Anbindung an bereits beste-
hende mathematische Bibliotheken.
Was die Modularisierbarkeit von Code betrifft, so hat sich Basic mit Visual Basic inzwischen zu
einer wahrlich vorbildlichen Programmiersprache entwickelt. Die Möglichkeiten der Anbin-
dung an bestehende mathematische Bibliotheken sind aber nach wie vor eher als lau einzustu-
fen, da solche Bibliotheken (sofern sind nicht in Visual Basic selbst, als ActiveX-Bibliotheken

92
Mathematische und finanzmathematische Funktionen und Anweisungen

oder in C implementiert sind, und das sind Bibliotheken aus dem Bereich der Numerischen
Mathematik auch heutzutage noch eher nicht, weil da immer noch FORTRAN herumgeistert)
von ihrem Aufrufmodell her meist nicht kompatibel sind.
Auch wenn es Visual Basic wohl nicht mehr zur lingua franca der numerischen Mathematik
bringen wird, ihre mathematische und auch finanzmathematische Grundausstattung ist reich-
haltig genug für die meisten Fragestellungen im naturwissenschaftlichen, wirtschaftlichen und
informationstechnologischen Bereich, und es spricht inzwischen absolut nichts mehr gegen die
Entwicklung eigener mathematischer Bibliotheken als solide Basis für künftige Projekte. Bei
einer solchen Bibliothek kann es sich um eine Klassenbibliothek für abstrakte Datentypen han-
deln, so etwa für die Vektor- und Matrizenrechnung, oder um ein gewöhnliches Bibliotheksmo-
dul, das spezifische Funktionen und Prozeduren etwa für den Bereich Statistik bereitstellt.

Mathematische und finanzmathematische Funktionen und Anweisungen


Nichtsdestoweniger bleibt jede eigene Implementation von Datentypen und Operationen auf
das mathematische Inventar der Sprache selbst angewiesen. Die folgende Tabelle gibt einen
Überblick über die mathematischen und finanzmathematischen Funktionen und Anweisungen
von Visual Basic.

Bezeichner Kurzbeschreibung
Abs Liefert den Absolutwert (vorzeichenlosen Wert) einer Zahl
Atn Liefert den Arcustangens einer Zahl als Winkel im Bogenmaß
Cos Liefert den Cosinus zu einem Winkel im Bogenmaß
DDB Liefert den Abschreibungswert eines Vermögenswerts über einen bestimmten
Zeitraum bei geometrisch degressiver Abschreibung
Exp Liefert den Wert der Exponentialfunktion (mit Basis e) zu einer Zahl
Fix Liefert den Vorkommaanteil einer Dezimalzahl als Ganzzahl
FV Liefert den künftigen Wert einer Annuität (Ansparung oder Kredit) bei konstan-
ter Zahlung, konstantem Zins und fester Laufzeit
Int Liefert den nächsten ganzzahligen Wert kleiner oder gleich einer Zahl
IPmt Liefert den Zinsanteil für eine bestimmte Periode bei Abzahlung oder Anspa-
rung mit konstanten Raten und konstantem Zinssatz
IRR Liefert den internen Ertragssatz für eine Folge regelmäßiger Ein- und Auszahlun-
gen
Log Liefert den natürlichen Logarithmus einer Zahl
MIRR Liefert den modifizierten internen Ertragssatz für eine Folge regelmäßiger, mit
unterschiedlichen Zinssätzen behafteten Ein- und Auszahlungen
NPer Liefert die Anzahl der Zeiträume für eine Annuität (Ansparung oder Kredit) bei
konstanter Zahlung und konstantem Zins
NPV Liefert den Nettobarwert einer Investition bei regelmäßigen Aus- und Einzah-
lungen und konstantem Diskontsatz
Pmt Liefert den Auszahlungswert (Höhe der Rate bei Kredit) für eine Annuität mit
einer festen Anzahl von Zeiträumen, konstanter Zahlung und konstantem Zins
PPmt Liefert den Kapitalanteil (bei Kredit: Tilgung) eines bestimmten Zeitraums für
eine Annuität (Ansparung oder Kredit) mit einer festen Anzahl von Zeiträumen,
konstanter Zahlung und konstantem Zins
Mathematische und finanzmathematische Funktionen und Anweisungen

93
Mathematische und finanzmathematische Funktionen und Anweisungen

Bezeichner Kurzbeschreibung
PV Liefert den Barwert für eine Annuität (Ansparung oder Kredit) bei konstanter
Zahlung, konstantem Zins und fester Laufzeit
Randomize Initialisiert den Zufallsgenerator mit einem Startwert
Rate Liefert den Zinssatz zu einer Annuität (Anzahlung oder Kredit) mit einer festen
Anzahl von Zeiträumen, konstanter Zahlung und konstantem Zins
Rnd Liefert eine gleich verteilte Zufallszahl zwischen 0 und 1
Round Liefert den Wert einer Zahl auf eine bestimmte Dezimalstelle gerundet
Mathematische und finanzmathematische Funktionen und Anweisungen

Sgn Liefert das Vorzeichen eines Werts als Faktor (-1, 0 oder 1)
Sin Liefert den Sinus zu einem Winkel im Bogenmaß
SLN Liefert den periodischen Abschreibungswert eines Vermögenswerts bei linearer
Abschreibung über einen bestimmten Zeitraum
Sqr Liefert die Quadratwurzel eines positiven Zahlenwerts
SYD Liefert den Abschreibungswert eines Vermögenswerts für eine bestimmte Peri-
ode nach dem Modell der Jahressummengewichtung
Tan Liefert den Tangens zu einem Winkel im Bogenmaß
Mathematische und finanzmathematische Funktionen und Anweisungen
Warnung

Wa rnung
...................................................
Die mit Visual Basic 6 (SP3) vorliegende Implementation der finanzmathematischen Funktionen
ist alles andere als fehlersicher. So erhält man in nicht klar zu bestimmenden Situationen oder
bei Angabe falscher Parameterwerte gerne mal den lästigen Laufzeitfehler 480, »Anwendungs-
oder objektdefinierter Fehler«, den man im Lauf der aktuellen Visual-Basic-Sitzung nicht mehr
los wird – selbst bei Angabe korrekter Parameterwerte. In diesem Fall hilft nur noch ein Neu-
start von Visual Basic.
Tipp

Tipp
...................................................
Aufgrund der internen Darstellung gewöhnlicher Zahlenwerte im hexadezimalen Format
kommt es bei verschiedenen Funktionen zu Rundungsfehlern, die gerade im finanzmathemati-
schen Bereich, aber auch anderswo für peinliche Fehler (so genannte »Pfennigfuchser-Fehler«)
im Bereich der letzten Nachkommastelle sorgen können. Sie vermeiden solche Fehler, indem Sie
für Währungsbeträge konsequent den Datentyp Currency und für dezimale Berechnungen mit
nachfolgenden Rundungsoperationen den Datentyp Decimal einsetzen. Gegebenenfalls erforder-
liche Typumwandlungen nimmt Visual Basic dann implizit vor.

Abs- Funktion
Function Abs(dZahl As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die Funktion Abs liefert den Absolutwert zu der Zahl dZahl, das heißt den Zahlenwert mit posi-
tivem Vorzeichen.

94
Atn- Funktion

Beispiel

Beis piel
...................................................
DeltaX = Abs(MouseX – X)
DeltaY = Abs(MouseY – Y)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Sgn

Atn- Funktion
Function Atn(d As Double) As Double

Mathematische und finanzmathematische Funktionen und Anweisungen


Beschreibung

Bes c hreibung
...................................................
Die zu den trigonometrischen Umkehrfunktionen zählende Arcustangensfunktion Atn ist die
Umkehrfunktion der Tangensfunktion (Tan). Sie liefert den Arcustangens zu der Zahl d als Win-
kel im Bogenmaß. Das Ergebnis der Funktion liegt immer im offenen Intervall ]-π/2; π/2[. Für
die Umwandlung in Grad ist der Wert mit 180/π = 57,2957795130823 zu multiplizieren.
Anwendung

Anwendung
...................................................
Diese Funktion berechnet den Winkel zwischen Hypothenuse und Ankathete eines rechtwinkli-
gen Dreiecks, wenn deren Längen bekannt sind, bzw. den zu einem Tangenswert (Steigung)
gehörigen Winkel.
Tipp

Tipp
...................................................
Da Visual Basic die Zahl π nicht als Konstante kennt, muss ein anderer Weg gefunden werden,
an ihren Wert zu kommen. Ein sehr eleganter Weg ist die Berechnung des Werts über die Funk-
tion Atn.
Dim Pi As Double
Pi = Atn(1) * 4 ' 3.14159265358979
Beispiel

Beis piel
...................................................
Print Atn(1) ' Ausgabe: 0,785398163397448
Verwandte Befehle

Verwa ndte Befehle


...................................................
Cos, Sin, Tan

Cos- Funktion
Function Cos(dWinkel As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den trigonometrischen Funktionen zählende Cosinusfunktion Cos liefert den Cosinus zu
dem im Bogenmaß angegebenen Winkel dWinkel. Das Ergebnis der Funktion liegt immer im
Intervall [-1; 1]. Für die Umwandlung eines Gradwerts in das Bogenmaß ist der Wert mit π/180
= 1,74532925199433E-02 zu multiplizieren.
Anwendung

Anwendung
...................................................
Diese Funktion berechnet aus dem Winkel zwischen Ankathete und Hypothenuse die Anka-
thete eines rechtwinkligen Dreiecks mit Hypothenuse 1.

95
Mathematische und finanzmathematische Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Dim Pi As Double
Pi = Atn(1) * 4 ' 3.14159265358979
Print Cos(Pi / 3) ' Ausgabe: 0,5
Verwandte Befehle

Verwa ndte Befehle


...................................................
Atn, Sin, Tan

DDB- Funktion
Mathematische und finanzmathematische Funktionen und Anweisungen

Function DDB( _
dKosten As Double, _
dRestwert As Double, _
dNutzungsDauer As Double, _
dPeriode As Double, _
[vFaktor As Variant = 2]) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion DDB ermöglicht die Berech-
nung der Abschreibung einer Investition dKosten mit dem Restwert dRestwert nach der ange-
nommenen Nutzungsdauer dNutzungsDauer für eine bestimmte Periode dPeriode. Fehlt der
optionale Parameter vFaktor oder hat er den Wert 2, berechnet die Funktion den Abschrei-
bungswert nach der geometrisch degressiven Methode, ansonsten mit der gleichen Formel,
jedoch mit vFaktor als Degressionsfaktor.
Anwendung

Anwendung
...................................................
dNutzungsDauer und dPeriode muss die gleiche Einheit (Monate oder Jahre) zugrunde liegen.
Diese Funktion berücksichtigt den Parameter dRestwert nur insofern, als sie 0 zurückliefert,
wenn der Restwert für eine Periode bereits erreicht ist. Mit anderen Worten, die Funktion rech-
net nicht mit der üblichen Formel
( Wert(Periode) – Restwert ) ⋅ Faktor
DDB = ------------------------------------------------------------------------------------------------
Nutzungszeit
sondern nach der schlichteren Formel
Wert(Periode) ⋅ Faktor
DDB = -------------------------------------------------------------
Nutzungszeit
Das kann zwar verwirren, gestattet aber einen Test, nach wie vielen Perioden eine Investition
einen bestimmten Restwert erreicht hat.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt, wie sich ein Wert von 10.000 € bei Abschreibung nach der
geometrisch degressiven Methode und einer Laufzeit von 10 Jahren entwickelt:
Laufzeit = 10
AnschaffungsWert = 10000
RestWert = 2000
For Per = 1 to Laufzeit – 1
Print DDB(AnschaffungsWert, RestWert, Laufzeit, Per)
Next

96
Exp- Funktion

Verwandte Befehle

Verwa ndte Befehle


...................................................
SLN, SYD

Exp- Funktion
Function Exp(dZahl As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die Wachstumsfunktion Exp ist die Umkehrfunktion zur natürlichen Logarithmusfunktion Log.
Sie liefert den Wert der Eulerschen Konstante (2,71828182845905) hoch dZahl.

Mathematische und finanzmathematische Funktionen und Anweisungen


Beispiel

Beis piel
...................................................
Print Exp(1) ' Ausgabe: 2,71828182845905
Print Exp(Log(10)) ' Ausgabe: 10
Verwandte Befehle

Verwa ndte Befehle


...................................................
Log

Fix- Funktion
Function Fix(dZahl As NumTyp) As NumTyp
Beschreibung

Bes c hreibung
...................................................
Die Rundungsfunktion Fix liefert den Ganzzahlanteil von dZahl, indem sie alle Nachkomma-
stellen abschneidet. Sie weist damit die gleiche Funktionalität wie CInt auf. Im Gegensatz zu
CInt richtet die Funktion den Datentyp des Rückgabewerts aber nach dem Datentyp des Para-
meters.
Warnung

Wa rnung
...................................................
Wie das Beispiel zeigt, ist die Dezimalrechnung mit den Datentypen Single und Double nicht
immer exakt. Das liegt daran, dass die Repräsentation dieser Werte intern im hexadezimalen
bzw. echten binären Zahlenformat erfolgt und viele endliche Dezimalbrüche im binären Zah-
lensystem nur als unendliche Binärbrüche darstellbar sind. Wenn Sie Exaktheit benötigen, müs-
sen Sie mit einem der Datentypen Currency oder Decimal rechnen!
Beispiel

Beis piel
...................................................
a = 27.003
Print Fix(a) ' Ausgabe: 27
Print (a – Fix(a)) ' Ausgabe: 3,00000000000011E-03

Dim b As Variant
b = CDec(a)
Print Fix(b) ' Ausgabe: 27
Print (b – Fix(b)) ' Ausgabe: 0,003
Verwandte Befehle

Verwa ndte Befehle


...................................................
CInt, Int, Round

97
Mathematische und finanzmathematische Funktionen und Anweisungen

FV- Funktion
Function FV( _
dZins As Double, _
dLaufzeit As Double, _
dRate As Double, _
[vJetztWert], _
[vTermin]) _
As Double
Beschreibung

Bes c hreibung
...................................................
Mathematische und finanzmathematische Funktionen und Anweisungen

Die zu den finanzmathematischen Funktionen zählende Funktion FV liefert den zukünftigen


Wert einer Annuität mit einer Laufzeit von dLaufzeit Zahlungsperioden, konstantem Zins
dZins und der Rate dRate. Der optionale Parameter vJetztWert ermöglicht die Angabe eines
Ausgangswerts bei bereits erfolgter Ansparung. Fehlt der optionale Parameter vTermin oder ist
er 0, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode erfolgt;
ist der Wert dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Beginn
einer Periode erfolgt.
Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dZins und dLaufzeit auf denselben Einheitszeit-
raum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen Funktionen
gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch positive Zah-
len dargestellt werden. Die Funktion lässt sich sowohl zur Berechnung von Krediten als auch
von Ansparungen verwenden, wird aber vorzugsweise für die Kreditberechnung eingesetzt, da
der zukünftige Wert bei Ansparungen meist einen Ausgangswert darstellt. Bei der Kreditberech-
nung sind dRate und dJetztWert als negative Werte anzugeben, bei der Ansparberechnung als
positive Werte.
Tipp

Tipp
...................................................
Die Funktionen PV und FV liefern mit vertauschten Vorzeichen für dRate und dJetztWert die
gleichen Ergebnisse.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt, wie sich eine Ansparung mit einer monatlichen Rate von
100 € und einem Zinssatz von 10% p.a. mit und ohne eine Starteinlage von 10.000 € über zehn
Jahre hin entwickelt:
Laufzeit = 10 * 12
MonatsRate = 100
Zins = 0.1 / 12
Starteinlage = 10000
Print FV(Zins, Monatsrate, Laufzeit) ' -18619,84
Print FV(Zins, Monatsrate, Laufzeit, Starteinlage) ' -41550,28
Das gleiche als Kredit:
Laufzeit = 10 * 12
MonatsRate = -100
Zins = 0.1 / 12
Starteinlage = -10000

98
Int- Funktion

Print FV(Zins, Monatsrate, Laufzeit) ' 8120,14


Print FV(Zins, Monatsrate, Laufzeit, Starteinlage) ' 12481,15
Verwandte Befehle

Verwa ndte Befehle


...................................................
IPmt, IRR, NPer, NPV, Pmt, PPmt, PV

Int- Funktion
Function Int(dZahl As NumTyp) As NumTyp
Beschreibung

Bes c hreibung
...................................................

Mathematische und finanzmathematische Funktionen und Anweisungen


Die Rundungsfunktion Int liefert die nächste Ganzzahl kleiner gleich dZahl. Im Gegensatz zu
Fix schneidet die Funktion nicht nur die Nachkommastellen ab, sondern rundet echt. Die Funk-
tion richtet den Datentyp des Rückgabewerts nach dem Datentyp des Parameters.
Warnung

Wa rnung
...................................................
Wie das Beispiel zeigt, ist die Dezimalrechnung mit den Datentypen Single und Double nicht
immer exakt. Das liegt daran, dass die Repräsentation dieser Werte intern im hexadezimalen
bzw. echten binären Zahlenformat erfolgt und viele endliche Dezimalbrüche im binären Zah-
lensystem nur als unendliche Binärbrüche darstellbar sind. Wenn Sie Exaktheit benötigen, müs-
sen Sie mit einem der Datentypen Currency oder Decimal rechnen.
Beispiel

Beis piel
...................................................
a = -27.002
Print Int(a) ' Ausgabe: -28
Print (a – Int(a)) ' Ausgabe: 0,998000000000001

Dim b As Variant
b = CDec(a)
Print Int(b) ' Ausgabe: -28
Print (b – Int(b)) ' Ausgabe: 0,998
Verwandte Befehle

Verwa ndte Befehle


...................................................
CInt, Fix, Round

IPmt- Funktion
Function IPmt( _
dZins As Double, _
dPeriode As Double, _
dLaufzeit As Double, _
dBarwert As Double, _
[vZukünftigerWert], _
[vTermin]) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion IPmt (engl.: Interest Payment)
liefert den Zinsanteil in der Periode dPeriode zu einer Annuität mit einer Laufzeit von dLaufzeit
Zahlungsperioden, konstantem Zins dZins und dem Barwert dBarwert (vgl. »PV-Funktion«,

99
Mathematische und finanzmathematische Funktionen und Anweisungen

S. 106). Der optionale Parameter vZukünftigerWert (vgl. »FV-Funktion«, S. 98) ermöglicht die
Angabe eines zukünftigen Werts, der den nach der letzten Zahlung erreichten Kontostand
angibt. Bei einem Kredit ist dieser Wert im Allgemeinen mit 0 anzugeben, was dem Vorgabe-
wert für den Parameter entspricht. Fehlt der optionale Parameter vTermin oder ist er 0, geht die
Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode erfolgt; ist der Wert
dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Beginn einer Periode
erfolgt.
Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dZins, dPeriode und dLaufzeit auf denselben
Mathematische und finanzmathematische Funktionen und Anweisungen

Einheitszeitraum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen
Funktionen gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch
positive Zahlen dargestellt werden. Die Funktion wird im Allgemeinen zur Berechnung von
Krediten verwendet. Für die Kreditberechnung setzen Sie dBarwert auf die Höhe des Kredits
(Zahlungsausgang) und vZukünftigerWert auf 0 (Kredit abbezahlt).
Tipp

Tipp
...................................................
Die Funktion PPmt liefert den Tilgungs- bzw. Kapitalanteil. Die Summe aus Tilgungs- bzw.
Kapitalanteil und Zins entspricht der von der Funktion Pmt gelieferten Rate.
Beispiel

Beis piel
...................................................
Das Projekt ZinsAnteil zeigt, wie sich Zins und Tilgung prozentual für einen Kredit beliebiger
Höhe bei einem Zinssatz von 10% p.a. über zehn Jahre hin entwickeln.
' Projekt: Annuität-Zinsanteil
Const Laufzeit = 10 * 12
Const Zins = 0.1 / 12
Const mRate = 100 ' 100 Prozent(!)

Private Sub Form_Load()


AutoRedraw = True
BarWert = PV(Zins, Laufzeit, mRate) ' Barwert in Prozent (!)
' Kreditmodalitäten
Print "Laufzeit", Laufzeit; "Monate"
Print "Zins p.a.", Zins * 12 * 100; "%"
Print "Periode", "Zinsanteil (%)", "Tilgungsanteil (%)"
Print String(40, "=")
' prozentualen Zins- und Tilgungsanteil ausgeben.
For i = 1 To Laufzeit Step 12
Print i, Round(IPmt(Zins, i, Laufzeit, BarWert), 2),
Print Round(PPmt(Zins, i, Laufzeit, BarWert), 2)
Next i
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, NPer, NPV, Pmt, PPmt, PV

IRR- Funktion
Function IRR(dWerte() As Double[, vErwartet As Variant = 0.1)] As Double

1 00
Log- Funktion

Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion IRR (engl.: Internal Rate of
Return) liefert den internen Ertragssatz für eine via dWerte() spezifizierte Folge regelmäßiger
Ein- und Auszahlungen (Cash Flows). Fehlt der optionale Parameter vErwartet, rechnet die
Funktion mit dem Erwartungswert 0,1, ansonsten mit dem angegebenen Wert.
Anwendung

Anwendung
...................................................
Der interne Ertragssatz ist der Zinssatz für eine Investition, die aus Ein- und Auszahlungen in
regelmäßigen Abständen besteht, wobei sich aber das Verhältnis zwischen Ein- und Auszahlun-

Mathematische und finanzmathematische Funktionen und Anweisungen


gen mit der Zeit verschieben kann (wie bei einem neuen Unternehmen üblich, das zu Beginn
große Investitionen tätigt und seine Einnahmen erst mit der Zeit verbessert, bis der Break-even
überschritten ist). Für alle finanzmathematischen Funktionen gilt, dass Zahlungsausgänge
durch negative Zahlen und Zahlungseingänge durch positive Zahlen dargestellt werden. Die
Elemente des Arrays dWerte enthalten die Werte der Cash Flows. Dabei ist die Reihenfolge eine
wichtige Größe. IRR wird iterativ berechnet. IRR verwendet vErwartet als Startwert und wieder-
holt die Berechnung so lange, bis das Ergebnis auf 0,00001 Prozent genau ist. Wenn nach 20
Versuchen kein Ergebnis gefunden werden kann (im Allgemeinen, weil vErwartet zu schlecht
ist), generiert IRR den Laufzeitfehler 5.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt beispielhaft, wie die Analyse eines Unternehmens aussehen
kann:
Dim dWerte(9) As Double
dWerte(0) = -50000 ' Investition bei Gründung
dWerte(1) = -25000 ' Unternehmensaufbau
dWerte(2) = 0 ' Break Even
dWerte(3) = 5000 ' Erster Gewinn im vierten Jahr
dWerte(4) = -1000 ' Verlust wg. schwacher Konjunktur
dWerte(5) = 7000 ' Gewinn im sechsten Jahr
dWerte(6) = 21000 ' Gewinn im siebten Jahr
dWerte(7) = 45000 ' Gewinn im achten Jahr
dWerte(8) = 60000 ' Gewinn im neunten Jahr
dWerte(9) = 110000 ' Gewinn im zehnten Jahr
Print Round(IRR(dWerte) * 100, 2) ' 17,32 Prozent
Verwandte Befehle

Verwa ndte Befehle


...................................................
MIRR, Rate

Log- Funktion
Function Log(dZahl As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die natürliche Logarithmusfunktion Log ist die Umkehrfunktion zur Wachstumsfunktion Exp.
Sie liefert den Wert, mit dem man die Eulersche Konstante (2,71828182845905) potenzieren
muss, um dZahl zu erhalten.

1 01
Mathematische und finanzmathematische Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Print Log(2.71828182845905) ' Ausgabe: 1
Print Exp(Log(10)) ' Ausgabe: 10
Verwandte Befehle

Verwa ndte Befehle


...................................................
Exp

MIRR- Funktion
Function MIRR( _
Mathematische und finanzmathematische Funktionen und Anweisungen

dWerte() As Double, _
dZinsFinanz As Double, _
dZinsReinv As Double) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion MIRR (engl.: Modified Internal
Rate of Return) liefert den modifizierten internen Ertragssatz für eine via dWerte() spezifizierte
Folge regelmäßiger Ein- und Auszahlungen (Cash Flows). Im Gegensatz zu IRR rechnet MIRR mit
unterschiedlichen Zinssätzen für die Finanzierung ungedeckter Ausgaben (dZinsFinanz) und die
Reinvestition von Gewinnen (dZinsReinv).
Anwendung

Anwendung
...................................................
Die beiden Zinswerte, dZinsFinanz und dZinsReinv, sind als Faktoren (Prozentwert dividiert
durch 100) anzugeben.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt beispielhaft, wie die Analyse eines Unternehmens aussehen
kann, wenn für Investitionen ein Zins von 10% und für Reinvestitionen der interne Ertragssatz
des Unternehmens angesetzt wird:
Dim dWerte(9) As Double
dWerte(0) = -50000 ' Investition bei Gründung
dWerte(1) = -25000 ' Unternehmensaufbau
dWerte(2) = 0 ' Break Even
dWerte(3) = 5000 ' Erster Gewinn im vierten Jahr
dWerte(4) = -1000 ' Verlust wg. schwacher Konjunktur
dWerte(5) = 7000 ' Gewinn im sechsten Jahr
dWerte(6) = 21000 ' Gewinn im siebten Jahr
dWerte(7) = 45000 ' Gewinn im achten Jahr
dWerte(8) = 60000 ' Gewinn im neunten Jahr
dWerte(9) = 110000 ' Gewinn im zehnten Jahr
Print Round(IRR(dWerte) * 100, 2) ' 17,32 Prozent
Print Round(MIRR(dWerte, 0.1, IRR(dWerte)) * 100, 2) ' 17,04 Prozent
Verwandte Befehle

Verwa ndte Befehle


...................................................
IRR, Rate

1 02
NPer- Funktion

NPer- Funktion
Function NPer( _
dZins As Double, _
dRate As Double, _
dBarwert As Double, _
[vZukünftigerWert], _
[vTermin]) _
As Double
Beschreibung

Bes c hreibung
...................................................

Mathematische und finanzmathematische Funktionen und Anweisungen


Die zu den finanzmathematischen Funktionen zählende Funktion NPer (engl.: Number of Peri-
ods) liefert die Laufzeit (Anzahl der Zahlungsperioden) einer Annuität mit konstantem Zins
dZins und dem Barwert dBarwert (vgl. die Funktion »PV-Funktion« S. 106). Der optionale Para-
meter vZukünftigerWert (vgl. »FV-Funktion«, S. 98) ermöglicht die Angabe eines zukünftigen
Werts, der den nach der letzten Zahlung erreichten Kontostand angibt. Bei einem Kredit ist die-
ser Wert im Allgemeinen mit 0 anzugeben, was dem Vorgabewert für den Parameter entspricht.
Fehlt der optionale Parameter vTermin oder ist er 0, geht die Funktion davon aus, dass die
Ratenzahlung jeweils zu Ende einer Periode erfolgt; ist der Wert dagegen 1, geht die Funktion
davon aus, dass die Ratenzahlung jeweils zu Beginn einer Periode erfolgt.
Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dZins, dRate auf denselben Einheitszeitraum
(meist Monat oder Jahr) bezogen sein müssen, wie der von der Funktionen erwartete Wert. Für
alle finanzmathematischen Funktionen gilt, dass Zahlungsausgänge durch negative Zahlen und
Zahlungseingänge durch positive Zahlen dargestellt werden. Wird die Funktion zur Berech-
nung eines Kredits eingesetzt, ist für dBarwert die Kredithöhe als negativer Wert zu spezifizie-
ren. Wird die Funktion zur Berechnung einer Ansparung eingesetzt, ist für dBarwert der augen-
blickliche Wert der Ansparung als positiver Wert anzugeben und für vZukünftigerWert das
Sparziel als negativer Wert.
Beispiel

Beis piel
...................................................
Das folgende Codefragment berechnet die Laufzeit für einen Kredit über 7.000 € zu 10% p.a.
sowie die Laufzeit einer Ansparung zu denselben Bedingungen:
Print NPer(0.1 / 12, 100, -7000) ' Laufzeit f. Kredit: 106
Print NPer(0.1 / 12, 100, 0, -7000) ' Laufzeit f. Ansparung: 55
Auf dieselben Ergebnisse kommt man auch mittels:
Print -NPer(0.1 / 12, 100, 0, 7000) ' Laufzeit f. Kredit: 106
Print -NPer(0.1 / 12, 100, 7000) ' Laufzeit f. Ansparung: 55
Warnung

Wa rnung
...................................................
Die Funktion liefert einen Laufzeitfehler, wenn die Kreditlaufzeit bei gegebenem Zins und gege-
bener Rate über alle Grenzen wachsen würde, sprich: die Rate zu klein ist, als dass jemals eine
Tilgung erfolgen könnte. (Solche Kredite würden Banken natürlich am liebsten geben: Man
zahlt ein Leben lang, und die Schulden werden immer größer.)
Print NPer(0.1 / 12, 100, -20000) ' Laufzeitfehler

1 03
Mathematische und finanzmathematische Funktionen und Anweisungen

Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, IPmt, NPV, Pmt, PPmt, PV

NPV- Funktion
Function NPV(dDiskontsatz As Double Werte() As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion NPV (engl.: Net Present Value)
liefert den Nettobarwert einer Investition für eine via dWerte() spezifizierte Folge regelmäßiger
Mathematische und finanzmathematische Funktionen und Anweisungen

Ein- und Auszahlungen (Cash Flows) bei festem Diskontsatz dDiskontsatz.


Anwendung

Anwendung
...................................................
Der Nettobarwert einer Investition ist der aktuelle Wert einer Folge zukünftiger regelmäßiger
Aus- und Einzahlungen. Für alle finanzmathematischen Funktionen gilt, dass Zahlungsaus-
gänge durch negative Zahlen und Zahlungseingänge durch positive Zahlen dargestellt werden.
Die Elemente des Arrays dWerte enthalten die Werte der erwarteten Cash Flows. Dabei ist die
Reihenfolge eine wichtige Größe. Die Investition beginnt mit dem Zeitraum des ersten Cash-
Flow-Werts und endet mit dem Auftreten des letzten Cash-Flow-Werts.
Im Gegensatz zur Funktion PV, die den Barwert einer Folge von Zahlungen unveränderlicher
Höhe bei konstantem Zins und konstanter Laufzeit berechnet, erlaubt NPV Zahlungen unter-
schiedlicher Höhe (und Vorzeichen) und ermittelt die Laufzeit selbstständig aus der Anzahl der
Werte. Die Funktion geht davon aus, dass die Zahlungen jeweils zum Ende der Zahlungsperio-
den erfolgen. Bezieht sich der erste Cash Flow auf den Beginn des ersten Zeitraums, so muss die
Folge mit der zweiten Zahlung beginnen und die erste Zahlung gesondert zum Ergebnis von NPV
addiert werden.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt beispielhaft, wie die NPV-Analyse für ein Unternehmen aus-
sehen kann:
Dim dWerte(9) As Double
dWerte(0) = -50000 ' Investition bei Gründung
dWerte(1) = -25000 ' Unternehmensaufbau
dWerte(2) = 0 ' Break Even
dWerte(3) = 5000 ' Erster Gewinn im vierten Jahr
dWerte(4) = -1000 ' Verlust wg. schwacher Konjunktur
dWerte(5) = 7000 ' Gewinn im sechsten Jahr
dWerte(6) = 21000 ' Gewinn im siebten Jahr
dWerte(7) = 45000 ' Gewinn im achten Jahr
dWerte(8) = 60000 ' Gewinn im neunten Jahr
dWerte(9) = 110000 ' Gewinn im zehnten Jahr
Print NPV(0.1, dWerte) ' 40254
Verwandte Befehle

Verwa ndte Befehle


...................................................
MIRR, Rate

1 04
Pmt- Funktion

Pmt- Funktion
Function Pmt( _
dZins As Double, _
dLaufzeit As Double, _
dBarwert As Double, _
[vZukünftigerWert], _
[vTermin]) _
As Double
Beschreibung

Bes c hreibung
...................................................

Mathematische und finanzmathematische Funktionen und Anweisungen


Die zu den finanzmathematischen Funktionen zählende Funktion Pmt (engl.: Payment) liefert
die zu zahlende Rate zu einer Annuität mit einer Laufzeit von dLaufzeit Zahlungsperioden,
konstantem Zins dZins und dem Barwert dBarwert (vgl. die Funktion »PV-Funktion«, S. 106).
Der optionale Parameter vZukünftigerWert (vgl. die Funktion »FV-Funktion«, S. 98) ermöglicht
die Angabe eines zukünftigen Werts, der den nach der letzten Zahlung erreichten Kontostand
angibt. Bei einem Kredit ist dieser Wert im Allgemeinen mit 0 anzugeben, was dem Vorgabe-
wert für den Parameter entspricht. Fehlt der optionale Parameter vTermin oder ist er 0, geht die
Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode erfolgt; ist der Wert
dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Beginn einer Periode
erfolgt.
Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dZins und dLaufzeit auf denselben Einheitszeit-
raum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen Funktionen
gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch positive Zah-
len dargestellt werden. Für die Kreditberechnung setzen Sie dBarwert auf die Höhe des Kredits
(Zahlungsausgang) und vZukünftigerWert auf 0 (Kredit abbezahlt).
Tipp

Tipp
...................................................
Die Funktionen IPmt und PPmt liefern den Zinsanteil und den Kapitalanteil zu einer bestimmten
Periode. Die Summe aus Kapitalanteil und Zinsanteil entspricht der von Pmt gelieferten Rate.
Beispiel

Beis piel
...................................................
Sie wollen einen Kredit über 250.000 € mit einer Laufzeit von 20 Jahren und einem festen Zins-
satz von 8,3% aufnehmen. Die monatliche Rate berechnet sich dann zu:
Print Pmt(.083 / 12, 20 * 12, -250000) ' Ausgabe: 2138
Die gleichen 250.000 € im Rahmen einer Lebensversicherung mit 4,6% Kapitalverzinsung
angespart, ergibt eine monatliche Rate von:
Print Pmt(.046 / 12, 20 * 12, 0, -250000) ' Ausgabe: 636,82
Man sieht, Geben ist eben doch billiger denn Nehmen.
Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, IPmt, NPer, NPV, PPmt, PV

1 05
Mathematische und finanzmathematische Funktionen und Anweisungen

PPmt- Funktion
Function PPmt( _
dZins As Double, _
dPeriode As Double, _
dLaufzeit As Double, _
dBarwert As Double, _
[vZukünftigerWert], _
[vTermin]) _
As Double
Beschreibung

Bes c hreibung
...................................................
Mathematische und finanzmathematische Funktionen und Anweisungen

Die zu den finanzmathematischen Funktionen zählende Funktion PPmt (engl.: Principal


Payment) liefert den Kapitalanteil in der Periode dPeriode zu einer Annuität mit einer Laufzeit
von dLaufzeit Zahlungsperioden, konstantem Zins dZins und dem Barwert dBarwert (vgl. »PV-
Funktion«, S. 106). Der optionale Parameter vZukünftigerWert (vgl. »FV-Funktion«, S. 98)
ermöglicht die Angabe eines zukünftigen Werts, der den nach der letzten Zahlung erreichten
Kontostand angibt. Bei einem Kredit ist dieser Wert im Allgemeinen mit 0 anzugeben, was dem
Vorgabewert für den Parameter entspricht. Fehlt der optionale Parameter vTermin oder ist er 0,
geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode erfolgt; ist
der Wert dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Beginn
einer Periode erfolgt.
Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dZins, dPeriode und dLaufzeit auf denselben
Einheitszeitraum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen
Funktionen gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch
positive Zahlen dargestellt werden. Die Funktion wird im Allgemeinen zur Berechnung von
Krediten eingesetzt und liefert dann den Tilgungsanteil zu einer bestimmten Periode. Für die
Kreditberechnung setzen Sie dBarwert auf die Höhe des Kredits (Zahlungsausgang) und vZu-
künftigerWert auf 0 (Kredit abbezahlt).
Tipp

Tipp
...................................................
Die Funktion IPmt liefert den Zinsanteil. Die Summe aus Tilgungs- bzw. Kapitalanteil und Zins
entspricht der von der Funktion Pmt gelieferten Rate.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel in »IPmt-Funktion« (S. 99).
Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, IPmt, NPer, NPV, Pmt, PV

PV- Funktion
Function PV( _
dZins As Double, _
dLaufzeit As Double, _
dRate As Double, _
[vJetztWert], _
[vTermin]) _
As Double

1 06
Randomize- Anweisung

Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion PV (engl.: Payment Value) lie-
fert den Barwert einer Annuität mit einer Laufzeit von dLaufzeit Zahlungsperioden, konstan-
tem Zins dZins und der Rate dRate. Der optionale Parameter vJetztWert ermöglicht die Angabe
eines Ausgangswerts bei bereits erfolgter Ansparung. Fehlt der optionale Parameter vTermin
oder ist er 0, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode
erfolgt; ist der Wert dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu
Beginn einer Periode erfolgt.
Anwendung

Anwendung
...................................................

Mathematische und finanzmathematische Funktionen und Anweisungen


Beachten Sie, dass die Werte für die Parameter dZins und dLaufzeit auf denselben Einheitszeit-
raum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen Funktionen
gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch positive Zah-
len dargestellt werden. Die Funktion lässt sich sowohl zur Berechnung von Krediten als auch
von Ansparungen verwenden, wird aber vorzugsweise für die Ansparberechnung eingesetzt, da
der Barwert bei Krediten üblicherweise einen Ausgangswert darstellt. Bei der Kreditberechnung
sind dRate und dJetztWert als positive Werte anzugeben, bei der Ansparberechnung als negative
Werte.
Tipp

Tipp
...................................................
Die Funktionen PV und FV liefern mit vertauschten Vorzeichen für dRate und dJetztWert die
gleichen Ergebnisse.
Beispiel

Beis piel
...................................................
Das folgende Codefragment ermittelt den Barwert einer auf 100.000 € abgeschlossenen Lebens-
versicherung mit einer Laufzeit von 35 Jahren und einem Zinssatz von 4,45%:
Zins = 0.045/12
Laufzeit = 35 * 12
Ansparung = -100000
Raten = Pmt(Zins, Laufzeit, 0, Ansparung) ' 99,33
Barwert = PV(Zins, Laufzeit, Raten) ' 21126,98
ZukWert = FV(Zins, Laufzeit, Raten) ' 100000 Probe stimmt!
Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, IPmt, IRR, NPer, NPV, Pmt, PPmt

Randomize- Anweisung
Sub Randomize ([vSeed])
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Randomize initialisiert den Zufallsgenerator mit einem Startwert (engl.: Seed).
Ausgehend von diesem Startwert lässt sich mittels der Zufallsfunktion Rnd eine gleich verteilte
Sequenz von Zufallszahlen berechnen. Zu einem bestimmten Startwert liefert der Zufallsfunk-
tion Rnd immer die gleiche Folge. Dabei benutzt sie jeweils den zuletzt gelieferten Wert als neuen
Startwert. Fehlt vSeed, nimmt die Anweisung den von der Funktion Timer gelieferten Wert als
Startwert.

1 07
Mathematische und finanzmathematische Funktionen und Anweisungen

Anwendung

Anwendung
...................................................
Eine wirklich zufällige Initialisierung des Zufallsgenerators lässt sich erreichen, indem man den
Wert der Funktion Timer als Startwert benutzt, der die Anzahl der seit Mitternacht (Systemzeit)
vergangenen Sekunden liefert. Wird Randomize in einem Programm dagegen gar nicht ausge-
führt, arbeitet Visual Basic mit dem Vorgabewert 0 als Startwert.
Um im gleichen Programmlauf mehrere Folgen von Zufallszahlen mit deterministischem Start-
wert zu erzeugen, übergeben Sie der Funktion Rnd jeweils bei Berechnung des letzten Folgenele-
ments einen negativen Wert und rufen danach Randomize mit dem Startwert der nächsten Folge
auf.
Mathematische und finanzmathematische Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Der Startwert 10 sorgt dafür, dass Rnd reproduzierbar die folgende »Zufallsfolge«
{0,5749933; 0,2375866; 0,5295308; 0,2520258} generiert:
Randomize 10
Print Rnd(1), Rnd(1), Rnd(1), Rnd(1) ' Folge für Startwert 10
Rnd(-1) ' Randomize vorbereiten
Randomize Timer
Print Rnd(1), Rnd(1), Rnd(1), Rnd(1) ' wirklich zufällige Folge
Verwandte Befehle

Verwa ndte Befehle


...................................................
Rnd

Rate- Funktion
Function Rate( _
dLaufzeit As Double, _
dRate As Double, _
dBarWert As Double, _
[vZukünftigerWert], _
[vTermin]) _
[vSchätzung As Variant = 0.1]
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion Rate liefert den Zinssatz einer
Annuität mit dem Barwert (vgl. »PV-Funktion«, S. 106) dBarWert, einer Laufzeit von dLaufzeit
Zahlungsperioden und der Zahlungsrate dRate. Der optionale Parameter vZukünftigerWert (vgl.
»FV-Funktion«, S. 98) ermöglicht die Angabe eines zukünftigen Werts, der den nach der letzten
Zahlung erreichten Kontostand angibt. Bei einem Kredit ist dieser Wert im Allgemeinen mit 0
anzugeben, was dem Vorgabewert für den Parameter entspricht. Umgekehrt ist bei einer Anspa-
rung dBarWert mit 0 anzugeben. Fehlt der optionale Parameter vTermin oder ist er 0, geht die
Funktion davon aus, dass die Ratenzahlung jeweils zu Ende einer Periode erfolgt; ist der Wert
dagegen 1, geht die Funktion davon aus, dass die Ratenzahlung jeweils zu Beginn einer Periode
erfolgt. Da die Funktion das Ergebnis mit einem iterativen Verfahren berechnet, benötigt sie für
den Start der Iteration einen Schätzwert vSchätzung. Fehlt dieser optionale Parameter, arbeitet
die Funktion mit dem Vorgabewert 0,1.

1 08
Rnd- Funktion und Rnd- Anweisung

Anwendung

Anwendung
...................................................
Beachten Sie, dass die Werte für die Parameter dRate und dLaufzeit auf denselben Einheitszeit-
raum (meist Monat oder Jahr) bezogen sein müssen. Für alle finanzmathematischen Funktionen
gilt, dass Zahlungsausgänge durch negative Zahlen und Zahlungseingänge durch positive Zah-
len dargestellt werden. Die Funktion lässt sich sowohl bei der Berechnung von Krediten als
auch von Ansparungen verwenden. Bei der Kreditberechnung ist dBarwert als negativer Wert
anzugeben, bei der Ansparberechnung dBarwert als 0 und dZukünftigerWert als negativer Wert.
Beispiel

Beis piel
...................................................
Das folgende Codefragment ermittelt den Zins in Prozent für eine Ansparung über 250.000 €

Mathematische und finanzmathematische Funktionen und Anweisungen


mit einer Laufzeit von 35 Jahren und einer monatlichen Rate von 250 €:
dLaufzeit = 35 * 12
dZukWert = -250000
dRate = 250
Print Rate(dLaufzeit, dRate, 0, dZukWert) * 1200; "%" ' Ausgabe: 4,42 %
Verwandte Befehle

Verwa ndte Befehle


...................................................
FV, IPmt, NPer, NPV, Pmt, PPmt, PV

Rnd- Funktion und Rnd- Anweisung


Function Rnd [(vSchalter)] As Single
Sub Rnd ([vSchalter])
Beschreibung

Bes c hreibung
...................................................
Rnd lässt sich sowohl als Funktion als auch als Anweisung verwenden. Die Anweisung unter-
scheidet sich von der Funktion nur insoweit, als sie keinen Wert liefert. Die Zufallsfunktion Rnd
ermittelt ausgehend von einem Startwert eine Zufallszahl mit dem Datentyp Single, die dem
halboffenen Intervall [0; 1[ entstammt. Die Berechnung ist gleichverteilt, das heißt, jede der im
Intervall als Single darstellbaren Zahlen wird mit gleicher Wahrscheinlichkeit ermittelt.
Der Wert des optionalen Parameters vSchalter bestimmt, wie die Funktion mit dem Startwert
verfährt. Fehlt der Parameter oder ist sein Wert größer als 0, berechnet die Funktion jeweils die
nächste Zufallszahl aus der vorangegangenen, indem sie diese als Startwert verwendet. Damit
liefert Rnd eine deterministische Folge von Zufallszahlen, die durch den ersten Startwert ausge-
wählt wird. Standardmäßig initialisiert Visual Basic den Startwert für jeden Programmlauf auf
0, so dass Rnd ohne weitere Vorkehrungen in der Tat die immer gleiche Folge liefert. Um eine
andere Folge auszuwählen, muss der Startwert zuvor mittels der Anweisung Randomize explizit
gesetzt werden. Hat der Parameter vSchalter den Wert 0, liefert Rnd erneut die vorangegangene
Zufallszahl. Ist vSchalter dagegen ein negativer Wert, legt die Funktion dem nächsten Aufruf
den durch Randomize (erneut) gesetzten Startwert zugrunde.
Anwendung

Anwendung
...................................................
Im Allgemeinen wird man vor dem ersten Rnd-Aufruf einen Randomize-Aufruf setzen, der für
eine Auswahl der Zufallsfolge sorgt. Eine wirklich zufällige Initialisierung des Zufallsgenerators
lässt sich erreichen, indem man den Wert der Funktion Timer, die die Anzahl der seit Mittnacht
(Systemzeit) vergangenen Sekunden liefert, als Startwert einsetzt. Dazu reicht es, Randomize
ohne Angabe eines Parameters auszuführen. Um im gleichen Programmlauf mehrere Folgen von
Zufallszahlen mit deterministischem Startwert zu erzeugen, setzen Sie vor jeden Randomize-Auf-
ruf die Anweisung Rnd(-1).

1 09
Mathematische und finanzmathematische Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Vgl. das Beispiel zu »Randomize-Anweisung« (S. 107).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Randomize
Verwandte Themen

Verwandte Them en
...................................................
Zeitgeber-Steuerelement (Timer) (S. 432)
Mathematische und finanzmathematische Funktionen und Anweisungen

Round- Funktion
Function Round(dZahl As NumTyp, [iDezStellen As Integer = 0]) As NumTyp
Beschreibung

Bes c hreibung
...................................................
Die Rundungsfunktion Round führt eine Kaufmannsrundung durch. Fehlt der Parameter iDezi-
malstellen oder hat der den Wert 0, liefert die Funktion die nächste Ganzzahl in der Umgebung
von dZahl und führt dabei – im Gegensatz zu Fix und Int – eine echte Kaufmannsrundung
durch. Jeder andere positive Wert für iDezimalstellen benennt eine Dezimalstelle hinter dem
Komma, an der die Rundung stattfinden soll. Die Funktion richtet den Datentyp des Rückgabe-
werts nach dem Datentyp des Parameters.
Warnung

Wa rnung
...................................................
Wie das Beispiel zeigt, ist die Dezimalrechnung mit den Datentypen Single und Double nicht
immer exakt. Das liegt daran, dass die Repräsentation dieser Werte intern im hexadezimalen
bzw. echten binären Zahlenformat erfolgt und viele endliche Dezimalbrüche im binären Zah-
lensystem nur als unendliche Binärbrüche darstellbar sind. Im Zusammenhang mit der Funk-
tion Round kann das zu peinlichen Fehlern führen. Wenn Sie Exaktheit benötigen, müssen Sie
mit einem der Datentypen Currency oder Decimal rechnen.
Beispiel

Beis piel
...................................................
Print Round(14.005, 2) ' 14 (erwartet: 14,01)
Print Round(14.015, 2) ' 14,02 (korrekt)
Print Round(14.025, 2) ' 14,02 (erwartet 14,03)
Print Round(14.035, 2) ' 14,04 (korrekt)
Print Round(14.045, 2) ' 14,04 (erwartet 14,03)
Print Round(14.055, 2) ' 14,06 (korrekt)
Verwandte Befehle

Verwa ndte Befehle


...................................................
CInt, Fix, Int

Sgn- Funktion
Function Sgn(dZahl As NumTyp) As Integer
Beschreibung

Bes c hreibung
...................................................
Die Vorzeichenfunktion Sgn liefert das Vorzeichen des Werts dZahl als Faktor. Das Ergebnis ist
1, wenn dZahl positiv ist, 0, wenn dZahl 0 ist, und -1, wenn dZahl negativ ist.

110
Sgn- Funktion

Anwendung

Anwendung
...................................................
Die Funktion Sgn ist zuweilen nützlich, wenn es darum geht, Laufzeitoptimierungen vorzuneh-
men und If-Anweisungen durch geschicktere Formulierung logischer Ausdrücke zu vereinfa-
chen oder ganz zu vermeiden.
Beispiel

Beis piel
...................................................
Die folgende Zeile wird erheblich schneller verarbeitet als die auskommentierte If-Anweisung
(allerdings haben die beiden Formulierungen nicht die gleiche Semantik, da Nullwerte nicht
mitgezählt werden):

Mathematische und finanzmathematische Funktionen und Anweisungen


Dim lZähler As Long
Zeit = Timer ' Laufzeitmessung beginnen
For i = 1 To 1000000
zv = Rnd – 0.5
lZähler = lZähler + Sgn(zv)
' If zv > 0 Then lZähler = lZähler + 1 Else lZähler = lZähler – 1
Next
Caption = Timer – Zeit ' Laufzeit als Titelzeile ausgeben
In der folgenden, dem Projekt Apfelmann entstammenden Routine führt die Formulierung der
zeitaufwändigen If-Abfrage mit den Funktionen Abs und Sgn zu einer Laufzeitverbesserung um
immerhin ca. 30 %. Messen Sie es nach, indem Sie einmal die eine und einmal die andere Zeile
auskommentieren!
Private Sub Apfel(m_x1, m_x2, m_y1, m_y2, step_x, step_y)
Dim r1 As Double, re As Double, im As Double
Dim zr As Double, zi As Double, it As Long

Zeit = Timer
For zr = m_x1 To m_x2 Step step_x ' alle Spalten in x-Richtung
For zi = m_y1 To m_y2 Step step_y ' alle Punkte in Spalte zr
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
For it = 0 To cMaxIterat ' Iteration für Punkt
r1 = re * re – im * im + zr
im = 2 * re * im + zi
re = r1
' If re < -cGrenze Or re > cGrenze Or im < -cGrenze Or im > cGrenze Then
If Sgn(cGrenze – Abs(re)) + Sgn(cGrenze – Abs(im)) = -2 Then
PSet (zr, zi), it * 16 ' Punkt ausgeben
Exit For
End If
Next it
Next zi
Next zr
Caption = Timer – Zeit
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
CInt, Fix, Int

111
Mathematische und finanzmathematische Funktionen und Anweisungen

Sin- Funktion
Function Sin(dWinkel As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den trigonometrischen Funktionen zählende Sinusfunktion Sin liefert den Sinus zu dem
im Bogenmaß angegebenen Winkel dWinkel. Das Ergebnis der Funktion liegt immer im Intervall
[-1; 1]. Für die Umwandlung eines Gradwerts in das Bogenmaß ist der Wert mit π/180 =
1,74532925199433E-02 zu multiplizieren.
Anwendung

Anwendung
...................................................
Mathematische und finanzmathematische Funktionen und Anweisungen

Diese Funktion berechnet aus dem Winkel zwischen Ankathete und Hypothenuse die Gegenka-
thete eines rechtwinkligen Dreiecks mit Hypothenuse 1.
Beispiel

Beis piel
...................................................
Dim Pi As Double
Pi = Atn(1) * 4 ' 3.14159265358979
Print Sin(Pi / 6) ' Ausgabe: 0,5 [= Sin(30°)]
Verwandte Befehle

Verwa ndte Befehle


...................................................
Atn, Cos, Tan

SLN- Funktion
Function SLN( _
dAnschaffungsKosten As Double, _
dRestwert As Double, _
dNutzungsDauer As Double) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion SLN (engl.: Straight Line De-
preciation) berechnet die periodische Abschreibung einer Investition dAnschaffungsKosten mit
dem Restwert dRestwert über die Nutzungsdauer dNutzungsDauer nach dem linearen (arithme-
tischen) Abschreibungsmodell.
Anwendung

Anwendung
...................................................
Der von SLN gelieferte Wert bezieht sich auf die gleiche Einheit (Monate oder Jahre) wie dNut-
zungsDauer. Er errechnet sich wie folgt:
Anschaffungswert – Endwert
SLN = ---------------------------------------------------------------------------
Nutzungsdauer
Beispiel

Beis piel
...................................................
Print SLN(10000, 100, 10) ' Ausgabe 990
Verwandte Befehle

Verwa ndte Befehle


...................................................
DDB, SYD

112
Sqr- Funktion

Sqr- Funktion
Function Sqr(dPositiveZahl As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die Wurzelfunktion Sqr liefert die Quadratwurzel von dPositiveZahl. Ist der Wert von dPosi-
tiveZahl negativ, meldet die Funktion einen Laufzeitfehler.
Beispiel

Beis piel
...................................................
Das folgende Codefragment berechnet die Lösung(en) der allgemeinen quadratischen Gleichung
ax² + bx +c = 0:

Mathematische und finanzmathematische Funktionen und Anweisungen


det = (b * b – 4 * a * c)
If det < 0 Then Print "Keine Lösung"
If det = 0 Then Print "x1, x2 = "; -b / 2 / a
If det > 0 Then
Print "x1 = "; (-b + det) / 2 / a
Print "x2 = "; (-b – det) / 2 / a
End If
Verwandte Befehle

Verwa ndte Befehle


...................................................
^ (Operator)

SYD- Funktion
Function SYD( _
dAnschaffungsKosten As Double, _
dRestwert As Double, _
dNutzungsDauer As Double_
dPeriode As Double) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den finanzmathematischen Funktionen zählende Funktion SYD (engl.: Sum of Years De-
preciation) berechnet die periodische Abschreibung einer Investition dAnschaffungsKosten mit
dem Restwert dRestwert über die Nutzungsdauer dNutzungsDauer für die Periode dPeriode nach
dem Abschreibungsmodell der Jahressummengewichtung.
Beispiel

Beis piel
...................................................
Der folgende Code zeigt eine alternative Implementation der Funktion SYD:
Function MySYD(Wert, Rest, Nutzung, per)
d = Nutzung * (Nutzung + 1) / 2
MySYD = (Wert – Rest) / d * (Nutzung + 1 – per)
End Function
Beide Funktionen liefern die gleichen Werte:
For per = 1 To 10
Print SYD(10000, 100, 10, per), ' 1800, 1620, 1440, 1260,...
Print MySYD(10000, 100, 10, per) ' 1800, 1620, 1440, 1260,...
Next

113
Funktionen und Anweisungen für Datums- / Zeitwerte

Verwandte Befehle

Verwa ndte Befehle


...................................................
DDB, SLN

Tan- Funktion
Function Tan(dWinkel As Double) As Double
Beschreibung

Bes c hreibung
...................................................
Die zu den trigonometrischen Funktionen zählende Tangensfunktion Tan liefert den Tangens zu
dem im Bogenmaß angegebenen Winkel dWinkel. Die Umkehrfunktion zu Tan ist Atn. Für die
Funktionen und Anweisungen für Datums- / Zeitwerte

Umwandlung von Grad in das Bogenmaß ist der Wert mit π/180 = 1,74532925199433E-02 zu
multiplizieren.
Anwendung

Anwendung
...................................................
Diese Funktion berechnet aus dem Winkel zwischen Ankathete und Hypothenuse die Steigung
der Hypothenuse, welche ihrerseits als Quotient zwischen Ankathete und Gegenkathete defi-
niert ist.
Beispiel

Beis piel
...................................................
Dim Pi As Double
Pi = Atn(1) * 4 ' 3.14159265358979
Print Sin(Pi / 4) / Cos(Pi / 4) ' 1
Print Tan(Pi / 4) ' 1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Atn, Cos, Sin

Funktionen und Anweisungen für Datums- / Zeitwerte


Mit der zunehmenden Bedeutung von Visual Basic als Programmiersprache für Front-end-
Anwendungen im Datenbankbereich versteht es sich beinahe von selbst, dass die Sprache insbe-
sondere für solche Datentypen Äquivalente anbietet, die bei der Datenbankprogrammierung
gemeinhin als grundlegende Datentypen gehandelt werden. Die Welt der Datums-/Zeitwerte
und ihrer Operationen stellt nicht zuletzt aus diesem Grund neben der Welt der Zeichenfolgen
und der Welt der numerischen Datentypen eine eigene Kategorie dar, um die Visual Basic die
Sprache Basic bereichert hat. Werte des Typs Date repräsentiert Visual Basic als 64-Bit-Gleit-
kommazahlen (8 Bytes) nach IEEE und kann somit Datumsangaben im Bereich zwischen dem
1. Januar 100 und dem 31. Dezember 9999 sowie Uhrzeiten im Bereich von 0:00:00 bis
23:59:59 unterscheiden. Datumswerte können Datumsangaben und Zeitangaben kombinieren,
aber auch je einzeln ausdrücken. Der Notation literaler Datums- und Zeitangaben liegt das
amerikanische Format zugrunde, das heißt, in Datumsangaben wird der Monat vor dem Tag
notiert, die Abtrennung erfolgt durch das Zeichen »/«, und Zeitangaben sind in 12-Stunden-
Darstellung gefolgt von »PM« oder »AM« zu treffen. Zudem ist die Darstellung durch ein füh-
rendes und ein abschließendes #-Zeichen einzuschließen.
An Operationen für den Datentyp Date hält Visual Basic eine ganze Latte parat, die mehr oder
weniger etwas mit der Konvertierung unter Berücksichtigung verschiedener Notationen oder
mit der Extraktion einer bestimmten Teilinformation zu tun haben. Die folgende Tabelle gibt
einen Überblick über alle für diesen Datentyp relevanten Funktionen und Anweisungen:

114
Funktionen und Anweisungen für Datums- / Zeitwerte

Bezeichner Kurzbeschreibung
CDate Interpretiert eine Zeichenfolge oder einen Zahlenwert als Datums-/Zeit-
wert
Date Liefert das aktuelle Systemdatum als Datums-/Zeitwert
Date Setzt den Datumsanteil von Datums-/Zeitwert als aktuelles Systemdatum
DateAdd Berechnet die Summe aus einem Datums-/Zeitwert und einem Zeitinter-
vall, das wahlweise in Sekunden, Minuten, Stunden, Tage etc. anzugeben
ist

Funktionen und Anweisungen für Datums- / Zeitwerte


DateDiff Berechnet das Zeitintervall zwischen zwei Datums-/Zeitwerten und liefert
das Ergebnis wahlweise in einer der Einheiten Sekunden, Minuten, Stun-
den, Tage etc.
DatePart Liefert eine Teilinformation aus einem Datums-/Zeitwert, wahlweise
Sekunden, Minuten, Stunden, Tage etc.
DateSerial Setzt einen Datums-/Zeitwert aus Ganzzahlwerten (Tag, Monat und Jahr)
zusammen
DateValue Interpretiert eine Zeichenfolge oder einen Zahlenwert als Datumsanteil
von Datums-/Zeitwert
Day Liefert den Tag aus einem Datums-/Zeitwert als Zahlenwert (1 bis 31)
FileDateTime Liefert den Zeitpunkt der Erstellung bzw. letzten Änderung einer Datei als
Datums-/Zeitwert
FormatDateTime Liefert die Darstellung eines Datums-/Zeitwerts als Zeichenfolge im spezi-
fizierten Format
Hour Liefert die Stunde aus einem Datums-/Zeitwert als Zahlenwert (0 bis 23)
Minute Liefert die Minute aus einem Datums-/Zeitwert als Zahlenwert (0 bis 59)
Month Liefert den Monat aus einem Datums-/Zeitwert als Zahlenwert (1 – 12)
MonthName Liefert für einen Zahlenwert zwischen 1 und 12 den Monatsnamen als Zei-
chenfolge
Now Liefert Systemdatum und -zeit als Datums-/Zeitwert
Second Liefert die Sekunde aus einem Datums-/Zeitwert als Zahlenwert (0 bis 59)
Time Liefert die aktuelle Systemzeit als Datums-/Zeitwert
Time Setzt den Zeitanteil von Datums-/Zeitwert als aktuelle Systemzeit
Timer Liefert den Wert des System-Timers (Sekunden seit Mitternacht)
TimeSerial Setzt einen Datums-/Zeitwert aus Ganzzahlwerten (Sekunde, Minute,
Stunde) zusammen
TimeValue Interpretiert eine Zeichenfolge oder einen Zahlenwert als Zeitanteil eines
Datums-/Zeitwerts
WeekDay Liefert den Wochentag aus einem Datums-/Zeitwert als Zahl (1 bis 7)
WeekDayName Liefert den Wochentag als Zeichenfolge für Werte zwischen 1 und 7
Year Liefert das Jahr aus einem Datums-/Zeitwert als Zahlenwert
Auf Datum und Zeit bezogene Funktionen und Anweisungen

115
Funktionen und Anweisungen für Datums- / Zeitwerte

CDate- Funktion
Function CDate(vWert) As Date
Siehe »Typumwandlung« (S. 57).

Date- Funktion und Date- Anweisung


Function Date() As Date
Date = datDatum
Beschreibung

Bes c hreibung
...................................................
Funktionen und Anweisungen für Datums- / Zeitwerte

Als Funktion liefert Date das aktuelle Systemdatum und als Anweisung setzt Date das aktuelle
Systemdatum (dauerhaft).
Beispiel

Beis piel
...................................................
Immer häufiger spielen sich Shareware-Programme als Timeware-Programme auf, indem sie
nach einer gewissen Zeit überraschend die Arbeit einstellen und einen so dazu »überreden«
wollen, sich für die Vollversion registrieren zu lassen. Für die Übergangszeit bietet sich ein klei-
nes Visual-Basic-Programm namens SharewareTrick an, das kurz am Systemdatum dreht:
Dim datSystem As Date

Private Sub Form_Load()


datSystem = Date
Date = "1.1.00"
Zeitware = Shell("notepad.exe", vbNormalFocus)
Timer1.Interval = 10000
End Sub

Private Sub Timer1_Timer()


Timer1.Interval = 0
Date = datSystem
End
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Now, Time

DateAdd- Funktion
Function DateAdd(Interval As String, Number As Double, Date) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion DateAdd addiert zu einem gegebenen Datums-/Zeitwert Date ein Zeitintervall Num-
ber, dem die Einheit Interval zugrunde gelegt ist.

Wert für Interval Beschreibung


"yyyy" Die Funktion interpretiert Number als Jahre
"q" Die Funktion interpretiert Number als Quartale
"m" Die Funktion interpretiert Number als Monate

116
DateDiff- Funktion

Wert für Interval Beschreibung


"ww" Die Funktion interpretiert Number als Wochen
"d", "w", "y" Die Funktion interpretiert Number als Tage
"h" Die Funktion interpretiert Number als Stunden
"n" Die Funktion interpretiert Number als Minuten
"s" Die Funktion interpretiert Number als Sekunden

Anwendung

Anwendung
...................................................

Funktionen und Anweisungen für Datums- / Zeitwerte


Der Datentyp Date verwendet für die interne Darstellung von Datums-/Zeitwerten einen Wert
vom Typ Double, der sich nicht so ohne Weiteres in seine Bestandteile (Sekunden, Minuten,
Stunden, Tage, Wochen, Monate Jahre) zerlegen lässt. Mit der Funktion DateAdd stellt Visual
Basic ein bequemes Mittel für das Rechnen mit Zeitwerten zur Verfügung.
Beachten Sie, dass der Wertebereich von Date auf Datums-/Zeitwerte zwischen dem 1.1.100
und dem 31.12.9999 beschränkt ist.
Beispiel

Beis piel
...................................................
Die folgende Zeile berechnet den Datums-/Zeitwert für ein Ereignis, das NewInterval Sekunden
in der Zukunft gelegen ist.
m_TriggerTime = DateAdd("s", NewInterval, Now)
Ein praxisnahes Beispiel für die Anwendung dieser Funktion ist das im Praxisteil vorgestellte
Projekt LongTimer (vgl. »LongTimer – der Timer mit Ausdauer«, S. 599).
Verwandte Befehle

Verwa ndte Befehle


...................................................
DateDiff, DatePart, DateSerial, DateValue, TimeSerial

DateDiff- Funktion
Function DateDiff(Interval As String, Date1, Date2,
[FirstDayOfWeek As VbFirstDayOfWeek = vbSunday], _
[FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1]) _
As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion DateDiff bildet die Differenz aus den beiden Datums-/Zeitwerten Date2 und Date1
und liefert das Ergebnis als Ganzzahl in der Einheit Interval. Die optionalen Parameter First-
DayOfWeek und FirstWeekOfYear beziehen sich auf exotische Formen der Datumsdarstellung und
können im Allgemeinen getrost weggelassen werden.

Wert für Interval Beschreibung


"yyyy" Funktion liefert das Ergebnis in der Einheit »Jahre»
"q" Funktion liefert das Ergebnis in der Einheit »Quartale»
"m" Funktion liefert das Ergebnis in der Einheit »Monate»
"w", "ww" Funktion liefert das Ergebnis in der Einheit »Wochen»

117
Funktionen und Anweisungen für Datums- / Zeitwerte

Wert für Interval Beschreibung


"d", "y" Funktion liefert das Ergebnis in der Einheit »Tage»
"h" Funktion liefert das Ergebnis in der Einheit »Stunden»
"n" Funktion liefert das Ergebnis in der Einheit »Minuten»
"s" Funktion liefert das Ergebnis in der Einheit »Sekunden»

Anwendung

Anwendung
...................................................
Der Datentyp Date verwendet für die interne Darstellung von Datums-/Zeitwerten einen Wert
Funktionen und Anweisungen für Datums- / Zeitwerte

vom Typ Double, der sich nicht so ohne Weiteres in seine Bestandteile (Sekunden, Minuten,
Stunden, Tage, Wochen, Monate Jahre) zerlegen lässt. Mit der Funktion DateDiff stellt Visual
Basic ein bequemes Mittel für das Rechnen mit Zeitwerten zur Verfügung.
Beachten Sie, dass der Wertebereich von Date auf Datums-/Zeitwerte zwischen dem 1.1.100
und dem 31.12.9999 beschränkt ist.
Warnung

Wa rnung
...................................................
Die Reihenfolge der Parameter Date1 und Date2 ist leider kontraintuitiv gewählt. DateDiff rech-
net: Date2 – Date1.
Beispiel

Beis piel
...................................................
Die folgende Zeile berechnet die Anzahl der Sekunden, die seit der Geburtsstunde des Autors
verstrichen sind:
Print DateDiff("s", #3/3/1959 11:32:00 PM#, Now)
Ein praxisnahes Beispiel für die Anwendung dieser Funktion ist das im Praxisteil vorgestellte
Projekt LongTimer (vgl. »LongTimer – der Timer mit Ausdauer«, S. 599).
Verwandte Befehle

Verwa ndte Befehle


...................................................
DateAdd, DatePart, DateSerial, DateValue, TimeSerial

DatePart- Funktion
Function DatePart( _
Interval As String,
Date,
[FirstDayOfWeek As VbFirstDayOfWeek = vbSunday], _
[FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1]) _
As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion DatePart extrahiert den über den Parameter Interval spezifizierten Bestandteil
des Datums-/Zeitwerts Date und liefert ihn als Wert vom Typ Long. Die optionalen Parameter
FirstDayOfWeek und FirstWeekOfYear beziehen sich auf exotische Formen der Datumsdarstel-
lung und können im Allgemeinen getrost weggelassen werden.

118
DateSerial- Funktion

Wert für Interval Beschreibung


"yyyy" Funktion extrahiert die Information »Jahre»
"q" Funktion extrahiert die Information »Quartale»
"m" Funktion extrahiert die Information »Monate»
"ww" Funktion extrahiert die Information »Wochen»
"w" Funktion extrahiert die Information »Tag der Woche»
"y" Funktion extrahiert die Information »Tag im Jahr»

Funktionen und Anweisungen für Datums- / Zeitwerte


"d" Funktion extrahiert die Information »Tag im Monat»
"h" Funktion extrahiert die Information »Stunden»
"n" Funktion extrahiert die Information »Minuten»
"s" Funktion extrahiert die Information »Sekunden»

Anwendung

Anwendung
...................................................
Der Datentyp Date verwendet für die interne Darstellung von Datums-/Zeitwerten einen Wert
vom Typ Double, der sich nicht so ohne Weiteres in seine Bestandteile (Sekunden, Minuten,
Stunden, Tage, Wochen, Monate Jahre) zerlegen lässt. Mit der Funktion DatePart stellt Visual
Basic ein bequemes Mittel für das Zerlegen von Datums-/Zeitwerten zur Verfügung.
Beispiel

Beis piel
...................................................
Print "Diese Woche ist die " & DatePart("ww", Now) & ". Kalenderwoche"
Verwandte Befehle

Verwa ndte Befehle


...................................................
Day, Hour, Minute, Month, MonthName, Second, WeekDay, Year

DateSerial- Funktion
Function DateSerial( _
iJahr As Integer, iMonat As Integer, iTag As Integer) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion DateSerial generiert aus den Ganzzahlwerten iTag, iMonat und iJahr einen
Datums-/Zeitwert.
Anwendung

Anwendung
...................................................
Die Funktion prüft die Werte der Parameter nicht, das heißt, sie löst auch keinen Laufzeitfehler
aus, wenn die Komponenten kein reelles Datum ergeben. Wichtig ist nur das Resultat: Es darf
sich kein Datum vor dem 1.1.100 und nach dem 31.12.9999 ergeben. Auf diese Weise gestattet
die Funktion sehr schön das Rechnen mit relativen Zeitangaben wie: heute, vor zwei Jahren,
drei Monaten, vier Tagen. Wenn Sie versuchen, dies allgemein »zu Fuß« auszurechnen, werden
Sie merken, dass Sie schnell in des Teufels Küche geraten, da die Monate unterschiedlich lang
sind und unser Gregorianische Kalender eine nicht unkomplizierte Schaltregel hat.

119
Funktionen und Anweisungen für Datums- / Zeitwerte

Beispiel

Beis piel
...................................................
Mit DateSerial gerät die Lösung des genannten Problems zum Einzeiler. Probieren Sie es aus;
für den 1.1.2001 stimmt die alternative Lösung, für den 1.1.2000 dagegen nicht.
d = Date
Date = "1.1.2000"
' Date = "1.1.2001"
Print DateSerial(Year(Date) – 2, Month(Date) – 3, Day(Date) – 4)
Print Date – 2 * 365 – 3 * 31 – 4 ' alternative Lösung
Date = d
Funktionen und Anweisungen für Datums- / Zeitwerte

Ein praxisnahes Beispiel für die Anwendung dieser Funktion ist das Projekt FormatDemo (vgl.
»Format-Funktion«, S. 69), das einen Halbjahreskalender ausgibt.
Verwandte Befehle

Verwa ndte Befehle


...................................................
TimeSerial

DateValue- Funktion
Function DateValue( sDatum As String) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion DateValue interpretiert die Zeichenfolge sDatum als Datum und generiert daraus
einen Datums-/Zeitwert. Falls die Zeichenfolge auch Zeitangaben enthält, werden diese nicht
berücksichtigt.
Anwendung

Anwendung
...................................................
Was die Notation des Datums betrifft, ist DateValue weitgehend tolerant. So ergänzt die Funk-
tion bei fehlendem Jahr das aktuelle Jahr aus dem Systemdatum des Computers und akzeptiert
darüber hinaus neben dem kurzen und dem langen Datumsformat (entsprechend den auf dem
System geltenden Datumseinstellungen) auch mittlere Datumsformate, in denen der Monat mit
mindestens drei Buchstaben abgekürzt ist und Tag und Monat gegebenenfalls vertauscht sind.
Tipp

Tipp
...................................................
CDate und TimeValue unterscheiden sich insofern, als CDate auch Werte anderer Datentypen als
String in einen Datums-/Zeitwert umsetzt und zusätzlich auch einen Zeitanteil berücksichtigt.
Beispiel

Beis piel
...................................................
Viele Wege führen nach Rom!
Print DateValue("1.2") ' "01.02.2000"
Print DateValue("1. Feb") ' "01.02.2000"
Print DateValue("1. Febr.") ' "01.02.2000"
Print DateValue("1. Februar 00") ' "01.02.2000"
Print DateValue("Feb, 1 00") ' "01.02.2000"
Print DateValue("00, Feb 01 ") ' "01.02.2000"
Print DateValue("1.2.00") ' "01.02.2000"
Print DateValue("1.2.2000 ") ' "01.02.2000"
Print DateValue("1. Feb") ' "01.02.2000"

1 20
Day- Funktion

Verwandte Befehle

Verwa ndte Befehle


...................................................
TimeSerial, CDate

Day- Funktion
Function Day(datWert As Date) As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion Day liefert den Tagesanteil des Datums-/Zeitwerts datWert als Ganzzahl zwischen
1 und 31.

Funktionen und Anweisungen für Datums- / Zeitwerte


Beispiel

Beis piel
...................................................
Siehe »Format-Funktion« (S. 69) und das dort vorgestellte Projekt FormatDemo.
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, Hour, Minute, Month, Second, Year

FileDateTime- Funktion
Function FileDateTime(sPfad As String) As Date
Siehe »FileDateTime-Funktion« (S. 139 ).

FormatDateTime- Funktion
Function FormatDateTime(vData, _
BenanntesFormat As VbDateTimeFormat = vbGeneralDate]) _
As String
Siehe »FormatDateTime-Funktion« (S. 74 ) und »Format-Funktion« (S. 69).

Hour- Funktion
Function Hour(datWert As Date) As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion Hour liefert den Stundenanteil des Datums-/Zeitwerts datWert als Ganzzahl zwi-
schen 0 und 23.
Beispiel

Beis piel
...................................................
Print "Es ist"; Minute(Time); " Minuten und "; Second(Time); _
"Sekunden nach"; Hour(Time)
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, Day, Minute, Month, Second, Year

Minute- Funktion
Function Minute(datWert As Date) As Integer

1 21
Funktionen und Anweisungen für Datums- / Zeitwerte

Beschreibung

Bes c hreibung
...................................................
Die Funktion Minute liefert den Minutenanteil des Datums-/Zeitwerts datWert als Ganzzahl
zwischen 0 und 59.
Beispiel

Beis piel
...................................................
Print "Es ist"; Minute(Time); " Minuten und "; Second(Time); _
"Sekunden nach"; Hour(Time)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Funktionen und Anweisungen für Datums- / Zeitwerte

DatePart, Day, Hour, Month, Second, Year

Month- Funktion
Function Month(datWert As Date) As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion Month liefert den Monatsanteil des Datums-/Zeitwerts datWert als Ganzzahl zwi-
schen 1 und 12.
Beispiel

Beis piel
...................................................
Siehe »Format-Funktion« (S. 69) und das dort vorgestellte Projekt FormatDemo.
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, Day, Hour, Minute, Second, Year

MonthName- Funktion
Function MonthName(lMonat As Long, bAbk As Boolean = False) As String
Siehe »MonthName-Funktion« (S. 82).

Now- Funktion
Function Now() As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion Now liefert die aktuelle Systemzeit mit Datums- und Zeitanteil.
Beispiel

Beis piel
...................................................
Print Now
Verwandte Befehle

Verwa ndte Befehle


...................................................
Time, Date

Second- Funktion
Function Second(datWert As Date) As Integer

1 22
Time- Funktion und Time- Anweisung

Beschreibung

Bes c hreibung
...................................................
Die Funktion Second liefert den Sekundenanteil des Datums-/Zeitwerts datWert als Ganzzahl
zwischen 0 und 59.
Beispiel

Beis piel
...................................................
Print "Es ist"; Minute(Time); " Minuten und "; Second(Time); _
"Sekunden nach"; Hour(Time)
Verwandte Befehle

Verwa ndte Befehle


...................................................

Funktionen und Anweisungen für Datums- / Zeitwerte


DatePart, Day, Hour, Month, Minute, Year

Time- Funktion und Time- Anweisung


Function Time() As Date
Time = datZeit
Beschreibung

Bes c hreibung
...................................................
Als Funktion liefert Time die aktuelle Systemzeit und als Anweisung setzt Time den Datums-/
Zeitwert datZeit als aktuelle Systemzeit (dauerhaft).
Anwendung

Anwendung
...................................................
Wer nicht gerade eine Uhr programmiert, dürfte sehr gut ohne diese Funktion bzw. Anweisung
auskommen. Es kommt zwar häufiger vor, dass man die aktuelle Systemzeit ausgeben muss – so
etwa beim Drucken oder wenn Datensätze mit Zeitstempeln versehen werden müssen, im Allge-
meinen wird dann aber die Funktion Now die bessere Lösung sein, da sie den Zeit- und den
Datumsanteil der Systemzeit ermittelt. Wenn es dagegen um die Bestimmung von Zeiträumen
innerhalb eines Tages geht, so etwa für Laufzeitmessungen, wird die Funktion Timer die bessere
Wahl sein.
Anwendung

Anwendung
...................................................
Wer kennt das nicht? Das Dokument ist erst in der Nacht fertig geworden, und der Empfänger
braucht das nicht unbedingt zu wissen. Anstatt umständlich auf den Zeitstempel der Datei los-
zugehen, ist es geschickter, der Anwendung eine Zeit lang eine falsche Zeit vorzugaukeln, wäh-
rend sie die Datei abspeichert. Genau das macht das Beispielprojekt ZeitStempel.
' Projekt: Zeitstempel
Const cVerzögerung = 10 ' Sekunden
Const cZivilZeit = #3:59:00 PM# ' Kurz vor Feierabend
Dim datSysZt As Date

Private Sub Form_Load()


datSysZt = Time ' aktuelle Zeit merken
Time = cZivilZeit ' Kurz vor Feierabend ...
Timer1.Interval = cVerzögerung * 1000 ' Timer setzen
End Sub

Private Sub Timer1_Timer()


Timer1.Interval = 0
t = Time

1 23
Funktionen und Anweisungen für Datums- / Zeitwerte

Time = datSysZt + (t – cZivilZeit) ' Zeit richtig korrigeren


If Time < datSysZt Then Date = Date + 1 ' Mitternachtskorrektur
End ' und Tschüss
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Now, Date

Timer- Funktion
Function Timer() As Single
Funktionen und Anweisungen für Datums- / Zeitwerte

Beschreibung

Bes c hreibung
...................................................
Die Funktion Timer liefert die seit Mitternacht (Systemzeit) vergangene Zeit in Sekunden mit
Nachkommaanteil als Fließkommawert einfacher Genauigkeit (Windows 9x: in 18tel Sekun-
denschritten; Windows NT: in 50stel Sekundenschritten).
Beispiel

Beis piel
...................................................
Siehe die Beispiele zu »Sgn-Funktion« (S. 110).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Time, Date

TimeSerial- Funktion
Function TimeSerial( _
iStd As Integer, iMin As Integer, iSek As Integer) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion TimeSerial generiert aus den Ganzzahlwerten iStd, iMin und iSek einen Datums-/
Zeitwert.
Anwendung

Anwendung
...................................................
Die Funktion prüft die Werte der Parameter nicht, das heißt, sie löst auch keine Laufzeitfehler
aus, wenn die Komponenten keine reelle Zeit ergeben. Ergibt die akkumulierte Zeit einen Wert
größer #23:59:59# oder kleiner #0:00:00#, liefert die Funktion gleichzeitig einen Datumsoffset
bezogen auf das Referenzdatum 30.12.1899. Auf diese Weise gestattet die Funktion sehr schön
das Rechnen mit relativen Zeitangaben wie: »vor 22 Stunden, 97 Minuten und 123 Sekunden«.
Beispiel

Beis piel
...................................................
cZt = #11:11:11#
For iSek = 0 to 400 Step 10
Print TimeSerial(Hour(cZt), Minute(cZt), Second(cZt) + iSek)
next iSek
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, DateSerial

1 24
TimeValue- Funktion

TimeValue- Funktion
Function TimeValue(sZeit As String) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion DateValue interpretiert die Zeichenfolge sZeit als Zeitangabe und generiert dar-
aus einen Datums-/Zeitwert. Falls die Zeichenfolge auch Datumsangaben enthält, werden diese
nicht berücksichtigt.
Anwendung

Anwendung
...................................................
Was die Notation der Zeit betrifft, ist TimeValue weitgehend tolerant, solange nur das Trennzei-

Funktionen und Anweisungen für Datums- / Zeitwerte


chen »:« erscheint und die Zeitangabe reell ist. So interpretiert die Funktion fehlende Minuten-
und Sekundenanteile als »00« und kommt auch mit den Zusätzen »am«, »AM«, »pm« und
»PM« zurecht, wenn die Zeit in 12-Stunden-Darstellung notiert ist.
Tipp

Tipp
...................................................
CDate und TimeValue unterscheiden sich insofern, als CDate auch Werte anderer Datentypen als
String in einen Datums-/Zeitwert umsetzt und zusätzlich einen Datumsanteil berücksichtigt.
Beispiel

Beis piel
...................................................
Alle Zeitangaben notieren die gleiche Zeit:
Print TimeValue("13:0") ' "13:00:00"
Print TimeValue("13:00:00") ' "13:00:00"
Print TimeValue("1 pm") ' "13:00:00"
Print TimeValue("13 pm") ' "13:00:00"
Print TimeValue("13 am") ' "13:00:00"
Print TimeValue("1 PM") ' "13:00:00"
Print TimeValue("13 AM") ' "13:00:00"
Verwandte Befehle

Verwa ndte Befehle


...................................................
DateValue, CDate

Weekday- Funktion
Function Weekday( _
datDatum As Date, _
[FirstDayOfWeek As VbDayOfWeek = vbSunday]) _
As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion Weekday interpretiert den Datums-/Zeitwert datDatum als Zeitangabe und liefert
dazu den Wochentag als Ganzzahl zwischen 1 und 7. Fehlt der optionale Parameter First-
DayOfWeek oder hat er den Wert vbSunday, interpretiert die Funktion den Sonntag als ersten Tag
der Woche, ansonsten den Tag, den die Konstante ausdrückt.
Warnung

Wa rnung
...................................................
Microsoft hat den Standardwert für den Parameter FirstDayOfWeek nicht richtig gewählt, da der
Aufruf Weekday(Now) ein falsches Ergebnis liefert. In unseren Sphären gilt der Montag als erster
Tag der Woche – wohl aufgrund der biblischen Devise »und am Siebten Tage ruhte der Herr«.
Es empfiehlt sich daher, die Funktion mit dem Wert vbMonday für ErsteTagWoche aufzurufen.

1 25
Dateiorientierte Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
Alle Zeitangaben notieren die gleiche Zeit:
Print WeekdayName(Weekday(Now)) ' Falscher Wochentag!!!
Print WeekdayName(Weekday(Now, vbMonday)) ' Richtiger Wochentag
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, DateValue, CDate

WeekdayName- Funktion
Dateiorientierte Funktionen und Anweisungen

Function WeekdayName( _
lTag As Long, _
[bAbk As Boolean = False], _
[FirstDayOfWeek As VbFirstDayOfWeek = vbUseSystemDayOfWeek]) _
As String
Siehe »WeekdayName-Funktion« (S. 92).

Year- Funktion
Function Year(datWert As Date) As Integer
Beschreibung

Bes c hreibung
...................................................
Die Funktion Year liefert den Jahresanteil des Datums-/Zeitwerts datWert als Ganzzahl zwi-
schen 100 und 9999.
Beispiel

Beis piel
...................................................
Siehe »Format-Funktion« (S. 69) und das dort vorgestellte Projekt FormatDemo.
Verwandte Befehle

Verwa ndte Befehle


...................................................
DatePart, Day, Hour, Minute, Month, Second

Dateiorientierte Funktionen und Anweisungen


Um es gleich vorwegzunehmen: Visual Basic weist nicht mehr die ursprüngliche Geschlossen-
heit der Sprache Basic gegenüber dem Dateisystem und der dateibezogenen Ein- und Ausgabe
auf. Die Sache ist komplizierter geworden, denn verloren gegangen ist eher wenig, hinzugekom-
men dagegen viel.
Freilich sind da noch die traditionellen Mittel, wohlbekannte Befehle wie Open, Input, Print#,
Get, Put und Close, mit denen sich letztlich jeder Datei zu Leibe rücken lässt und die auch eine
gesunde Basis für das delikate Thema der Abwärtskompatibilität darstellen. Zudem sind die
dateisystembezogenen Befehle ChDir, ChDrive, MkDir, RmDir, Name weiterhin vorhanden. Ja, sie
haben sogar noch Gesellschaft in Form recht nützlicher Befehle wie Dir, FileCopy, FileLen,
GetAttr und SetAttr usw. erhalten, die man sich zu Zeiten von QBasic etwa noch als entspre-
chende DOS-Kommandos mit Zeichenfolgenoperationen selbst zusammenbasteln und über die
Shell-Anweisung ausführen musste. Darüber hinaus versteht es sich schon fast von selbst, dass
Dateinamen inzwischen lang und Pfadangaben UNC-konform (engl.: Universal Naming Con-
vention, dazu gleich mehr) sein können, was letztlich Tür und Tor für den netzwerkweiten
Zugriff auf Dateien öffnet, ohne auf logische Laufwerke oder andere Krücken aus der DOS-
Zeit angewiesen zu sein. Damit lässt sich schon was anfangen.

1 26
Dateiorientierte Funktionen und Anweisungen

Komplett neu ist dagegen alles, was der Sprache von der objektorientierten Seite her an Poten-
zial zuteil geworden ist. So beispielsweise das FileSystemObject-Objekt, das als operative
Grundlage des Windows-Explorers ein wahres Füllhorn an Möglichkeiten darstellt, wenn es
darum geht, etwas über das Dateisystem in Erfahrung zu bringen, Manipulationen darin vorzu-
nehmen oder auch nur mit Textdateien zu arbeiten. Zudem ist das Tor weit offen für beliebige
Erweiterungen in dieser Richtung – es steht Ihnen frei, Ihre ganz persönliche Klassenbibliothek
für dateibezogenene Operationen zu schreiben und fortan alle Dateizugriffe über die darin defi-
nierten Objekte abzuwickeln. Das könnte beispielsweise den Vorteil haben, dass diese Objekte
Ihren Anwendungen den ganzen Ballast logistischer und formaler Natur abnehmen, den
bestimmte Dateiformate so mit sich bringen. Paradebeispiel für diesen Ansatz sind die Anwei-
sungen LoadPicture, SavePicture, Load und Unload. (Wer genau hinsieht, wird erkennen, dass

Dateiorientierte Funktionen und Anweisungen


zumindest die ersten drei Anweisungen in BLoad und BSave ihre Vorläufer hatten). So bequem
solche Operationen auch sind, ihre Implementation – und da beißt die Maus keinen Faden ab –
lebt letztlich wieder von den erwähnten traditionellen Mitteln des Dateizugriffs, es sei denn,
man kann dafür von entsprechenden – zumeist in C oder C++ geschriebenen – Bibliotheksrouti-
nen profitieren oder gar von Betriebssystemroutinen aus der reichhaltigen Windows API (vgl.
hierzu »Routinen aus DLLs und der Windows-API einsetzen«, S. 185).
Ein etwas konsequenterer Ansatz, der der Idee der objektorientierten Programmierung näher
steht, besteht darin, die im Programm verwendeten Datenstrukturen selbst als Objekte zu ver-
packen und ihnen Operationen wie SaveMyObject und LoadMyObject zu spendieren. Ein komple-
xes Objekt, das seinerseits verschiedene Objekte als Elemente enthält, wird in seiner Save-
Methode dann schlicht die Save-Methoden dieser Objekte aufrufen usw. Wann immer aber –
und das gilt auf letzter Ebene für alle Objektrepräsentationen – die Werte elementarer Datenty-
pen zu speichern sind, geht es ans »Eingemachte«, und die traditionellen Mittel sind wieder
gefragt.
Das alles ist aber noch nicht genug. Tatkräftige Unterstützung gibt es auch noch vonseiten der
Steuerelemente. Da wären schon mal die Standardsteuerelemente der Klassen FileListBox und
DriveListBox, die eine interaktive Auswahl von Dateien und logischen Laufwerken ermögli-
chen. Da wären die Standarddialoge, die eine große Hilfe beim Öffnen und Speichern von
Dateien darstellen und eine Fülle von Operationen so ganz nebenbei und kostenlos mit sich
bringen (vgl. »Standarddialoge-Steuerelement (CommonDialog)«, S. 444). Und nicht zuletzt wäre
da auch noch die schier unerschöpfliche Fülle an Möglichkeiten, mittels so genannter Daten-
quellen (Data-Steuerelement, RemoteData-Steuerelement, ADO-Daten-Steuerelement, ADO-
Recordset-Objekte) sowie DAO- und ADO-Objekten mit Daten zu hantieren, die in Datenban-
ken organisiert sind.
Nicht nur weil die historische Entwicklung der Sprache Basic es so hervorgebracht hat, sondern
auch weil es der Aufbau dieses Buches so will, geht es erst im Kapitel »Objekte und Klassen«
(S. 195) um die Dateioperationen von Objekten – und da eher nur am Rande. Ein wenig über
den Umgang mit Datenbanken finden Sie im Abschnitt »Data-Datensteuerelement (Data)«
(S. 402).
Wer aber die in diesem Abschnitt vorgestellte traditionelle Grundlage aller Dateioperationen
kennt und verstanden hat, wird auf der objektorientierten Seite keine Not haben, beides mitein-
ander zu verheiraten. Die folgende Tabelle gibt einen Überblick über die traditionellen Funktio-
nen und Anweisungen, die unmittelbar oder mittelbar etwas mit Dateizugriffen zu tun haben.

Bezeichner Kurzbeschreibung
ChDir Ändert das aktuelle Arbeitsverzeichnis
ChDrive Setzt das aktuelle logische Laufwerk
Auf Dateioperationen bezogene Funktionen und Anweisungen

1 27
Dateiorientierte Funktionen und Anweisungen

Bezeichner Kurzbeschreibung
Close Schließt eine oder mehrere zuvor geöffnete Dateien
CurDir Liefert das aktuelle Arbeitsverzeichnis auf dem angegebenen logischen
Laufwerk
Dir Liefert den nächsten Dateinamen, der auf ein Suchmuster passt
Environ Liefert eine oder alle Umgebungsvariablen
EOF Testet, ob das Dateiende erreicht ist
FileAttr Ermittelt den Öffnungsmodus einer Datei
Dateiorientierte Funktionen und Anweisungen

FileCopy Kopiert eine Datei


FileDateTime Liefert den Zeitpunkt der Erstellung bzw. letzten Änderung einer Datei als
Datums-/Zeitwert
FileLen Liefert die Länge einer Datei in Bytes
FreeFile Liefert die nächste freie Dateinummer
Get Liest Daten aus einer indexsequenziellen Datei oder Binärdatei
GetAttr Liefert die Attribute einer Datei oder eines Ordners bzw. Verzeichnisses
Input Liest die angegebene Anzahl an Zeichen aus einer Datei und liefert diese
als Unicode-Zeichenfolge
Input # Liest den Wert einer oder mehrerer Variablen aus einer Textdatei
InputB Liest die angegebene Anzahl an Bytes aus einer Datei und liefert diese als
Bytearray (ANSI-Zeichenfolge)
Kill Löscht alle Dateien, die auf das angegebene Suchmuster passen
Line Input # Liest eine Zeile aus einer geöffneten sequenziellen Datei in eine Variable
vom Typ String ein
Loc Liefert die aktuelle Schreib- bzw. Leseposition (Byte-Nummer) einer geöff-
neten Datei
Lock Regelt die Zugriffsmöglichkeiten anderer Programme auf eine bereits
geöffnete Datei
LOF Liefert die Länge einer Datei in Bytes
LSet Zuweisungsoperation, die Daten beliebiger Datentypen für die Ausgabe in
eine Datei als Zeichenfolge aufbereitet
MkDir Generiert ein neues Verzeichnis
Name Benennt eine Datei um oder verschiebt diese in ein anderes Verzeichnis
Open Öffnet eine Datei zum Lesen oder Schreiben
Print# Schreibt Daten im gebietsspezifischen Format in eine sequenzielle Datei
Put Schreibt Daten in eine indexsequenzielle Datei oder Binärdatei
Reset Schließt alle geöffneten Dateien
RmDir Löscht ein Verzeichnis
Seek Liefert die aktuelle Schreib- oder Leseposition in einer geöffneten Datei
Auf Dateioperationen bezogene Funktionen und Anweisungen

1 28
Dateiorientierte Funktionen und Anweisungen

Bezeichner Kurzbeschreibung
Seek Setzt die aktuelle Schreib- oder Leseposition in einer geöffneten Datei
SetAttr Setzt ein oder mehrere Attribute für eine Datei oder ein Verzeichnis
Shell Startet eine andere Anwendung und liefert deren Task-ID
Unlock Regelt die Zugriffsmöglichkeiten anderer Programme auf eine bereits
geöffnete Datei
Write# Schreibt Daten in standardisiertem Format in eine sequenzielle Datei

Dateiorientierte Funktionen und Anweisungen


Auf Dateioperationen bezogene Funktionen und Anweisungen

UNC- Pfad und Laufwerkspfad


Ein wichtige Größe im Umgang mit Dateien ist ihre Position im lokalen Dateisystem respektive
im Netzwerk. Um eine irgendwo im Netzwerk (das kann auch auf dem lokalen System sein)
gelegene Datei anzusprechen, geben Sie den UNC-Pfad der Datei an, der nach folgendem
Schema notiert wird:
\\Server\Freigabe\[Verzeichnis ... \]Dateiname.Erw

Liegt die Datei dagegen auf dem lokalen Computer oder existiert für seine im Netzwerk gele-
gene Position eine Netzlaufwerkverbindung, die der betreffenden Freigabe einen Laufwerks-
buchstaben Laufw zuordnet, lässt sie sich auch über ihren traditionellen Laufwerkspfad anspre-
chen.
Laufw:\[Verzeichnis ... \]Dateiname.Erw

Beide Pfadangaben können nach allen Regeln der Kunst absolut oder relativ zum jeweils aktuel-
len Arbeitsverzeichnis sein; der Unterschied zwischen beiden besteht eigentlich nur darin, dass
der absolute Laufwerkspfad einen Laufwerksbuchstaben mit nachfolgenden Doppelpunkt hat,
wo der absolute UNC-Pfad einen Servernamen und eine Freigabe enthält.

Fehler und deren Behandlung


»Wo gehobelt wird, fallen Späne«. Da Dateioperationen sozusagen aus der geschlossenen Welt
eines Programms hinausführen und mit anderen Programmen am Gerangel um Gemeingut
(gemeinsam genutzte Ressourcen) teilnehmen, ist es völlig normal, dass zur Laufzeit Fehler auf-
treten können, die zur Entwurfszeit nicht absehbar waren. Die zu solchen Fehlern führenden
Konstellationen sind recht vielfältig, so dass man sich beim Programmentwurf einer stattlichen
Anzahl möglicher Laufzeitfehler gegenüber sieht, die es einzukalkulieren gilt. Hier einige der
Ursachen für häufige Fehler:

Nr. Fehlermeldung Mögliche Ursachen


52 Dateiname oder -nummer Der Dateiname einer anzulegenden Datei entspricht nicht
falsch der Konvention für Dateinamen. Ihr Programm hat nicht
das Recht, die Datei auf einer Freigabe anzulegen, (z.B.
weil das Kennwort nicht richtig ist). Die verwendete Datei-
nummer wurde entweder durch eine Close-Anweisung
bereits freigegeben oder nie im Rahmen einer Open-Anwei-
sung vergeben, etwa weil diese gescheitert ist.
Häufige Laufzeitfehler im Zusammenhang mit Dateioperationen

1 29
Dateiorientierte Funktionen und Anweisungen

Nr. Fehlermeldung Mögliche Ursachen


53 Datei nicht gefunden Die Datei kann nicht geöffnet werden, weil sie nicht exis-
tiert.
55 Datei bereits geöffnet Die Datei kann nicht geöffnet werden, weil sie bereits
geöffnet ist. Passiert bei Open, Name, FileCopy, SetAttr,
Kill.
57 Fehler beim Lesen von/ Das Ein- bzw. Ausgabegerät enthält einen defekten Daten-
Schreiben auf Gerät träger oder die Netzwerkverbindung ist während der
Dateioperation zusammengebrochen.
Dateiorientierte Funktionen und Anweisungen

58 Datei existiert bereits Sie versuchen, eine Datei mit Name umzubenennen, der
angegebene Dateiname ist aber bereits an eine andere
Datei vergeben.
61 Datenträger voll Der freie Platz auf einer Diskette, Festplatte oder Netz-
werkfreigabe reicht für die Durchführung der Operation
nicht aus.
62 Einlesen hinter Dateiende Die Dateioperation passt nicht zu dem Modus, in dem die
Datei geöffnet wurde. Beispielsweise dürfen Sie EOF nicht
im Modus Binary und die Funktion Input nicht im Modus
Input verwenden.
70 Zugriff verweigert Sie haben versucht, auf eine Datei oder einen Datensatz
zuzugreifen, die bzw. der von einem anderen Prozess
gesperrt wurde, oder es fehlt das Schreibrecht, um auf dem
entsprechenden Datenträger zu schreiben.
71 Datenträger nicht bereit Im angegebenen Laufwerk befindet sich kein Datenträger
oder das Laufwerk wurde nicht verriegelt.
75 Fehler beim Zugriff auf Das Format der Pfadangabe ist nicht korrekt, das Ausga-
Pfad/Datei begerät unterstützt keine Schreiboperationen oder die
Datei ist schreibgeschützt.
76 Pfad nicht gefunden Der angegebene Pfad existiert nicht oder der Server, der
ihn freigibt, ist nicht am Netz.
Häufige Laufzeitfehler im Zusammenhang mit Dateioperationen

In Form der On Error GoTo-Anweisung stellt Basic ein Mittel bereit, solchen Laufzeitfehlern zu
begegnen. Mehr darüber finden Sie im Abschnitt »Fehlerbehandlung« (S. 43).

Dateien
Um in Visual Basic eine Datei mit traditionellen Mitteln bearbeiten zu können, muss sie
zunächst durch eine Open-Anweisung geöffnet werden – ein Vorgang, der unter anderem die
Zugriffsrechte anderer Prozesse auf diese Datei einschränken kann und ihr eine logische Datei-
nummer zuordnet. Diese Dateinummer ist für alle folgenden Operationen anzugeben, die mit
dieser Datei in Zusammenhang stehen. Die Zugriffsrechte auf die Datei oder Teile der Datei las-
sen sich auch danach noch mittels Lock- und Unlock-Anweisungen entsprechend den Erforder-
nissen handhaben. Sobald kein weiterer Zugriff auf die Datei mehr erfolgt, kann sie mittels
Close geschlossen werden. Diese Operation schreibt gegebenenfalls noch nicht geschriebene
Pufferinhalte und gibt die Dateinummer wieder frei.

1 30
ChDir- Anweisung

Was die Dateioperationen betrifft, so ist zu beachten, dass Basic traditionell drei Dateikonzepte
unterstützt, die sich darin unterscheiden, welche Art von Information gespeichert wird und wie
der Zugriff auf diese Information erfolgt: die sequenzielle Datei (auch Textdatei genannt), die
indexsequenzielle Datei und die Binärdatei. Für jede dieser Dateiarten gibt es spezifische Ope-
rationen, die speziell auf ihren Zweck zugeschnitten sind.
Sequenzielle Dateien enthalten durch spezifische Trennzeichen voneinander abgetrennte Zei-
chenfolgen, die textuelle Repräsentationen von Werten unterschiedlicher Datentypen darstel-
len. Zum Schreiben dieser Werte verwendet man die Anweisungen Print# und Write#, wobei
erstere die gebietsspezifische Zeichenfolgendarstellung eines Werts generiert und letztere die
internationale. Das Lesen besorgt dagegen die Anweisung Input# oder – wenn auch die Trenn-
zeichen gelesen werden sollen – die Funktion Input. Im speziellen Fall von Textdateien ermög-

Dateiorientierte Funktionen und Anweisungen


licht die Anweisung Line Input# das zeilenweise Lesen.
Indexsequenzielle Dateien enthalten eine Folge von Datensätzen. Da alle Datensätze eine feste
Länge aufweisen, kann Basic die Position eines bestimmten Datensatzes aus der Datensatznum-
mer und der Datensatzlänge errechnen, so dass keine Trennzeichen notwendig sind. Das Schrei-
ben von Datensätzen besorgt die Anweisung Get und das Lesen die Anweisung Put.
Binärdateien liegt dagegen a priori keine bestimmte Interpretation zugrunde. Sie werden als ein-
fache Aneinanderreihung von Bytes behandelt, und es unterliegt der Verantwortung des Pro-
gramms, sie zu einzelnen Werten für Variablen der unterschiedlichen Datentypen zu gruppie-
ren. Als Leseoperationen stehen dafür die Funktion Input und die Anweisung Get zur
Verfügung und als Schreiboperation die Anweisung Put.

ChDir- Anweisung
ChDir sPfad
Beschreibung

Bes c hreibung
...................................................
Windows kennt und pflegt in der Systemumgebung eines Programms für jedes Laufwerk ein
aktuelles Arbeitsverzeichnis. Das standardmäßige Arbeitsverzeichnis (vgl. »CurDir-Funktion«,
S. 134) ist das aktuelle Arbeitsverzeichnis auf dem standardmäßigen Laufwerk (vgl. »ChDrive-
Anweisung«, S. 132). Die Anweisung ChDir setzt sPfad als neues aktuelles Arbeitsverzeichnis
auf dem in sPfad spezifizierten Laufwerk. Enthält sPfad keine Laufwerksspezifikation, setzt die
Funktion das standardmäßige Arbeitsverzeichnis auf sPfad.
Anwendung

Anwendung
...................................................
Ist der in sPfad spezifizierte Pfad nicht existent, löst die Funktion den Laufzeitfehler 76, »Pfad
nicht gefunden« aus. Solange das standardmäßige Arbeitsverzeichnis lokal auf dem Computer
liegt, zeigt ChDir bei Angabe eines UNC-Pfads für sPfad keine Wirkung – meldet aber auch kei-
nen Fehler. Ergibt sich dagegen die Situation, dass das standardmäßige Arbeitsverzeichnis auf
einem anderen Computer liegt (vgl. »CurDir-Funktion«, S. 134) und somit bereits ein UNC-
Pfad ist, kommt ChDir auch bei Angabe eines UNC-Pfads seiner Aufgabe nach.
Warnung

Wa rnung
...................................................
Mit dem UNC-Pfad ist das so eine Sache. Wie unter CurDir näher ausgeführt, besteht zwar die
Möglichkeit, das standardmäßige Arbeitsverzeichnis von vornherein als UNC-Pfad zu erhalten,
Visual Basic sieht aber keine Mittel vor, das standardmäßige Arbeitsverzeichnis, sofern es ein-
mal auf ein lokales Verzeichnis gesetzt wurde, wieder auf einen anderen Computer (etwa einen
File Server) im Netzwerk zu verlagern, sprich: in einen UNC-Pfad umzuwandeln. Damit könnte
man natürlich leben, wenn sich ChDir darauf beschränken würde, ein UNC-Arbeitsverzeichnis
bei Angabe eines UNC-Pfades als UNC-Arbeitsverzeichnis beizubehalten. Leider ist das jedoch

1 31
Dateiorientierte Funktionen und Anweisungen

nicht so: ChDir setzt bei Angabe eines UNC-Pfads, der in das Dateisystem des lokalen Compu-
ters führt, ungefragt den Laufwerkspfad.
Beispiele

Beis piele
...................................................
Angenommen das Programm, das den folgenden Code enthält, ist im Verzeichnis C:\VB-Pro-
gramme gelegen und wird über den Explorer gestartet:
Print App.Path ' C:\VB-Programme
Print CurDir ' C:\VB-Programme (wie App.Path)
ChDir ".." ' Ein Verzeichnis höher
Print CurDir ' C:\
Dateiorientierte Funktionen und Anweisungen

ChDir "Windows" ' relativer Pfad


Print CurDir ' C:\Windows
ChDir "C:\VB-Programme" ' absoluter Pfad auf Standardlaufwerk
Print CurDir ' C:\VB-Programme
ChDir "D:\Eigene Dateien" ' absoluter Pfad auf Nicht-Standardlaufwerk
Print CurDir ' C:\VB-Programme (C ist Standardlaufwerk)
ChDrive "D" ' erst jetzt ändert sich Standardlaufwerk
Print CurDir ' D:\Eigene Dateien (D ist Standardlaufwerk)

Angenommen das Programm, das den folgenden Code enthält, liegt im Verzeichnis
\\Adler\c\VB-Programme\ und wird über die Netzwerkumgebung des Explorers gestartet:
Print App.Path ' \\Adler\c\VB-Programme\
Print CurDir ' \\Adler\c\VB-Programme\ (wie App.Path)
ChDir ".." ' Ein Verzeichnis höher
Print CurDir ' \\Adler\c\
ChDir "Windows" ' relativer Pfad
Print CurDir ' \\Adler\c\windows
ChDir "C:\VB-Programme" ' UNC-Pfad ist ab jetzt verloren
Print CurDir ' C:\VB-Programme
Verwandte Befehle

Verwa ndte Befehle


...................................................
ChDrive, CurDir

ChDrive- Anweisung
Sub ChDrive (sLaufw As String)
Beschreibung

Bes c hreibung
...................................................
Windows kennt und pflegt in der Systemumgebung eines Programms für jedes Laufwerk ein
aktuelles Arbeitsverzeichnis. Die Anweisung ChDrive setzt das erste Zeichen von sLaufw als
neues aktuelles Laufwerk. Das aktuelle Arbeitsverzeichnis auf diesem Laufwerk wird damit
zum standardmäßigen Arbeitsverzeichnis.
Anwendung

Anwendung
...................................................
Ist sLaufw eine leere Zeichenfolge, ändert ChDrive das aktuelle Laufwerk nicht, meldet aber
auch keinen Fehler. Existiert das erste Zeichen von sLaufw nicht als logisches Laufwerk, löst die
Funktion den Laufzeitfehler 68, »Gerät nicht verfügbar«, aus.

1 32
Close- Anweisung

Warnung

Wa rnung
...................................................
Ergibt sich die Situation, dass das standardmäßige Arbeitsverzeichnis auf einem anderen Com-
puter liegt (vgl. »CurDir-Funktion«, S. 134) und somit durch einen UNC-Pfad beschrieben
wird, geht dieser mit dem nächsten Aufruf von ChDrive unwiederbringlich verloren, das heißt,
als standardmäßiges Arbeitsverzeichnis lassen sich fortan nur noch Verzeichnisse einstellen, auf
die der Zugriff über ein logisches Laufwerk erfolgen kann.
Beispiel

Beis piel
...................................................
Siehe das Beispiel zu »ChDir-Anweisung« (S. 131).

Dateiorientierte Funktionen und Anweisungen


Verwandte Befehle

Verwa ndte Befehle


...................................................
ChDir, CurDir

Close- Anweisung
Close [#]iDateiNr[, [#]DateiNr1, ...]
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Close schließt die unter den Dateinummern iDateiNr, iDateiNr1 usw. (mittels
Open) geöffneten Dateien oder Geräte. Gegebenenfalls existierende Schreibpuffer werden zuvor
herausgeschrieben. Wird der Befehl ohne Parameter aufgerufen, schließt er alle mit Dateinum-
mern assoziierten Dateien und Geräte.
Anwendung

Anwendung
...................................................
Bevor ein Programm mit traditionellen Mitteln auf eine Datei oder ein Gerät zugreifen kann,
muss es eine Open-Anweisung durchführen, die der Datei eine Dateinummer zuordnet und gege-
benenfalls Pufferspeicher organisiert. Aus Gründen der Effizienz puffert Visual Basic alle
Schreib- und Leseoperationen für Dateien, die im Input-, Output- oder Append-Modus geöffnet
wurden, und führt sie blockweise aus. Das hat unter anderem die Folge, dass Schreiboperatio-
nen wie Print# ihre Daten nicht direkt auf den Datenträger schreiben, sondern immer erst,
wenn der Schreibpuffer voll ist. Der Befehl Close hat nun folgende Funktionen: Er bewirkt für
jede genannte Dateinummer ein explizites Herausschreiben gegebenenfalls noch gefüllter
Schreibpuffer mit nachfolgender Freigabe des Puffers und der Dateinummer. Die Freigabe einer
Dateinummer durch Close hebt gleichzeitig alle Zugriffsbeschränkungen auf, die für die betref-
fende Datei mittels Open und Lock getroffen wurden.
Entgegen anders lautenden Informationen in der Online-Hilfe zu Visual Basic entfernt Close
alle Sperren, die mit Lock gesetzt und nicht explizit mit Unlock freigegeben wurden.
Tipp

Tipp
...................................................
Zwar schließt ein Visual-Basic-Programm bei Beendigung von sich aus alle Dateien und Geräte
durch einen impliziten Close-Aufruf, dennoch ist es guter defensiver Programmierstil, eine Datei
unmittelbar, nachdem der letzte Zugriff darauf erfolgt ist, wieder zu schließen. Das verkürzt die
Einschränkungen, denen andere Programme in Bezug auf diese Datei ausgesetzt sind, auf ein
Minimum.
Beispiel

Beis piel
...................................................
Der folgende Code lässt sich in einem Programm einsetzen, dessen Aufrufe protokolliert werden
sollen:

1 33
Dateiorientierte Funktionen und Anweisungen

Open "Aufrufe.log" For Append As 1


Print #1, "Aufruf am "; Now
Close 1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Open

CurDir- Funktion
Function CurDir[(sLaufw As String)] As String
Dateiorientierte Funktionen und Anweisungen

Beschreibung

Bes c hreibung
...................................................
Windows kennt und pflegt in der Systemumgebung eines Programms für jedes Laufwerk ein
aktuelles Arbeitsverzeichnis und ein aktuelles Laufwerk. Im Allgemeinen ist das standardmä-
ßige Arbeitsverzeichnis dann das aktuelle Arbeitsverzeichnis auf dem aktuellen Laufwerk. Die
Funktion CurDir liefert das aktuelle Arbeitsverzeichnis auf dem Laufwerk sLaufw. Fehlt der
optionale Parameter sLaufw, liefert die Funktion das standardmäßige Arbeitsverzeichnis.
Anwendung

Anwendung
...................................................
Unmittelbar nach Programmstart entspricht das standardmäßige Arbeitsverzeichnis dem Ver-
zeichnis, aus dem heraus der Start erfolgt ist. Erfolgt der Start direkt durch Aufruf der ausführ-
baren Datei aus einem Fenster des Explorers heraus, deckt sich das Arbeitsverzeichnis mit dem
Programmverzeichnis (vgl. »App.Path-Eigenschaft«, S. 264). Wird der Programmstart dagegen
von einem anderen Programm veranlasst, erbt das Visual-Basic-Programm schlicht das stan-
dardmäßige Arbeitsverzeichnis des Aufrufers.
Das ist so, wenn der Aufruf aus einem Kommandozeileninterpreter oder Scripting-Host heraus
erfolgt, wenn er von einem anderen Visual-Basic-Programm aus mittels einer Shell-Anweisung
erfolgt oder wenn er über eine Verknüpfung führt, in deren Eigenschaften unter AUSFÜHREN IN
ein anderer Pfad als das Programmverzeichnis eingetragen ist. Das ist aber auch so, wenn das
standardmäßige Arbeitsverzeichnis des Aufrufers auf einem anderen Computer im Netzwerk
liegt. In diesem Fall lässt sich das standardmäßige Verzeichnis nur als UNC-Pfad notieren,
wenn es kein logisches Laufwerk für die entsprechende Freigabe gibt.
Warnung

Wa rnung
...................................................
Ist das standardmäßige Verzeichnis einmal ein Laufwerkspfad, lassen sich fortan nur noch sol-
che Verzeichnisse als standardmäßiges Arbeitsverzeichnis setzen, die über ein logisches Lauf-
werk ansprechbar sind. UNC-Pfade sind nicht mehr möglich.
Tipp

Tipp
...................................................
Beim Öffnen von Dateien, für die kein absoluter Pfad spezifiziert ist, bezieht sich Visual Basic
auf das ererbte Arbeitsverzeichnis. Das aber kann mal so und mal so aussehen, je nach dem, ob
das Programm in der Entwicklungsumgebung, als kompilierte Fassung, über eine Verknüpfung
oder aus einem Explorer-Fenster heraus gestartet wurde. Als probates Mittel, um einen defi-
nierten und situationsunabhängigen Ausgangspunkt für das Laden von Hilfsdateien zu erhal-
ten, empfiehlt es sich, entsprechende Pfadangaben auf die Exe-Datei zu beziehen und das stan-
dardmäßige Arbeitsverzeichnis via ChDir auf den Wert von App.Path zu setzen.
Beispiel

Beis piel
...................................................
Siehe »ChDir-Anweisung« (S. 131)

1 34
Dir- Funktion

Verwandte Befehle

Verwa ndte Befehle


...................................................
ChDir, ChDrive

Dir- Funktion
Function Dir [(sSuchmuster As String, _
[Attributvkt As VbFileAttribute = vbNormal])] As String
Beschreibung

Bes c hreibung
...................................................
Die Funktion Dir kennt zwei unterschiedliche Arbeitsmodi. Wird sie unter Angabe eines Werts

Dateiorientierte Funktionen und Anweisungen


für den optionalen Parameter sSuchmuster aufgerufen, interpretiert sie diesen als Suchmuster
für Dateinamen und liefert den ersten Dateinamen, der passt. Passt das Suchmuster auf keinen
Dateinamen, gibt sie die leere Zeichenfolge zurück. Wird die Funktion Dir, nachdem sie einmal
mit Suchmuster aufgerufen wurde, ohne den optionalen Parameter sSuchmuster aufgerufen, lie-
fert sie den jeweils nächsten Dateinamen, der auf das Suchmuster passt. Der zweite optionale
Parameter Attributvkt ermöglicht die Angabe eines Attributvektors, der die Ergebnismenge um
Dateien mit entsprechenden Attributen erweitert(!).
Anwendung

Anwendung
...................................................
Die überaus nützliche Funktion Dir vereinigt in sich das Funktionsschema der Win32-API-
Funktionen FindFirstFile, FindNextFile und FindClose. Um alle Dateinamen in einem Ver-
zeichnis zu erhalten, die auf ein gegebenes Suchmuster passen und darüber hinaus bestimmte
Attribute aufweisen, legen Sie mit dem ersten Aufruf von Dir das Suchmuster und gegebenen-
falls den Attributvektor fest und rufen Dir ab dann so oft parameterlos auf, bis die Funktion die
leere Zeichenfolge liefert. Das Suchmuster besteht aus einem Pfadanteil (absolut oder relativ
notiert) und einem Dateianteil, wobei der Pfadanteil das Verzeichnis spezifiziert, das durch-
sucht wird, und der Dateianteil ein Dateinamensmuster, das auch die Platzhalter »?« (Zeichen
an dieser Stelle wird nicht unterschieden) und »*« (Zeichen ab dieser Stelle werden nicht unter-
schieden) enthalten kann. Fehlt der Pfadanteil oder ist er relativ notiert, bezieht die Funktion
den Pfad auf das standardmäßige Arbeitsverzeichnis (vgl. »CurDir-Funktion«, S. 134).
Um den Namen eines Datenträgers zu erfahren, geben Sie das Stammverzeichnis des Laufwerks
als Suchmuster an (z.B. C:\) und die Konstante vbVolume als Attributvektor. In anderen Pfaden
hat vbVolume keine Wirkung. Die in der VbFileAttribute-Aufzählung enthaltene Konstante vbA-
lias ist für zukünftige Zwecke definiert. Unter Visual Basic 6.0 (SP3) löst sie einen Laufzeitfeh-
ler aus.
Warnungen

Wa rnungen
...................................................
Da diese Funktion in der von Microsoft stammenden Dokumentation recht lieblos abgehandelt
wurde, ist viel Falsches darüber zu lesen, insbesondere was den Attributvektor betrifft. Richtig
ist: Die Funktion schränkt die Ergebnismenge nicht auf Dateien mit bestimmten Attributen ein,
sondern sie erweitert die zu vbNormal gehörige Ergebnismenge um die Dateien, die eines der im
Attributvektor genannten zusätzlichen Attribute tragen.
Die mit Visual Basic vorliegende Implementation von Dir ist nicht für den rekursiven Aufruf
geeignet. Das Beispiel zu »RmDir-Anweisung» (S. 155) zeigt einen Work-around. Ein Beispiel für
eine alternative Implementation, die speziell für rekursive Prozeduren geeignet ist, finden Sie im
Abschnitt »Routinen aus DLLs und der Windows-API einsetzen« (S. 185).

1 35
Dateiorientierte Funktionen und Anweisungen

Tipp

Tipp
...................................................
Falls Sie sich nur für Dateien mit bestimmten Attributen interessieren, übergeben Sie Dir diese
Attribute als Attributvektor und filtern dann die gewünschten Dateien mittels GetAttr aus der
von Dir gelieferten Ergebnismenge selbst heraus.
Beispiel

Beis piel
...................................................
Das folgende Codefragment liefert alle Dateien im Verzeichnis C:\Eigene Dateien, deren Datei-
name mit »T« beginnt, mindestens zwei Zeichen enthält und die Erweiterung »txt« trägt:
sDatName = Dir("C:\Eigene Dateien\T?*.txt")
Dateiorientierte Funktionen und Anweisungen

While sDatName <> ""


Print sDatName
Dir
Wend

Und dieses Codefragment liefert nur die Dateien aus dem Verzeichnis C:\, die verborgen und
schreibgeschützt sind:
Attr = vbHidden + vbReadOnly
Pfad = "C:\"
sDatName = Dir(Pfad + "*.*", Attr)
While sDatName <> ""
If (GetAttr(Pfad + sDatName) And Attr) = Attr Then ' Filter
Print sDatName
End If
sDatName = Dir
Wend
Verwandte Befehle

Verwa ndte Befehle


...................................................
ChDir, CurDir, FileDateTime, GetAttr
Verwandte Themen

Verwandte Them en
...................................................
Routinen aus DLLs und der Windows-API einsetzen (S. 185)

Environ- Funktion
Function Environ(sEnvVar As String)
Function Environ(iEnvIndex As Integer)
Beschreibung

Bes c hreibung
...................................................
Wird die Funktion Environ mit einer Zeichenfolge als Parameter aufgerufen, spezifiziert sEnvVar
den Namen einer Umgebungsvariablen. Environ liefert dann den Wert dieser Umgebungsvariab-
len oder die leere Zeichenfolge, wenn diese nicht bekannt ist. Bei Aufruf der Funktion mit
einem Zahlenwert liefert die Funktion dagegen die durch iEnvIndex spezifizierte Zeile aus der
Umgebungsdefinition oder die leere Zeichenfolge, falls die Umgebungsdefinition weniger Zeilen
umfasst.

1 36
EOF- Funktion

Anwendung

Anwendung
...................................................
Auch wenn diese Funktion nicht unmittelbar etwas mit Dateizugriffen zu tun hat, mittelbar hat
sie es schon, weil sie Informationen über vordefinierte Pfade (PATH, TEMP, TMP, windir, winboot-
dir usw.) liefert.
Beispiel

Beis piel
...................................................
Der folgende Code gibt die gesamte Umgebungsinformation eines Programms aus:
i = 1
While Environ(i) <> ""

Dateiorientierte Funktionen und Anweisungen


Print Environ(i)
i = i + 1
Wend

Vgl. auch das Beispiel zu »Kill-Anweisung« (S. 144).

EOF- Funktion
Function EOF(iDateiNummer As Integer) As Boolean
Beschreibung

Bes c hreibung
...................................................
Die Funktion EOF liefert True, wenn das Dateiende einer unter der Nummer iDateiNummer geöff-
neten Datei beim Lesen erreicht ist, ansonsten False.
Anwendung

Anwendung
...................................................
Leseoperationen auf Dateien können nur so lange durchgeführt werden, bis das Dateiende
erreicht ist. Um festzustellen, ob dies der Fall ist, wird die Funktion EOF eingesetzt. Bei Dateien,
die mit dem Zugriffsmodus Input geöffnet wurden, liefert sie False, wenn die letzte Leseopera-
tion (meist Line Input #) durch das Ende der Datei beendet wurde. Im Zusammenhang mit den
Zugriffsmodi Binary und Random liefert sie True, wenn die letzte Leseoperation (Input bzw. Get)
aufgrund des Dateiendes nicht oder nicht vollständig ausgeführt werden konnte.
Warnung

Wa rnung
...................................................
Die Online-Hilfe zu EOF bezichtigt diese Funktion, Laufzeitfehler zu produzieren, wenn sie im
Zugriffsmodus Binary für die Kontrolle der Input-Funktion benutzt wird. Das ist falsch. Input
ist so implementiert, dass es im Modus Binary generell keinen Laufzeitfehler auslöst. Zu einem
Laufzeitfehler kann es dagegen kommen, wenn EOF im Zugriffsmodus Input für die Kontrolle
der Funktion Input benutzt wird und diese mehr als ein Zeichen je Aufruf liest.
Beispiel

Beis piel
...................................................
Der folgende Code liest die Textdatei Scandisk.log zeilenweise für die Ausgabe durch Print:
Open "c:\scandisk.log" For Input As 1
While Not EOF(1)
Line Input #1, sZeile
Print sZeile
Wend
Close 1

1 37
Dateiorientierte Funktionen und Anweisungen

Verwandte Befehle

Verwa ndte Befehle


...................................................
LOF, Loc, Get, Input, Line Input, Open, Seek

FileAttr- Funktion
Function FileAttr(iDateiNummer As Integer[, iTyp As Integer = 1])
Beschreibung

Bes c hreibung
...................................................
Die Funktion FileAttr liefert eine Aussage darüber, in welchem Modus die zu der Dateinum-
mer iDateiNummer gehörige Datei geöffnet wurde. Es sind folgende Funktionswerte möglich: 1
Dateiorientierte Funktionen und Anweisungen

steht für Input, 2 für Output, 4 für Random, 8 für Append und 32 für Binary.
Anwendung

Anwendung
...................................................
Der zweite, optionale Parameter wird nur noch aus Kompatibilitätsgründen mitgeschleppt. Er
hatte eine Bedeutung, als es noch 16-Bit-Systeme gab. Auf 32-Bit-Systemen muss er 1 sein.
Beispiel

Beis piel
...................................................
Open sDatei For Binary As 2
Print FileAttr(2) ' Ausgabe: 32
Close2
Verwandte Befehle

Verwa ndte Befehle


...................................................
Open

FileCopy- Anweisung
Sub FileCopy(sQuellDatei As String, sZielDatei As String)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung FileCopy erstellt eine Kopie der Datei sQuellDatei als sZielDatei.
Anwendung

Anwendung
...................................................
Es versteht sich, dass sQuellDatei einen gültigen Pfad zu einer existierenden Datei und sZielDa-
tei einen gültigen Pfad mit gültigem Dateinamen enthalten müssen.
Die Funktion löst verschiedene Laufzeitfehler aus – so den Laufzeitfehler 76, wenn mit den Pfa-
den etwas nicht in Ordnung ist, den Laufzeitfehler 53, wenn die Datei nicht existiert, und den
Laufzeitfehler 55, wenn die Datei zum Schreiben geöffnet wurde.
Warnung

Wa rnung
...................................................
Sollte unter dem Dateinamen sZielDatei bereits eine andere Datei existieren, wird diese kom-
mentarlos überschrieben.
Beispiel

Beis piel
...................................................
FileCopy sQuellDatei, sZieldatei
Verwandte Befehle

Verwa ndte Befehle


...................................................
Kill, Name

1 38
FileDateTime- Funktion

FileDateTime- Funktion
Function FileDateTime(sDatei As String) As Date
Beschreibung

Bes c hreibung
...................................................
Die Funktion FileDateTime liefert das letzte Änderungsdatum bzw. das Erstellungsdatum der
Datei oder des Verzeichnisses sDatei als Datums-/Zeitwert.
Beispiel

Beis piel
...................................................
Print FileDateTime ("C:\Windows") ' Datum der Windows-Installation

Dateiorientierte Funktionen und Anweisungen


Verwandte Befehle

Verwa ndte Befehle


...................................................
FileLen, GetAttr

FileLen- Funktion
Function FileLen(sDatei As String) As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion FileDateTime liefert die Länge der Datei sDatei in Bytes. Spezifiziert sDatei ein
Verzeichnis, gibt die Funktion den Wert 0 zurück.
Anwendung

Anwendung
...................................................
Ein Aufruf dieser Funktion für eine zum Schreiben geöffnete Datei liefert die Länge der Datei,
bevor diese zum Schreiben geöffnet wurde. Die aktuelle Länge einer bereits geöffneten Datei
ermittelt die Funktion LOF.
Beispiel

Beis piel
...................................................
Print FileLen("C:\Msdos.sys") ' muss größer 1024 Bytes sein
Verwandte Befehle

Verwa ndte Befehle


...................................................
FileDateTime, GetAttr, LOF

FreeFile- Funktion
Function FreeFile[(iBereich As Integer)]
Beschreibung

Bes c hreibung
...................................................
Die Funktion FreeFile liefert jeweils die kleinste freie Dateinummer im Block iBereich. Fehlt
der optionale Parameter iBereich oder hat er den Standardwert 0, entstammt die gelieferte
Dateinummer dem Block 0 bis 255, ansonsten dem Block 256 bis 512.
Anwendung

Anwendung
...................................................
Nachdem Dateinummern globale Größen in einem Modul sind, ist es in größeren Programmen
oft schwierig, den Überblick darüber zu behalten, welche bereits vergeben sind und welche
nicht. Indem Sie sich neue Dateinummern von FreeFile zuteilen lassen, entlasten Sie sich von
der gesamten Problematik.

1 39
Dateiorientierte Funktionen und Anweisungen

Beispiel

Beis piel
...................................................
iBer = FreeFile
Open sDatei For Input As iBer
...
Close iBer
Vgl. auch das Beispiel im Abschnitt »Fehlerbehandlung« (S. 43).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Open
Dateiorientierte Funktionen und Anweisungen

Get- Anweisung
Get [#]iDateiNr, [lSatzNr], Variable
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Get ist das Gegenstück zur Anweisung Put. Sie liest Daten aus der Datei mit der
Dateinummer iDateiNr und weist diese der Datensatzvariablen Variable als Wert zu. Bei
Angabe einer Satznummer lSatzNr liest die Anweisung im Modus Random den entsprechenden
Datensatz unter Berücksichtigung der bei der Open-Anweisung vereinbarten Datensatzlänge und
im Modus Binary ab der Byteposition lSatzNr. Fehlt lSatzNr, liest die Anweisung jeweils den
nächsten Datensatz (Random) bzw. ab der aktuellen Leseposition (Binary) und aktualisiert
danach den Datensatzzeiger bzw. die aktuelle Leseposition.
Die Datensatzvariable kann einen beliebigen Typ tragen. Objekte lassen sich mittels Get jedoch
nicht en bloc einlesen.
Anwendung

Anwendung
...................................................
Wenn es um das Schreiben und Lesen von Dateiformaten ging, waren Get und Put schon immer
die Arbeitspferde der Sprache Basic. Die Arbeitsweise dieser Anweisungen ist traditionell auf
indexsequenzielle Dateien zugeschnitten, deren Bearbeitung im Modus Random erfolgt. Get und
Put werden aber auch – jedoch mit leicht modifizierter Arbeitsweise – im Modus Binary einge-
setzt.

Der Modus Random


Beim Öffnen von Dateien im Modus Random wird normalerweise eine Datensatzlänge in Bytes
festgelegt, die fortan bestimmt, wie viele Byte mit jeder Get- bzw. Put-Operation je Datensatz
gelesen bzw. geschrieben werden. Die Zählung der Datensätze beginnt bei 1. Den Bytebedarf
der elementaren Datentypen entnehmen Sie der Tabelle im Abschnitt »Elementare Datentypen«
(S. 49); den von Datentypen mit fester Länge sowie von benutzerdefinierten Datentypen ermit-
telt man am besten mittels LenB, da die Speicherausrichtung der Datenfelder noch eine zusätzli-
che Rolle spielt. Trägt die Datensatzvariable einen Typ variabler Länge (bzw. einen Typ, der
Felder variabler Länge enthält), muss der Datensatz einen Deskriptor (lies: Längenangabe) ent-
halten. Dabei gilt, dass ein Deskriptor dem Wert unmittelbar vorausgeht. Mithin muss also der
Längenbedarf eines oder mehrerer Deskriptoren bei der Berechnung der Datensatzlänge
berücksichtigt werden. Für Zeichenfolgen variabler Länge schlagen dabei 2 Längenbyte (!) zu
Buche, für Variant-Variablen gleichfalls zunächst 2 Bytes für den VarType-Typ plus gegebenen-
falls weitere Längenbyte für Wertanteile mit variablen Längen. Dynamische Arrays schlagen
mit 2 Bytes für den Array-Deskriptor zu Buche plus 8 Bytes je Dimension. Die maximale Daten-
satzlänge beträgt 32.767.

1 40
Get- Anweisung

Die Wertzuweisung an Variablen mit Datentypen fester Länge erfolgt als linksbündige Prokrus-
tes-Zuweisung (vgl. »LSet-Anweisung«, S. 80), wenn die Datensatzlänge nicht dem Längenbe-
darf der Variablen entspricht.

Der Modus Binary


Für den Modus Binary gilt im Wesentlichen dasselbe, mit folgenden Abweichungen: Eine
Datensatzlänge wird nicht berücksichtigt, und die Anweisung liest ab der aktuellen Position
bzw. der Position lSatzNr so viele Bytes, wie für den Wert der Datensatzvariablen erforderlich
sind. Zeichenfolgen variabler Länge behandelt Get daher wie Zeichenfolgen fester Länge und
liest nur so viele Zeichen, wie der Wert der String-Variablen aktuell enthält – ein Deskriptoran-

Dateiorientierte Funktionen und Anweisungen


teil entfällt somit. Analoges gilt auch für Arrays. Im Zusammenhang mit benutzerdefinierten
Datentypen finden Deskriptoranteile einzelner Datenfelder jedoch sehr wohl Berücksichtigung.
Warnung

Wa rnung
...................................................
Get liest ANSI-Zeichenfolgen als Unicode und Put schreibt Unicode-Zeichenfolgen als ANSI-
Code.
Beispiel

Beis piel
...................................................
Der folgende Code schreibt eine Zeichenfolge und einen Double-Wert in eine indexsequenzielle
Datei und liest diese Werte dann einmal im Modus Random und einmal im Modus Binary:
' Schreiben der Daten
Open "Test.Idx" For Random As 1 Len = 8
Dim sDatenSatz As String ' Zeichenfolge (Unicode!)
Dim a As Double ' Double-Wert
sDatenSatz = "abc" ' Initialisierung
a = 2.1E-122
Put 1, , sDatenSatz ' erster Datensatz wird geschrieben
Put 1, 17, a ' 17ter Datensatz
Close 1

' Lesen der Daten im Modus Random


sDatenSatz = "" ' Initialisierung
a = 0
Open "Test.Idx" For Random As 1 Len = 8
Get 1, , sDatenSatz ' erster Datensatz wird gelesen
Print Len(sDatenSatz); sDatenSatz ' Ausgabe: "3 abc" (Deskriptor!)
Get 1, 17, a ' Doublewert braucht 8 Bytes!
Print a ' Ausgabe: 2,1E-122
Close 1

' Lesen der Daten im Modus Binary


sDatenSatz = Space(3) ' drei Unicodezeichen sind zu lesen
a = 0 ' Initialisierung
Open "Test.Idx" For Binary As 1
Get 1, 3, sDatenSatz ' Deskriptoranteil überspringen!
Print Len(sDatenSatz), sDatenSatz ' Ausgabe: "3 abc" (Deskriptor!)
Get 1, (17 – 1) * 8 + 1, a ' Datensatzlänge 8 einberechnen
Print a ' Ausgabe: 2,1E-122
Close 1

1 41
Dateiorientierte Funktionen und Anweisungen

Verwandte Befehle

Verwa ndte Befehle


...................................................
Input, Input#, Line Input#, Open, LenB, LSet, Print#, Put
Verwandte Themen

Verwandte Them en
...................................................
Elementare Datentypen (S. 49); Benutzerdefinierte Datentypen (S. 60)

GetAttr- Funktion
Function GetAttr(sPfad As String) As Integer
Dateiorientierte Funktionen und Anweisungen

Beschreibung

Bes c hreibung
...................................................
Die Funktion GetAttr liefert die Attribute der Datei oder des Verzeichnisses sPfad als Attribut-
vektor.
Anwendung

Anwendung
...................................................
Um festzustellen, ob in dem Attributvektor ein bestimmtes Attribut (als Bit) gesetzt ist, führen
Sie eine And-Operation mit dem für das Attribut definierten Wert durch. Als Element des Auf-
zählungstyps VbFileAttribute ist für ihn eine Konstante definiert. Zur Auswahl stehen:

Konstante Wert Beschreibung


vbNormal 0 Keines der Bits im Attributvektor ist gesetzt. Es handelt sich um
eine gewöhnliche Datei.
vbReadOnly 1 Datei/Verzeichnis ist schreibgeschützt.
vbHidden 2 Datei/Verzeichnis ist verborgen.
vbSystem 4 Datei ist Systemdatei bzw. Verzeichnis ist Systemverzeichnis.
vbVolume 8 Logischer Datenträger (wird von GetAttr nicht geliefert)
vbDirectory 16 Verzeichnis
vbArchive 32 Datei wurde seit der letzten Datensicherung geändert
Konstanten für Dateiattribute

Beispiel

Beis piel
...................................................
Dim Attribut As VbFileAttribut
Attribut = vbHidden
If Attribut And GetAttr(sDatei) Then ' Datei ist verborgen
Wie man das Vorhandensein mehrerer Attribute prüft, zeigt das Beispiel zur »Dir-Funktion«
(S. 135).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Dir, FileAttr, SetAttr

Input- und InputB- Funktion


Function Input(lZeichenAnz, [#]iDateiNr) As String
Function InputB(lBytes, [#]iDateiNr) As String

1 42
Input #- Anweisung

Beschreibung

Bes c hreibung
...................................................
Die Funktion Input liest lBytes Bytes aus der unter der Dateinummer iDateiNr im Modus Input
oder Binary geöffneten Datei und liefert diese als Unicode-Zeichenfolge, wobei aus jedem Byte
ein Unicode-Zeichen wird. In Abweichung dazu liefert InputB ein echtes Byte-Array in Form
einer ANSI-Zeichenfolge.
Anwendung

Anwendung
...................................................
Traditionell ist Input (heute InputB genannt) die Leseoperation für Binärdateien (Modus:
Binary), Get die Leseoperation für indexsequenzielle Dateien (Modus: Random) und Input# die

Dateiorientierte Funktionen und Anweisungen


Leseoperation für Textdateien (Modus: Input). Binärdateien lassen sich aber genauso gut auch
mit Get lesen und Textdateien mit Input. Im Gegensatz zu Input# liefert Input alle gelesenen
Zeichen, einschließlich Kommas, Wagenrücklaufzeichen (Chr(13) bzw. vbCr), Zeilenvorschub-
zeichen (Chr(10) bzw. vbLf), Anführungszeichen und führende Leerzeichen.
Warnung

Wa rnung
...................................................
Fallen Sie nicht darauf herein, dass Input einzelne Bytes in Unicode-Zeichen umwandelt – und
somit aus einem Byte zwei Bytes macht. Um wirklich die gelesene Bytefolge zu erhalten, müssen
Sie mit InputB arbeiten.
Wenn Sie Input oder InputB beim Lesen einer Textdatei mittels EOF kontrollieren wollen, riskie-
ren Sie einen Laufzeitfehler, sobald die Funktion mehr als ein Byte auf einmal lesen muss. Man
arbeitet in diesem Fall besser mit dem Wert von LOF bzw. der Differenz aus den Werten von LOF
und Seek.
Beispiel

Beis piel
...................................................
Open sTextDatei For Input As 1 ' Textdatei
sGesamteDatei = Input(LOF(1), 1) ' Gesamte Datei auf einmal lesen
Close 1
Open sBinärDatei For Binary As 1 ' Binärdatei
sGesamteDatei = InputB(LOF(1), 1) ' Gesamte Datei als Bytearray lesen
Close 1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Get, Print#, Put, LOF, EOF

Input #- Anweisung
Input #iDateiNr, Variable[, Variable ...]
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Input# liest den im literalen Standardformat repräsentierten Wert einer oder
mehrerer Variablen aus einer sequenziellen Datei, die im Modus Input oder Binary geöffnet
wurde. Als Trennzeichen zwischen zwei aufeinander folgenden Werten wertet die Anweisung
ein Komma oder ein Wagenrücklaufzeichen Chr(13) bzw. vbCr sowie die Kombination
Chr(13)+Chr(10) bzw. vbCrLf. Führende und abschließende Leerzeichen sowie doppelte Anfüh-
rungszeichen schneidet die Anweisung ab.

1 43
Dateiorientierte Funktionen und Anweisungen

Anwendung

Anwendung
...................................................
Der traditionelle Zweck der Anweisung Input# ist, Daten aus sequenziellen Dateien zu lesen,
denen unterschiedliche Datentypen zugrunde gelegt sind. Die Anweisung nimmt daher beim
Lesen des Werts für eine Variable eines bestimmten Datentyps von sich aus eine entsprechende
Typumwandlung vor.
Warnung

Wa rnung
...................................................
Im Unterschied zu Line Input# interpretiert Input# auch Kommas als Trennzeichen, wenn diese
nicht von Anführungszeichen eingeschlossen sind. Daher hat die Funktion insbesondere
Dateiorientierte Funktionen und Anweisungen

Schwierigkeiten mit dem Einlesen von Dezimalzahlen mit Nachkommaanteil sowie Datums-
werten, wenn diese mit Print# geschrieben wurden. Print# legt der textuellen Darstellung von
Zahlen- und Datumswerten nämlich das gebietsspezifische Format zugrunde. Für das Gebiets-
schema »Deutsch (Standard)« ist das Dezimaltrennzeichen ein Komma, und das Datumsformat
ist komplett anders als das amerikanische. Sie sollten die Daten daher mit der Write#-Anwei-
sung in die Datei schreiben, weil diese grundsätzlich das internationale Standardformat benutzt,
das auch für die Notation von Literalen im Quelltext verwendet wird.
Beispiel

Beis piel
...................................................
' Daten schreiben
Open "test.seq" For Output As 1
Write #1, 270; "Er sagte, ""Hi!""" ' Die Anweisung schreibt 2 Werte (!)
Close 1
' Daten lesen
Dim i As Integer, a As String, b As String
Open "test.seq" For Input As 1
Print Input(24, 1) ' So steht es in der Datei: 270,"Er sagte, ""Hi!"""
Seek 1, 1 ' Lesezeiger wieder an den Anfang
Input #1, i, a, b ' Die Anweisung liest drei Werte (!), wegen "
Print i, a, b ' Ausgabe: 270 Er sagte, Hi!
Verwandte Befehle

Verwa ndte Befehle


...................................................
EOF, Get, Line Input#, Input, Print#, Put, Write#
Verwandte Themen

Verwandte Them en
...................................................
Literale und Konstanten (S. 27)

Kill- Anweisung
Sub Kill(sSuchmuster As String)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Kill löscht alle Dateien, deren Dateiname auf das Suchmuster sSuchmuster
passt.
Anwendung

Anwendung
...................................................
Das Suchmuster besteht aus einem Pfadanteil (absolut oder relativ notiert) und einem Dateian-
teil, wobei der Pfadanteil das Verzeichnis spezifiziert, das durchsucht wird, und der Dateianteil
ein Dateinamensmuster, das auch die Platzhalter »?« (Zeichen an dieser Stelle wird nicht unter-

1 44
Line Input #- Anweisung

schieden) und »*« (Zeichen ab dieser Stelle werden nicht unterschieden) enthalten kann. Fehlt
der Pfadanteil oder ist er relativ notiert, bezieht die Anweisung den Pfad auf das standardmä-
ßige Arbeitsverzeichnis (vgl. »CurDir-Funktion«, S. 134).
Beispiel

Beis piel
...................................................
sPfad = Environ("Temp")
if sPfad <> "" Then Kill(sPfad + "*.tmp")
Verwandte Befehle

Verwa ndte Befehle


...................................................
RmDir

Dateiorientierte Funktionen und Anweisungen


Line Input #- Anweisung
Line Input #iDateiNr, sVariable
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Line Input# liest eine Textzeile aus einer sequenziellen Datei, die im Modus
Input oder Binary geöffnet wurde, und weist diese der Zeichenfolgenvariablen sVariable als
Wert zu. Als Trennzeichen zwischen zwei aufeinander folgenden Textzeilen wertet die Anwei-
sung das Wagenrücklaufzeichen Chr(13) bzw. vbCr sowie die Kombination Chr(13)+Chr(10)
bzw. vbCrLf.
Anwendung

Anwendung
...................................................
Der traditionelle Zweck der Anweisung Line Input# ist, Zeichenfolgen für die Textverarbeitung
aus sequenziellen Dateien zu lesen. Im Unterschied zu Input# behandelt Line Input# weder
Kommas als Trennzeichen, noch schneidet die Anweisung Leerzeichen und doppelte Anfüh-
rungszeichen ab. Zum Schreiben der Daten, die mit Line Input# gelesen werden sollen, verwen-
den Sie am besten Print#.
Beispiel

Beis piel
...................................................
Der folgende Code liest eine Textdatei zeilenweise in ein dynamisches Zeichenfolgenarray.
Dim sZeilen() As String
Dim lZeilen As Long
Open "Textdatei.txt" For Input As 1
While Not EOF(1)
ReDim Preserve sZeilen(lZeilen + 1) As String
Line Input #1, sZeilen(UBound(sZeilen))
lZeilen = UBound(sZeilen)
Wend
Verwandte Befehle

Verwa ndte Befehle


...................................................
EOF, Get, Input, Input#, Print#, Put, Write#

1 45
Dateiorientierte Funktionen und Anweisungen

Loc- Funktion
Function Loc(iDateiNr As Integer) As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion Loc liefert abhängig vom Modus, in dem die Datei mit der DateiNr geöffnet
wurde, die Nummer des zuletzt bearbeiteten Datensatzes oder die Position des zuletzt gelesenen
oder geschriebenen Bytes.
Anwendung

Anwendung
...................................................
Visual Basic verwaltet für jede Datei einen Dateizeiger, der die aktuelle Schreib-/Leseposition
Dateiorientierte Funktionen und Anweisungen

angibt. Den »nackten« Wert dieses Zeigers liefert die Funktion Seek als Byte-Nummer, gleich in
welchem Modus eine Datei geöffnet wurde. Loc liefert dagegen den logischen Dateizeiger. Im
Modus Binary unterscheidet sich der Wert des logischen Dateizeigers von dem des gewöhnli-
chen Dateizeigers dahingehend, dass er um 1 kleiner ist als dieser. Im Modus Random hat der
logische Dateizeiger dagegen den Wert des zuletzt gelesenen oder geschriebenen Datensatzes. Es
gilt die Formel:
( Dateizeiger – 1 )
Datensatznummer = ----------------------------------------------
Datensatzlänge
Mithin liefert Loc vor der ersten Dateioperation den Wert 0.
Warnung

Wa rnung
...................................................
Loc liefert für sequenzielle Dateien zwar einen Wert, dieser ist aber unbrauchbar, da er auf eine
Datensatzlänge von 128 gemünzt ist. Sie arbeiten in diesem Fall besser mit Seek.
Beispiel

Beis piel
...................................................
Open "test.idx" For Random As 1 Len = Datensatzlänge
For i = 1 To iDatensätze
Put 1, , bdt(i)
Next
Print Loc(1) ' Wert von iDatensätze
Close1
Verwandte Befehle

Verwa ndte Befehle


...................................................
EOF, LOF, Seek

Lock- Anweisung
Sub Lock([#]iDateiNr As Integer[, lDatensatz As Long])
Sub Lock([#]iDateiNr As Integer, [lStartNr As Long] To lEndNr As Long)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Lock sperrt einen einzelnen Datensatz lDatensatz oder einen Bereich von Daten-
sätzen lStartNr bis lEndNr in der Datei mit der Dateinummer iDateiNr vor dem Zugriff durch
andere Prozesse. Fehlt bei Gebrauch der ersten Syntax der optionale Parameter lDatensatz, ver-
hängt die Anweisung die Sperre über die gesamte Datei. Fehlt bei Gebrauch der zweiten Syntax
der optionale Parameter lStartNr, sperrt die Anweisung alle Datensätze von der Nummer 1 bis
zur Nummer lEndNr. Bei Dateien, die im Modus Binary geöffnet wurden, beziehen sich die
Bereichsangaben auf Positionen des Dateizeigers.

1 46
LOF- Funktion

Anwendung

Anwendung
...................................................
Wenn in einem System oder in einem Netzwerk mehrere Programme gleichzeitig Schreibzugriffe
auf dieselbe Datei durchführen, kann das recht unangenehme Inkonsistenzen zur Folge haben.
Das Anweisungspaar Lock/Unlock ermöglicht es einem Programm, sich temporär die Exklusiv-
rechte für das Beschreiben eines gewissen Teils der Datei zu sichern. Lock löst den Laufzeitfehler
70, »Zugriff verweigert«, aus, wenn ein anderes Programm bereits eine Sperre auf einen Bereich
hält, der mit dem angegebenen Bereich überlappt.
Warnung

Wa rnung
...................................................

Dateiorientierte Funktionen und Anweisungen


Bei Lock/Unlock-Anweisungen für sequenzielle Dateien (Input, Output, Append) ignoriert Visual
Basic Bereichsangaben und sperrt immer die gesamte Datei. Entgegen anders lautenden
Informationen in der Online-Hilfe zu Visual Basic 6.0 entfernt Close (respektive das Program-
mende) jedoch alle Sperren, die mit Lock gesetzt und nicht explizit mit Unlock freigegeben wur-
den. Sie sollten aber dennoch darauf achten, jede Lock-Anweisung mit einer Unlock-Anweisung
zu paaren, um errichtete Sperren zum frühestmöglichen Zeitpunkt wieder aufzuheben.
Beispiel

Beis piel
...................................................
Der folgende Code schreibt eine Reihe von Datensätzen in die gemeinsame genutzte Datei Kun-
den.idx:
Open "Kunden.idx" For Random As 1 Len = Datensatzlänge
On Error GoTo Fehler70
Lock 1, lStartBereich To lEndBereich ' Sperre errichten
On Error GoTo 0
For i = lStartBereich To lEndBereich
Put 1, i, bdt(i)
Next
Unlock 1, lStartBereich To lEndBereich ' Sperre aufheben
Close 1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Open, Unlock
Verwandte Themen

Verwandte Them en
...................................................
Fehlerbehandlung (S. 43)

LOF- Funktion
Function LOF(iDateiNummer As Integer) As Long
Beschreibung

Bes c hreibung
...................................................
Die Funktion LOF liefert die Länge der unter der Nummer iDateiNummer geöffneten Datei in
Bytes.
Anwendung

Anwendung
...................................................
Wo immer die Länge einer geöffneten Datei eine Rolle spielt, beispielsweise wenn es darum
geht, eine Datei en bloc mittels Input einzulesen oder die Anzahl der bereits geschriebenen Bytes
(nicht jedoch Datensätze) zu ermitteln, ist LOF das Mittel zum Zweck.

1 47
Dateiorientierte Funktionen und Anweisungen

Tipp

Tipp
...................................................
Die Länge einer noch nicht geöffneten Datei ermittelt die Funktion FileLen.
Beispiel

Beis piel
...................................................
Der folgende Code liest die unter der Dateinummer 1 geöffnete Datei in einem Stück:
sDatei = Input(LOF(1), 1)
Verwandte Befehle

Verwa ndte Befehle


...................................................
Dateiorientierte Funktionen und Anweisungen

Loc, FileLen, Get, Input, Line Input, Open, Seek

LSet- Anweisung
LSet sString1 = sString2
LSet bdtVar = bdtWert
Siehe »LSet-Anweisung« (S. 80).

MkDir- Anweisung
Sub MkDir(sVerzeichnisname As String)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung MkDir legt unter dem Namen sVerzeichnisname ein neues Verzeichnis an.
Anwendung

Anwendung
...................................................
Der Wert des Parameters sVerzeichnisname kann ein (absoluter oder relativer) UNC-Pfad oder
Laufwerkspfad sein. Enthält sVerzeichnisname keinen Pfadanteil, legt die Anweisung das Ver-
zeichnis als Unterverzeichnis des standardmäßigen Verzeichnisses an (vgl. »CurDir-Funktion«,
S. 134). Falls das Verzeichnis bereits existiert oder die Rechte für das Anlegen des Verzeichnis-
ses nicht ausreichen, löst die Anweisung den Laufzeitfehler 75, »Fehler beim Zugriff auf Pfad/
Datei«, aus.
Beispiel

Beis piel
...................................................
MkDir "C:\Visual-Basic-Daten\MeineDaten" ' Laufwerkspfad
MkDir "\\Tiger\c\Visual-Basic-Daten\MeineDaten" ' UNC-Pfad
Verwandte Befehle

Verwa ndte Befehle


...................................................
ChDir, CurDir, RmDir

Name- Anweisung
Name sAlterDateiname As sNeuerDateiname
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Name ändert den Namen der Datei oder des Verzeichnisses sAlterDateiname in
sNeuerDateiname. Falls sich die Pfadanteile von sAlterDateiname und sNeuerDateiname unter-
scheiden, wird die Datei bzw. das Verzeichnis verschoben.

1 48
Open- Anweisung

Anwendung

Anwendung
...................................................
Die Werte der Parameter sAlterDateiname und sNeuerDateiname können (absolute oder relative)
UNC-Pfade oder Laufwerkspfade sein. Fehlt ein Pfadanteil, bezieht sich die Anweisung auf das
standardmäßige Verzeichnis (»CurDir-Funktion«, S. 134). Name lässt sich nur auf einzelne
Dateien und Verzeichnisse anwenden, Platzhalterzeichen wie »*« oder »?« kann die Anweisung
nicht interpretieren – sie lösen den Laufzeitfehler 52, »Dateiname oder -Nummer falsch«, aus.
Falls die Datei oder das Verzeichnis sAlterDateiname nicht existiert, löst die Anwendung den
Laufzeitfehler 53, »Datei nicht gefunden«, aus. Existiert dagegen sNeuerDateiname bereits als
Datei oder Verzeichnis, kommt es zum Laufzeitfehler 58, »Datei existiert bereits«.

Dateiorientierte Funktionen und Anweisungen


Beispiel

Beis piel
...................................................
Kill sPfad + "Daten.dat"
Name sPfad + "Daten.tmp" As sPfad + "Daten.dat
Verwandte Befehle

Verwa ndte Befehle


...................................................
Kill

Open- Anweisung
Open sName For Modus [Access Zugriffsart] [Sperre] As [#] iNr
[Len = lDatensatzlänge]
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Open öffnet die Datei sName und ordnet ihr für den weiteren Zugriff die Datei-
nummer iNr zu. Zugleich legt die Anweisung einen Bearbeitungsmodus Modus fest, der als
Input, Output, Random oder Binary anzugeben ist. Mittels des optionalen Schlüsselwortes Access
gefolgt von Read, Write oder Read Write für Zugriff lässt sich zudem die Art des Zugriffs
genauer festlegen. Darüber hinaus besteht die Möglichkeit, für den indexsequenziellen Zugriff
im Modus Random eine Datensatzlänge lDatensatzlänge zwischen 1 und 32767 als Len-Zusatz
anzugeben.
Anwendung

Anwendung
...................................................
Für den schreibenden oder lesenden Zugriff auf eine Datei ist es erforderlich, diese zuvor mit
Open unter Angabe des entsprechenden UNC- oder Laufwerkspfades zu öffnen. Dabei kann es
sich um einen absoluten oder relativen Pfad handeln. Ist sName nur als Dateiname ohne Pfadan-
teil spezifiziert, geht die Anweisung davon aus, dass die Datei im standardmäßigen Verzeichnis
zu finden ist.
Als Dateinummer iNr lässt sich ein Wert zwischen 1 und 511 wählen, der fortan als Alias der
Datei für jegliche Zugriffe fungiert, bis diese mittels Close wieder geschlossen wird. Bei der Ver-
gabe der Dateinummer ist zu beachten, dass diese nicht bereits einer anderen Datei zugeordnet
wurde (vgl. »FreeFile-Funktion«, S. 139). Open ordnet der Datei je nach Bearbeitungsmodus
und Zugriffsart auch einen Schreib- und/oder Lesepuffer sowie einen Dateizeiger zu, wobei der
Dateizeiger die jeweils aktuelle Position für die nächste Dateioperation wiedergibt, falls diese
nicht explizit die Angabe einer Startposition enthält.
Für Modus kennt Visual Basic als reine Textmodi Input, Output und Append, wobei mit Input nur
ein lesender Zugriff möglich ist und mit Output und Append nur ein schreibender. Ein Access-
Zusatz für diese Modi ergibt keinen Sinn, da die Zugriffsart ja bereits feststeht. Daneben gibt es
noch den indexsequenziellen Zugriffsmodus Random für den rein datensatzorientierten Zugriff
sowie den binären Zugriffsmodus Binary, der als flexibelster Modus sowohl für den textorien-

1 49
Dateiorientierte Funktionen und Anweisungen

tierten als auch für den datensatzorientierten Zugriff geeignet ist. Dateioperationen finden im
Allgemeinen mit Bezug auf eine Byteposition statt, einzig Operationen im Modus Random liegt
eine Datensatznummer zugrunde, bei der die Datensatzlänge lDatensatzlänge eine Rolle spielt.
Der Dateizeiger gibt in diesem Fall die Datensatznummer an und nicht die Byteposition. In allen
anderen Modi hat die Angabe einer Datensatzlänge keinen Effekt. Für den Modus Append setzt
Open den Dateizeiger an das Ende der Datei, ansonsten an den Anfang.
Wird eine Datei im Modus Binary oder Random mit dem Zusatz Access Read geöffnet, führt jeder
Versuch, eine Schreiboperation darauf auszuführen, zu dem Laufzeitfehler 75, »Fehler bei
Zugriff auf Datei«. Analoges gilt für den Zusatz Access Write und Lesezugriffe. Lautet der
Zusatz Access Read Write oder fehlt der Access-Zusatz, öffnet Open die Datei in diesen beiden
Dateiorientierte Funktionen und Anweisungen

Modi für den Schreib- und Lesezugriff. Ein- und Ausgabeoperationen beziehen sich in diesem
Fall auf den gleichen Puffer und den gleichen Dateizeiger.
Eine Datei lässt sich auch mehrfach öffnen, sofern sie nicht in einem der Modi Input, Output
oder Append geöffnet wird. In diesem Fall verwendet Visual Basic für die zugehörigen Datei-
nummern den gleichen Puffer, so dass zu jeder Zeit über jede der Dateinummern ein und der-
selbe Dateiinhalt verfügbar ist. Dateizeiger gibt es aber je Dateinummer einen eigenen (vgl. Bei-
spiel).
Gleich, in welchem Modus Sie eine Datei öffnen, Visual Basic verwendet standardmäßig die
Zugriffsart Shared, denn diese Zugriffsart erlegt Programmen die geringsten Einschränkungen
für den gemeinsamen Zugriff auf dieselbe Datei auf. Vom Prinzip her ist das zwar erwünscht,
im Einzelfall kann es aber dazu führen, dass sich Programme gegenseitig ins Handwerk pfu-
schen, weil ihre Puffer unter ungünstigen Bedingungen unterschiedliche Versionen des gleichen
Datensatzes oder des gleichen Dateibereichs enthalten können. Es gibt drei Möglichkeiten, dem
entgegenzuwirken: Die erste ist das härteste Geschütz und besteht darin, die Datei gleich beim
Öffnen durch Angabe einer der Zugriffsarten Lock Read, Lock Write oder Lock Read Write für den
exklusiven Lesezugriff, Schreibzugriff oder Schreib-/Lesezugriff zu öffnen. Die zweite besteht
darin, sich die gesamte Datei unmittelbar vor einem Schreib- bzw. Lesezugriff mittels Lock für
den exklusiven Zugriff zu reservieren. Diese beiden Techniken können natürlich scheitern,
wenn ein anderes Programm seinerseits eine Sperre auf die Datei errichtet hat – sei es auch nur
eine Sperre für einen einzelnen Datensatz respektive für einen kleinen Bereich der Datei. Die
dritte und moderateste Möglichkeit, auf einen bestimmten Datensatz oder Dateibereich unge-
stört zugreifen zu können, ist das Sperren genau dieses Datensatzes oder Bereichs mittels Lock
und das sofortige Entsperren mittels Unlock nach dem Zugriff. Die Wahrscheinlichkeit, dass
diese Technik scheitert, ist am geringsten, da es nur dann zu dem Laufzeitfehler 70, »Zugriff
verweigert«, kommt, wenn ein anderes Programm eine Sperre auf die gesamte Datei oder auf
genau denselben Datensatz bzw. Dateibereich errichtet hat. Insbesondere, wenn auch die ande-
ren Programme mit der gleichen Technik arbeiten, sind kaum Kollisionen zu befürchten – was
natürlich eine Fehlerbehandlung nicht entbehrlich macht.
Auch wenn Visual Basic bei Programmende offene Dateien automatisch schließt, sollten Sie
generell darauf achten, eine Datei unmittelbar nach der letzten Dateioperation mittels Close zu
schließen. Das gibt die Dateinummer und den Puffer frei und ermöglicht anderen Programmen
wieder den uneingeschränkten Zugriff auf die Datei. Insbesondere entfernt Close auch alle
Sperren, die mit Lock gesetzt und nicht explizit mit Unlock freigegeben wurden.
Beispiel

Beis piel
...................................................
Der folgende Codeauszug demonstriert zum einen die Fehlerbehandlung im Zusammenhang
mit der Open-Anweisung und verschiedenen Dateioperationen. Die Variable sDateipfad enthält
die leere Zeichenfolge als Wert. Daher scheitern alle dateibezogenen Operationen. Der Benutzer
kann den Vorgang abbrechen, wiederholen oder überspringen (ignorieren). Letzteres ist zu
empfehlen, um die verschiedenen Fehlermeldungen zu erhalten. Löscht man das erste Kommen-

1 50
Print #- Anweisung

tarzeichen in der zweiten Zeile, läuft der Code fehlerlos und demonstriert, wie es sich mit den
Dateizeigern verhält, wenn eine Datei im Modus Binary zweimal geöffnet wird.
sDateipfad = "" ' Als Dateiname nicht erlaubt!
' sDateipfad = "Test1" ' Dateiname ist OK
On Error GoTo OpenFehler ' Fehlerbehandlung einrichten
Open sDateipfad For Binary As 1
Open sDateipfad For Binary As 2

Put 1, 1, "abcd"
Print Seek(1), Seek(2) ' Dateizeiger #1 = 5, #2 = 1

Dateiorientierte Funktionen und Anweisungen


Put 2, 1, StrReverse(Input(LOF(2), 2))
Print Seek(1), Seek(2) ' Dateizeiger #1 = 5, #2 = 5
Seek 1, 1 ' Dateizeiger #1 = 1, #2 = 5
Seek 2, 1 ' Dateizeiger #1 = 1, #2 = 1
Print LOF(1), Input(LOF(1), 1) ' Ausgabe: 4, "dcba"
Print LOF(2), Input(LOF(2), 2) ' Ausgabe: 4, "dcba"
On Error GoTo 0 ' Fehlerbehandlung beenden
Close 1, 2
Exit Sub

OpenFehler: ' Routine für Fehlerbehandlung


sFehler = "Fehler" + Str(Err.Number) + ": " + Err.Description
Select Case MsgBox(sFehler, vbAbortRetryIgnore, "Fehler")
Case vbAbort: Error 1001
Case vbRetry: Resume
Case vbIgnore: Resume Next
End Select

Vgl. auch die Beispiele in »Close-Anweisung« (S. 133), »EOF-Funktion« (S. 137), »FileAttr-
Funktion« (S. 138), »FreeFile-Funktion« (S. 139), »Get-Anweisung« (S. 140), »Input- und
InputB-Funktion« (S. 142), »Input #-Anweisung« (S. 143) und »Loc-Funktion« (S. 146) sowie
das Beispiel im Abschnitt »Fehlerbehandlung« (S. 43).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Close, FreeFile

Print #- Anweisung
Print #iDateiNr[, Ausdr1[Trennz [Ausdr2] ... ]]
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Print # führt Ausgaben im gebietsspezifischen Format in die unter der Datei-
nummer iDateiNr geöffnete sequenzielle Datei durch. Die auf die Dateinummer folgende Para-
meterliste Ausdr1, Ausdr2 usw. darf Werte beliebiger Standardtypen enthalten. Print # gibt diese
Werte unter Beachtung des jeweils zwischen den Parametern stehenden Trennzeichens Trennz
aus.
Anwendung

Anwendung
...................................................
Während Print nur noch als Methode eines Form-, UserControl- und Debug-Objekts verfügbar
und somit sozusagen zur objektorientierten Seite von Visual Basic übergelaufen ist, ist Print#

1 51
Dateiorientierte Funktionen und Anweisungen

nach wie vor auf der traditionellen Seite der Sprache verblieben. Charakteristikum für die Aus-
gabe von Print# im Gegensatz zu Write# ist, dass die literale Darstellung der Werte im Allge-
meinen im gebietsspezifischen Format erfolgt. »Im Allgemeinen« deshalb, weil es auch Werte
gibt, die ungeachtet des Gebietsschemas nicht übersetzt werden. So die Werte True und False
des Datentyps Boolean und das Wort »Error« in der Ausgabe eines Error-Werts. Und obwohl
die Anweisung Null als »Null« in eine Datei schreibt, gibt sie den Wert Empty als leere Zeichen-
folge und somit gar nicht aus.
Als Trennzeichen Trennz sind das Semikolon und das Komma erlaubt. Bei Angabe eines Semi-
kolons setzt die Anweisung den folgenden Wert unmittelbar hinter den vorigen, wie bei der
Verkettung von Zeichenfolgen. Das Komma hingegen bewirkt, dass Print# den folgenden Wert
Dateiorientierte Funktionen und Anweisungen

an die nächste Tabulatorposition setzt und den Zwischenraum gegebenenfalls mit Leerzeichen
auffüllt. Der Abstand zwischen je zwei Tabulatorpositionen beträgt 14 Zeichen. Ist im
Anschluss an den letzten Parameter der Liste kein Trennzeichen spezifiziert, ergänzt die Anwei-
sung einen Wagenrücklauf Chr(13) und einen Zeilenvorschub Chr(10) bzw. vbCrLf. Als Werte
in der Parameterliste sind auch die Ausdrücke Spc(n) und Tab(n) zulässig, die jedoch keine
eigenständigen Zeichenfolgenfunktionen darstellen, sondern als Argument von Print, Print#
und Write# zulässig sind. Spc(n) fügt n Leerzeichen ein, und Tab(n) füllt die aktuelle Zeile bis
zur Tabulatorposition n mit Leerzeichen.
Warnung

Wa rnung
...................................................
Die Anweisung gibt Zeichenfolgen im ANSI-Code und nicht im Unicode aus.
Es ist im Allgemeinen nicht möglich, Fließkommawerte und Datumswerte, die mit Print#
geschrieben wurden, mittels Input # wieder in Variablen des gleichen Typs einzulesen, da Print
# seinen Ausgaben das gebietsspezifische Format verpasst, Input# aber Literale im standardisier-
ten Format erwartet. Damit das klappt, müssen Sie die Daten mit Write# und nicht mit Print#
schreiben.
Tipp

Tipp
...................................................
Im Gegensatz zu Write# versieht Print# Zeichenfolgen nicht automatisch mit Anführungszei-
chen. Wenn Sie ausschließlich Zeichenfolgen ausgeben, also reine Textverarbeitung betreiben,
ist Print# in jedem Fall die bessere Lösung. Zum zeilenweisen Lesen der Daten verwenden Sie
dann die Anweisung Line Input#.
Beispiel

Beis piel
...................................................
Die Prozedur Ersetze sucht in einer Textdatei alle Vorkommen der Zeichenfolge sSuch und
ersetzt diese gegen die Zeichenfolge sErsetz.
Function Ersetze(sDatei As String, sSuch As String, sErsetz As String)
Dim sZeile As String
Open sDatei For Input As 1
Open "Ersetz.tmp" For Output As 2 ' Temporäre Ausgabedatei anlegen
While Not EOF(1)
Line Input #1, sZeile ' Zeile lesen
Print #2, Replace(sZeile, sSuch, sErsetz) ' Ersetzen und schreiben
Wend
Close 1, 2 ' beide Dateien schließen
Kill sDatei ' Ausgangsdatei löschen
Name "Ersetz.tmp" As sDatei ' Temporäre Datei umbenennen
End Function

1 52
Put- Anweisung

Verwandte Befehle

Verwa ndte Befehle


...................................................
Input, Input#, Line Input#, Print, Write#
Verwandte Themen

Verwandte Them en
...................................................
Literale und Konstanten (S. 27)

Put- Anweisung
Put [#]iDateiNr, [lSatzNr], Wert

Dateiorientierte Funktionen und Anweisungen


Beschreibung

Bes c hreibung
...................................................
Die Anweisung Put ist das Gegenstück zur Anweisung Get. Sie schreibt die über den Parameter
Wert spezifizierten Daten in der gegebenen Repräsentation (typerhaltend) in die Datei mit der
Dateinummer iDateiNr. Ist eine Satznummer lSatzNr angegeben, schreibt die Anweisung im
Modus Random den Wert Wert als Datensatz unter Berücksichtigung der bei der Open-Anweisung
vereinbarten Datensatzlänge und im Modus Binary als schlichte Bytefolge ab der Byteposition
lSatzNr. Fehlt lSatzNr, schreibt die Anweisung den Wert als nächsten Datensatz (Random) bzw.
an der jeweils aktuellen Schreibposition (Binary) und aktualisiert danach den Datensatzzeiger
bzw. die aktuelle Schreibposition.
Der Parameter Wert kann einen beliebigen Typ tragen, nicht jedoch einen Objekttyp.
Anwendung

Anwendung
...................................................
Wenn es um das Schreiben und Lesen von Dateiformaten ging, waren Get und Put schon immer
die Arbeitspferde der Sprache Basic. Die Arbeitsweise dieser Anweisungen ist traditionell auf
indexsequenzielle Dateien zugeschnitten, deren Bearbeitung im Modus Random erfolgt. Get und
Put werden aber auch – jedoch mit leicht modifizierter Arbeitsweise – im Modus Binary einge-
setzt.

Der Modus Random


Beim Öffnen von Dateien im Modus Random wird normalerweise eine Datensatzlänge in Bytes
festgelegt, die fortan bestimmt, wie viele Bytes mit jeder Get- bzw. Put-Operation je Datensatz
gelesen bzw. geschrieben werden. Die Zählung der Datensätze beginnt bei 1. Den Bytebedarf
der elementaren Datentypen entnehmen Sie der Tabelle im Abschnitt »Elementare Datentypen«
(S. 49); den von Datentypen mit fester Länge sowie von benutzerdefinierten Datentypen ermit-
telt man am besten mittels LenB, da die Speicherausrichtung der Datenfelder noch eine zusätzli-
che Rolle spielt. Liegt Wert ein Typ variabler Länge zugrunde (bzw. ein Typ, der Felder variab-
ler Länge enthält), erweitert das den Datensatz um einen Deskriptor (lies: Längenangabe).
Dabei gilt, dass ein Deskriptor dem Wert unmittelbar vorausgeht. Mithin muss also der Län-
genbedarf eines oder mehrerer Deskriptoren bei der Berechnung der Datensatzlänge berück-
sichtigt werden. Für Zeichenfolgen variabler Länge schlagen dabei 2 Längenbytes (!) zu Buche
(Zeichenfolgen dürfen demnach nicht länger als 65.535 Zeichen sein), für Variant-Variablen
gleichfalls zunächst 2 Bytes für den VarType-Typ plus gegebenenfalls weitere Längenbytes für
Wertanteile mit variablen Längen. Dynamische Arrays schlagen mit 2 Bytes für den Array-Des-
kriptor zu Buche plus 8 Bytes je Dimension. Die maximale Datensatzlänge beträgt 32.767.
Put schreibt Wert linksbündig in den Datensatz, ohne Füllbytes anzuhängen, wenn die Reprä-
sentation von Wert kürzer als die Datensatzlänge ist. Sollte die Repräsentation von Wert länger
sein als die bei Open angegebene Datensatzlänge, kommt es zum Laufzeitfehler 59, »Falsche
Datensatzlänge«.

1 53
Dateiorientierte Funktionen und Anweisungen

Der Modus Binary


Für den Modus Binary gilt im Wesentlichen dasselbe, mit folgenden Abweichungen: Eine
Datensatzlänge wird nicht berücksichtigt, und die Anweisung schreibt ab der aktuellen Position
bzw. der Position lSatzNr so viele Bytes, wie die Darstellung von Wert benötigt. Zeichenfolgen
variabler Länge behandelt Put wie Zeichenfolgen fester Länge, schreibt also nur so viele Bytes
wie der Wert an Zeichen enthält – ein Deskriptoranteil entfällt somit. Analoges gilt auch für
Arrays. Im Zusammenhang mit benutzerdefinierten Datentypen finden Deskriptoranteile ein-
zelner Datenfelder jedoch sehr wohl Berücksichtigung.
Warnung

Wa rnung
...................................................
Dateiorientierte Funktionen und Anweisungen

Put schreibt Unicode-Zeichenfolgen als ANSI-Code und Get liest ANSI-Zeichenfolgen als Uni-
code.
Beispiel

Beis piel
...................................................
Die folgende Prozedur Crypt32 nimmt eine einfache 32 Bit-Verschlüsselung einer Datei sDatei
mit dem Wert lKennzahl vor. Der gleiche Wert entschlüsselt die Datei auch wieder; probieren
Sie es aus.
Sub Crypt32(lKennzahl As Long, sDatei As String)
Dim lData As Long
Open sDatei For Binary As 1
For i = 1 To LOF(1) – Len(lData) + 1
Get 1, i, lData
Put 1, i, lData Xor lData
Next i
Close 1
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Get, Input, Input#, LenB, Line Input#, LSet, Open, Print#
Verwandte Themen

Verwandte Them en
...................................................
Elementare Datentypen (S. 49); Benutzerdefinierte Datentypen (S. 60)

Reset- Anweisung
Reset
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Reset schließt alle offenen Dateien, die mittels Open-Anweisungen geöffnet wur-
den.
Anwendung

Anwendung
...................................................
Sinn und Zweck dieser Anweisung ist es, im Fehlerfall oder bei einem überraschenden Pro-
grammabbruch schnell aufräumen zu können. Reset erzwingt insbesondere die Ausgabe von
Pufferinhalten in Dateien, die zum Schreiben geöffnet wurden. Es besteht kein Unterschied zwi-
schen dem parameterlosen Aufruf von Close und Reset.

1 54
RmDir- Anweisung

Verwandte Befehle

Verwa ndte Befehle


...................................................
Close, End

RmDir- Anweisung
Sub RmDir(sVerzeichnisname As String)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung RmDir löscht das Verzeichnis sVerzeichnisName.

Dateiorientierte Funktionen und Anweisungen


Anwendung

Anwendung
...................................................
Der Wert des Parameters sVerzeichnisName kann ein (absoluter oder relativer) UNC-Pfad oder
Laufwerkspfad sein. Enthält sVerzeichnisName keinen Pfadanteil, geht die Anweisung davon
aus, dass das Verzeichnis ein Unterverzeichnis des standardmäßigen Verzeichnisses (vgl.
»CurDir-Funktion«, S. 134) ist. Falls das Verzeichnis noch Dateien enthält, löst die Anweisung
den Laufzeitfehler 75, »Fehler beim Zugriff auf Pfad/Datei«, aus. Existiert das Verzeichnis
überhaupt nicht, kommt es zum Laufzeitfehler 76, »Pfad nicht gefunden«.
Beispiel

Beis piel
...................................................
Die rekursive Prozedur DelTree löscht ein Verzeichnis mit allen Dateien und Unterverzeichnis-
sen.
Sub DelTree(sPfad As String)
Dim sUVz As String
If Right(sPfad, 1) = "\" Then ' "\" am Ende?
sPfad = Left(sPfad, Len(sPfad) – 1) ' Abschneiden
End
On Error GoTo Fehlerbehandlung ' Falls Kill scheitert
' oder Schreibschutz
Kill sPfad + "\*.*"
sUVz = Dir(sPfad + "\", vbDirectory)
While sUVz <> "" ' Unterverz. abklappern
If sUVz <> "." And sUVz <> ".." Then
DelTree (sPfad + "\" + sUVz) ' Rekursion
sUVz = Dir(sPfad + "\", vbDirectory) ' da Dir nicht rekursiv
Else ' arbeitet
sUVz = Dir ' Nächstes Verzeichnis löschen
End If
Wend
RmDir sPfad
On Error GoTo 0
Exit Sub
Fehlerbehandlung:
Resume Next
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
ChrDir, CurDir, Kill, MkDir

1 55
Dateiorientierte Funktionen und Anweisungen

Seek- Anweisung und Seek- Funktion


Function Seek(iDateiNr As Integer) As Long
Seek [#]iDateiNr, lPosition
Beschreibung

Bes c hreibung
...................................................
Als Funktion liefert Seek die aktuelle Position des Dateizeigers der unter der Dateinummer iDa-
teiNr geöffneten Datei. Für den Modus Random gibt diese Angabe die Nummer des nächsten zu
lesenden oder zu schreibenden Datensatzes ab Dateianfang wieder, für alle anderen Modi die
Nummer des nächsten zu lesenden oder zu schreibenden Bytes ab Dateianfang. Das erste Byte
Dateiorientierte Funktionen und Anweisungen

bzw. der erste Datensatz trägt die Nummer 1.


Als Anweisung setzt Seek den Wert lPosition als neue Position des Dateizeigers. Im Modus
Random ist diese Position eine Datensatznummer, in allen anderen Modi eine Bytenummer.
Anwendung

Anwendung
...................................................
Lese- und Schreiboperationen verschieben den Dateizeiger jeweils immer nur um die gelesene
Anzahl von Bytes bzw. Datensätzen, was dem Muster für den sequenziellen Dateizugriff ent-
spricht. Seek ermöglicht die Orientierung und Positionierung innerhalb von Dateien, wenn
indexsequenzielle Dateizugriffe erforderlich sind.
Warnung

Wa rnung
...................................................
Als Anweisung setzt Seek nichts weiter als den Dateizeiger. Falls der Wert von lPosition größer
als die von LOF gelieferte Dateilänge ist, bewirkt die nächste Schreiboperation einer zum Schrei-
ben geöffneten Datei eine entsprechende Verlängerung. Dagegen führt die nächste Leseopera-
tion, gleich im welchem Modus die Datei geöffnet wurde, zum Laufzeitfehler 62, »Einlesen hin-
ter Dateiende«.
Tipp

Tipp
...................................................
Die Syntax für die Dateioperationen Get und Put sieht die Angabe expliziter Positionsangaben
vor, so dass auf Seek verzichtet werden kann.
Beispiel

Beis piel
...................................................
Open sDatei For Output As 1
Seek 1, lOffs ' Dateizeiger auf bestimmte Zeile
Line Input #1, sZeile ' Zeile lesen
Print Seek(1) ' Dateizeiger abfragen

Die folgende Zeile zeigt, was passiert, wenn Seek über das Dateiende hinausschießt:
Open "Test" For Input As 1 ' Die Datei enthält 4 Bytes!
Seek 1, 10000 ' Dateizeiger auf 10000 setzen
Print Loc(1) ' Ausgabe: 9999
Print Seek(1) ' Ausgabe: 10000
Input #1, a ' Laufzeitfehler 62
Close

Vgl. auch das Beispiel zu »Open-Anweisung« (S. 149).


Verwandte Befehle

Verwa ndte Befehle


...................................................
Get, Loc, Open, Put

1 56
SetAttr- Anweisung

SetAttr- Anweisung
Sub SetAttr(sPfad As String, iAttributvektor As Integer)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung SetAttr setzt die Attribute der Datei oder des Verzeichnisses sPfad entsprechend
dem Attributvektor iAttributvektor.
Anwendung

Anwendung
...................................................
Das Dateisystem pflegt für jeden Namenseintrag einen Attributvektor (Bytewert), dessen Ele-
mente (Bits des Bytewerts) eine genauere Aussage darüber machen, welcher Art die zugeordnete

Dateiorientierte Funktionen und Anweisungen


Datei (bzw. das Verzeichnis) ist. Die folgende Tabelle gibt einen Überblick über die möglichen
Attribute sowie über die Konstanten, die in Visual Basic als Elemente des Aufzählungstyps
VbFileAttribute für diese Attribute definiert sind. SetAttr ignoriert Attribute, die es nicht set-
zen kann – so ist es beispielsweise nicht möglich, mittels SetAttr aus einer Datei ein Verzeichnis
zu machen.

Konstante Beschreibung
vbNormal (0) Keines der Bits im Attributvektor ist gesetzt, es handelt sich um eine
gewöhnliche Datei
vbReadOnly (1) Datei/Verzeichnis ist schreibgeschützt
vbHidden (2) Datei/Verzeichnis ist verborgen
vbSystem (4) Datei ist Systemdatei bzw. Verzeichnis ist Systemverzeichnis
vbVolume (8) Logischer Datenträger (wird von SetAttr nicht gesetzt)
vbDirectory (16) Verzeichnis (wird von SetAttr nicht gesetzt)
vbArchive (32) Datei wurde seit der letzten Datensicherung geändert
Konstanten für Dateiattribute

Beispiel

Beis piel
...................................................
Die folgenden Zeilen zeigen, wie man temporär einen Schreibschutz auf eine Datei entfernt und
dann wieder errichtet:
SetAttr sDateName, GetAttr(sDateiname) And Not vbReadOnly
...
SetAttr sDateName, GetAttr(sDateiname) Or vbReadOnly
Falls nicht klar ist, ob eine Datei schreibgeschützt ist oder nicht, schreiben Sie vorsichtiger:
AttrVekt = GetAttr(sDateiname)
SetAttr sDateName, AttrVekt And Not vbReadOnly
...
SetAttr sDateName, AttrVekt
Verwandte Befehle

Verwa ndte Befehle


...................................................
Dir, FileAttr, GetAttr

1 57
Dateiorientierte Funktionen und Anweisungen

Shell- Anweisung
Function Shell( _
sAnwendName As String, _
[FensterStil As VbAppWinStyle = vbMinimizedFocus]) _
As Double
Beschreibung

Bes c hreibung
...................................................
Die Funktion Shell ermöglicht den Start einer anderen Anwendung sAnwendName als eigenstän-
dige Anwendung und liefert als Funktionswert die Task-ID des zugehörigen Prozesses respek-
tive 0, wenn der Start nicht erfolgreich verlaufen ist. Die Bedeutung der Werte für den optiona-
Dateiorientierte Funktionen und Anweisungen

len Parameter FensterStil listet die folgende Tabelle auf.

Konstante Beschreibung
vbHide (0) Das Fenster der Anwendung ist nicht sichtbar, erhält aber den
Fokus.
vbNormalFocus (1) Das Fenster der Anwendung ist sichtbar, hat Normalgröße und
erhält den Fokus.
vbMinimizedFocus (2) Die Anwendung startet als Symbol, erhält aber den Fokus
(Standardwert).
vbMaximizedFocus (3) Die Anwendung startet mit maximiertem Fenster und erhält
den Fokus.
vbNormalNoFocus (4) Das Fenster der Anwendung ist sichtbar, hat Normalgröße,
erhält aber nicht den Fokus.
vbMinimizedNoFocus (6) Die Anwendung startet als Symbol, ohne den Fokus zu erhal-
ten.
Fensterstile für den Start einer Anwendung aus Visual Basic heraus

Anwendung

Anwendung
...................................................
Das gestartete Programm erbt das standardmäßige Verzeichnis des aufrufenden Programms
(vgl. »CurDir-Funktion«, S. 134). Mit der von Shell gelieferten Task-ID lässt sich mit den inhä-
renten Mitteln von Visual Basic nicht anderes anfangen, außer sie der Anweisung AppActivate
zu übergeben, um der gestarteten Anwendung den Fokus zuzuschanzen. Das könnte etwa
geschehen, um diese Anwendung mittels der Anweisung SendKeys fernzusteuern. Auf diese
Weise lassen sich »die Geister, die man rief« beispielsweise auch wieder loswerden.
Tipp

Tipp
...................................................
Um eine Anwendung unter Vorgabe eines bestimmten Arbeitsverzeichnisses zu starten, stellen
Sie dieses Verzeichnis vor dem Shell-Aufruf mittels ChDrive und ChDir als standardmäßiges
Arbeitsverzeichnis ein.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel zur »Date-Funktion und Date-Anweisung« (S. 116).

1 58
Unlock- Anweisung

Unlock- Anweisung
Sub Unlock([#]iDateiNr As Integer[, lDatensatz As Long])
Sub Lock([#]iDateiNr As Integer, [lStartNr As Long] To lEndNr As Long)
Beschreibung

Bes c hreibung
...................................................
Die Anweisung Unlock hebt bestehende (programmeigene) Sperren für einen einzelnen Daten-
satz lDatensatz oder einen Bereich von Datensätzen lStartNr bis lEndNr auf, die für die Datei
mit der Dateinummer iDateiNr mittels eines vorangegangenen Lock-Aufrufs errichtet wurden.
Fehlt bei Gebrauch der ersten Syntax der optionale Parameter lDatensatz, hebt Unlock eine

Dateiorientierte Funktionen und Anweisungen


Sperre auf, die für die gesamte Datei errichtet wurde. Fehlt bei Gebrauch der zweiten Syntax
der optionale Parameter lStartNr, entsperrt die Anweisung alle Datensätze von der Nummer 1
bis zur Nummer lEndNr. Bei Dateien, die im Modus Binary geöffnet wurden, beziehen sich die
Bereichsangaben auf Positionen des Dateizeigers.
Anwendung

Anwendung
...................................................
Wenn in einem System oder in einem Netzwerk mehrere Programme gleichzeitig Schreibzugriffe
auf dieselbe Datei durchführen, kann das recht unangenehme Inkonsistenzen zur Folge haben.
Das Anweisungspaar Lock/Unlock ermöglicht es einem Programm, sich temporär die Exklusiv-
rechte für das Beschreiben eines gewissen Teils der Datei zu sichern. Jeder Unlock-Anweisung
muss eine gleichlautende Lock-Anweisung vorangegangen sein, sonst löst diese den Laufzeitfeh-
ler 70, »Zugriff verweigert« aus.
Warnung

Wa rnung
...................................................
Bei Lock/Unlock-Anweisungen für sequenzielle Dateien (Input, Output, Append) ignoriert Visual
Basic Bereichsangaben und sperrt immer die gesamte Datei. Entgegen anders lautenden
Informationen in der Online-Hilfe zu Visual Basic 6.0 entfernt Close (respektive das Program-
mende) jedoch alle Sperren, die mit Lock gesetzt und nicht explizit mit Unlock wieder freigege-
ben wurden.
Beispiel

Beis piel
...................................................
Der folgende Code schreibt eine Reihe von Datensätzen in die gemeinsame genutzte Datei Kun-
den.idx:
Open "Kunden.idx" For Random As 1 Len = Datensatzlänge
On Error GoTo Fehler70
Lock 1, lStartBereich To lEndBereich ' Sperre errichten
On Error GoTo 0
For i = lStartBereich To lEndBereich
Put 1, i, bdt(i)
Next
Unlock 1, lStartBereich To lEndBereich ' Sperre aufheben
Close 1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Lock, Open

Write #- Anweisung
Write #iDateiNr[, Ausdr1[Trennz [Ausdr2] ... ]]

1 59
Dateiorientierte Funktionen und Anweisungen

Beschreibung

Bes c hreibung
...................................................
Die Anweisung Write # schreibt Daten im Standardformat für literale Werte in die unter der
Dateinummer iDateiNr geöffnete sequenzielle Datei. Die auf die Dateinummer folgende Para-
meterliste Ausdr1, Ausdr2 usw. darf Werte beliebiger Standardtypen enthalten. Write # gibt diese
Werte unter Beachtung des jeweils zwischen den Parametern stehenden Trennzeichens Trennz
aus.
Anwendung

Anwendung
...................................................
Da Print# Daten im gebietsspezifischen Format schreibt, wird Write# immer dann anstelle von
Dateiorientierte Funktionen und Anweisungen

Print# eingesetzt, wenn die geschriebenen Daten später mittels Input# wieder eingelesen werden
sollen. Das Standardformat für literale Werte sieht insbesondere vor, dass Zeichenfolgen in
Anführungszeichen und Datumswerte im Format #mm/tt/jjjj# notiert werden.
Als Trennzeichen Trennz sind das Semikolon und das Komma erlaubt. Im Gegensatz zu Print #
unterscheidet Write# nicht zwischen den beiden Trennzeichen und trennt aufeinanderfolgende
Werte der Parameterliste durch ein Komma. Ist im Anschluss an den letzten Parameter der Liste
kein Trennzeichen spezifiziert, ergänzt die Anweisung einen Wagenrücklauf Chr(13) und einen
Zeilenvorschub Chr(10) bzw. vbCrLf.
Warnung

Wa rnung
...................................................
Write# gibt Zeichenfolgen im ANSI-Code und nicht im Unicode aus.
Tipp

Tipp
...................................................
Im Gegensatz zu Write# versieht Print# Zeichenfolgen nicht automatisch mit Anführungszei-
chen. Wenn Sie ausschließlich Zeichenfolgen ausgeben, also reine Textverarbeitung betreiben,
ist Print# in jedem Fall die bessere Lösung. Zum zeilenweisen Lesen der Daten verwenden Sie
dann die Anweisung Line Input#.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel zu »Input #-Anweisung« (S. 143).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Input#, Open, Print#
Verwandte Themen

Verwandte Them en
...................................................
Literale und Konstanten (S. 27)

1 60
Variablen
Eine Variable ist ein auf einen bestimmten Datentyp (Datenformat) zugeschnittener »Behälter«,
der einen Bezeichner (lies: einen Namen) trägt und einen (in dem Datenformat gehaltenen)
Wert enthält.
Beschreibung

Bes c hreibung
...................................................
Charakteristikum der Variable ist, dass ihr Wert veränderlich ist, das heißt, er kann nach Belie-
ben zur Laufzeit im Rahmen von Zuweisungsoperationen sowie von Funktions- und Prozedur-
aufrufen geändert werden. Mit dieser Eigenschaft ist die Variable unverzichtbarer Bestandteil
einer jeden Programmiersprache und Medium für den formalen Umgang mit Daten jeglicher
Art.
Anwendung

Anwendung
...................................................
Für die Wahl des Variablenbezeichners gelten die üblichen Vorschriften für die Bezeichnerwahl
(vgl. »Bezeichner und Namensraum«, S. 34). Variablen erhalten ihren Wert durch Zuweisung
eines Literals, einer Konstante, einer anderen gleichartigen Variablen, eines Funktionswerts
oder eines Ausdrucks, wobei die jeweiligen Datenformate miteinander verträglich sein müssen.
Dim MyVar1 As Integer, MyVar2 As Integer, MyVar3 As Integer
Dim MyVar4 As Integer
MyVar1 = 17 ' Variable MyVar1 erhält Literal als Wert
MyVar2 = MyVar1 ' Variable MyVar2 erhält Wert von MyVar1
MyVar3 = MyVar1 + 17 ' Variable MyVar3 erhält Ergebnis von Berechnung
MyVar4 = Max(MyVar1, MyVar3) ' Variable MyVar4 erhält Funktionswert

Somit können Variablen für alles stehen, was einen in einen Datentyp gefassten Wert darstellt.
Auch wenn es die Sprache Visual Basic im Vergleich zu anderen Programmiersprachen nicht
gerade offensichtlich macht: Es besteht ein gewisser Unterschied zwischen Variablen, die einen
einfachen Datentyp, und solchen, die einen komplexen Datentyp tragen. Zu den einfachen
Datentypen zählen: alle elementaren Datentypen (vgl. »Elementare Datentypen«, S. 49), ausge-
nommen String und Variant; weiterhin: Aufzählungsdatentypen (vgl. »Enum-Aufzählungen«,
S. 62), alle benutzerdefinierten Datentypen, die ihrerseits nur einfache Datentypen als Felder
enthalten; der Typ String* für Zeichenfolgen fester Länge und Datenfelder fester Größe, deren
Elemente einen einfachen Datentyp tragen. Diese Datentypen zeichnen sich dadurch aus, dass
sich ihre Repräsentation während des Programmablaufs von der Länge her nicht verändert und
sie deshalb als kompakte Bytefolge gespeichert werden können. Die einfachen Datentypen noch
abgerechnet, die als spezielle öffentliche Datentypen im Objektkatalog des Systems registriert
sind und ihrerseits aus einfachen Datentypen ausgebaut sind, rechnet man alle anderen Daten-
typen zu den komplexen Datentypen. Insbesondere zählen dynamische Zeichenfolgen des Typs
String, der flexible Datentyp Variant, dynamische Arrays sowie alle zu Objekten gehörigen
Datentypen (Klassen) zu den komplexen Datentypen. Komplexe Datentypen lassen sich nicht
kompakt speichern, sondern bestehen aus Deskriptoranteilen (Verweisen, Längen etc.) und
Wertanteilen.
Während die komplexen Datentypen String und Variant mit einem elementaren Datentyp als
Untertyp noch relativ einfach und größtenteils intuitiv zu handhaben sind, ist der Umgang mit
dynamischen Arrays und Objekten nicht ohne ein gewisses Verständnis für die Natur der
»dahinter liegenden« Größen zu bewerkstelligen. Obwohl andere Programmiersprachen hier
eine recht klare Linie zwischen Variablen ziehen, die für eine konkrete Größe stehen und sol-
chen, die nur einen Verweis auf eine andere Größe darstellen, gibt es in Visual Basic das Kon-
zept des Verweises offiziell nur in Bezug auf die Parameterübergabe bei Funktionsaufrufen.

1 61
Variablendeklaration

»Hinter den Kulissen« arbeitet aber auch Visual Basic massiv mit Verweisen. Deutlich wird das
beispielsweise, wenn man eine Objektvariable einer abstrakten Klasse (etwa der Klasse Form)
vereinbart, der man zwar konkrete via Set ins Leben gerufene und von Form abstammende
Objekte als Werte zuweisen kann, nicht jedoch via Set einen Wert der Klasse Form selbst – einen
solchen gibt es nämlich nicht als konkreten Wert, weil eine Objektvariable des Typs Form ein
reiner Verweis ist.
»Verständnis für die Natur eines Werts zu haben«, bedeutet für den Visual-Basic-Programmie-
rer natürlich nicht, dass er bis auf das Genaueste wissen muss, wie Visual Basic Objekte reprä-
sentiert (das ist auch C++-Programmierern im Allgemeinen nicht bis auf das Letzte klar, weil es
letztlich vom Compiler abhängt, wie er ein Objekt repräsentiert). Das genau ist ja die Stärke der
Variablendeklaration

abstrakten Datentypen, deren Implementationen hinter Objekten verborgen bleiben. Es bedeu-


tet aber sehr wohl, dass man bei der Verwendung von Variablen nicht alle Werte in einen Topf
schmeißen darf und insbesondere wissen muss, ob man es mit einer Variablen für einen einfa-
chen Datentyp, einen dynamischen Datentyp, ein konkretes Objekt oder ein abstraktes Objekt
zu tun hat.

Variablendeklaration
Dim [WithEvents] VarName[([Indizes])] [As Typ]
Dim VarName[([Indizes])] [As [New] Typ]
Dim [WithEvents] VarName[...], [WithEvents] VarName[...][, ...]
Private VarName[([Indizes])] [As [New] Typ]
Private [WithEvents] VarName[([Indizes])] [As Typ]
Private [WithEvents] VarName[...], VarName[...][, ...]
Public VarName[([Indizes])] [As [New] Typ]
Public [WithEvents] VarName[([Indizes])] [As Typ]
Public [WithEvents] VarName[...], VarName[...][, ...]
Static VarName[([Indizes])] [As [New] Typ]
Static VarName[...], VarName [...][, ...]
Option Explicit
Beschreibung

Bes c hreibung
...................................................
Visual Basic ist eine typisierende Programmiersprache. Zwar nimmt der Compiler von sich aus
eine – für den Programmierer weitgehend transparente – implizite Typzuordnung und Typum-
wandlung von Werten je nach Erfordernis vor, doch dieses Standardverhalten überdeckt nur
einen kleinen Teil der mit Visual Basic verfügbaren Typenvielfalt. Der volle Umfang der von
Visual Basic unterstützten Datentypen mit allen ihren Repräsentationsformen und Geltungsbe-
reichen lässt sich nur bei Verwendung der expliziten Variablendeklaration nutzen. Jede Dekla-
ration impliziert eine Initialisierung mit dem Standardwert des – implizit oder explizit – verein-
barten Datentyps.
Anwendung

Anwendung
...................................................
Bei der expliziten Deklaration von Variablen unterscheiden Programmiersprachen traditionell
zwischen der statischen und der automatischen Vereinbarung. Statische Variablen, für deren
Deklaration das Schlüsselwort Static erforderlich ist, finden ihre Repräsentation im Datenseg-
ment des Prozesses, während automatische Variablen ihr (meist kurzes) Dasein auf dem Stack
fristen. Visual Basic erlaubt die Vereinbarung statischer Variablen nur auf Prozedurebene

1 62
Variablendeklaration

(innerhalb von Prozedur- bzw. Funktionskörpern) und ermöglicht damit Prozeduren »mit
Gedächtnis«: Im Gegensatz zur automatischen Variablen, die bei jedem Aufruf neu auf dem
Stack angelegt wird, bleibt eine statische Variable und damit auch ihr Wert von einem Aufruf
zum nächsten erhalten.
Bei der Darstellung komplexer Datentypen, so beispielsweise von dynamischen Arrays und
Objekten, kommt – bei beiden Vereinbarungsarten – ein dritter Speicherbereich ins Spiel, der
Heap. In diesem Fall stellt die statisch oder automatisch vereinbarte Variable eine Referenz auf
den eigentlichen Wert dar, der seinerseits auf dem Heap liegt. Der Variablendeklaration muss
dann eine explizite oder implizite Initialisierung mit New folgen, damit die Variable einen von
Empty, Nothing bzw. Null abweichenden Wert erhält. Implizit erfolgt die Initialisierung, wenn
bei der Deklaration der Variablen das Schlüsselwort New auftaucht. Äquivalent sind daher:

Variablendeklaration
Dim myForm As Form1
Set MyForm = New Form1
MyForm.Show

und

Dim myForm As New Form1


MyForm.Show

In diesem Fall kann also eine implizite Initialisierung durch Nennung erfolgen.
Visual Basic unterscheidet bei der expliziten, automatischen Variablendeklaration weiterhin
zwischen einer Vereinbarung auf Prozedurebene und einer Vereinbarung auf Modulebene (im
Bereich ALLGEMEIN). Vereinbarungen auf Prozedurebene und auf Modulebene lassen sich mit
dem traditionellen Basic-Schlüsselwort Dim treffen. Vereinbarungen auf Modulebene lassen sich
alternativ auch mittels der neuen Visual-Basic-Schlüsselwörter Private und Public treffen. Pri-
vate entspricht dabei dem Schlüsselwort Dim und begrenzt den Geltungsbereich der Variablen
auf das aktuelle Modul. Public dehnt dagegen den Geltungsbereich der Variablen auf alle
Module aus.
Bei der Deklaration einer Objektvariablen auf Modulebene ist der Zusatz WithEvents möglich.
Er spezifiziert, dass die Objektvariable auf ein Objekt verweisen wird, das von sich aus (mittels
RaiseEvent) Ereignisse generiert und die der »Besitzer« (das ist die Ebene, auf der die Objektva-
riable bekannt ist) behandeln oder weiterreichen sollte. Zur Behandlung solcher Ereignisse las-
sen sich dann in dem jeweiligen Modul unter dem Namen der Objektvariablen Behandlungs-
routinen bereitstellen – so wie man das von Steuerelementen, die auf einem Formular platziert
wurden, oder von Menüeinträgen her gewöhnt ist.
' Bereich Allgemein
Private WithEvents myObject As MyClass
...
Private Sub myObject_EventOfMyClass()
...

In der Tat nimmt Visual Basic für jedes Steuerelement, das auf einem Formular platziert wird,
implizit nichts anderes als eine WithEvents-Deklaration vor und vereinbart dabei den unter der
Eigenschaft Name des Steuerelements genannten Bezeichner als Objektvariable. WithEvents lässt
sich nur bei der Vereinbarung von Instanzen konkreter Klassen verwenden und schließt eine
gleichzeitige Verwendung des Spezifizierers New aus.

1 63
Variablendeklaration

Abkürzungen
Visual Basic vereinbart Variablen bei schlichter Nennung implizit als automatische Variablen
und ordnet ihnen den Datentyp Variant zu:
Private Sub Form_Click()
Set f = Me ' f ist Variant mit Objektreferenz
For i = 1 to 10 ' i ist Variant mit numerischem Wert
s = s + CStr(i) ' a ist Variant mit Stringwert
Next i
f.Caption = s ' Fenstertitel ändert sich zu 12345678910
End Sub
Variablendeklaration

Ein weitere, recht praktische Möglichkeit für die Abkürzung von Variablendeklarationen lie-
fern die traditionellen Typkennzeichen $, %, &, !, # der Sprache Basic. Mehr dazu unter »Typ-
kennzeichen und Bezeichnerbereiche für Typen« (S. 167).
Beispiele

Beis piele
...................................................
Das Projekt DMzuEuroRechner benutzt die explizite Variablendeklaration mit dem Datentyp
Long für die Rundung auf zwei Stellen hinter dem Komma. Das Formular enthält die Textfelder
TextDM und TextEuro, die bei Verlust des Eingabefokus den Wert des jeweils anderen Feldes an
ihren eigenen Wert anpassen.
' Projekt: DMzuEuroRechner
Private Const iKurs As Single = 1.95583

Private Sub TextDM_LostFocus()


Dim l As Long
l = TextDM.Text * 100 / iKurs ' implizite Typumwandlung
TextEuro.Text = l / 100 ' Typumwandlung und Rundung
End Sub

Private Sub TextEuro_LostFocus()


Dim l As Long
l = TextEuro.Text * iKurs * 100 ' implizite Typumwandlung
TextDM.Text = l / 100 ' Typumwandlung und Rundung
End Sub

Im folgenden Beispielprojekt NewForm erzeugt das von Visual Basic automatisch gestartete
Formular bei jedem Mausklick eine weitere Instanz seiner selbst. Die zuständige Variable frm-
Var wird implizit durch Nennung initialisiert. Jede Formularinstanz zählt die Mausklicks, auf
die es bereits reagiert hat, und gibt sie aus. Für das Zählen der Klicks ist iKlicks als statische
Variable vereinbart.
' Projekt: NewForm
Private frmVar As New Form1
Private Sub Form_Click()
Static iKlicks As Integer ' mit 0 initialisiert
iKlicks = iKlicks + 1
Print iKlicks; ". Klick in dieses Formular"
frmVar.Show ' implizite Initialisierung
End Sub

1 64
Variablendeklaration

Das kleine Programm zeigt sehr schön, dass jedes Formularobjekt auch von dieser statischen
Variablen seine eigene Kopie erhält. Von jedem Formular aus lässt sich immer nur ein weiteres
Formular starten, da fVar global deklariert ist. Schließt der Benutzer ein Fenster, bleibt das For-
mularobjekt erhalten und sein Fenster kommt durch den nächsten Klick in das jeweils vorge-
ordnete Formular erneut zur Anzeige. Man erkennt das an dem erhaltenen Wert von iKlicks,
den ein Mausklick in das wieder sichtbare Formular zu Tage fördert.

Warnung
Warnung

...................................................
Die Syntax von Visual Basic für die akkumulierende Variablenvereinbarung ist leider in fehler-
trächtiger Abweichung zu anderen Programmiersprachen (etwa zu C/C++, Pascal, Delphi)

Variablendeklaration
gestaltet, was gerade geübten Programmierern, die in vielen Sprachen zu Hause sind, gerne zum
Stolperstein wird. Die resultierenden Bugs sind nicht nur extrem schwer zu finden, sie sind noch
dazu ziemlich lästig, weil die implizite Typumwandlung des Compilers zuweilen die seltsamsten
Kapriolen auf Lager hat. Wer glaubt, mit der Formulierung
Dim s1, s2, s3, s4 As String
Dim i1, i2 As Integer

vier String-Variablen und zwei Integer-Variablen zu vereinbaren, ist bereits auf dem Holzweg,
wie der folgende Code zeigt:
i1 = 1234
i2 = 5678
s1 = i1 ' erwartet: s1 = "1234"
s2 = i2 ' erwartet: s2 = "5678"
s3 = s1 + s2 ' erwartet: Stringaddition
s4 = CStr(i1) + CStr(i2) ' Stringaddition nach expliziter Typumwandlung
Print s3, s4 ' unerwartete Ausgabe: 6912 12345678

Tatsächlich betrachtet der Compiler in diesem Codefragment i1, s1, s2 und s3 als Variablen
vom Typ Variant, wie der Debugger schnell anhand des Initialisierungswerts Leer enthüllt. Die
korrekte Formulierung lautet:
Dim s1 As String, s2 As String, s3 As String, s4 As String
Dim i1 As Integer, i2 As Integer
i1 = 1234
i2 = 5678
s1 = i1 ' s1 = "1234"
s2 = i2
s3 = s1 + s2 ' Stringaddition
s4 = CStr(i1) + CStr(i2) ' CStr ist nun eigentlich unnötig
Print s3, s4 ' erwartete Ausgabe: 12345678 12345678

Würde man den impliziten Typumwandlungsmechanismus nutzen, ließe sich die gesamte Vari-
ablendeklaration auf die Zeile
Dim s1 As String, s2 As String

beschränken. Wenn nämlich s1 und s2 Zeichenfolgen sind, nimmt Visual Basic bei den Zuwei-
sungen
s1 = i1 ' Typumwandlung: von Variant mit numerischen
s2 = i2 ' Daten in String

eine implizite Typumwandlung in den Datentyp String vor.

1 65
Variablendeklaration

Generell merke man sich die einfache Regel: Visual Basic ordnet jeder Variablen, die nicht
explizit und mit unmittelbar anschließender Nennung eines Datentyps deklariert wurde, den
Datentyp Variant zu. Auf diese Weise werden auch schlichte Schreibfehler schnell zur Falle.
Visual Basic vereinbart für den vertippten Bezeichner eine eigene Variable des Typs Variant.
Tipp

Tipp
...................................................
Gewöhnen Sie sich an, Variablen explizit zu vereinbaren und auch explizite Typumwandlungen
hinzuschreiben. Das hilft, unliebsame Überraschungen durch falsche Typisierung und durch
ungewollte Doppelverwendung weitgehend zu vermeiden. Sie erhalten eine bessere Kontrolle
über die Datentypen und gleichzeitig auch einen schnelleren Code. Wenn Sie wollen, dass Sie
Variablendeklaration

der Compiler zur expliziten Typdeklaration zwingt, fügen Sie die Anweisung
Option Explicit

in den Bereich ALLGEMEIN des jeweiligen Moduls ein. Auf diese Weise schützen Sie sich (und
ihre Kunden) vor unbemerkten Tippfehlern in Bezeichnern, die Visual Basic sonst ungefragt als
eigenständige Variablen des Typs Variant vereinbart und mit dem jeweiligen Standardwert ini-
tialisiert. Wenn Sie in der Entwicklungsumgebung von Visual Basic über das Menü EXTRAS/
OPTIONEN auf der Eigenschaftsseite EDITOR die Einstellung VARIABLENDEKLARATION ERFOR-
DERLICH treffen, setzt der Editor diese Anweisung automatisch in jedes neue Modul, das Sie
anlegen.
Wenn Sie es lieber auf die »sanfte Art« beigebracht haben wollen: Streuen Sie bei der Deklara-
tion (explizit oder implizit) Großbuchstaben in die Variablenbezeichner ein und tippen Sie die
Bezeichner später in Kleinbuchstaben. Der Editor von Visual Basic wandelt den Bezeichner bei
Verlassen der Zeile automatisch in die bei der Deklaration gewählte Schreibweise um. Bleibt die
Kleinschreibung erhalten, weist dies auf einen Tippfehler hin.
Const cMinLänge = 1
Const cMaxLänge = 1000
Private lFileLength As Long
...
' Bei Schreibfehlern korrigiert Visual Basic die Schreibweise nicht!
If lFileLength < cMaxLänge And lfilelenght > cminläng Then

Nachdem Dim-Anweisungen an beliebiger Stelle im Programm stehen dürfen, ist es darüber


hinaus eine Frage des Programmierstils, wo Sie Ihre Variablen explizit deklarieren:
● direkt »vor Ort«, unmittelbar vor der Initialisierung (populär)
● gleich zu Anfang der Prozedur (klassisch)
Die Deklaration »vor Ort« wird zwar immer populärer, weil sie angeblich die Lesbarkeit von
Programmen verbessern soll, meines Erachtens bewirkt sie aber eher das Gegenteil: Deklaratio-
nen, die irgendwo mitten im Programmtext versteckt sind, lassen sich schwer auffinden, wenn
der Typ der Variablen an späterer Stelle einmal unklar ist. Dagegen ist die Deklaration »zu
Beginn« ein klare Sache – man weiß immer, wo die Deklaration einer Variablen zu finden ist.
Welchen Stil auch immer Sie bevorzugen, bleiben Sie ihm treu. Es hat wenig Sinn, beide zu
mischen, dann ist die Verwirrung nämlich komplett. Eine Variable mit eingestreuter Deklara-
tion liest sich schnell als Variant, wenn einige zu Beginn deklarierte Variablen auf den klassi-
schen Deklarationsstil hindeuten
Verwandte Befehle

Verwa ndte Befehle


...................................................
ReDim

1 66
Typkennzeichen und Bezeichnerbereiche für Typen

Verwandte Themen

Verwandte Them en
...................................................
ActiveX-Steuerelemente (OCX) – Windows-Standardsteuerelemente (S. 433); Arrays (S. 55);
Datentypen und ihre Operationen (S. 49); Funktionen selbst definieren (S. 181); Geltungsbe-
reiche von Variablen (S. 173); Klassen als Datentypen für Objektvariablen (S. 196); Objekte
und Klassen (S. 195); Prozeduren selbst definieren (S. 183); Typkennzeichen und Bezeichner-
bereiche für Typen (S. 167); Variableninitialisierung (S. 168)

Typkennzeichen und Bezeichnerbereiche für Typen


$, %, &, !, #

Variablendeklaration
DefTyp AbisZ [, AbisZ[, ...]]
DefBool, DefByte, DefInt, DefLng, DefCur, DefSng, DefDbl, DefDec, DefDate, DefStr,
DefObj, DefVar
Beschreibung

Bes c hreibung
...................................................
Neben der expliziten Typdeklaration unterstützt Visual Basic natürlich auch die traditionellen
impliziten Möglichkeiten der Typdeklaration durch frei definierbare Präfixe (Bezeichnerberei-
che) und durch vordefinierte Suffixe (Typkennzeichen).
Anwendung

Anwendung
...................................................
Syntaktisch gesehen findet die Deklaration hier durch Erweiterung des Bezeichners um ein Zei-
chen statt. Die Suffixlösung – einst die populärere – muss mit einem festen Vorrat an Typkenn-
zeichen auskommen: $ für String, % für Integer, & für Long, ! für Single, # für Double. Selbst
angesichts der reicheren Typenvielfalt von Visual Basic ist dieser Vorrat nicht mehr aufgestockt
worden (nicht zuletzt mangels weiterer Sonderzeichen). Verwendung findet am ehesten noch
das Zeichenfolgenzeichen $
For i% = 1 to 100 ' Implizite Deklaration durch Typkennzeichen
a$ = a$ + Val(i%)
Next i%
Die Präfixlösung erfordert eine Deklaration, die festlegt, welches Präfix welchen Datentyp
kennzeichnen soll. Präfixe sind aus der Menge der für Bezeichner zulässigen Zeichen zu wählen.
Dabei können auch mehrere Präfixe, ja sogar Buchstabenbereiche, ein und denselben Datentyp
kennzeichnen. Der Compiler bemängelt allerdings, wenn Sie versuchen, einen Buchstaben meh-
reren Datentypen zuzuordnen.
' Bereich Allgemein
DefLng L,X-Z
DefStr S
DefBool B
DefCur C
DefObj O

Damit erhalten alle Variablen, deren Bezeichner mit einem der Zeichen L, X, Y oder Z beginnt,
bei schlichter Nennung (implizite Deklaration) automatisch den Typ Long. Zeichenfolgenvari-
ablen werden dagegen durch einen mit S beginnenden Bezeichner implizit vereinbart usw. Bei
expliziter Typdeklaration oder Verwendung eines vordefinierten Suffix ist diese Namenskon-
vention außer Kraft.
DefCur C
...

1 67
Variableninitialisierung

cWertInEuro ' Typ ist Currency


c$ = "DM" ' Typ ist String
Dim cents As Integer ' Typ ist Integer

Visual Basic verwendet implizit die Vereinbarung


DefVar A-Z

das heißt, alle Variablen erhalten bei impliziter Deklaration den Standardtyp Variant. Um Long
als neuen Standardtypen zu vereinbaren, schreiben Sie:
DefLong A-Z
Variableninitialisierung

Eine solche Vereinbarung kann durchaus sinnvoll sein, weil sie nicht nur den Code schneller
macht, sondern auch eine explizite Deklaration des komplizierten Typs Variant erzwingt.
Tipp

Tipp
...................................................
Um den Typ einer Variablen mittels Suffix festzulegen, genügt es, das Suffix bei erstmaliger
Nennung des Variablenbezeichners zu gebrauchen. Für weitere Nennungen ist ein Suffix nicht
mehr erforderlich – aber auch nicht schädlich. Wenn Sie nicht wissen, welchen Typ eine Vari-
able hat, können Sie den Typ mittels TypeName in Erfahrung bringen.
a$ = 10 ' implizite Deklaration als String, 10 ist "10"
Print a, TypeName(a) ' Ausgabe: 10 String
Verwandte Befehle

Verwa ndte Befehle


...................................................
Option Base, Option Explicit
Verwandte Themen

Verwandte Them en
...................................................
Elementare Datentypen (S. 49); Variableninitialisierung (S. 168); Geltungsbereiche von Vari-
ablen (S. 173); Arrays (S. 55); Funktionen selbst definieren (S. 181); Prozeduren selbst defi-
nieren (S. 183)

Variableninitialisierung
[Let] SimpleVar = Ausdruck
Set ObjektVar = [New] ObjektAusdr
Set ObjektVar = Nothing
Beschreibung

Bes c hreibung
...................................................
Im klassischen Programmiermodell für typisierende Sprachen muss eine Variable vor ihrem ers-
ten Einsatz als »Rechtswert« (lies: auf der rechten Seite des Gleichheitszeichens oder als Para-
meter bei einem Funktions-/Prozeduraufruf) geeignet deklariert und initialisiert werden. Basic
war in dieser Hinsicht schon immer etwas legerer, weil es weder die Deklaration noch die Initi-
alisierung zwingend vorschreibt, sondern bei Nennung eines Bezeichners eine implizite Deklara-
tion und im selben Aufwasch auch eine Initialisierung mit dem Standardwert des jeweiligen
Datentyps vornimmt. Somit kann der Basic-Programmierer im Allgemeinen davon ausgehen,
dass jede Variable zu jedem Zeitpunkt einen definierten Zustand besitzt (das ist nicht in allen
Sprachen so). Dennoch wird in den meisten Fällen eine explizite Variableninitialisierung nicht
nur die Lesbarkeit verbessern, sondern auch vonnöten sein.

1 68
Variableninitialisierung

Anwendung

Anwendung
...................................................
Die Initialisierung von Variablen, die keine Objektvariablen sind, erfolgt grundsätzlich durch
eine einfache Let-Zuweisung, wobei das optionale Schlüsselwort Let so gut wie immer der Ein-
fachheit halber weggelassen wird. Visual Basic nimmt bei einer solchen Zuweisung gegebenen-
falls erforderliche Typumwandlungen von sich aus vor – was nicht gerade immer zum
gewünschten Ergebnis führt.
Anders sieht die Sache bei Objektvariablen aus. Erfolgt die Deklaration einer Objektvariablen
unter Angabe von New, erzeugt Visual Basic das entsprechende Objekt umgehend, das heißt, die
Variable wird im Rahmen der Deklaration vollständig initialisiert (lies: an ein vollständig initia-
lisiertes Objekt gebunden). Fehlt der Spezifizierer New, initialisiert Visual Basic die Objektvari-

Variableninitialisierung
able zunächst mit dem Standardwert Empty für den Datentyp Object (welcher für Objekte aller
Klassen benutzt werden kann). Dem muss an späterer Stelle eine explizite Initialisierung der
Objektvariablen im Rahmen einer Set-Anweisung unter Angabe des Schlüsselwortes New sowie
einer konkreten Klasse folgen, die das Objekt schließlich ins Leben ruft:
Dim myObject As Object ' Deklaration
...
Set myObject = New Form1 ' an späterer Stelle ...
Warnung

Wa rnung
...................................................
Wie schon angedeutet, spielt Visual Basic dem Programmierer gerne mal den einen oder ande-
ren Streich, indem es von sich aus implizite Typzuordnungen und -umwandlungen vornimmt.
Eine notorische Ursache für Ungereimtheiten im Programmverhalten ist die auf die gebietsspezi-
fische Zahlendarstellung (Ländereinstellungen des Systems) zurückzuführende Punkt-/Komma-
Problematik bei der Initialisierung mit numerischen Literalen und literalen Zeichenfolgen. Wer
mit der Gebietseinstellung »Deutsch (Standard)« auf seinem System einen Zahlenwert als lite-
rale Zeichenfolge spezifiziert, muss darauf achten, das Dezimalsymbol als echtes Komma zu
schreiben. Punkte in literalen Zeichenfolgen ignoriert Visual Basic geflissentlich. Diese Proble-
matik ist inzwischen fast schon älter als des Kaisers Bart, und man muss sich wahrlich die Frage
stellen, warum Microsoft die Sprache inzwischen nicht um einen entsprechenden Schalter
erweitert hat (etwa Option Locale), der es erlaubt, das Problem mit globaler Wirkung schlicht
abzuschalten.
Ein weiteres Problem wirft zuweilen die Initialisierung mit literalen Werten in hexadezimaler
Darstellung auf. Visual Basic betrachtet ein vierstelliges Hex-Literal grundsätzlich als Wert vom
Typ Integer, auch wenn der Linkswert vom Typ Long ist. Somit konvertiert Visual Basic bei-
spielsweise den Wert &HFFFF in -1 und nicht in 65.535. Als Lösung bietet es sich an, dem Literal
entweder eine (oder mehrere) führende Null(en) zu verpassen oder das Typkennzeichen & anzu-
hängen (vgl. unter Beispiele).
Tipp

Tipp
...................................................
Mit Visual Basic 6 hat sich zumindest etwas getan, was die Beilegung der Punkt-/Komma-Pro-
blematik betrifft, wenn auch nicht gerade viel. Die neue Funktion StrConv ermöglicht unter
anderem die Angabe einer Gebietsschema-ID für die Umwandlung einer Zeichenfolge in den
Typ Variant mit Untertyp String. Damit lässt sich ein bestimmtes Gebietsschema als Referenz-
schema verwenden, was eine gewisse Unabhängigkeit von den Systemeinstellungen bedeutet.
Sollte eine Variable trotz sorgfältig geprüfter Deklaration und Initialisierung ihren Wert aus
unerklärlichen Gründen plötzlich ändern, sind Sie aller Wahrscheinlichkeit nach einer Verlet-
zung der Regeln für den Geltungsbereich aufgesessen. In den meisten Fällen wurde ein Proze-
durparameter genauso benannt wie eine globale Variable.

1 69
Variableninitialisierung

Beispiele

Beis piele
...................................................
' String
Dim A As String ' "" (Standardwert)
Dim B As String ' "" (Standardwert)
A = "Literal" ' "Literal"
B = A + A ' "LiteralLiteral"
A = 100 ' "100" implizite Str-Umwandlung
A = Hex$(65) ' "41"

' String *
Variableninitialisierung

Dim A As String * 6 ' "||||||" (Standardwert mit | als


' Nullzeichen)
A = "String" ' "String"
A = "Integer" ' "Intege" Wert ist abgeschnitten
A = "DM" ' "DM " mit Leerzeichen aufgefüllt

' Byte
Dim A As Byte ' 0 (Standardwert)
A = i% ' 0 (implizite Typumwandlung
' geht gut, solange i% < 256)
A = AscB(s$) ' geht immer gut
A = Asc(s$) ' geht nicht immer gut, wenn s$ Unicode

' Integer
Dim A As Integer ' 0 (Standardwert)
Dim B As Integer ' 0 (Standardwert)
A = 10 ' 10
A = &HFFFF ' -1 (Zweierkomplement)
A = 10.5 ' 10 (Nachkommastellen abgeschnitten)
A = -10.5 ' -10 (Nachkommastellen abgeschnitten)
B = A ' 10
B = "10.5" ' 105 (implizite Val-Umwandlung, Punkt nicht als
' Komma erkannt, wegen Ländereinstellungen!)

' Long
Dim A As Long ' 0 (Standardwert)
A = 123456789& ' 123456789 (Long-Literal wegen &)
A = &HFFFF ' -1 (Zweierkomplement und Interpretation als
' Integer-Literal)
A = &HFFFF& ' 65535 (Long-Literal)
A = &HFFFFFFFF ' -1 (Zweierkomplement)
b% = 10: A = b% ' 10 (implizite Typumwandlung)
A = "123,456789" ' 123 (implizite Val-Umwandlung
' Nachkommastellen abgeschnitten)
A = "123.456789" ' 123456789 (implizite Val-Umwandlung und Punkt nicht
' als Komma erkannt, wegen Ländereinstellungen!)

' Single
Dim A As Single ' 0.0 (Standardwert)
A = 1023.1234567 ' 1023.123 (nicht mehr als 7 Stellen)

1 70
Variableninitialisierung

A = 1E-23 ' 1E-23


A = "123,123456" ' 123.1234 (implizite Val-Umwandlung)
A = "123.456789" ' 1.234568E+8 (Rundung und Punkt wird wegen
' Ländereinstellungen nicht als Komma erkannt!)

' Double
Dim A As Double ' 0.0 (Standardwert)
A = 1023.1234567 ' 1023.1234567 (maximal 14 Stellen)
A = &HFFFFFFFF ' -1 (Hexzahl zuerst als Long, Zweierkomplement)
A = "123,123456" ' 123.1234 (implizite Val-Umwandlung)

Variableninitialisierung
A = "123.456789" ' 1.234568E+8 (Rundung! Punkt wird wegen
' Ländereinstellungen nicht als Komma erkannt!)

' Boolean
Dim A As Boolean ' False (Standardwert)
Dim B As Boolean ' False (Standardwert)
A = True ' True
A = (A <> True) ' False
A = 1234 ' True
A = 0 ' False

' Currency
Dim A As Currency ' 0 (Standardwert)
A = 12345.1234 ' 12345.1234 (Literal)
A = "12345.1234" ' 123451234 (implizite Val-Umwandlung, Punkt wird
' wegen Ländereinstellungen nicht als Komma erkannt!)
A = 12.123456 ' 12.1235 (Rundung auf vier Stellen hinter dem Komma)
A = &HFFFFFFFF ' -1 (Longliteral und Zweierkomplement)

' Decimal
Dim A As Variant ' Datentyp kann nicht direkt vereinbart werden!
A = CDec("123456789012345678901234567890") ' 29 Stellen erlaubt
A = CDec("12.12") ' 1212 (implizite Val-Umwandlung, Punkt wird
' wegen Ländereinstellungen nicht als Komma erkannt!)
A = CDec("12,12") ' 12.12
A = CDec(12.12) ' 12.12 (Wandlung über Single)
A = CDec(&HFFFF) ' -1 (Zweierkomplement und Interpretation als
' Integer -Literal)

' Date
Dim A As Date ' 00:00:00
A = "01.01.2000" ' 01.01.00
A = "1.1.00" ' 01.01.00
A = 12.12 ' 11.01.1900 02:52:48 (Wandlung über Single)
A = "1.1" ' 01.01.00 (aktuelles Jahr wird ergänzt)
A = &HFFFF ' 29.12.1899 (Hausnummer, Wandlung über Integer)
A = "11.11.11 11:11" ' Faschingsbeginn im Jahre 2011
A = "12:23:01" ' 12:23:01 (Uhrzeit!)

' Object
Dim A As Object ' Nothing (Standardwert)

1 71
Variableninitialisierung

Dim B As New Form1 ' B ist Objekt der Klasse Form1


Set A = New Form1 ' A ist Objektvariable und verweist auf neues Objekt
' der Klasse Form1. New ist erforderlich!
B.Hide ' Set oder New ist nicht erforderlich!
Set A = B ' Altes Objekt von A stirbt, und A wird Objektvariable
' für B. Set ist erforderlich!
A.Show ' B-Formular wird angezeigt
B.Caption = "B" ' Titelleiste von B-Formular ändert sich in "B", denn
' Objektvariable A ist Synonym für Objekt B

' Variant
Variableninitialisierung

Dim A As Variant ' Empty (Standardwert)


Dim B ' Empty (Standardwert)
Dim C As Object ' Nothing (Standardwert)
B = Null ' Null
A = C ' Nothing
A = "1234" ' "1234"
A = 1234 ' 1234
A = TypeName(A) ' "Integer"

' Arrays
Dim A(20) As Integer ' A ist Arrayvariable für Array mit 21 Feldern
' bei standardmäßiger Indexzählung ab 0, sonst
' mit 20 Feldern. Alle Feldwerte sind mit 0
' (Standardwert für Integer) initialisiert.
Dim B(3 To 30) As Date ' B ist Arrayvariable für Array mit 28 Feldern.
' Die Indexzählung beginnt ab 3 und geht bis 30.
' Alle Feldwerte sind mit 00:00:00, dem
' Standardwert für Date, initialisiert.
Dim C(10,2) As Integer ' C ist Arrayvariable für zweidimensionales Array
Dim D() ' D wird als dynamisches Datenfeld des Typs
' Variant vereinbart (Visual Basic nimmt keine
' Initialisierung vor)
ReDim D(2) ' D wird dimensioniert, dabei erhalten alle
' Felder den Wert Empty (Standardwert für
' Variant).
Verwandte Befehle

Verwa ndte Befehle


...................................................
Property Let, Property Set
Verwandte Themen

Verwandte Them en
...................................................
Datentypen und ihre Operationen (S. 49); Geltungsbereiche von Variablen (S. 173); Variab-
lendeklaration (S. 162)

1 72
Geltungsbereiche von Variablen

Geltungsbereiche von Variablen


Private, Public, Dim
Beschreibung

Bes c hreibung
...................................................
Der Geltungsbereich oder Gültigkeitsbereich einer Variablen ist der Teil des Codes, in dem eine
Variable und ihr Wert bekannt sind. Der engste Geltungsbereich ist die Prozedurebene. Er gilt
für Variablen, die innerhalb einer Prozedur bzw. Funktion als automatische oder statische
Variablen vereinbart werden, sowie für alle Argumentvariablen. Der nächstgrößere Geltungsbe-
reich ist die Modulebene. Er gilt für automatische Variablen, die mittels Private oder Dim außer-

Geltungsbereiche von Variablen


halb eines Prozedurkörpers vereinbart werden. Den größten Geltungsbereich, die Programme-
bene, haben Variablen, wenn sie auf Modulebene mittels Public als öffentliche Variablen
vereinbart werden.
Wird ein Variablenbezeichner in zwei unterschiedlichen Geltungsbereichen eingeführt, wovon
der eine den anderen überlappt, bezeichnet er zwei unterschiedliche Variablen, von denen die
eine nur im kleineren Geltungsbereich sichtbar ist und die andere im gesamten größeren Gel-
tungsbereich, abzüglich des kleineren. Es besteht aber die Möglichkeit, von der Prozedurebene
aus gleichnamige Variablen anzusprechen, die der Programmebene angehören, indem man den
Bezeichner mit dem Modulnamen qualifiziert:
' Modul Form1
Public iWert As Integer ' auf Programmebene vereinbart
Sub MeineSub()
Dim iWert As Integer ' auf Prozedurebene vereinbart
...
iWert = Form1.iWert ' Mit Modulnamen qualifiziert
...
Anwendung

Anwendung
...................................................
In der geschilderten Weise klingt das zunächst einmal recht abstrakt. Die Geltungsbereiche
haben aber große Vorteile. Zunächst einmal unterliegt man bei der Programmierung von Proze-
duren und Funktionen so gut wie keinen Einschränkungen, was die Wahl der Bezeichner
betrifft. Zu beachten ist lediglich, dass man keinen Bezeichner erwischt, der auf Modulebene als
Private vereinbart wurde und dessen aktueller Wert innerhalb der Prozedur benötigt wird. Die
auf Modulebene gelegene Variable, Funktion oder Prozedur wäre dann nämlich nicht ansprech-
bar.
Für öffentliche Bezeichner lässt sich die Herkunft dagegen jederzeit durch Qualifizierung aus-
drücken, so dass hier keine Schwierigkeiten zu befürchten sind. Das ermöglicht es insbesondere
Objekten, ihre öffentlichen Elementvariablen und Methoden gegenseitig anzusprechen:
Sub Form1_Load()
Dim frm2 As New Form2
frm2.ShowInTaskBar = False ' Qualifizierung
Tipp

Tipp
...................................................
Die Bezeichner der öffentlichen Elemente von öffentlichen Datentypen lassen sich über den
Objektkatalog (Taste (F2)) herausfinden.
Verwandte Themen

Verwandte Them en
...................................................
Bezeichner und Namensraum (S. 34)

1 73
Funktionen und Prozeduren
ProzedurBez [ParamListe]
Call ProzedurBez [(WerteListe)]
[Let] Var = FunktionsBez[(WerteListe)]
:= (Operator für benannte Parameter)
Man kann sagen, was mal will, einem Basic-Programmierer der sechziger Jahre würde ein heu-
tiges Visual-Basic-Programm nicht nur ausgesprochen »spanisch« vorkommen, er würde es
wahrscheinlich gar nicht als solches erkennen. In der Tat hat die Einführung von Funktionen
und Prozeduren den Charakter der Sprache von Grund auf und nachhaltig verändert – Spagetti-
Code ade, es lebe die strukturierte Programmierung. Das mit Visual Basic vorliegende Funk-
tions- und Prozedurkonzept ist inzwischen soweit mit dem der Sprache C/C++ kompatibel, dass
Visual Basic vollen Zugriff auf Bibliotheken bietet, die dem Standard für DLLs genügen. Dazu
zählen natürlich in erster Linie die Systembibliotheken von Windows (Windows-APIs), aber
auch die gesamte Palette an DLLs, die zur Unterstützung der einen oder anderen Anwendung
geschrieben wurden.
Ein eingefleischter C/C++-Programmierer wird aber immer noch das Konzept des Funktionszei-
gers vermissen, das Visual Basic wohl deshalb nicht explizit unterstützt, weil noch nicht einmal
das Konzept des Zeigers an sich seinen Weg in die Sprache gefunden hat. Erfreulicherweise
kann Visual Basic aber dennoch Systemdienste nutzen, für deren Aufruf die Angabe einer Rück-
ruffunktion erforderlich ist – es gibt ein Hintertürchen, wenn auch nur ein recht schmales.
Beschreibung

Bes c hreibung
...................................................
Funktionen/Prozeduren stellen ein eigenständiges Stück Code dar, das eine definierte Schnitt-
stelle zum restlichen Teil des Programms hat. Auf diese Weise erreichen Funktionen und Proze-
duren eine weitgehende semantische Geschlossenheit, die für die strukturierte Programmierung
eine wichtige Voraussetzung ist. Die Definition der Schnittstelle findet sich im so genannten
Funktionskopf bzw. Prozedurkopf. Ein solcher Kopf enthält einen Bezeichner mit optionalem
Spezifizierer für den Geltungsbereich, eine formale Auflistung mit Deklaration aller Argument-
variablen, in der für jede Variable festgelegt wird, ob der entsprechende Parameter als Wert
oder als Verweis übergeben wird, sowie – im Falle einer Funktion – den Typ des Rückgabe-
werts. Die Definition dessen, was eine Prozedur/Funktion macht (ihr Code), findet sich schließ-
lich als Anweisungsfolge im Prozedurkörper bzw. Funktionskörper.
Das dem Bezeichnerwesen von Visual Basic zugrunde liegende Qualifizierungsmodell ordnet
eine Funktion/Prozedur immer dem Modul als privates oder öffentliches Element zu, das seinen
Körper enthält. Im Zusammenhang mit Objekten und Klassen spricht man statt von Funktio-
nen und Prozeduren von Methoden. Um auf eine Funktion/Prozedur von DLLs zugreifen zu
können, die nicht standardmäßig von Visual Basic unterstützt werden, sind in dem jeweiligen
Modul explizite Importdeklarationen nötig (vgl. »Routinen aus DLLs und der Windows-API
einsetzen«, S. 185)
Anwendung

Anwendung
...................................................
In Visual Basic ist die Unterscheidung zwischen Prozeduren und Funktionen sehr streng. Eine
Prozedur verkörpert eine Anweisung und wird wie eine solche notiert. Eine Funktion ist dage-
gen eine Operation, die einen Wert mit einem zugrunde liegenden Datentyp verkörpert. Mithin
lässt sich eine Funktion also überall da notieren, wo ein Wert erwartet wird: als Rechtswert bei
Zuweisungen und in Ausdrücken. Rein formal gesehen besteht der Unterschied zwischen Proze-
duren und Funktionen somit darin, dass Prozeduren keinen Wert zurückgeben, während Funk-

1 75
Geltungsbereiche von Variablen

tionen einen Funktionswert liefern. In allen anderen Aspekten sind sich die beiden mehr ähnlich
als dass sie sich unterscheiden. So lässt sich eine Anweisung ohne Schwierigkeiten als Funktion
formulieren und eine Funktion ebenso einfach als Prozedur – die Wertübergabe lässt sich ja
über Parameter lösen.

Aufruf
Der Aufruf einer Funktion kann überall dort erfolgen, wo ein Wert mit dem Ergebnistyp der
Funktion stehen kann. Man notiert dazu einfach den Funktionsbezeichner gefolgt von einer
geklammerten Werteliste mit Komma als Trennzeichen, welche der Reihenfolge nach die einzel-
nen Parameter mit Werten versorgt.
Geltungsbereiche von Variablen

sDateiname = Left(sDateiname,10)

Für den Aufruf von Prozeduren kennt Visual Basic dagegen zwei unterschiedliche Notationen:
das Anweisungsformat oder das Call-Format. Das Anweisungsformat sieht die Nennung des
Prozedurbezeichners mit nachfolgender nicht geklammerter Werteliste als eigenständige Anwei-
sung vor.
Rnd 1.1234

Das Call-Format überlässt der Anweisung Call den Aufruf der Prozedur, wobei diese im
Anschluss an das Schlüsselwort Call wie eine Funktion – also mit geklammerter Werteliste –
notiert wird.
Call Rnd (1.1234)

Die Werteliste kann auch fehlen, wenn die Funktions-/Prozedurdefinition dies zulässt. Ein leeres
Klammerpaar ist dann nicht zu notieren:
datZeit = Now ' Now ist parameterlose Funktion (Eigenschaft)
Rnd ' Prozedur ist für parameterlosen Aufruf definiert

Benannte Argumente
Seit noch nicht langer Zeit unterstützt Visual Basic auch das Konzept der benannten Argumente
für Funktionen und Prozeduren (genauer: Visual Basic 6.0 (SP3) unterstützt das Konzept in
zunehmendem Maße, da die Objektbibliothek VB dem Konzept bisher noch nicht angepasst
wurde). Es sieht vor, dass für den Aufruf einer Funktion/Prozedur anstelle einer Werteliste auch
eine Wertzuordnungsliste übergeben werden kann, deren Einträge eine explizite Wertzuord-
nung zwischen dem Bezeichner eines Parameters und seinem Wert vorschreiben. Das hat den
Vorteil, dass die Reihenfolge der Elemente in der Liste nicht mehr an die Vereinbarungsreihen-
folge angepasst sein muss, erspart aber nicht die Versorgung obligatorischer Parameter mit
Werten. Während in einfachen Wertelisten weggelassene optionale Parameter zumindest durch
ein Komma zu notieren sind, es sei denn, sie stehen am Schluss der Liste, müssen in Wertzuord-
nungslisten tatsächlich nur so viele Einträge enthalten sein, wie es obligatorische Parameter
gibt. Die ganze Sache sieht dann so aus:
Sub MeineProzedur(a, Optional b = 0, Optional c = 0, Optional d = 2)
...
End Sub
Sub Demo()
MeineProzedur 2, , , 1 ' Aufruf mit Werteliste
MeineProzedur d:= 1, a:= 2 ' Aufruf mit Wertzuordnungsliste
End Sub

1 76
Geltungsbereiche von Variablen

Gegenseitiger und rekursiver Aufruf


Funktionen und Prozeduren können jederzeit andere Funktionen und Prozeduren aufrufen,
deren Bezeichner im jeweiligen Geltungsbereich bekannt sind. Erlaubt ist auch der Selbstaufruf
– man spricht dann von einer rekursiven Funktion oder einer rekursiven Prozedur. Bei rekursi-
vem Aufruf ist allerdings auf einen sicheren Abbruch der Rekursion zu achten, damit kein Lauf-
zeitfehler wegen Überlaufs des Stapelspeichers auftritt. Die Festlegung des Funktionswerts einer
Funktion erfolgt durch Zuweisung eines Werts an den Funktionsbezeichner innerhalb des
Funktionskörpers. Als Linkswert verkörpert der Funktionsbezeichner nichts weiter als eine
Variable mit dem Rückgabetyp der Funktion – als Rechtswert dagegen einen rekursiven Aufruf!
Function Fakultät(a)

Geltungsbereiche von Variablen


If a < 2 Then
Fakultät = 1
Else
Fakultät = a * Fakultät(a-1)
End If
End Function

In allen Fällen ist anstelle der rekursiven aber auch eine iterative Formulierung möglich, die
zwar weniger elegant aussieht, dafür aber sicherer und meist auch schneller ist:
Function Fakultät(zahl)
Dim Erg
Erg = 1
while zahl > 1
Erg = Erg * zahl
zahl = zahl -1
Wend
Fakultät = Erg
End Function
Tipp

...................................................
Tipp
Es lohnt sich, beim Programmentwurf auf eine gute Strukturierung durch Funktionen und Pro-
zeduren zu achten. Wer zu viel in eine Funktion/Prozedur packt, verschenkt Universalität. Fas-
sen Sie Ihren Code daher am besten in viele kleine möglichst allgemein und übersichtlich gehal-
tene Funktionen/Prozeduren und dokumentieren Sie die Aufrufschnittstellen gut in Form von
Kommentaren.
Warnungen

...................................................
Wa rnungen
Da in Visual Basic sowohl Sprungmarken als auch mehrere Befehle in einer Zeile durch einen
Doppelpunkt notiert werden, ist folgender Aufruf zweideutig:
Save: Print " Me"
Der Compiler betrachtet Save hier als Sprungmarke, wie folgendes Programm zeigt:
Private Sub Form_Load()
Save: Print " Me" ' Ausgabe: Me
Call Save: Print "Me", ' Ausgabe: Save Me
End Sub

Sub Save()

1 77
Parameterübergabe an Funktionen und Prozeduren

Print "Save ";


End Sub

Ein kleiner Tipp: Der Editor der Entwicklungsumgebung zieht Sprungmarken automatisch an
den Zeilenanfang. Daran müssten Sie bereits merken, dass etwas nicht stimmt. Am besten aber,
Sie gewöhnen sich an, keine Anweisungen hinter Sprungmarken zu setzen, das erhöht auch die
Lesbarkeit des Programms.
Der Compiler von Visual Basic kann arithmetische Ausdrücke aus Optimierungsgründen intern
umstellen. Vermeiden Sie daher Function-Aufrufe innerhalb eines arithmetischen Ausdrucks,
wenn die Funktion als Seiteneffekt den Wert von Variablen ändert, die in diesem Ausdruck auf-
treten.
Parameterübergabe an Funktionen und Prozeduren

Verwandte Themen

...................................................
Verwa ndte Them en
Methoden (S. 199); Eigenschaften (S. 201); Ereignisroutinen (S. 204)

Parameterübergabe an Funktionen und Prozeduren


[Geltungsbereich] [Static] Function FuncName ([ParamListe]) [As Typ]
...
End Function
[Geltungsbereich] [Static] Sub ProcName ([ParamListe])
...
End Sub
Function IsMissing(ArgumentName) As Boolean
Funktionen/Prozeduren lassen sich als parametergesteuerte Unterprogramme auffassen, die aus
den Werten ihrer Parameter weitere Werte generieren und zudem gewisse Seiteneffekte haben.
Die Sichtbarkeit des Bezeichners FuncName bzw. ProcName beschränkt sich auf den vereinbarten
Geltungsbereich Geltungsbereich.
Geltungsbereich = Public | Private | Friend
Fehlt die Angabe eines Geltungsbereichs oder lautet der Spezifizierer Public, ist der Bezeichner
auf Programmebene bekannt. Lautet der Spezifizierer dagegen Private, ist der Bezeichner nur
auf Modulebene bekannt. In Klassenmodulen ist weiterhin die Angabe des Spezifizierers Friend
möglich, der die Sichtbarkeit der Methode auf das aktuelle Projekt beschränkt und einen expli-
ziten Aufruf durch Besitzer von Objekten dieser Klasse vereitelt. Die zusätzliche Angabe des
Spezifizierers Static bewirkt, dass alle innerhalb der Funktion/Prozedur implizit oder explizit
deklarierten Variablen generell als statische Variablen vereinbart werden, so dass diese von
einem Aufruf zum nächsten ihren Wert behalten und nur beim ersten Aufruf automatisch initi-
alisiert werden.
Jeder Funktion/Prozedur ist eine Parameterliste ParamListe zugeordnet, die bis zu 59 Parame-
tervereinbarungen umfassen, aber auch leer sein kann.
ParamListe = [Param[, Param ...]]
Die Vereinbarung eines einzelnen Parameters Param hat die Gestalt
Param = [Optional][ByVal | ByRef][ParamArray] Var[()] As Typ [= Vorgabe]
Ein Parameter kann als Platzhalter für einen Eingabewert, einen Ausgabewert oder einen Ein-/
Ausgabewert fungieren, der innerhalb der Funktion/Prozedur über die Argumentvariable Var
verfügbar wird. Die Deklaration von Argumentvariablen für reine Eingabeparameter erfordert

1 78
Parameterübergabe an Funktionen und Prozeduren

den Spezifizierer ByVal, die von Argumentvariablen für Ausgabe- bzw. Ein-/Ausgabeparameter
den Spezifizierer ByRef. Letzterer ist optional, da Visual Basic Argumentvariablen auch implizit
mit dem Zusatz ByRef vereinbart. Arrays und Objekte lassen sich ausschließlich als ByRef-Para-
meter übergeben.
Parameter sind im Allgemeinen obligatorisch, es sei denn, die zugehörige Argumentvariable
wird mit dem Zusatz Optional vereinbart. Ein obligatorischer Parameter muss beim Aufruf der
Funktion/Prozedur mit einem Wert versorgt werden, ein optionaler kann auch weggelassen
werden. Als Vorgabewert für optionale Parameter nimmt Visual Basic den standardmäßigen
Initialisierungswert des Datentyps Typ, sofern keine explizite Zuweisung eines Vorgabewerts
Vorgabe deklariert ist. Um innerhalb der Funktion/Prozedur festzustellen, ob für einen optiona-
len Variant-Parameter beim Aufruf ein Wert spezifiziert wurde, lässt sich die Funktion IsMis-

Parameterübergabe an Funktionen und Prozeduren


sing einsetzen. Sie ist vom Typ Boolean und liefert den Wert True, wenn der im Argument
genannte optionale Parameter beim Aufruf weggelassen wurde.
Sub TestProc(Optional OptParam)
If IsMissing(OptParam) Then
...
End Sub

Für den letzten Parameter in einer Parameterliste ist darüber hinaus der Spezifizierer ParamArray
erlaubt – unter der Voraussetzung jedoch, dass die Argumentvariable als dynamisches Array
des Typs Variant ohne weitere Spezifizierer vereinbart wird. Eine Funktion/Prozedur, für die
ein ParamArray-Parameter vereinbart ist, kann beliebig lange Parameterlisten verarbeiten (vgl.
Print).
Anwendung

Anwendung
...................................................
Für die Reihenfolge der Parameter gibt es keine Vorschriften. Es ist aber üblich, Eingabepara-
meter an den Beginn der Parameterliste zu setzen, Ein-/Ausgabeparameter in der Mitte und die
Ausgabeparameter an den Schluss. Allerdings hat die exakt umgekehrte Reihenfolge den Vor-
teil, dass sich optionale Parameter an den Schluss setzen lassen, damit sie nicht notiert werden
müssen. Wenn Sie jedoch die Aufrufsyntax der »benannten Argumente« benutzen, spielt die
Reihenfolge ohnehin keine Rolle.
Der Unterschied zwischen reinen Eingabeparametern und Parametern mit Ein- und Ausgabe-
funktion bzw. reiner Ausgabefunktion ist konzeptueller Natur und erfordert aufseiten des Pro-
grammierers eine gewisse Disziplin. Da ByVal-Variablen beim Aufruf Kopien der übergebenen
Werte erhalten, kann die Funktion/Prozedur damit anstellen, was sie will: Eventuelle Wertände-
rungen verbleiben auf der Prozedurebene und sind für den Aufrufer generell unsichtbar. Anders
verhält es sich, wenn die Deklaration einer Argumentvariablen mit dem standardmäßigen Spe-
zifizierer ByRef erfolgt. In diesem Fall wird aus der Argumentvariablen eine Zeigervariable,
deren Wert die Adresse des in dem entsprechenden Parameter übergebenen Werts ist – ein Kon-
zept, das als solches in Visual Basic nirgendwo sonst so offen zu Tage tritt. Am Gebrauch der
Argumentvariablen ändert sich äußerlich dadurch nichts, außer dass sie als Platzhalter für einen
Ausgabewert bzw. Ein-/Ausgabewert fungieren kann. Nach außen hin wirksame Wertänderun-
gen sind sinnvollerweise nur möglich, wenn als Parameter eine Variable (also ein Linkswert)
übergeben wurde, da diese das indirekte Ziel jeglicher Wertänderungen seitens der Argument-
variablen ist. Wird einem ByRef-Parameter ein literaler Wert, eine Konstante, ein Funktionswert
oder der Wert eines berechneten Ausdrucks übergeben, steht dieser nur als Eingabewert zur
Verfügung; der Versuch einer Änderung führt zwar zu keinem Laufzeitfehler, bleibt aber wir-
kungslos.

1 79
Parameterübergabe an Funktionen und Prozeduren

Warnung

Wa rnung
...................................................
Nachdem Visual Basic alle Parameter, die nicht explizit mit ByVal spezifiziert werden, als ByRef-
Parameter vereinbart, sind bei sorglosem Umgang mit Argumentvariablen für Eingabewerte
unerwünschte Rückwirkungen auf die Ebene des Aufrufers möglich – ein Eingabewert kann so
unbemerkt zum Ein-/Ausgabewert mutieren. Fehler dieser Art sind meist schwer zu finden. Um
sie auszuschließen, besteht auch die Möglichkeit, Variablen, die nur Eingabewerte bereitstellen,
in der Werteliste zu klammern. Visual Basic sieht einen geklammerten Wert als Ausdruck an
und verhindert so Rückwirkungen auf die Variable.
Beispiele

Beis piele
...................................................
Parameterübergabe an Funktionen und Prozeduren

Die Funktion Standardabweichung berechnet die Standardabweichung einer Messreihe mit der
Menge der Messwerte als Grundgesamtheit. Die Anzahl der Parameter für den Aufruf der
Funktion ist nicht festgelegt, wie die Aufrufe zeigen.
...
Print Standardabweichung(15.2, 11.1, 13.4,12.2, 18.3) ' 2,517...
Print Standardabweichung(15.2, 11.1, 13.4,12.2, 18.3, 12.1) ' 2,417...
...
Function Standardabweichung(ParamArray MessWerte())
Dim iAnz As Integer
iAnz = UBound(MessWerte) + 1
For Each i In MessWerte
Sum = Sum + i
Qsum = Qsum + i * i
Next i
Standardabweichung = Sqr((iAnz * Qsum – Sum * Sum) / (iAnz * iAnz))
End Function

Die folgende Prozedur demonstriert den Unterschied zwischen einem ByRef- und einem ByVal-
Parameter sowie die Wirkung eines Ausdrucks auf einen ByRef-Parameter:
...
Dim iWert1, iWert2 As Integer
iWert1 = 10
iWert2 = 10
ByValByRef iWert1, iWert2
Print iWert1, iWert2 ' Ausgabe: 10 100
iWert2 = 10
ByValByRef iWert1, (iWert2) ' (iWert2) ist Ausdruck!
Print iWert1, iWert2 ' Ausgabe: 10 10
...
Sub ByValByRef(ByVal a As Integer, b As Integer)
a = a * a
b = b * b
End Sub
Verwandte Themen

Verwandte Them en
...................................................
Ereignisroutinen (S. 204)

1 80
Funktionen selbst definieren

Funktionen selbst definieren


[Public| Private | Friend][Static] Function Name [(ParamListe)][ As Typ]
[Anweisungsfolge]
[Name = Ausdruck]
[Exit Function]
[Anweisungsfolge]
[Name = Ausdruck]
End Function
Beschreibung

Bes c hreibung
...................................................

Funktionen selbst definieren


Die Definition einer eigenen Funktion (Methode) gliedert sich in drei Schritte:
1. Deklaration der prozeduralen Schnittstelle
2. Deklaration eines Rückgabetyps
3. Definition des Funktionskörpers mit Zuweisung des Funktionswerts
Die prozedurale Schnittstelle einer Funktion umfasst die Spezifikation des Funktionsbezeichners
sowie die Deklaration der Parameterliste. Dieser Schritt ist im Abschnitt »Parameterübergabe
an Funktionen und Prozeduren« (S. 178) ausführlich beschrieben.
Da eine Funktion im Gegensatz zu einer Prozedur einen Wert verkörpert, den sie als Funktions-
wert zurückliefert, definiert der Rückgabetyp Typ den Datentyp des Werts, den die Funktion
zurückgibt. Fehlt die Angabe eines Rückgabetyps, lautet die Voreinstellung Variant. Zu den
möglichen Rückgabetypen zählen die elementaren Datentypen Boolean, Byte, Integer, Long,
Currency, Single, Double, Date, String (Decimal wird derzeit nur als Untertyp von Variant unter-
stützt), benutzerdefinierte Datentypen, Variant sowie Objektverweise des Typs Object. Darüber
hinaus kann eine Funktion auch ein dynamisches Array mit einem der genannten Datentypen
als Elementtyp zurückgeben.
Der Funktionskörper kann eine beliebige Anweisungsfolge enthalten, die für die Berechnung
des Funktionswerts sowie der gegebenenfalls über Argumentvariablen zurückzugebenden Aus-
gabewerte erforderlich ist. Der Funktionswert Ausdruck wird dem Funktionsbezeichner Name
zugewiesen und die anderen Ausgabewerte den entsprechenden Argumentvariablen.
Die an beliebiger Stelle erlaubte Anweisung Exit Function gibt die Kontrolle unmittelbar an den
Aufrufer zurück. Falls dem Funktionsbezeichner bis dahin noch kein Rückgabewert zugewiesen
wurde, liefert die Funktion den standardmäßigen Initialisierungswert des Rückgabetyps.
Anwendung

Anwendung
...................................................
Der Unterschied zwischen einem Ausdruck und einer Funktion ist gar nicht so groß. Beide lie-
fern einen Wert, den sie auf Basis anderer Werte berechnen. Im Gegensatz zu einem Ausdruck
legt eine Funktion im Allgemeinen aber ihre Schnittstelle mit der Außenwelt en bloc in Form
der prozeduralen Schnittstelle offen – so zumindest der hehre Anspruch. In der Praxis sieht es
oft anders aus: Um Aufrufparameter zu sparen, wird viel mit globalen Variablen hantiert, was
zwar das Laufzeitverhalten der Funktion verbessern kann, jedoch gegen die goldenen Regeln
für die strukturierte Programmierung verstößt und nicht selten zu schwer auffindbaren Bugs im
Code führt. Gewöhnen Sie sich an, nach Möglichkeit alle Werte, die eine Funktion vom Aufru-
fer benötigt, über die prozedurale Schnittstelle zugänglich zu machen und gegebenenfalls als
optionalen Parameter mit sinnvollem Vorgabewert zu deklarieren. Der Gebrauch von globalen
Variablen sollte weitgehend auf das Wesentliche beschränkt bleiben. ByVal-Parameter schützen
zwar vor ungewollten Seiteneffekten, kosten aber aufgrund der zu erstellenden Kopien bei Wer-
ten mit umfangreichen Repräsentationen – etwa bei Zeichenfolgen oder benutzerdefinierten
Datentypen – wertvolle Laufzeit. ByRef-Parameter sind dann oft die bessere Wahl.

1 81
Funktionen selbst definieren

Die größte Kunst bei der Programmierung besteht darin, es einer potenziellen Anweisungsfolge
anzusehen, dass sie eine gute Funktion abgibt, und dann die Schnittstelle dieser Funktion geeig-
net festzulegen. Das Motto dafür lautet, wie schon einst bei Cäsar: Teile und herrsche. Je allge-
meiner und je kürzer eine Funktion, desto besser. Das erleichtert die Fehlersuche ebenso wie die
spätere Codepflege.
Zu guter Letzt noch ein Wort zum Gebrauch der Anweisung Exit Function. Eine weitere gol-
dene Regel der strukturierten Programmierung besagt, dass Routinen möglichst nur einen Aus-
gang haben sollten. Gegen den überlegten Gebrauch von Exit Function ist natürlich nichts ein-
zuwenden. Je komplizierter die Logik jedoch wird, desto unübersichtlicher und schwerer lesbar
wird eine Funktion, wenn sie zu viele Ausgänge hat. Am besten, Sie spalten den Code dann in
Funktionen selbst definieren

mehrere kleine Funktionen auf.


Tipp

Tipp
...................................................
Bei Problemstellungen, in denen die Laufzeit eine Rolle spielt, können Funktionsaufrufe zum
Hemmschuh werden, insbesondere wenn noch ByVal-Parameter im Spiel sind. In einigen Fällen
verbessert sich das Laufzeitverhalten, wenn man zu Inline-Formulierungen übergeht, also
anstelle eines Funktionsaufrufs den eigentlichen Code der Funktion setzt. Allerdings ist auch
der Visual-Basic-Compiler in der Lage, von sich aus Funktionen in Inline-Code zu verwandeln,
sofern der Compilerschalter CODE-AUSFÜHRUNGSGESCHWINDIGKEIT OPTIMIEREN gesetzt ist, so
dass sich Vergleichsmessungen lohnen.
Beispiel

Beis piel
...................................................
Die rekursive Funktion NextPrim ermittelt die nächste Primzahl, die kleiner oder gleich dem Ein-
gabeparameter lZahl ist. Für negative Werte und 0 liefert die Funktion den Wert 0.
Function NextPrim(ByVal lZahl As Long) As Long
Dim i As Long
If lZahl <= 3 Then
If lZahl <= 0 Then
NextPrim = 0
Else
NextPrim = lZahl
End If
Else
For i = 2 To Sqr(lZahl) ' Alle möglichen Teiler prüfen
If lZahl Mod i = 0 Then ' Ist i Teiler?
NextPrim = NextPrim(lZahl – 1) ' Ja: Rekursion liefert Ergebnis
Exit Function ' Das war's schon
End If
Next
NextPrim = lZahl ' Kein Teiler, lZahl ist Primzahl
End If
End Function
Verwandte Befehle

Verwa ndte Befehle


...................................................
Sub
Verwandte Themen

Verwandte Them en
...................................................
Ereignisroutinen (S. 230)

1 82
Prozeduren selbst definieren

Prozeduren selbst definieren


[Private | Public][Static] Sub Name [(ParamListe)]
[Anweisungsfolge]
[Exit Sub]
[Anweisungsfolge]
End Sub
Beschreibung

Bes c hreibung
...................................................
Die Definition einer eigenen Prozedur (Methode) gliedert sich in zwei Schritte:

Prozeduren selbst definieren


1. Deklaration der prozeduralen Schnittstelle
2. Definition des Prozedurkörpers
Die prozedurale Schnittstelle einer Prozedur umfasst die Spezifikation des Prozedurbezeichners
sowie die Deklaration der Parameterliste. Dieser Schritt ist im Abschnitt »Parameterübergabe
an Funktionen und Prozeduren« (S. 178) ausführlich beschrieben.
Der Prozedurkörper kann eine beliebige Anweisungsfolge enthalten, die für die Berechnung der
gegebenenfalls über Argumentvariablen zurückzugebenden Ausgabewerte erforderlich ist. Aus-
gabewerte werden einfach den entsprechenden Argumentvariablen zugewiesen.
Die an beliebiger Stelle erlaubte Anweisung Exit Sub unterbricht die Ausführung der Prozedur
und gibt die Kontrolle unmittelbar an den Aufrufer zurück.
Anwendung

Anwendung
...................................................
Der gesamte Code eines Visual-Basic-Programms liegt in Form von Prozeduren und Funktionen
vor, die sich teils gegenseitig aufrufen, teils vom Laufzeitsystem aufgrund entsprechender
Benutzerinteraktionen im Zuge der Ereignisbehandlung (Ereignisprozeduren) aufgerufen wer-
den. Während eine Funktion einen Rückgabewert liefern muss und somit als Wert zu betrach-
ten ist, erweitert eine Prozedur das Spektrum der in Visual Basic verfügbaren Anweisungen. Da
Prozeduren aber genau wie Funktionen über Ein-/Ausgabeparameter mit ihren Aufrufern kom-
munizieren, ist der Unterschied zwischen Funktionen und Prozeduren mehr eine Frage der For-
mulierung einer Lösung und damit des persönlichen Stils als des Einsatzzwecks, denn jede
Funktion lässt sich letztlich auch als Prozedur schreiben und umgekehrt. Eine Prozedur legt
genauso wie eine Funktion ihre Schnittstelle mit der Außenwelt en bloc in Form der prozedura-
len Schnittstelle offen. Gewöhnen Sie sich an, nach Möglichkeit alle Werte, die eine Prozedur
vom Aufrufer benötigt, über die prozedurale Schnittstelle zugänglich zu machen und gegebe-
nenfalls als optionalen Parameter mit sinnvollem Vorgabewert zu deklarieren. Das vereinfacht
die Handhabung der Prozedur. Der Gebrauch von globalen Variablen sollte weitgehend auf das
Wesentliche beschränkt bleiben. ByVal-Parameter schützen zwar vor ungewollten Seiteneffek-
ten, kosten aber aufgrund der zu erstellenden Kopien bei Werten mit umfangreichen Repräsen-
tationen – etwa bei Zeichenfolgen oder benutzerdefinierten Datentypen – wertvolle Laufzeit.
ByRef-Parameter sind dann meist die bessere Wahl.

Sub Main
In einem Standardmodul kommt der Prozedur mit dem Bezeichner Main eine spezielle Bedeu-
tung zu: Sie lässt sich im Dialog PROJEKTEIGENSCHAFTEN eines Projekts anstelle eines Formular-
objekts als Startroutine einer Komponente (lies: ausführbare Datei oder Bibliothek) festlegen.
Lassen Sie sich dabei nicht durch die unglücklich gewählte deutsche Beschriftung »Startobjekt«
verwirren. Startobjekt ist in dem Fall das Standardmodul, das die Prozedur Main bereitstellt.
Enthält ein Projekt mehrere Standardmodule, darf jeweils nur in einem die Prozedur Main defi-
niert sein.

1 83
Prozeduren selbst definieren
Prozeduren selbst definieren

Sub Main eines Standardmoduls als Startroutine festlegen


Das Laufzeitsystem von Visual Basic führt Main in diesem Fall bei jedem Start der Komponente
als Startcode aus. Main ist dann gegebenenfalls für den Aufruf des Startformulars verantwort-
lich, wenn die Komponente im Stand-alone-Modus und nicht als Automatisierungsobjekt aus-
geführt wird.
Sub Main()
...
If App.StartMode = vbSModeStandalone Then
StartForm.Show
...
Beispiel

Beis piel
...................................................
Das folgende Beispiel ist eine recht nützliche Sortierroutine für Arrays mit beliebigem Element-
typ. Sie arbeitet nach dem Bubble-Sort-Algorithmus. Die Routine selbst ist eine Prozedur,
bedient sich aber einer Funktion für den Vergleich und einer Prozedur für das Vertauschen von
Werten. Obwohl die Routine bereits recht allgemein formuliert ist – sie funktioniert mit allen
elementaren Datentypen – sind noch Anpassungen an andere Datentypen denkbar. Haben Sie
beispielsweise schon einmal Bilder nach Farben sortiert?
...
Dim b()
b() = Array("Essig", "Fliege", "Apfel", "Gold")
BubbleSort b()
For Each i In b
Print i; " "; ' Ausgabe: Apfel Essig Fliege Gold
Next
Print
b() = Array(23.3, 45.2, 15.3, 893.2, 123, 12.123)
BubbleSort b()
For Each i In b
Print i; " "; ' Ausgabe: 893,2 123 45,2 15,3 12,123
Next
...

1 84
Routinen aus DLLs und der Windows- API einsetzen

Sub BubbleSort(Werte()) ' ByRef!


For j = UBound(Werte) To 1 Step -1 ' rückwärts durch Array
For i = 0 To j – 1 ' vorwärts durch unsort. Teil
If Vgl(Werte(i), Werte(i + 1)) Then
Vertausche Werte(i), Werte(i + 1)
End If
Next i
Next j
End Sub

Prozeduren selbst definieren


Function Vgl(a, b) As Boolean ' Vergleichsoperation ByRef-Parameter
Select Case VarType(a) ' Abhängig von Untertyp
Case vbString
If StrComp(a, b, vbTextCompare) = 1 Then Vgl = True
Case vbInteger To vbBoolean
If a < b Then Vgl = True ' Vergleich könnte auch anders lauten
End Select
End Function

Sub Vertausche(a, b) ' ByRef-Parameter!


c = a: a = b: b = c
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Function
Verwandte Themen

Verwandte Them en
...................................................
Ereignisroutinen (S. 204)

Routinen aus DLLs und der Windows- API einsetzen


[Public | Private] Declare Function APIFkt Lib "API" _
[Alias "APIRoutine"][(ParamListe)] As Typ
[Public | Private] Declare Sub APIProc Lib "API"
[Alias "APIRoutine"][(ParamListe)]
Beschreibung

Bes c hreibung
...................................................
Bei der Windows-API handelt es sich um die Menge der Betriebssystemroutinen, die Windows
für die Anwendungsprogrammierung zur Verfügung stellt. Obwohl Visual Basic an sich eine
geschlossene Programmierwelt mit integrierter Automatisierungsschnittstelle zu ActiveX-
Steuerelementen und ActiveX-Komponenten ist, stellt die Sprache aber auch Mittel und Wege
bereit, in gewöhnlichen DLLs beheimatete Routinen anzusprechen, die nicht in Visual Basic
programmiert sind. Dazu zählen nicht nur die gut tausend Funktionen und Prozeduren der
Win32-API, von denen nur wenige in der standardmäßigen Bibliothek von Visual Basic eine
Entsprechung gefunden haben, sondern auch die gesamte Vielfalt der Bibliotheksprodukte zahl-
loser Drittanbieter, die sich auf dem Windows-Markt tummeln.
Sich bei der Visual-Basic-Programmierung auf bereits bestehende DLL-Routinen zu stützen, hat
nicht nur Vorteile, sondern auch ganz klare Nachteile: Aufrufe von DLL-Routinen bzw. der
Einsatz von API-Funktionen führen aus der Geborgenheit der Visual-Basic-Umgebung heraus.

1 85
Prozeduren selbst definieren

Die Umsicht des Compilers endet nämlich mit den Schnittstellendeklarationen für die externen
Routinen. Da die Routinen in einer anderen Programmiersprache geschrieben sind – für die
Windows-API ist das C/C++ –, gilt es, sich an die Regeln dieser Sprache zu halten. Es ist zwar
nicht unbedingt erforderlich, diese Sprache selbst zu können, vorteilhaft ist es aber allemal. Um
ein gewisses Verständnis der Sprache und der von ihr verwendeten Repräsentationen für die ele-
mentaren Datentypen kommt man daher nicht herum, damit die Übergabe von Parametern und
Funktionswerten auch klappt.
Darüber hinaus ist natürlich auch ein Verständnis der verwendeten Bibliothek in ihrem Funk-
tionszusammenhang erforderlich. Auf die Windows-API bezogen bedeutet das, dass man
zunächst einmal wissen muss, welche Funktionen es gibt, in welcher Bibliothek diese zu finden
Prozeduren selbst definieren

sind (dafür gibt es das Add-In API-VIEWER), mit welchen Konzepten und Datentypen diese
Funktionen arbeiten, welche Seiteneffekte sie haben und welche Pflichten mit ihrer Benutzung
verbunden sind. Letzteres ist ein recht heikles Thema, da das Laufzeitsystem von Visual Basic
sämtliche Verwaltungsarbeiten im Zusammenhang mit komplexen Datentypen, ins Leben geru-
fenen Objekten, geöffneten Dateien usw. von sich aus übernimmt und notfalls auch einmal hin-
terher räumt, wenn etwa eine Datei nicht geschlossen oder gesperrte Datensätze nicht wieder
entsperrt wurden. Die Windows-API weist da bei weitem keine solche Toleranz auf und fordert
einen wahrhaft peniblen Umgang mit den angeforderten Ressourcen, seien es Handles, Lauf-
zeitinstanzen oder sonstige Größen, die aufseiten des Betriebssystems eine Speicherbelegung
bewirken.
DLLs werden im selben Prozess wie die Visual-Basic-Anwendung ausgeführt. Fehler durch
Angabe falscher Parameterwerte können sich daher katastrophal auswirken und nicht nur das
Programm zum Absturz bringen, sondern zuweilen auch Windows. Leider kann der Visual-
Basic-Compiler im Zusammenhang mit DLL-Routinen nur eine sehr unvollständige Typüber-
prüfung durchführen, die über das Grobformale nicht hinausgeht. Obwohl die Abbildung der
elementaren Datentypen zwischen C/C++ und Visual Basic noch halbwegs geradlinig ist, treten
bereits die ersten Komplikationen auf, wenn Zeichenfolgen ins Spiel kommen. Da stellt sich die
Frage, ob Unicode oder ANSI-Code und ob ein C-String mit Nullbyte am Ende oder ein Pascal-
String mit Deskriptor erwartet wird. Richtig schwierig kann es bei den benutzerdefinierten
Datentypen werden, wenn nicht klar ist, mit welcher Speicherausrichtung (8, 16 oder 32 Bit)
eine DLL in Bezug auf die zusammengesetzten Datentypen, die sie verwendet, kompiliert wor-
den ist. In anderer Hinsicht problematisch ist der Umgang mit Zeigern, einem Konzept, das es
in Visual Basic offiziell gar nicht gibt und das gewissermaßen nur über die Hintertür in Form
von ByRef-Parametern bei Funktionen/Prozeduren zugänglich wird. Ein noch offensichtlicheres
Hintertürchen ist der AddressOf-Operator, mit dessen Hilfe sich schließlich sogar Funktionszei-
ger auf Visual-Basic-Routinen gewinnen lassen, wenn Rückrufroutinen gefordert sind.
Um eine DLL-Routine in einem Modul ansprechen zu können, muss diese im Bereich ALLGE-
MEIN über eine geeignete Declare-Anweisung als öffentliche (Public) oder moduleigene
(Private) Funktion (Function) oder Prozedur (Sub) deklariert sein (öffentliche Vereinbarungen
importierter Routinen sind in Visual Basic 6.0 nur in Standardmodulen erlaubt). Der Bezeich-
ner APIFkt bzw. APIProc ermöglicht es, die importierte Routine innerhalb des vereinbarten Gel-
tungsbereichs wie eine ganz gewöhnliche Funktion oder Prozedur aufzurufen. Falls dieser
Bezeichner mit dem Bezeichner APIRoutine der Routine übereinstimmt, kann der optionale
Alias-Zusatz entfallen, ansonsten nicht. Ein Alias-Zusatz ermöglicht es insbesondere, auch
Routinen einzuführen, deren Bezeichner in Visual Basic keine gültigen Bezeichner wären, etwa
weil sie mit einem Unterstrich beginnen. Der obligatorische Lib-Zusatz macht den Namen der
DLL bekannt, in der die Routine enthalten ist. Er muss als literale Zeichenfolge notiert sein. Die
optionale Parameterliste ParamListe und der bei Funktionsdeklarationen zusätzlich anzuge-
bende Rückgabetyp Typ unterliegen den gleichen Anforderungen wie bei der Definition einer
gewöhnlichen Funktion/Prozedur (vgl. »Parameterübergabe an Funktionen und Prozeduren«,

1 86
Routinen aus DLLs und der Windows- API einsetzen

S. 178). Für einen ordnungsgemäßen Aufruf der Bibliotheksroutine ist es aber unerlässlich, dass
Sie die Parameter- und Typanforderungen der Routine mit den sprachlichen Mitteln von Visual
Basic exakt abbilden.
Anwendung

Anwendung
...................................................
Eines vorweg: Der Einsatz von API-Routinen wird nur Programmierern empfohlen, die bereits
eine gewisse Vorstellung davon haben, was einen bei der Programmierung mit der Win32-API
erwartet. Vom Prinzip her ist es ist zwar denkbar, sich der Win32-API von Visual Basic aus zu
nähern, für die ernsthafte Programmierung ist der Weg aber zu steinig. Wer sich dagegen einen
Vorgeschmack holen oder die Win32-API zur Lösung spezifischer Probleme in Anspruch neh-

Prozeduren selbst definieren


men will, der kann dies von Visual Basic aus tun und muss nicht gleich die Programmiersprache
wechseln.

Win32- API
Für die Windows-API liegt mit der zum Lieferumfang von Visual Basic gehörenden Datei
Win32api.txt eine Deklarationsdatei vor, die alle für die Programmierung mit der Win32-API
erforderlichen Konstantendefinitionen, Funktionsdeklarationen und Typvereinbarungen bereit-
stellt. Öffnet man diese Datei im API-Viewer, nachdem dieser über den Add-In-Manager des
Menüs ADD-INS der Visual-Basic-Entwicklungsumgebung geladen wurde, wird die Handha-
bung von API-Funktionen aus Visual Basic heraus zu einer rein formalen Angelegenheit: Man
sucht sich die benötigten Definitionen heraus, stellt eine Auswahl zusammen und kopiert diese
über die Zwischenablage in den Bereich ALLGEMEIN des betroffenen Moduls. (Beachten Sie,
dass für bestimmte API-Funktionen auch Typvereinbarungen erforderlich sein können, um den
einen oder anderen Parameter mit einem Wert zu versorgen.)

Der API- Viewer liefert die Deklarationen für drei API- Funktionen und eine Typvereinbarung

1 87
Prozeduren selbst definieren

Worauf Sie beim Aufruf einer so deklarierten Routine wirklich peinlich achten sollten: Setzen
Sie nicht auf implizite Typumwandlungen, sondern bedienen Sie jeden Parameter mit dem
»richtigen« Datentyp. In besonderen Fällen, wenn eine API-Routine unterschiedliche Datenty-
pen für denselben Parameter akzeptiert und Ihr Programm die Routine mit mehr als einem
Parametertyp aufruft, bleibt der »Datentyp« Any als einziger Ausweg, der Typüberprüfung von
Visual Basic zu entrinnen.
Beachten Sie jedoch, dass Sie dann für die Einhaltung des Datentyps selbst verantwortlich sind.
Die Deklarationen einiger Routinen in Win32api.txt enthalten As Any-Vereinbarungen. Sollten
Sie die entsprechenden Routinen nur mit einem bestimmten Parametertyp aufrufen, können Sie
die Deklaration auf diesen Typ zuschneiden, um von der Typüberprüfung des Compilers zu
Prozeduren selbst definieren

profitieren. Vielfach ist es auch sinnvoll, eine Routine mit einem As Any-Parameter für jeden der
benötigten Parametertypen spezifisch zu deklarieren – jeweils unter Verwendung eines anderen
Bezeichners.
Die folgende Tabelle gibt einen Überblick darüber, wie verschiedene von der Win32-API ver-
wendete C/C++-Datentypen in Visual Basic deklariert sind und welche Art von Wert für den
Aufruf erforderlich ist.

API-Datentyp Visual-Basic-Deklaration Parameter verlangt ...


ATOM ByVal Var As Integer Wert, Variable oder Ausdruck mit Datentyp
Integer
BOOL, BOOLEAN ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
BYTE ByVal Var As Byte Wert, Variable oder Ausdruck mit Datentyp Byte
CHAR ByVal Var As Byte Wert, Variable oder Ausdruck mit Datentyp Byte
COLORREF ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
DWORD ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
HWND, HDC, ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
HMENU (von Windows vergebener Handle für Fenster,
Gerätekontext, Menü)
INT, UINT ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
LONG ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
LPARAM ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
LPDWORD [ByRef] Var As Long Variable vom Datentyp Long
LPINT, LPUINT [ByRef] Var As Long Variable vom Datentyp Long
LPRECT [ByRef] Var As bdtTyp Variable vom Datentyp bdtTyp (benutzerdefi-
nierter Typ)
LPSTR, LPCSTR ByVal Var As String Wert, Variable oder Ausdruck mit Datentyp
String
LPVOID [ByRef] Var As Any Variable des entsprechenden Typs (bei Übergabe
einer Variablen vom Typ String ist dem Wert
das Schlüsselwort ByVal voranzustellen)
LPWORD [ByRef] Var As Integer Variable mit Datentyp Integer
LRESULT ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
Deklaration grundlegender Datentypen der Win32- API in Visual Basic

1 88
Routinen aus DLLs und der Windows- API einsetzen

API-Datentyp Visual-Basic-Deklaration Parameter verlangt ...


NULL As Any oder ByVal Nothing oder ByVal 0& oder vbNullString
ByVal Var As Long
SHORT ByVal Var As Integer Wert, Variable oder Ausdruck mit Datentyp
Integer
VOID – (Rückgabetyp einer Prozedur)
WORD ByVal Var As Integer Wert, Variable oder Ausdruck mit Datentyp
Integer

Prozeduren selbst definieren


WPARAM ByVal Var As Long Wert, Variable oder Ausdruck mit Datentyp Long
Deklaration grundlegender Datentypen der Win32- API in Visual Basic

Zeichenfolgen und ihre Besonderheiten


Bei Durchsicht der in der obigen Tabelle aufgelisteten Datentypen wird Ihnen vielleicht aufge-
fallen sein, dass Zeichenfolgen überraschenderweise eine ByVal-Deklaration erfordern. Das ist
kein Druckfehler, sondern eine gewisse Ungereimtheit, die Visual Basic im Umgang mit Zei-
chenfolgen anhaftet – die berühmte Ausnahme von der Regel also. Während der ByVal-Zeichen-
folgenparameter lpBuffer nach allen Regeln der Kunst in dem Szenario
...
a = "ByVal!"
TestByVal a
Print a ' Ausgabe: "ByVal!"
...
Sub TestByVal(ByVal lpBuffer As String)
lpBuffer = "ByRef?"
End Sub

nur als Eingabeparameter taugt, behandelt Visual Basic den gleichen Parameter als Ein-/Ausga-
bewert, wenn eine Declare-Vereinbarung vorliegt:
Private Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
...
Dim sUN As String, lLen As Long
sUN = Space(20) ' String der Länge 20 generieren
lLen = Len(sUN) ' Stringlänge in Variable
If GetUserName(sUN, lLen) Then ' Benutzername (hier: Rudi)
Print lLen, Len(sUN), sUN ' Ausgabe: 20 5 "Rudi|"
sUN = Left(sUN, lLen – 1) ' Länge anpassen, Nullbyte abschneiden
...

Dieser Code zeigt bereits recht eindrucksvoll, mit welchen Besonderheiten man bei der Verwen-
dung von Routinen der Win32-API zu rechnen hat, wenn Zeichenfolgen mit im Spiel sind. Da
Visual Basic für Zeichenfolgen intern den für die Automatisierung erforderlichen C/C++-Daten-
typ BSTR verwendet, treffen hier zwei recht unterschiedliche Repräsentationen aufeinander. Die
auf das gewöhnliche Zeichenfolgenformat der Sprache C/C++ eingestellte Routine GetUserName
erwartet die Adresse eines Puffers, in den sie den Namen des Computers (im ANSI-Format)
ohne Deskriptor und mit anhängendem Nullbyte schreiben kann. Die Länge des bereitgestellten
Puffers erfährt sie über den Parameter nSize – er nimmt die Funktion des Längendeskriptors
ein. Ist der Puffer zu klein dimensioniert, um den Namen des Computers aufnehmen zu können,

1 89
Prozeduren selbst definieren

liefert die Funktion das Ergebnis 0 und gibt die benötigte Pufferlänge über den Ein-/Ausgabepa-
rameter nSize zurück. Bei ausreichender Pufferlänge überträgt die Routine den Namen des
Computers in den Puffer, setzt nSize auf die Länge der geschriebenen Zeichenfolge unter
Berücksichtigung des angehängten Nullbytes und gibt den Funktionswert 1 zurück. Das von
Visual Basic verwendete Zeichenfolgenformat BSTR setzt sich aus einem vier Bytes umfassenden
Deskriptor, der die Länge der Zeichenfolge beschreibt, und dem Puffer für die Zeichenfolge
(Unicode) zusammen. Ein Nullbyte wird weder gesetzt noch interpretiert. Damit dürfte klar
sein, warum als Vorbereitung für den Aufruf der Routine die Zeile
sUserName = Space(20) ' String der Länge 20 generieren
Prozeduren selbst definieren

erforderlich ist. Sie sorgt dafür, dass der Zeichenpuffer Platz für 20 Zeichen bietet. Als zweite
Voraussetzung für den erfolgreichen Aufruf der Routine muss diese die Adresse des Zeichenfol-
genpuffers erfahren. Da der Zeichenfolgenpuffer in Visual Basic keine eigenständige Größe dar-
stellt, mussten die Entwickler hier tricksen: Sie haben den Compiler so ausgelegt, dass er den
ByVal-Parameter des Typs String in der Parameterliste einer via Declare importierten Routine
nicht als Kopie übergibt, sondern statt dessen die Adresse eines Zeichenfolgenpuffers mit einer
in ANSI gewandelten Kopie der Zeichenfolge bereitstellt (API-Routinen mit angehängtem »A«
im Bezeichner arbeiten mit ANSI-Code, solche mit angehängtem »W« mit Unicode). So weit, so
gut. Die Routine kann so zwar in den Puffer der übergebenen Zeichenfolge schreiben, eine Län-
genanpassung ist ihr aber nicht möglich, weil das von ihr angehängte Nullbyte aufseiten von
Visual Basic nicht interpretiert wird. Visual Basic wandelt somit die gesamte Zeichenfolge in
ihrer ursprünglichen Länge sofort nach dem Aufruf wieder in Unicode um. Mithin ist die Länge
der Zeichenfolge nach dem Aufruf der API-Routine unverändert und muss explizit angepasst
werden:
a = Left(a, lLen – 1) ' Länge anpassen und Nullbyte abschneiden

DLL- Routinen im Allgemeinen


Zu echten Hürden wachsen sich die in der Beschreibung geschilderten Problemfelder eigentlich
nur im Zusammenhang mit DLLs aus, die der Hersteller nicht eigens mittels einer Deklarations-
datei für die Benutzung mit dem Add-In API-VIEWER der Entwicklungsumgebung auf die
Zusammenarbeit mit Visual Basic vorbereitet hat. Einem geübten und in mehreren Sprachen
versierten Programmierer wird es bei Kenntnis einer Bibliothek zwar nicht sehr schwer fallen,
sich die entsprechenden Informationen selbst zusammenzustellen, der Arbeitsaufwand ist aber
nicht zu unterschätzen.
Während Visual Basic für die zum Kern von Windows zählenden Bibliotheken User32,
Kernel32 und GDI32 weder eine Dateierweiterung noch einen Pfad erwartet, muss der Lib-
Abschnitt in der Declare-Anweisung bei anderen DLLs zumindest eine Dateierweiterung enthal-
ten und in besonderen Fällen auch einen Pfad. Beim dynamischen Binden von DLLs durchsucht
Windows der Reihe nach: das Verzeichnis der Exe-Datei, die die Dienste der DLL anfordert,
das standardmäßige Arbeitsverzeichnis, das Systemverzeichnis von Windows (meist: C:\Win-
dows\System\) das Windows-Verzeichnis (meist: C:\Windows) und schließlich die in der DOS-
Umgebungsvariablen PATH spezifizierten Verzeichnisse. Sollte die DLL in keinem der genannten
Verzeichnisse zu finden sein, ist der Zugriffspfad explizit zu nennen.
Eine gute Orientierungshilfe für eigene Deklarationen bietet die zum Lieferumfang von Visual
Basic gehörende Deklarationsbibliothek Win32api.txt. Laden Sie die Datei am besten in einen
Texteditor und vergleichen Sie die darin zu findenden Visual-Basic-Deklarationen mit den origi-
nalen C/C++-Deklarationen der Win32-API. Die folgende Tabelle zeigt, wie die Deklaration
grundlegender C/C++-Datentypen in Visual Basic aussieht und welcher Wert dann jeweils
erwartet wird.

1 90
Routinen aus DLLs und der Windows- API einsetzen

C/C++-Datentyp Visual-Basic-Deklaration Parameter verlangt ...


bdt* [ByRef] Var As bdt Variable mit benutzerdefiniertem Datentyp
bdt
char ByVal Var As Byte Wert, Variable oder Ausdruck mit Daten-
typ Byte
char*, char[] [ByRef] Var As Byte Variable vom Datentyp Byte oder erstes
Element von Byte-Array
double ByVal Var As Double Wert, Variable oder Ausdruck mit Daten-

Prozeduren selbst definieren


typ Double
double*, double[] [ByRef] Var As Double Variable mit Datentyp Double oder erstes
Element von Double-Array
float ByVal Var As Single Wert, Variable oder Ausdruck mit Daten-
typ Single
float*, float[] [ByRef] Var As Single Variable mit Datentyp Single oder erstes
Element von Single-Array
hyper ByVal Var As bdt64 Wert, Variable oder Ausdruck mit benut-
zerdefiniertem 64-Bit-Datentyp
hyper* [ByRef] Var As bdt64 Variable mit benutzerdefiniertem 64-Bit-
Datentyp
int*, int[] [ByRef] Var As Long Variable mit Datentyp Long oder erstes Ele-
ment von Long-Array
long*, long[] [ByRef] Var As Long Variable mit Datentyp Long oder erstes Ele-
ment von Long-Array
int, long ByVal Var As Long Wert, Variable oder Ausdruck mit Daten-
typ Long
short ByVal Var As Integer Wert, Variable oder Ausdruck mit Daten-
typ Integer
short*, short[] [ByRef] Var As Integer Variable mit Datentyp Integer oder erstes
Element von Integer-Array
void* [ByRef] Var As Any Variable mit Datentyp Long (wird als
Adresse interpretiert)
wchar_t ByVal Var As Integer Wert, Variable oder Ausdruck mit Daten-
typ Integer
wchar_t* Variable mit Datentyp Integer
wchar_t* ByVal Var As String, Wert, Variable oder Ausdruck mit Daten-
wchar_t[] [ByRef] Var As Integer typ String bzw. Variable vom Datentyp
Integer oder erstes Element von Integer-
Array
Deklaration elementarer C/ C+ + - Datentypen in Visual Basic

Diese Aufstellung dürfte gut 95 Prozent der Fälle abdecken, die einem bei der Parameterdekla-
ration begegnen – von schlichten Umbenennungen dieser Datentypen einmal abgesehen. Fehlt
die Angabe ByVal oder ByRef für einen Parameter, behandelt ihn Visual Basic als ByRef-Parame-

1 91
Prozeduren selbst definieren

ter. In einzelnen Fällen (insbesondere im Zusammenhang mit As Any-Vereinbarungen) kann es


auch nötig sein, einen ByRef-Parameter mit einem Wert oder einen ByVal-Parameter mit einer
Adresse zu bedienen. In diesem Fall besteht im Zusammenhang mit Declare-Funktionen/-Proze-
duren die Möglichkeit, einzelne Parameterwerte durch Voranstellen von ByVal oder ByRef expli-
zit als Wert oder als Adresse zu übergeben. Lassen Sie aber Vorsicht walten, die Übergabe eines
Werts anstelle einer Adresse führt im Allgemeinen sicher zum Absturz der Visual-Basic-Anwen-
dung.
Verschiedentlich erwartet eine DLL-Routine auch einen Funktionszeiger als Parameter, wenn
sie für einen bestimmten Zweck eine anwendungseitige Funktion (Rückruffunktion) aufrufen
muss – etwa, wie im Falle der API-Routinen waveOutOpen und waveInOpen der Multimediaerwei-
Prozeduren selbst definieren

terung Winmm.dll von Windows 9x, wo die Rückrufroutine für die Pflege des Ein- bzw. Ausga-
bepuffers verantwortlich ist. Speziell für solche Fälle unterstützt Visual Basic den AddressOf-
Operator. Für das Generieren von Funktionszeigern mit AddressOf sind allerdings eine Reihe
von Einschränkungen zu beachten: Der gesamte Code, der mit dem Aufruf der API-Routine
zusammenhängt (Deklaration und Aufruf der API-Routine) muss in einem Standardmodul ent-
halten sein – AddressOf-Aufrufe in Klassen- oder Formularmodulen sind nicht erlaubt. Die Rou-
tine, deren Adresse AddressOf preisgibt, muss eine benutzerdefinierte Funktion oder Prozedur
sein – via Declare importierte externe Routinen, sind nicht zulässig (als Work-around schreibt
man eigene Routinen, die die Importroutinen umhüllen).
Warnung

Wa rnung
...................................................
Die ByVal-Deklaration von String-Parametern hat im Zusammenspiel mit Declare-Routinen
eine andere Bedeutung als in den Parameterlisten gewöhnlicher Sub- und Function-Definitionen
– sie dient der ByRef-Übergabe des Zeichenfolgenpuffers eines String-Werts. Zudem ist eine
Vor- und Nachbehandlung der Werte von Zeichenfolgenparametern nötig.
Tipps

Tipp
...................................................
Falls Sie nicht über die Datei Win32api.txt verfügen, finden Sie diese in der Version vom
3.8.1995 unter http://www.microsoft.com/OfficeDev/Articles/Exe/Win32api.exe.
Wenn Ihnen die Geschichte mit den Zeichenfolgen im obigen Beispiel nicht ganz geheuer vor-
kommt oder Sie mit unbekannten Datentypen konfrontiert werden, können Sie auch mit Byte-
Arrays arbeiten. Beachten Sie aber, dass Visual Basic dann keine automatische Umwandlung
von und nach Unicode vornimmt. Der Code für das im Abschnitt »Zeichenfolgen und ihre
Besonderheiten« (S. 189 ) genannte Beispiel sieht dann etwa so aus:
Private Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (lpBuffer As Byte, nSize As Long) As Long
...
Dim sUN (20) As Byte, i As Long
lLen = 20
If GetUserName(sUN, lLen) Then ' Benutzername (hier: Rudi)
For i = 0 to lLen – 2 ' 0-Basiert, Nullbyte abschneiden
Print Chr(a(i)) ' Ausgabe: "Rudi" (Kein Unicode!)
Next i
...
Beispiele

Beis piele
...................................................
Das folgende Beispiel zeigt eine alternative Implementation der Dir-Funktion mit Hilfe der ent-
sprechenden Win32-API-Routinen:

1 92
Routinen aus DLLs und der Windows- API einsetzen

Option Explicit
Private Declare Function FindFirstFile Lib "kernel32" Alias _
"FindFirstFileA" (ByVal lpFileName As String, lpFindFileData _
As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias _
"FindNextFileA" (ByVal hFindFile As Long, lpFindFileData _
As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile _
As Long) As Long
Private Const MAX_PATH = 260

Prozeduren selbst definieren


Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * MAX_PATH
cAlternate As String * 14
End Type

Private Sub TestDir() ' Testen der alternativen Dir-Funktion


Dim a As String
a = Dir("*.frm")
While a <> ""
a = Dir
Print a
Wend
End Sub

Private Function Dir(Optional sSuchm As String = "", Optional AttrVkt _


As VbFileAttribute = vbNormal) As String
Static w32FD As WIN32_FIND_DATA
Static lHandle As Long
w32FD.dwFileAttributes = AttrVkt
If sSuchm <> "" Then ' Erster Aufruf von Dir
lHandle = FindFirstFile(sSuchm, w32FD)
If lHandle Then
Dir = Left(w32FD.cFileName, InStr(w32FD.cFileName, Chr(0)) – 1)
End If
Else ' weiterer Aufruf von Dir
If FindNextFile(lHandle, w32FD) Then
Dir = Left(w32FD.cFileName, InStr(w32FD.cFileName, Chr(0)) – 1)
Else ' keine weiteren Dateinamen mehr
FindClose (lHandle) ' Handle freigeben

1 93
Prozeduren selbst definieren

End If
End If
AttrVkt = w32FD.dwFileAttributes
End Function

Die hier vorgestellte Alternative zum Dir-Befehl von Visual Basic ist gleichfalls nicht rekursiv
verwendbar, liefert aber immerhin den passenden Attributvektor. Eine für den rekursiven Auf-
ruf taugliche Variante von Dir ergibt sich, wenn lHandle nicht als statische Variable, sondern
als Ein-/Ausgabeparameter vereinbart wird:
Private Function Dir(lHandle As Long, Optional sSuchm As String = "", _
Prozeduren selbst definieren

Optional AttrVkt As VbFileAttribute = vbNormal) As String

In diesem Fall muss sich der Aufrufer um den Such-Handle kümmern.


Hier noch ein Beispiel für den Einsatz einer von Visual Basic gestellten Funktion ZähleFenster
als Rückruffunktion für die API-Funktion EnumWindows. Die Rückruffunktion wird beim Aufruf
von EnumWindows installiert und dann (solange sie den Wert 1 liefert) für jedes Fenster einmal
aufgerufen.
Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, _
ByVal lParam As Long) As Long
Private lFenster As Long

' Rückruffunktion, zählt Fenster in globaler Variable


Function ZähleFenster (ByVal hwnd As Long, ByVal data As Long) As Long
lFenster = lFenster + 1
ZähleFenster = 1 ' True, damit die Aufzählung weitergeht
End Function

' Liefert Anzahl der bei Windows registrierten Fenster


Function FensterAnz() As Long
Dim Dummy As Long
Dummy = EnumWindows(AddressOf ZähleFenster, 0)
FensterAnz = lFenster
End Function

Ein Beispiel für den Einsatz der API-Funktion SendMessage im Zusammenhang mit einem Kom-
binationsfeld-Steuerelement finden Sie im Abschnitt »Printer-Objekt«, S. 284.
Verwandte Befehle

Verwa ndte Befehle


...................................................
Function, Sub
Verwandte Themen

Verwandte Them en
...................................................
Variablendeklaration (S. 162); Elementare Datentypen (S. 49); Benutzerdefinierte Datenty-
pen (S. 60)

1 94
Objekte und Klassen
Wenn etwas aus der heutigen Programmierwelt nicht mehr wegzudenken ist, dann sind das
Objekte. Während die klassische imperative Programmierung mit ihrem so genannten »anwen-
dungszentrierten Ansatz« noch die strikte Trennung zwischen Daten und Code predigte und
weitgehend monolithische Anwendungen hervorbrachte, die über oft sehr komplexen Daten-
strukturen operierten, hat sich die objektorientierte Programmierung geradezu die gegenteilige
Ansicht zu eigen gemacht: Sie geht davon aus, dass die Repräsentation und die Manipulation
von Daten eng zusammengehören und nichts weiter als unterschiedliche Aspekte des gleichen
»Dings« sind – nämlich des Objekts.
Wo in der imperativen Programmierung eine Variable oder ein Wert eines bestimmten Daten-
typs vereinbart und initialisiert wird, wird in der objektorientierten Programmierung eine
Objektvariable oder ein Objekt einer bestimmten Klasse vereinbart und instanziiert. Und wo
die imperative Programmierung mit einer losen Sammlung von Funktionen und Prozeduren
arbeitet, die nur implizit – nämlich über die Datentypen der Ein-/Ausgabeparameter und des
Funktionswerts – auf einen oder mehrere Datentypen zugeschnitten sind, sorgt der Klassenbe-
griff bei der objektorientierten Programmierung für eine feste Zuordnung zwischen einer kon-
kreten Datenstruktur (Eigenschaften des Objekts) und den zugehörigen Operationen (Metho-
den des Objekts). Die Operation eines Objekts hat einen Ich-Bezug; das hat eine gewöhnliche
Funktion oder Prozedur nicht.
Als eine der Altvordern heutiger Programmiersprachen hatte die einstige Interpretersprache
Basic nicht nur gewisse Mühe, mit der Tradition der klassischen imperativen Programmierung
aufzuschließen, auch der Übergang zur objektorientierten Programmierung verlief nicht ganz
schmerzlos, wenngleich sich das Ergebnis mit Blick auf Visual Basic 6.0 wahrlich sehen lassen
kann. Während die Integration benutzerdefinierter Funktionen und Prozeduren noch völlig
geradlinig und auch ohne bleibende Narben vor sich ging (man betrachte sich die Sprache etwa
auf dem Stand von QuickBasic oder QBasic), bescherte die Einführung des Objektbegriffs der
Sprache jedoch nachhaltig eine Spaltung, die gerade bei unerfahrenen Programmierern zuweilen
für eine gewisse Verwirrung sorgt. Angesichts dessen, was die Sprache dadurch aber an Aus-
druckskraft und Vielseitigkeit gewonnen hat, ist diese Spaltung jedoch leicht in Kauf zu neh-
men.
Im Vergleich mit anderen Programmiersprachen war der unkomplizierte Umgang mit den Win-
dows-Steuerelementen seit jeher eine der großen Stärken der integrierten Entwicklungsumge-
bung von Visual Basic (und wohl auch das hinter dem Produkt steckende Erfolgsrezept), insbe-
sondere die Möglichkeit, auf relativ einfache Art und Weise zu benutzerdefinierten
Steuerelementen zu gelangen, die sich auch jenseits von Visual Basic erfolgreich einsetzen lie-
ßen. Bis hin zur Version 3.0 war es noch der VBX-Standard, ein reiner 16-Bit-Standard, der für
die Implementierung der Steuerelemente maßgeblich war. VBX lag zweifelsohne ein Objektmo-
dell zugrunde, wenngleich dies damals noch nicht so explizit zum Ausdruck kam, da die umge-
bende Landschaft fehlte. Als Microsoft Visual Basic mit der Version 4.0 an die 32-Bit-Welt
anpasste, erhielt die Sprache mit VBA (Visual Basic for Applications), damals auch »Object
Basic« genannt, einen neuen und vollständig objektorientierten Kern. VBA unterwarf Visual
Basic der Herrschaft des COM (Component Object Model) und verheiratete die objektorien-
tierte Seite der Sprache mit OLE 2.0. VBX blieb dabei als nicht COM-konformer Standard auf
der Strecke. An seiner Stelle hielt der neue 32-Bit-Standard OCX (OLE Control) – seinerseits
eine Erweiterung von OLE 2.0 – Einzug in die Welt der Steuerelemente.
Der durch das COM geschaffene Objektbegriff ist unabhängig von einer spezifischen Program-
miersprache oder -plattform. Er beinhaltet:

1 95
Klassen als Datentypen für Objektvariablen

1. Einen Standardmechanismus für die global (= weltweit) eindeutige Benennung eines COM-
Objekts mit einer GUID (Globally Unique Identifier), der systemweit (auf Basis der System-
registrierung) das Auffinden und Laden des Objekts sowie das Auffinden der für die Bearbei-
tung des Objekts zuständigen Anwendungen ermöglicht
2. Einen Standardmechanismus (Referenzenzählung), durch den ein Objekt selbstständig ver-
folgen kann, inwieweit es noch benötigt wird
3. Einen Standardmechanismus zur Fehlermeldung und einen Satz an Fehlercodes
4. Einen Standardmechanismus für das Ansprechen von Eigenschaften und Methoden
5. Einen Standardmechanismus für den Austausch von Objekten
DCOM (Distributed COM) dehnt die COM-Spezifikation auf Netzwerke aus.
Klassen als Datentypen für Objektvariablen

Bei OLE 2.0, das Microsoft seit einiger Zeit mit Zielrichtung Internet unter dem Namen
ActiveX vermarktet, handelt es sich um eine Sammlung verschiedener COM-konformer Tech-
nologien, die das Miteinander von Objekten und Komponenten für die Gestaltung verteilter
Anwendungen ermöglichen. Nicht nur Windows bietet inzwischen immer mehr Bestandteile
seiner selbst als ActiveX-Komponenten feil, ein großer Teil der gängigen Anwendungen ange-
fangen von den »Schlachtschiffen« Word, Excel und Access aus der Microsoft Office Suite über
den Internet Explorer bis hin zu kleinsten Hilfsanwendungen ist mit von der Partie.
War die Objektorientierung für Visual Basic vor der Version 4.0 mehr oder minder nur die Ein-
trittskarte in die »ereignisreiche« Welt der grafisch orientierten Benutzerschnittstelle von Win-
dows, so erschließt sie der Sprache seit der Adaption des COM-Objektbegriffs im Zuge der
Version 4.0 die gesamte Welt des ActiveX und der Automatisierung – darunter: ActiveX-Steuer-
elemente, ActiveX-Komponenten, ActiveX-Container, ActiveX-Datenobjekte (ADOs), Auto-
matisierungsobjekte, Automatisierungsserver.

Klassen als Datentypen für Objektvariablen


{Dim | Public | Private | Static} [WithEvents] ObjVar As ObjTyp
{Dim | Public | Private | Static} ObjVar As New ObjTyp
Set ObjVar = [New] {Klasse | Nothing}
Set ObjVar = ObjAusdr
Beschreibung

Bes c hreibung
...................................................
Seit Visual Basic Module für die Definition eigener Objektdatentypen oder Klassen erlaubt,
haben sich die Möglichkeiten für die Definition und Ausgestaltung benutzerdefinierter Datenty-
pen drastisch erweitert. Die Vereinbarung einer Variablen ObjVar für einen gegebenen Objekt-
datentyp Klasse geschieht im Rahmen einer Dim-, Private-, Public- oder Static-Anweisung, mit
den üblichen Auswirkungen für den Geltungsbereich. Falls Klasse auf die Signalisierung von
Ereignissen eingerichtet ist und die Variablendeklaration auf Modulebene erfolgt, kann die Ver-
einbarung zusätzlich das Schlüsselwort WithEvents enthalten. Dies eröffnet die Möglichkeit, in
dem Modul Ereignisroutinen bereitzustellen, die auf Ereignisse des der Variablen zugeordneten
Objekts reagieren. Ohne WithEvents besteht die Möglichkeit, das Schlüsselwort New anzugeben,
was den Compiler zu einer impliziten Instanziierung der Objektvariablen bei ihrem ersten Ein-
satz veranlasst.
Fehlt das Schlüsselwort New bei der Variablendeklaration, initialisiert Visual Basic die verein-
barte Objektvariable standardmäßig mit dem Wert Nothing. In diesem Fall ist eine explizite Set-
Zuweisung (mit der Variablen als Linkswert) erforderlich, um ihr ein konkretes Objekt zuzu-
ordnen. Je nach Beschaffenheit des Rechtswerts in der Anweisung erhält die Objektvariable
dabei als Wert entweder einen (weiteren) Verweis auf ein bereits bestehendes Objekt oder einen
Verweis auf eine neue Instanz des Objekts. Ersteres geschieht, wenn der Rechtswert ObjAusdr in

1 96
Klassen als Datentypen für Objektvariablen

der Zuweisung durch eine andere Objektvariable oder als Funktionsergebnis bereitgestellt wird.
Zur Instanziierung eines neuen Objekts des Objektdatentyps Klasse kommt es dagegen, wenn
der Rechtswert durch das Schlüsselwort New gefolgt von dem Objektdatentyp gebildet wird
(oder, wie gesagt, eine New-Deklaration erfolgt ist).
Mit Blick auf die objektorientierte Programmierung unterstützt Visual Basic den vordefinierten
Datentyp Object. Es handelt sich dabei um einen generischen (lies: universellen) Objektdaten-
typ, der es einer Objektvariablen ermöglicht, auf Objekte einer beliebigen Klasse zu referieren
und somit einen beliebigen Objektdatentyp anzunehmen. (Da Object auch als Untertyp von
Variant definiert ist, gilt das hier Gesagte auch für Variant). Einer Object-Variablen kann also
mit einer Set-Zuweisung jedes beliebige Objekt zugeordnet werden – um den Preis einer späten
Bindung zur Laufzeit.

Klassen als Datentypen für Objektvariablen


Das Konzept des Polymorphismus ermöglicht darüber hinaus die Vereinbarung von Objektva-
riablen übergeordneter Schnittstellenklassen (beispielsweise Form oder UserControl) und deren
Verwendung für Objekte spezifischer Klassen, die Implementationen für die jeweiligen Schnitt-
stellen bereitstellen. Ein und dieselbe Objektvariable kann dann für Objekte unterschiedlichen
Typs verwendet werden, solange diese die gleiche Schnittstelle implementieren.
Anwendung

Anwendung
...................................................
Obwohl Klassen mehr oder weniger direkte Nachfahren der benutzerdefinierten Type-Datenty-
pen sind, existieren doch eine Reihe signifikanter Unterschiede. Die folgende Tabelle gibt einen
Überblick.

Variable mit Type-Datentyp Objektvariable


Benutzerdefinierter Datentyp ent- Objekt kann neben Eigenschaften (Datenelemente)
hält nur Datenelemente (Element auch Methoden (Funktionen/Prozeduren mit »Ich-
kann aber Objektvariable sein). Bezug«) haben sowie auf Ereignisse reagieren und
Ereignisse auslösen.
Visual Basic initialisiert den Wert Eine frisch deklarierte Objektvariable hat den Wert
der Variablen automatisch unter Nothing, verweist also auf kein Objekt. Wertzuweisun-
Beachtung der Vorgabewerte für die gen an eine Objektvariable erfordern das Schlüsselwort
Datentypen der Elemente. Set (anstelle von Let). Wenn dabei ein neues Objekt
generiert werden soll, ist entweder bei der Deklaration
oder bei der Zuweisung das Schlüsselwort New erforder-
lich. (Bei WithEvents-Deklaration darf New nur in einer
Set-Anweisung stehen!)
Die Variable repräsentiert einen Der Wert einer Objektvariablen ist ein Verweis auf ein
konkreten Wert des benutzerdefi- Objekt. Es können mehrere unterschiedliche Objektva-
nierten Datentyps. (ByRef-Parameter riablen auf ein und dasselbe Objekt verweisen.
in Funktions-/Prozeduraufrufen
behandelt Visual Basic wie tempo-
räre Umbenennungen ein- und der-
selben Variablen).
Der Wert einer benutzerdefinierten Ein Objekt existiert so lange, wie eine Objektvariable
Variablen existiert so lange wie die darauf verweist. Visual Basic baut ein Objekt ab, wenn
Variable. der Geltungsbereich der letzten darauf verweisenden
Variablen erlischt, diese den Wert Nothing erhält oder
einen neuen Wert zugewiesen bekommt.
Vergleich zwischen Type-Datentypen und Objektdatentypen

1 97
Klassen als Datentypen für Objektvariablen

Variable mit Type-Datentyp Objektvariable


Zuweisungsoperator kann Kopie des Für Objektvariablen sind nur Set-Zuweisungen defi-
Werts erzeugen. niert, die mit Referenzen auf ein gegebenes Objekt han-
tieren. Jede Set-Zuweisung erzeugt eine neue Referenz
auf ein gegebenes Objekt.
Die Kopie eines Objekts kann nur das Objekt selbst
anfertigen. Das Objekt muss dazu eine geeignete
Methode bereitstellen.
Da Visual Basic keine Vergleichsope- Für den Vergleich von Objektreferenzen ist der Is-Ope-
Klassen als Datentypen für Objektvariablen

ratoren für benutzerdefinierte Typen rator definiert. Er liefert den Wert True, wenn zwei
kennt (das wäre auch nicht sehr Objektvariablen auf ein und dasselbe Objekt verwei-
sinnvoll), muss beispielsweise die sen, ansonsten False.
Gleichheit komponentenweise
(Datenfeld für Datenfeld) geprüft
werden.
Eine Private-Definition eines benut- Der Objektdatentyp ist in einem eigenen Klassenmodul
zerdefinierter Datentyps kann in definiert und somit im gesamten Projekt sichtbar. Dar-
jedem Modul (im Bereich ALLGE- über hinaus kann er veröffentlicht (registriert) werden
MEIN) geschehen, eine Public-Defi- was ihn für alle Projekte auf dem jeweiligen System
nition nur in einem Standardmodul. sichtbar macht.
Der Zugriff auf Datenelemente Der Zugriff auf Eigenschaften und Methoden erfolgt
erfolgt durch Notation des Punkt- durch Notation des Punktoperators oder durch With-
operators oder durch With-Qualifi- Qualifizierung. Der Besitzer eines Objekts (lies: der
zierung. Alle Datenelemente haben Besitzer einer Objektvariablen mit einer gültigen Refe-
den gleichen Geltungsbereich. renz auf das Objekt) kann nur die als Public oder –
innerhalb ein und desselben Projekts – Friend deklarie-
ren Eigenschaften und Methoden ansprechen. Als Pri-
vate deklarierte Eigenschaften oder Methoden sind nur
im Codemodul des Objektdatentyps bekannt.
Innerhalb des Codemoduls eines Objektdatentyps ist
keine Qualifizierung beim Zugriff auf Eigenschaften
und Methoden erforderlich. Die Qualifizierung kann
jedoch optional durch Voranstellen des Bezeichners Me
erfolgen (vgl. folgende Abbildung).
Es gibt kein »Standarddatenele- Für den Objektdatentyp kann eine Standardeigenschaft
ment«. definiert sein. Der Zugriff darauf erfordert nur die
Objektvariable ohne weitere Qualifizierung.
Der Wert lässt sich einer Variant- Da für Variant der Untertyp Object definiert ist, lassen
Variablen nicht zuweisen. Zuwei- sich einer Variant-Variablen die Werte beliebiger
sungen (nicht jedoch die LSet- Objektvariablen mittels Set zuweisen.
Zuweisung) setzen für Rechts- und
Linkswert exakt den gleichen Daten-
typ voraus.
Vergleich zwischen Type-Datentypen und Objektdatentypen

1 98
Klassen als Datentypen für Objektvariablen

Wann immer Sie mit einer Größe arbeiten wollen, die nur als Objektdatentyp zur Verfügung
steht – und das sind so gut wie alle in Visual Basic definierten Datentypen jenseits der elementa-
ren und benutzerdefinierten Datentypen sowie der Arrays –, müssen Sie eine Objektvariable
vereinbaren. Die Visual-Basic-Entwicklungsumgebung bietet Ihnen bei der Programmierung mit
Objekten in recht eindrucksvoller Weise Unterstützung an, indem sie (ähnlich wie bei den
Funktionsparametern) die zu der Klasse einer Objektvariablen gehörigen Eigenschaften und
Methoden parat hält und Ihnen beim Tippen als Auswahlliste einblendet (vgl. die folgende
Abbildung). Auf diese Weise haben Sie jederzeit einen guten Überblick über die Strukturele-
mente eines Objekts.

Klassen als Datentypen für Objektvariablen


Die Entwicklungsumgebung bietet die Eigenschaften und Methoden eines Objekts während des Schreibens an

Für die Definition eigener Objektdatentypen müssen Sie Klassenmodule in Ihr Projekt einfügen
(mehr dazu im Abschnitt »Selbst definierte Klassen«, S. 318).
Tipp

Tipp
...................................................
Der über den Befehl OBJEKTKATALOG im Menü ANSICHT oder die Taste (F2) aufgerufene
Objektkatalog gibt einen Überblick über sämtliche unter Visual Basic verfügbaren Objektda-
tentypen und deren Eigenschaften, Methoden und Ereignisse (siehe folgende Abbildung).
Beispiel

Beis piel
...................................................
Der folgende Codeauszug aus dem Beispielprojekt FormMitEreignis zeigt die WithEvents-Ver-
einbarung einer privaten Objektvariablen sowie deren Set-Initialisierung im Rahmen einer Pro-
perty-Routine mit dem Wert einer öffentlichen Eigenschaft, die den Objektdatentyp BasisForm
trägt (das vollständige Beispiel ist im Abschnitt »Ereignisroutinen«, S. 204, abgedruckt).
' Klasse: clsFormMitEreignis
Private WithEvents mBasisForm As BasisForm ' Formular ist Eigenschaft

Public Property Set BasisForm(ByVal newBasisForm As BasisForm)


Set mBasisForm = newBasisForm ' Wert der Eigenschaft setzen
End Property ' (Formularobjekt zuordnen)
Methoden

Metho den
...................................................
[Public | Private | Friend][Static] Function Name [(ParmListe)][ As Typ]
[Public | Private | Friend][Static] Sub Name [(ParmListe)]

1 99
Klassen als Datentypen für Objektvariablen
Klassen als Datentypen für Objektvariablen

Der Objektkatalog hebt die Objektdatentypen des aktuellen Projekts sowie deren implementierte Eigensc haften,

Ereignisse und Methoden durc h Fettsc hrift hervor (vgl. Beispiel zu »Ereignisroutinen«, S. 204)

Beschreibung

Bes c hreibung
...................................................
In der objektorientierten Programmierung versteht man unter Methode nichts anderes als eine
zu einem spezifischen Objektdatentyp gehörige Funktion oder Prozedur, die über der konkreten
Datenstruktur eines Objekts dieses Datentyps operieren kann. Dieser »Ich-Bezug« auf ein spezi-
fisches Objekt ist zugleich das auffälligste Merkmal der Methode. Eine Methode »sieht« alle
Eigenschaften, Datenfelder und Methoden ihres Objekts, gleich welchen Geltungsbereich diese
haben. Als Geltungsbereich für eine Methode kann Public, Private oder Friend vereinbart
werden. Standardmäßig vereinbart Visual Basic den Geltungsbereich Public. Mit Private als
Geltungsbereich kann eine Methode von anderen Methoden des gleichen Objekts aufgerufen
werden, nicht jedoch vom Besitzer des Objekts (Modulebene). Umgekehrt macht der Geltungs-
bereich Public eine Methode für alle sichtbar, die über eine Referenz auf das Objekt verfügen
(Systemebene) – insbesondere auch für den Besitzer. Darüber hinaus ist in Formular- und Klas-
senmodulen auch eine eingeschränkte öffentliche Deklaration mit dem Schlüsselwort Friend
möglich, die den Geltungsbereich auf die Formular- und Klassenmodule des aktuellen Projekts
verengt (Prozessebene). Ist bei der Deklaration einer Methode der Zusatz Static angegeben,
vereinbart Visual Basic implizit alle Variablen der Methode als Static (statische Variablen ver-
gessen ihren Wert von einem Aufruf zum nächsten nicht).
Neben den gewöhnlichen Methoden sieht das Objektmodell von Visual Basic zwei Arten von
Methoden vor, denen eine besondere Funktionalität zukommt: Ereignisroutinen und Property-
Methoden. Ereignisroutinen sind für die Nachrichtenbehandlung zuständig und Property-
Methoden für das Setzen (Set und Let) und Abfragen (Get) der Eigenschaften eines Objekts.
(Mehr dazu in den folgenden beiden Abschnitten.)
Ist eine Methode als Standardelement (Standardeigenschaft) eines Objektdatentyps definiert
(vgl. Dialogfeld PROZEDURATTRIBUTE), kann ihr Aufruf durch alleinige Notation des Objektbe-
zeichners unter Weglassung des Methodenbezeichners geschehen.

200
Klassen als Datentypen für Objektvariablen

Anwendung

Anwendung
...................................................
Da sich Visual Basic spätestens seit der Version 4 nicht mehr als »Sprache mit Objektorientie-
rung«, sondern als objektorientierte Sprache versteht, muss man sich natürlich die Frage stellen,
inwieweit nicht alle Funktionen und Prozeduren Methoden eines Objekts sind. In der Tat ist
eine derartige Betrachtung ebenso richtig wie sinnlos, da auch Datentypen wie Integer und Long
eine objektorientierte Sicht rechtfertigen, die konkrete Implementation jedoch anders aussieht.
Auch weist der Objektkatalog so manche Funktion/Prozedur als »Methode« des einen oder
anderen Moduls aus, das aber selbst nicht als Klasse in Erscheinung tritt. Die Grenze zwischen
Methode und Funktion/Prozedur ist am einfachsten pragmatisch zu ziehen: Betrachten Sie als
Methode, was sich wie eine Methode notieren lässt, und alles andere als Funktion/Prozedur.

Klassen als Datentypen für Objektvariablen


Diese Sicht ist zwar nicht »immer« richtig, wie ein Blick auf die »Methode« Print etwa des
Form-Objekts offenbart (sie ist im Objektkatalog nicht zu finden), so doch aber »in aller Regel«.
Insbesondere verbleiben so alle traditionell zu Basic gehörenden Routinen sowie alles zu den
elementaren Datentypen Gehörige im Bereich der Funktionen/Prozeduren.
Der Objektbezug einer Methode muss in jeder Situation gewahrt sein; im eigenen Klassenmodul
ist er implizit, ansonsten explizit. Der Aufruf einer Methode innerhalb ihres Klassenmoduls
unterscheidet sich syntaktisch nicht vom Aufruf einer Funktion/Prozedur, da keine Qualifizie-
rung durch einen Objektbezeichner gefordert ist. Optional kann aber eine Qualifizierung erfol-
gen, indem die den Ich-Bezug ausdrückende spezielle Objektvariable Me angegeben wird bzw.
eine Objektvariable, die auf das gleiche Objekt wie Me verweist (vgl. das Beispiel zu »Printer-
Objekt«, S. 284).
[Erg =] [Me.]Methode[(ParamListe)]
Von jedem anderen Modul aus kann der Aufruf der Methode dagegen nur unter Angabe eines
Objekts bzw. einer Objektvariablen erfolgen, vorausgesetzt, die Methode ist mit dem Geltungs-
bereich Public (bzw. Friend innerhalb des gleichen Projekts) deklariert worden:
[Erg =] MeinObjekt.MethodeVonMeinObjekt[(ParamListe)]
Ansonsten gilt für Methoden dasselbe wie für Funktionen/Prozeduren.
Tipp

Tipp
...................................................
Wenn es Sie stört, dass Visual Basic bei Deklarationen implizit den Geltungsbereich Public
annimmt, können Sie eine Option Private-Anweisung in das betreffende Modul setzen.
Beispiel

Beis piel
...................................................
Vgl. »Eigenschaften« (S. 201)
Verwandte Themen

Verwandte Them en
...................................................
Funktionen und Prozeduren (S. 175)
Eigenschaften

Eigens c ha ften
...................................................
[Public | Private | Friend][Static] Property Get Eigenschaft () As Typ
[Public | Private | Friend][Static] Property Let Eigenschaft _
(NeuerWert As Typ)
[Public | Private | Friend][Static] Property Set Eigenschaft _
(NeuerWert As ObjektTyp)

201
Klassen als Datentypen für Objektvariablen

Beschreibung

Bes c hreibung
...................................................
Bei den Eigenschaften wird es am deutlichsten: Es gibt die Innensicht und die Außensicht eines
Objekts. Letztere ist Teil der ersteren und offenbart die Eigenschaften des Objekts. Die Innen-
sicht gibt den Blick frei auf die tatsächliche Repräsentation der von einem Objekt gespeicherten
Daten, also auf die Datenstrukturen und Datenfelder, die das Objekt ausmachen und über
denen seine Methoden operieren. Als Objektdatenfelder fungieren gewöhnliche, auf (Klassen-)
Modulebene deklarierte Variablen, denen ihrerseits ein Datentyp bzw. ein Objektdatentyp
zugrunde liegt. Der Zugriff auf diese Datenstrukturen von innerhalb des Moduls unterscheidet
sich nicht vom Zugriff auf gewöhnliche Variablen und ist allen im gleichen Modul definierten
Methoden ohne Einschränkungen gestattet. Die Innensicht deckt sich also weitgehend mit der
Klassen als Datentypen für Objektvariablen

Sicht der traditionellen Programmierung.


Von größerem Interesse ist die Außensicht auf ein Objekt. Visual Basic beugt sich hier inzwi-
schen weitgehend den Regeln des COM: Property-Methoden fungieren als Schleusen für die
Abfrage und das Setzen der Werte von Eigenschaften. Was der Besitzer eines Objekts als Wert
einer Eigenschaft tatsächlich zu sehen bekommt, ist der Funktionswert einer Property Get-
Funktion, deren Bezeichner den Namen der Eigenschaft und deren Ergebnistyp den Datentyp
der Eigenschaft stellt. Der Funktionswert kann zwar mit dem Wert eines Datenfelds des
Objekts übereinstimmen, muss aber nicht. Mit anderen Worten, es kann genauso gut sein, dass
der Wert einer Eigenschaft in Außenansicht kein Gegenstück innerhalb des Objekts in Form
einer Variablen hat, sondern von der Property Get-Funktion errechnet wird.
Das Gleiche, jedoch mit umgekehrten Vorzeichen, gilt für das Setzen von Eigenschaften: Die
Let- oder Set-Zuweisung eines Werts an eine Eigenschaft übersetzt der Compiler in den Aufruf
einer Property Let- bzw. Property Set-Methode des Objekts, die den Namen der Eigenschaft
trägt. Man sieht, es lassen sich auch unterschiedliche Geltungsbereiche für das Lesen und Setzen
einer Eigenschaft festlegen. Eigenschaften, für die keine Property Get-Funktion definiert (oder
sichtbar) ist, sind lesegeschützt, und solche, für die keine Property Let- bzw. Property Set-
Methoden existieren (oder sichtbar sind), sind schreibgeschützt (vgl. auch: AmbientProperties-
Objekt).
Da es den Methoden eines Objekts freigestellt ist, auch von den objekteigenen Property-Metho-
den Gebrauch zu machen, sind alle Eigenschaften eines Objekts auch in der Innensicht des
Objekts bekannt.
Anwendung

Anwendung
...................................................
Angesichts dieser Tatsache stellt sich natürlich die Frage, was eigentlich geschieht, wenn eine
Variable auf Modulebene als Public vereinbart wird. In der Tat vereinbart der Compiler dann
die entsprechenden Property-Methoden implizit, so dass Sie prinzipiell die Wahl haben, welche
der Schreibweisen Sie bevorzugen. Aufgrund eines Fehlers in Visual Basic 6.0 vereinbart der
Compiler die entsprechenden Property-Methoden allerdings nicht in jedem Fall, wie die ent-
sprechende Diskussion im Abschnitt »Parameterübergabe bei Funktionsaufrufen«, S. 574, des
Praxisteils zeigt.) Da die explizite Vereinbarung von Property-Methoden einen größeren Spiel-
raum bietet, in der Methode kann beispielsweise eine Überprüfung von Werten stattfinden, soll-
ten Sie aber tendenziell diese Schreibweise benutzen.
Welche Eigenschaften ein Objekt in welchem Geltungsbereich offenbart, liegt im Ermessen des
Programmierers. Eine Richtlinie für die Programmierung mit Objekten ist jedoch, dass es so
wenige wie möglich sein sollten und dass der Geltungsbereich so eng wie möglich gewählt wer-
den sollte; das hält die Implementation übersichtlich und beugt Unsinn vor, den andere Anwen-
dungen mit dem Objekt treiben könnten. Da eine Private-Eigenschaft (mangels Vererbung)
faktisch nichts anderes ist als eine auf Modulebene vereinbarte Private-Variable – der Zugriff
darauf ist ja nur mit objekteigenen Methoden möglich –, stellt sich bei der Wahl des Geltungs-
bereichs (zur Zeit) eigentlich nur die Frage: Friend oder Public? Friend-Deklarationen sorgen

202
Klassen als Datentypen für Objektvariablen

dafür, dass ein Bezeichner nur innerhalb des Projekts sichtbar ist, in dem die jeweilige Klasse
kompiliert wird. Der Unterschied wirkt sich jedoch erst im Zusammenhang mit ActiveX-Steuer-
elementen und -Komponenten aus, die einer Veröffentlichung unterzogen werden.
Tipp

Tipp
...................................................
Angenommen, Sie schreiben ein Benutzersteuerelement und wollen eine Eigenschaft des
zugrunde liegenden UserControl-Objekts übernehmen. Sie können dann den Bezeichner der
Eigenschaft beibehalten, wenn Sie für eine geeignete Qualifizierung sorgen. Das verhindert den
rekursiven Aufruf der Methode.
Property Set Picture(NewPicture As Picture)

Klassen als Datentypen für Objektvariablen


UserControl.Picture = Picture ' Qualifizierung!
End Property
Beispiel

Beis piel
...................................................
Der folgende Code zeigt die Implementation einer einfachen in einem Klassenmodul definierten
Klasse Vektor und den Umgang mit einigen Eigenschaften und Methoden von Objekten dieser
Klasse.
' Irgendwo in einem Formular des Projekts ...
Dim a As New Vektor
Dim b As New Vektor
a.x = 1: a.y = 1: a.z = 1 ' Initialisierung: Eigenschaften setzen
b.Init 2, 2, 2 ' Initialisierung: Init-Methode
a.Addiere b
Print a.Printwert
Print a.SkalarProdukt(b)
Print a.Betrag
' Klassenmodul: Vektor.cls
Option Explicit
Public x As Double ' Eigenschaften, weil Public!
Public y As Double
Public z As Double

Property Set Copy(v As Vektor) ' Kopieren eines Werts


x = v.x: y = v.y: z = v.z
End Property

Property Get Betrag() As Double ' Länge des Vektors (wird errechnet!)
Betrag = Sqr(x * x + y * y + z * z)
End Property

Function SkalarProdukt(v As Vektor) As Double ' Skalarprodukt


SkalarProdukt = v.x * x + v.y * y + v.z * z
End Function

Sub Addiere(v As Vektor) ' Vektorsumme


x = x + v.x
y = y + v.y
z = z + v.z
End Sub

203
Klassen als Datentypen für Objektvariablen

Sub Skaliere(faktor As Double) ' skalares Produkt


x = x * faktor
y = y * faktor
z = z * faktor
End Sub

Function Produkt(v As Vektor) As Vektor ' Vektorprodukt


Produkt.x = y * v.z – z * v.y
Produkt.y = z * v.x – x * v.z
Produkt.z = x * v.y – y * v.x
Klassen als Datentypen für Objektvariablen

End Function

Property Get Printwert() As String ' Vektor als Zeichenfolge


Printwert = "(" + CStr(x) + "," + CStr(y) + "," + CStr(z) + ")"
End Property

Sub Init(a As Double, b As Double, c As Double) ' Initialisierung


x = a: y = b: z = c
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Let, =
Verwandte Themen

Verwandte Them en
...................................................
Datentypen und ihre Operationen (S. 49); »Selbst definierte Klassen« (S. 318)

Ereignisroutinen
Sub SignalisierendesObjekt_Ereignis([ParamListe])
...
End Sub
Event Ereignis[(ParamListe)]
RaiseEvent Ereignis[(WerteListe)]
[Private | Public | Dim] WithEvents Eigenschaft As Typ
Beschreibung

Bes c hreibung
...................................................
Der Kernmechanismus der ereignisorientierten Benutzerschnittstelle von Windows besteht
darin, dass ein Objekt Ereignisroutinen bereitstellt, um spezifisch auf äußere Vorkommnisse
reagieren zu können. Ein solches Vorkommnis, Ereignis genannt, kann beispielsweise ein
Mausklick auf eine in einem Formular angeordnete Schaltfläche, eine Wertänderung in einem
Textfeld oder schlicht eine Nachricht eines anderen Objekts sein. Der ausgeklügelte Benach-
richtigungsmechanismus von Windows sieht aufseiten des Programms eine Nachrichtenschleife
vor, die – grob gesagt – eine geeignete Zustellung der Ereignisse an die einzelnen Objekte vor-
nimmt und den Aufruf bereitgestellter Ereignisroutinen bedingt. (Die von Windows verschick-
ten Nachrichten enthalten einen Ereigniscode sowie weitere Parameter mit ereignisspezifischer
Bedeutung, die eine genauere Beschreibung des Ereignisses darstellen). Der Visual-Basic-Compi-
ler sorgt dafür, dass die Implementierung dieses Mechanismus für den Programmierer größten-
teils transparent bleibt und sich nur in einigen wenigen Vorgaben bemerkbar macht, die bei der
Programmierung mit Ereignissen formal zu beachten sind. Von einer wie auch immer gearteten

204
Ereignisroutinen

»Verdrahtung« zwischen Ereignisroutinen und Nachrichten bekommt der Visual-Basic-Pro-


grammierer überhaupt nichts zu sehen, auch entzieht sie sich seiner Kontrolle.
Zu den vordefinierten Objekten von Visual Basic (dazu zählen insbesondere die auf dem jewei-
ligen System verfügbaren Steuerelemente und ActiveX-Komponenten) gehört eine breite Vielfalt
von Ereignissen, für die sich Ereignisroutinen implementieren lassen.
Objekte können aber nicht nur auf Ereignisse reagieren, sie sind auch ihrerseits in der Lage,
Ereignisse zu signalisieren. Damit ein Objekt ein Ereignis Ereignis mittels RaiseEvent auslösen
kann, muss das zugehörige Objektmodul (Klassenmodul, Steuerelementmodul, Formularmodul
oder Designermodul) eine Event-Deklaration enthalten, die das Gerüst der Ereignisroutine als
Prozedur mit dem Bezeichner Ereignis deklariert. Wird für die Ereignisprozedur eine Parame-
terliste ParamListe vereinbart, muss bei Auslösung des Ereignisses wie bei einem Funktionsauf-

Klassen als Datentypen für Objektvariablen


ruf eine Werteliste für die einzelnen Parameter bereitgestellt werden. Für die Behandlung eines
solchen von einem Objekt ausgelösten Ereignisses ist der Besitzer des Objekts zuständig, aber
nicht verpflichtet. Er kann zu diesem Zweck eine Objektvariable für das Objekt mit dem Zusatz
WithEvents deklarieren und unter ihrem Namen kombiniert mit dem Ereignisnamen eine Ereig-
nisroutine bereitstellen, deren Struktur auf das objektseitig vorgegebene Gerüst passt.
Anwendung

Anwendung
...................................................
Die Bereitstellung einer Ereignisroutine erfolgt auf Modulebene, und zwar im Klassenmodul des
Objekts, das die Behandlung des Ereignisses durchführen soll. (Außer dem Standardmodul sind
alle in Visual Basic verfügbaren Modularten letztlich Klassenmodule und somit auf die Ereig-
nisbehandlung eingerichtet.)
Eine Ereignisroutine hat grundsätzlich die Form einer öffentlichen oder privaten Sub-Prozedur,
deren Bezeichner nach folgendem Schema zu bilden ist: Name des signalisierenden Objekts plus
Unterstrich plus Name des Ereignisses, zum Beispiel Form_Load. Die folgende Abbildung zeigt
die Auswahl einer Ereignisroutine für die Implementierung in einem Formularmodul.

Auswahl einer Ereignisprozedur für die Implementierung

Man sieht, die Entwicklungsumgebung von Visual Basic kommt einem bei der Implementierung
von Ereignisroutinen weitgehend entgegen: Im linken Listenelement wählt man die Objektvari-
able und im rechten das Ereignis aus. An Objektvariablen stehen neben dem Bezeichner der
jeweiligen Basisklasse des Objekts (Form, UserControl, PropertyPage usw.) die Bezeichner sämt-
licher im Entwurfsbereich platzierten Steuerelemente und ActiveX-Komponenten zur Verfü-
gung sowie alle mit WithEvents auf Modulebene deklarierten Objektvariablen.

205
Klassen als Datentypen für Objektvariablen

Für den Mechanismus der Ereignisbehandlung macht es keinen Unterschied, wer die Benach-
richtigung eines Ereignisses veranlasst hat – das Betriebssystem, ein Steuerelement, eine Kompo-
nente oder irgendein anderes Objekt. Bei benutzerdefinierten (lies: in Klassenmodulen definier-
ten) Objektdatentypen muss man nur darauf achten, die entsprechenden Objekte auf
Modulebene unter Angabe von WithEvents zu deklarieren, damit der Besitzer deren Ereignisse
auch zu sehen bekommt. Für Benutzersteuerelemente, die sich in die Werkzeugsammlung einfü-
gen lassen, erledigt das Visual Basic von sich aus, sobald ein Objekt dieses Typs auf die Ent-
wurfsfläche gezogen wird.
Wie aber sieht die Bearbeitungsreihenfolge aus, wenn sich Ereignisse häufen? Das Laufzeitsys-
tem entnimmt die Ereignisse einer Ereigniswarteschlange unter Beachtung verschiedener Priori-
Klassen als Datentypen für Objektvariablen

sierungsregeln (so kommen Timer- und MouseMove-Ereignisse beispielsweise nur zur Behandlung,
wenn keine anderen Ereignisse warten) und ruft die dafür vorgesehenen Ereignisroutinen nach-
einander auf. Mit anderen Worten: solange die Bearbeitung eines Ereignisses andauert, kommt
kein weiteres Ereignis zum Zuge.
Tipps

Tipps
...................................................
Bei der Implementierung neuer Ereignisse empfiehlt es sich, das Ereignis zuerst im Modul des
signalisierenden Objekts zu deklarieren (Event) und sich dann im Modul des Objekts, das auf
das Ereignis reagieren soll, das Gerüst der Ereignisroutine von Visual Basic einfügen zu lassen.
Die Reaktivität eines Programms hängt sehr stark davon ab, wie viel an Laufzeit eine Ereignis-
routine für die Behandlung des ihm zugeordneten Ereignisses benötigt. Guter Programmierstil
ist es, nicht zu viel in eine Ereignisroutine hineinzupacken. Sollten aufwändigere Berechnungen
anfallen, tut die Routine gut daran, zwischendurch immer mal wieder die Prozedur/Funktion
DoEvents aufzurufen, damit die Behandlung inzwischen aufgelaufener Ereignisse erfolgen kann.
Sobald die Warteschlange abgearbeitet ist, erhält die Routine, die den DoEvents-Aufruf abge-
setzt hat, die Kontrolle wieder zurück und kann ihre Aufgabe zu Ende bringen. So gut das
klingt, problemfrei ist diese Programmiertechnik nicht. Sie wirft im Wesentlichen zwei Prob-
leme auf: Reentranz und Rekursion. Mit Ersterem ist gemeint, dass eine derartige Routine
erneut zum Aufruf kommen kann, noch bevor sie fertig ist, und mit Letzerem, dass die Routine
ihrerseits Ereignisse anstoßen kann, die wiederum zum Aufruf ihrer selbst führen, noch bevor
sie fertig ist. Liegen Rekursion und Reentranz vor, wird das früher oder später zur Auslösung
eines Stack-Überlauffehlers führen, wenn die Routine – vergleichbar mit einer Endlosschleife –
in der Regel öfter betreten als verlassen wird. Rekursion alleine ist kein Problem, wenn gewähr-
leistet ist, dass die Routine fertig ist, bevor das von ihr angestoßene Ereignis wieder zu ihrem
Aufruf führt – mithin, wenn die Latenzzeit des Ereignisses größer ist als die Ausführungszeit.
Reentranz für sich genommen ist auch kein Problem, solange sie nicht zur Regel wird und zu
einer immer tieferen Verschachtelung der Aufrufe führt. Allerdings muss die Routine speziell
darauf ausgelegt sein, damit es nicht zu unerwünschten Seiteneffekten kommt, etwa im Zusam-
menhang mit statischen und globalen Variablen. Um der Kumulation reentranter Aufrufe vor-
zubeugen, empfiehlt es sich, einen Rekursionszähler (statische Zählvariable) einzuführen und
den DoEvents-Aufruf mit dem Zählerstand zu koppeln. Einer Rekursion beugt das zwar nicht
vor, einem Stacküberlauf jedoch schon – gleichwohl wird die Anwendung weiterhin auf den
Benutzer reagieren, auch wenn es zu Beeinträchtigungen der Reaktivität kommen kann.
Beispiel

Beis piel
...................................................
Das Projekt FormMitEreignis stellt eine Wrapper-Klasse für ein Formularobjekt des Typs
BasisForm vor. Ein Objekt dieser Klasse, das eine Formularvariable als Eigenschaft besitzt,
ergänzt die Funktionalität des dieser Variablen zugeordneten Formulars um die Behandlung
eines zusätzliches Ereignisses namens FeldwertGeändert. Das Formular BasisForm enthält zwei
Textfelder namens Text1 und Text2 sowie eine Statusleiste namens StatusLeiste1. Die Signali-

206
Standardereignisse

sierung des Ereignisses erfolgt, wenn sich der Wert eines der Textfelder ändert. Die für die
Behandlung des Ereignisses zuständige Methode des Wrapper-Objekts ist mBasis-
Form_FeldwertGeändert.
' Klasse: clsFormMitEreignis
Option Explicit
Private WithEvents mBasisForm As BasisForm ' Formular ist Eigenschaft

' Eigenschaft veröffentlichen


Public Property Get BasisForm() As BasisForm
Set BasisForm = mBasisForm ' Wert der Eigenschaft bekannt geben

Standardereignisse
End Property

Public Property Set BasisForm(ByVal newBasisForm As BasisForm)


Set mBasisForm = newBasisForm ' Wert der Eigenschaft setzen
End Property ' (Formularobjekt zuordnen)

' Von mBasisForm signalisiertes Ereignis behandeln


Private Sub mBasisForm_FeldwertGeändert()
mBasisForm.StatusLeiste1.SimpleText = "Feldwert hat sich geändert"
End Sub
' Formular: BasisForm
Option Explicit
Event FeldwertGeändert() ' Signalisiertes Ereignis deklarieren
Private obj As New clsFormMitEreignis ' Objektvariable vereinbaren

Private Sub Command1_Click()


End ' Schaltfläche beendet Programm
End Sub ' (Objekt wird automatisch abgebaut)

Private Sub Form_Load()


StatusLeiste1.Style = sbrSimple ' Stilattribut der Statusleiste
Set obj.BasisForm = Me ' Objekt generieren, als Wert der
End Sub ' Eigenschaft sich selbst setzen

Private Sub Text1_Change()


RaiseEvent FeldwertGeändert ' Textfeld löst Ereignis aus
End Sub

Private Sub Text2_Change()


RaiseEvent FeldwertGeändert ' Textfeld löst Ereignis aus
End Sub

Standardereignisse
Ein Visual-Basic-Programm, das nicht nur aus Standardmodulen besteht, wird von Beginn an in
eine »ereignisreiche Welt hineingeboren«. Als ereignisorientierte Systemumgebung hält Win-
dows die in Ausführung befindlichen Programme ständig über alle sie betreffenden Vorkomm-
nisse auf dem Laufenden – dazu zählen: Informationen über den eigenen Ausführungszustand
(Programmstart, Programmende, Herunterfahren des Systems etc.), über geänderte Systembe-

207
Standardereignisse

dingungen (Bildschirmmodus, Sprachtreiber etc.) und natürlich über alle an sie gerichteten
Benutzeraktionen. Darüber hinaus melden sich Objekte auch gegenseitig die verschiedensten
Vorkommnisse oder leiten Meldungen einfach weiter (Delegation). Wer von der prozeduralen
Programmierung her kommt, für den ist es erst einmal ungewohnt, sich in diesem Kanon von
Ereignissen zurechtzufinden, weil der Programmablauf als Ganzes nicht mehr so ohne Weiteres
ersichtlich ist. Vielmehr zerfällt das Programm in eine Fülle von Ereignisroutinen, deren Koor-
dination »hinter den Kulissen« vom Visual-Basic-Laufzeitsystem betrieben wird, ohne dass vor-
dergründig etwas zu sehen ist. Letztlich machen die Ereignisse die Programmierung aber auch
wieder einfach, da man sich um die Ablaufsteuerung keine großen Gedanken machen muss.
Beschreibung

Bes c hreibung
...................................................
Standardereignisse

Die folgende Tabelle gibt einen Überblick über die wichtigsten vordefinierten Ereignisse, die ein
Objekt in Abhängigkeit von seinem Objektdatentyp zu Gesicht bekommen kann. Details zu den
einzelnen Ereignissen finden Sie in den anschließenden Unterabschnitten. Beachten Sie, dass die
Liste nicht vollständig ist, da jedes Steuerelement und jeder Objektdatentyp seine eigenen Ereig-
nisse definieren kann. Schlagen Sie dazu unter dem jeweiligen Steuerelement bzw. Objektdaten-
typ nach.

Ereignis Beschreibung Betroffene Objekte


Activate Signalisiert, dass das Fenster des Form, DataReport, MDI-Form
Objekts zum aktiven Fenster wird
Click Signalisiert die Ausführung eines Die meisten Steuerelemente, Form,
Mausklicks im Fensterbereich des MDI-Form, UserControl, UserDocu-
Objekts ment, PropertyPage
DblClick Signalisiert die Ausführung eines Die meisten Steuerelemente, Form,
Doppelklicks im Fensterbereich des MDI-Form, UserControl, UserDocu-
Objekts ment, PropertyPage
Deactivate Signalisiert, dass das Fenster des Form, DataReport, MDI-Form
Objekts nicht mehr aktives Fenster
ist
DragDrop Signalisiert dem Objekt das Ende Die meisten Steuerelemente, Form,
einer Drag&Drop-Operation: Ein MDI-Form, UserControl, UserDocu-
anderes Objekt wurde in den ment, PropertyPage
Bereich des Objekts abgelegt.
DragOver Tritt während einer Drag&Drop- Die meisten Steuerelemente, Form,
Operation auf und signalisiert dem MDI-Form, UserControl, UserDocu-
Objekt, dass ein anderes Objekt in ment, PropertyPage
seinen Bereich gezogen wird
GotFocus Signalisiert dem Objekt, dass es den Die meisten Steuerelemente, Form,
Eingabefokus erhalten hat MDI-Form, UserControl, UserDocu-
ment, Extender, PropertyPage
Initialize Signalisiert dem Objekt, dass es DataReport, DHTMLPageDesigner,
soeben generiert wurde und den ein- Form, MDIForm, PropertyPage, User-
maligen Initialisierungscode ausfüh- control, UserDocument, WebClass
ren kann (beim Formularobjekt
kommt Initialize vor Load)

208
Standardereignisse

Ereignis Beschreibung Betroffene Objekte


KeyDown Signalisiert dem Objekt (i.a. dem, Die meisten Steuerelemente, Form,
das den Fokus besitzt) das Nieder- MDIForm, PropertyPage, UserControl,
drücken einer beliebigen Taste der UserDocument
Tastatur
KeyPress Signalisiert dem Objekt (i.a. dem, Die meisten Steuerelemente, Form,
das den Fokus besitzt), dass ein Zei- MDIForm, PropertyPage, UserControl,
chen mit ANSI-Code über die Tasta- UserDocument
tur eingegeben wurde

Standardereignisse
KeyUp Signalisiert dem Objekt (i.a. dem, Die meisten Steuerelemente, Form,
das den Fokus besitzt) das Loslassen MDIForm, PropertyPage, UserControl,
einer beliebigen Taste der Tastatur UserDocument
LinkClose Signalisiert dem Objekt das Ende Label, PictureBox, Form, MDIForm,
einer DDE-Verbindung TextBox
LinkError Signalisiert dem Objekt das Auftre- Label, PictureBox, Form, MDIForm,
ten eines Fehlers während einer TextBox
DDE-Verbindung
LinkExecute Signalisiert dem Objekt eine DDE- Label, PictureBox, Form, MDIForm,
Kommandozeichenfolge während TextBox
einer DDE-Verbindung
LinkOpen Signalisiert dem Objekt, dass eine Label, PictureBox, Form, MDIForm,
Zielanwendung eine DDE-Verbin- TextBox
dung eröffnen will
Load signalisiert dem Objekt, dass es Form, MDIForm, PropertyPage
soeben geladen wurde
LostFocus Signalisiert dem Objekt, dass es den Die meisten Steuerelemente, Form,
Fokus verloren hat MDI-Form, UserControl, UserDocu-
ment, Extender, PropertyPage
MouseDown Signalisiert dem Objekt das Nieder- Die meisten Steuerelemente, Form,
drücken einer Maustaste MDI-Form, UserControl, UserDocu-
ment, PropertyPage
MouseMove Signalisiert dem Objekt, dass die Die meisten Steuerelemente, Form,
Maus über ihm bewegt wurde MDI-Form, UserControl, UserDocu-
ment, PropertyPage
MouseUp Signalisiert dem Objekt das Loslas- Die meisten Steuerelemente, Form,
sen einer Maustaste MDI-Form, UserControl, UserDocu-
ment, PropertyPage
OLECompleteDrag Signalisiert der Quellkomponente Die meisten Steuerelemente, Form,
einer OLE-Drag&Drop-Operation MDI-Form, UserControl, UserDocu-
die Durchführung der Operation ment, PropertyPage
OLEDragDrop Signalisiert der Zielkomponente Die meisten Steuerelemente, Form,
einer OLE-Drag&Drop-Operation MDI-Form, UserControl, UserDocu-
den Abschluss der Aktion ment, PropertyPage

209
Standardereignisse

Ereignis Beschreibung Betroffene Objekte


OLEDragOver Tritt während einer OLE- Die meisten Steuerelemente, Form,
Drag&Drop-Operation auf und sig- MDI-Form, UserControl, UserDocu-
nalisiert der Zielkomponente das ment, PropertyPage
Betreten oder Verlassen ihres
Bereichs
OLEGiveFeedback Signalisiert der Quellkomponente Die meisten Steuerelemente, Form,
während einer OLE-Drag&Drop- MDI-Form, UserControl, UserDocu-
Operation, dass sie gerade über eine ment, PropertyPage
Standardereignisse

Zielkomponente gezogen wird und


dort das OLEDragOver-Ereignis ausge-
löst hat
OLESetData Signalisiert der Quellkomponente Die meisten Steuerelemente, Form,
nach Annahme einer OLE- MDI-Form, UserControl, UserDocu-
Drag&Drop-Operation die Art des ment, PropertyPage
von der Zielkomponente erwünsch-
ten Datenformats
Paint Signalisiert dem Objekt, seinen Die meisten Steuerelemente, Form,
Fensterinhalt neu zu zeichnen MDI-Form, UserControl, UserDocu-
ment, PropertyPage
QueryUnload Signalisiert dem Objekt, dass es ent- Form, MDI-Form, PropertyPage
laden werden soll – was es aber
ablehnen kann.
Resize Signalisiert dem Objekt Änderungen PictureBox, CoolBar, DataReport,
seiner Fenstergröße Data, Form, MDIForm, OLE, UserCon-
trol, UserDocument
Terminate Signalisiert dem Objekt, dass es DataReport, DHTMLDesigner, Form,
abgebaut wird, weil keine Verweise MDIForm, PropertyPage, UserControl,
mehr auf es existieren (folgt i.a. auf UserDocument, WebClass
Unload)
Unload Signalisiert dem Objekt, dass es ent- Form, MDI-Form, PropertyPage
laden wird und seinen Aufräumcode
ausführen kann; Ablehnen ist nicht
möglich (folgt auf QueryUnload)
Validate Signalisiert einem Objekt, dass es Steuerelemente, die den Fokus erhal-
dabei ist, den Fokus zu verlieren, ten können
und die Benutzereingabe auf ihre
Gültigkeit hin prüfen soll

Anwendung

Anwendung
...................................................
Der Programmierer kann sich darauf verlassen, dass sein Programm in bestimmten Situationen
bestimmte Ereignisse übermittelt bekommt, was letztlich einer Ablaufsteuerung gleichkommt.
So sieht das Ablaufmodell eines Formularobjekts vor, dass dieses im Zuge seiner Entstehung
zuerst das Initialize-, dann das Load- und schließlich das Resize-Ereignis zu sehen bekommt.
Was an weiteren Ereignissen eintrudelt, hängt von der Aufrufsituation und den Benutzer-

21 0
Standardereignisse

aktionen ab. Die drei letzten Ereignisse, die ein Formular vor dem Ableben zu sehen bekommt,
sind QueryUnload, Unload und Terminate.
Das Schöne an Visual Basic ist, dass man sich nicht viele Gedanken darüber machen muss, in
welchem Rahmen mit welchen Ereignissen zu rechnen ist (über die Ereignisse selbst sollte man
sich natürlich schon Gedanken machen). Der Code-Editor ist intelligent genug, für jedes auf
Modulebene bekannte WithEvents-Objekt sowie für das dem Modul an sich untergelegte
Objekt genau die Ereignisse anzubieten, die es signalisiert bekommt. Was nicht im Angebot ist,
muss entweder – wie im Falle von Benutzersteuerelement- oder Klassenmodulen – erst aufseiten
des Objektdatentyps implementiert oder irgendwie anderweitig gelöst werden. Programmierer,
die es gewöhnt sind, mit dem Source Development Kit (SDK) oder der Microsoft-Klassenbiblio-
thek (MFC) zu programmieren, werden mit Sicherheit so manche Windows-Nachricht vermis-

Standardereignisse
sen, die Visual Basic nicht in ein Ereignis ummünzt, sondern einfach unter den Tisch kehrt.
Man kann mit Visual Basic zwar viel machen, aber eben nicht alles.
Beispiel

Beis piel
...................................................
Das folgende Programm verdeutlicht die Ereignisreihenfolge für den Aufruf und Abbau eines
Formularobjekts:
' Formularmodul zum Testen der Ereignisreihenfolge
Option Explicit

Private Sub Form_Activate()


Debug.Print "Activate"
End Sub

Private Sub Form_Deactivate()


Debug.Print "Deactivate"
End Sub

Private Sub Form_GotFocus()


Debug.Print "GotFocus"
End Sub

Private Sub Form_Initialize()


Debug.Print "Initialize"
End Sub

Private Sub Form_Load()


Debug.Print "Load"
End Sub

Private Sub Form_LostFocus()


Debug.Print "LostFocus"
End Sub

Private Sub Form_Paint()


Debug.Print "Paint"
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)


Debug.Print "QueryUnload"

21 1
Standardereignisse

End Sub

Private Sub Form_Resize()


Debug.Print "Resize"
End Sub

Private Sub Form_Terminate()


Debug.Print "Terminate"
End Sub
Standardereignisse

Private Sub Form_Unload(Cancel As Integer)


Debug.Print "Unload"
End Sub

Wird das Formular sofort nach dem Erscheinen wieder geschlossen, lautet die Ausgabe:

Ereignisprotokoll für Programmstart und Programmende

Wie man sieht, tritt weder ein LostFocus- noch ein Deactivate-Ereignis auf. Aber auch das Got-
Focus-Ereignis trifft nur dann ein, wenn sich auf dem Formular kein Steuerelement befindet, das
den Fokus annehmen kann. Und das Paint-Ereignis tritt nur auf, wenn die Eigenschaft AutoRe-
draw des Formulars auf False gesetzt ist.

Activate- Ereignis und Deactivate- Ereignis


Sub Objekt_Activate ()
Sub Objekt_Deactivate ()
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, MDIForm, DataReport
Beschreibung

Bes c hreibung
...................................................
Das Activate-Ereignis geht dem GotFocus-Ereignis voraus und signalisiert, dass das Fenster des
Objekts das aktive Fenster der Anwendung geworden ist. Es tritt nur auf, wenn die Visible-
Eigenschaft des Objekts auf True gesetzt und bereits ein Show-Aufruf erfolgt ist. Weiterhin tritt
es nur auf, wenn der Fokus innerhalb der Anwendung auf ein anderes Fenster verschoben wird.
Erhält das Fenster den Fokus von einer anderen Anwendung zurück, bleibt das Ereignis aus.
Umgekehrt signalisiert das Deactivate-Ereignis, dass das Fenster des Objekts den Fokus an ein
anderes Fenster der Anwendung abgegeben hat. Dabei folgt es unmittelbar auf das LostFocus-
Ereignis. LostFocus und Deactivate bleiben aus, wenn das Objekt und sein Fenster abgebaut
werden.

21 2
Activate- Ereignis und Deactivate- Ereignis

Anwendung

Anwendung
...................................................
Die Behandlung des Activate-Ereignisses kann sinnvoll sein, wenn das Objekt den Fokus gleich
an ein anderes Fenster weitergeben soll. Deactivate kann dagegen ausgenutzt werden, um die
Aktivierung in einer bestimmten Reihenfolge zu erzwingen.
Hinweis

Hinweis
...................................................
Zeigt ein Formular aus einer von Visual Basic generierten Exe-Datei heraus ein Dialogfeld an,
das aus einer gleichfalls mit Visual Basic generierten DLL stammt, erhält das Formular regulär
die Ereignisse Deactivate und LostFocus. Das Deactivate-Ereignis kann jedoch in bestimmten

Standardereignisse
Konstellationen auch ausbleiben: wenn das Objekt eine prozessexterne Komponente ist; wenn
das Dialogfeldobjekt nicht in Visual Basic programmiert wurde; wenn der Aufruf der DLL
innerhalb der Entwicklungsumgebung erfolgt.
Beispiel

Beis piel
...................................................
Der folgende Code stellt ein Formular vor, das keine weiteren Steuerelemente enthält, und auf
ein Click-Ereignis hin eine weitere Instanz seiner selbst zur Anzeige bringt. Die Ereignisse Acti-
vate, Deactivate, GotFocus und LostFocus werden im Direktfenster protokolliert.
' Formularmodul zum Testen der Aktivierungsreihenfolge
Option Explicit
Dim f As New Form1

Private Sub Form_Load()


AutoRedraw = True
End Sub

Private Sub Form_Click()


f.Show
End Sub

Private Sub Form_Activate()


Debug.Print "Activate"
End Sub

Private Sub Form_Deactivate()


Debug.Print "Deactivate"
End Sub

Private Sub Form_GotFocus()


Debug.Print "GotFocus"
End Sub

Private Sub Form_LostFocus()


Debug.Print "LostFocus"
End Sub

Startet man das Programm, klickt einmal auf das Formular und beendet dann das Programm
durch Schließen beider Fenster, sieht die Ausgabe so aus:

21 3
Standardereignisse

Ereignisprotokoll für die Aktivierung eines Fensters


Standardereignisse

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
GotFocus, LostFocus

Change- Ereignis
Sub Objekt_Change([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................
ComboBox, DataCombo, DataGrid, DateTimePicker, DirListBox, DriveListBox, FlatScrollBar,
HScrollBar, ImageCombo, Label, MaskEdBox, PictureBox, RichTextBox, Slider, TextBox,
ToolBar, UserControl, UserDocument, UpDown, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Das Change-Ereignis wird ausgelöst, wenn sich der Standardwert des Steuerelements geändert
hat. Die genaue Ursache für das Ereignis hängt von der Natur des einzelnen Steuerelements ab:
Beim Textfeld und Kombinationsfeld ist es die Änderung des Werts nach Eingabe eines weite-
ren Zeichens, bei Bildlaufleisten eine Positionsänderung der Bildlaufmarke und bei listenfeldba-
sierten Steuerelementen die Auswahl eines Werts durch den Benutzer.
Das Ereignis wird auf jeden Fall auch dann ausgelöst, wenn der Wert der Standardeigenschaft
explizit durch Code gesetzt wird.
Anwendung

Anwendung
...................................................
Das Change-Ereignis eignet sich gut dafür, mehrere voneinander abhängige Steuerelemente zu
synchronisieren, so etwa die bekannte Kaskadensteuerung der Steuerelemente DriveListBox,
DirListBox und FileListBox (vgl. »Laufwerklistenfeld-Steuerelement (DriveListBox)«, S. 410).
Warnung

Wa rnung
...................................................
Die leichtfertige Verwendung des Change-Ereignisses kann zur Auflösung von Ereignislawinen
führen, wenn sich zwei Steuerelement gegenseitig oder mehrere Steuerelemente zyklisch aktuali-
sieren. Ein häufiges Problem im Zusammenhang mit der Behandlung dieses Ereignisses ist auch
der rekursive Aufruf, der entsteht, wenn die Routine ihren eigenen Standardwert zu ändern ver-
sucht.
Beispiel

Beis piel
...................................................
Der folgende Code ist reentrant, weil die hier nicht näher ausgeführte Routine LookupFullValue
den Wert des Textfelds vervollständigt, wenn sie in ihrer Datenbasis einen passenden Wert fin-
det. Da das ein weiteres Change-Ereignis auslöst, kommt es zum Wiedereintritt in die Routine,
wobei die statische Variable Reenter den erneuten Aufruf von LookupFullValue verhindert. Ver-
zichtet man auf die statische Variable, muss die Routine LookupFullValue so implementiert sein,

21 4
Click- Ereignis

dass sie den Wert des Textfelds nicht ändert, wenn der gefundene Eintrag bereits vollständig
eingegeben wurde. In diesem Fall bricht die Rekursion dann spätestens nach dem zweiten Auf-
ruf ab.
Private Sub Text1_Change()
Static Reenter As Boolean
If Not Reenter Then
Reenter = True
LookupFullValue Text1 ' Wert ggf. vervollständigen
Reenter = False
End If

Standardereignisse
End Sub

Click- Ereignis
Sub MDIForm_Click()
Sub Form_Click()
Sub Objekt_Click([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CheckBox, ComboBox, CommandButton, CoolBar, DataGrid, DBCombo, DBGrid,
DBList, DirListBox, FileListBox, Form, Frame, Grid, Image, Label, ListBox, ListView,
MDIForm, Menu, OLE, OptionButton, PictureBox, ProgressBar, PropertyPage, RichTextBox,
Slider, SSTab, StatusBar, TabStrip, TextBox, ToolBar, TreeView, UserControl, UserDocu-
ment
Beschreibung

Bes c hreibung
...................................................
Das Click-Ereignis wird ausgelöst, wenn der Benutzer über einem (nicht gesperrten) Steuerele-
ment oder in den Client-Bereich eines Formulars einen Mausklick ausführt. Falls das Objekt in
der Lage ist, den Fokus zu erhalten und diesen noch nicht besitzt, geht dem Click-Ereignis das
GotFocus-Ereignis voran.
Form-Objekte sowie die meisten Steuerelemente signalisieren das Ereignis bei rechtem oder lin-
kem Mausklick. Objekte des Typs CheckBox, CommandButton, ListBox und OptionButton beachten
dagegen nur die linke Maustaste.
Zudem gibt es eine Reihe von Situationen, in denen Steuerelemente das Click-Ereignis auch
unabhängig von einer Betätigung der Maustaste signalisieren. So, wenn:
● der Benutzer in einem ComboBox- oder ListBox-Objekt per Tastatur oder Pfeilschaltfläche
ein anderes Element auswählt
● der Benutzer die Leertaste drückt und ein OptionButton-, CommandButton- oder CheckBox-
Objekt gerade den Fokus hat
● der Benutzer die Eingabetaste drückt und ein CommandButton-Objekt existiert, dessen
Default-Eigenschaft auf True gesetzt ist
● der Benutzer die Taste (Esc) drückt und ein CommandButton-Objekt existiert, dessen Can-
cel-Eigenschaft auf True gesetzt ist
● der Benutzer die Zugriffstaste ((Alt) + unterstrichenes Zeichen in der Beschriftung) für
ein Steuerelement drückt
● sich die Value-Eigenschaft eines Steuerelements ändert und diese den Typ Boolean trägt
Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.

21 5
Standardereignisse

Anwendung

Anwendung
...................................................
Das Click-Ereignis wird entweder als Auslöser für einen beliebigen Befehl (CommandButton)
genutzt oder für das Treffen von Einstellungen, die das Verhalten der Anwendung in der einen
oder anderen Weise in einem komplexeren Zusammenhang nachhaltig verändern (CheckBox,
OptionButton).
Warnung

Wa rnung
...................................................
Das Click-Ereignis wird auch bei einem Doppelklick signalisiert und geht dem DblClick-Ereig-
nis grundsätzlich voraus. Falls die Click-Behandlungsroutine jedoch ein Objekt mit eigener
Nachrichtenschleife (Formular oder Dialog: beispielsweise Msgbox) aufruft, kommt es trotz
Standardereignisse

Doppelklicks nicht zu einem DblClick-Ereignis!


Tipp

Tipp
...................................................
Das Click-Ereignis beinhaltet keinerlei Informationen darüber, wo der Mausklick aufgetreten
ist und welche Maustaste dafür benutzt wurde. Wenn diese Informationen für die Programmlo-
gik eine Rolle spielen, muss eines der Ereignisse MouseDown oder MouseUp, die unmittelbar vor
bzw. nach Click auftreten, ausgewertet werden.
Beispiel

Beis piel
...................................................
Der folgende Code stellt ein Formular vor, das die Ereignisse MouseDown, MouseUp, Click und
DblClick im Direktfenster protokolliert.
' Formularmodul zum Testen der Mausereignisreihenfolge
Option Explicit

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


Debug.Print "MouseUp"
End Sub

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


Debug.Print "MouseDown"
End Sub

Private Sub Form_Click()


Debug.Print "Click"
End Sub
Private Sub Form_DblClick()
Debug.Print "DblClick"
End Sub
Die Ereignisfolge für einen einfachen Mausklick sieht so aus:

Ereignisprotokoll für das Click-Ereignis

21 6
DblClick- Ereignis

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
MouseDown, MouseUp, MouseMove, DblClick

DblClick- Ereignis
Sub MDIForm_DblClick()
Sub Form_DblClick()
Sub Objekt_DblClick([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................

Standardereignisse
Animation, ComboBox, DataGrid, DBCombo, DBGrid, DBList, FileListBox, Form, Frame, Grid,
Image, Label, ListBox, ListView, MDIForm, Menu, OLE, OptionButton, PictureBox, Property-
Page, StatusBar, TextBox, ToolBar, TreeView, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das DblClick-Ereignis wird ausgelöst, wenn der Benutzer über einem (nicht gesperrten) Steuer-
element oder in den Client-Bereich eines Formulars doppelklickt. Form-Objekte sowie die meis-
ten Steuerelemente signalisieren das Ereignis bei rechtem oder linkem Mausklick. Objekte des
Typs ListBox und OptionButton beachten dagegen nur die linke Maustaste. ComboBox-Objekte
signalisieren einen Doppelklick nur, wenn sie die Form eines einfachen Kombinationsfelds
haben, das heißt, wenn die Eigenschaft Style den Wert 1 hat.
Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Der Doppelklick hat für grafisch orientierte Benutzerschnittstellen traditionell die Bedeutung
der Auswahl eines Elements mit gleichzeitiger Bestätigung der Standardaktion. Da dem
DblClick-Ereignis immer ein Click-Ereignis vorausgeht, überlässt man die Elementauswahl
üblicherweise der Click-Behandlungsroutine und reagiert auf das DblClick-Ereignis nur mit der
Bestätigung, beispielsweise durch Aufruf der Click-Routine der Standardschaltfläche
(CommandButton-Objekt, dessen Default-Eigenschaft auf True gesetzt ist).
Tipp

Tipp
...................................................
Um zu erfahren, ob ein linker oder rechter Doppelklick erfolgt ist und an welcher Position er
aufgetreten ist, können Sie die Parameter der Ereignisse MouseDown oder MouseUp, die jedem
DblClick-Ereignis vorangehen, auswerten.
Warnungen

Wa rnungen
...................................................
Ein Doppelklick ist nur dann ein Doppelklick, wenn der Benutzer mit derselben Maustaste
innerhalb der in der Systemsteuerung festgelegten Zeit zweimal klickt. Wird diese Zeit über-
schritten, signalisiert das betreffende Objekt zweimal hintereinander die Ereignisfolge für das
Click-Ereignis. Man sollte daher bei der Gestaltung der Logik der Benutzerschnittstelle darauf
achten, dass dies keine Probleme bereitet. So wäre es beispielsweise wenig sinnvoll, eine Lösch-
operationen an das Click-Ereignis zu binden, während das DblClick-Ereignis eine Auswahl mit
impliziter Bestätigung trifft.
Falls die Behandlungsroutine für das Click-Ereignis ein Formular oder einen Dialog (beispiels-
weise mit Msgbox) aufruft, kommt es trotz Doppelklicks nicht zu einem DblClick-Ereignis.

21 7
Standardereignisse

Beispiel

Beis piel
...................................................
Die Ereignisfolge für einen Doppelklick sieht so aus (Programmcode vgl. »Click-Ereignis«,
S. 215):
Standardereignisse

Ereignisprotokoll für das DblClic k- Ereignis

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
MouseDown, MouseMove, MouseUp, Click

DragDrop- Ereignis
Sub MDIForm_DragDrop(Source As Control, X As Single, Y As Single)
Sub Form_DragDrop(Source As Control, X As Single, Y As Single)
Sub Objekt_DragDrop([Index As Integer], Source As Control, _
X As Single, Y As Single)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, Coolbar, Data, DataGrid, DataList,
DataRepeater, DateTimePicker, DBCombo, DBGrid, DBList, DirListBox, DriveListBox, File-
ListBox, FlatScrollBar, Form, Frame, Grid, HScrollBar, Image, ImageCombo, Label, List-
Box, ListView, MaskEdBox, MDIForm, MMControl, MonthView, MSFlexGrid, MSHFlexGrid, OLE,
OptionButton, PictureBox, ProgressBar, PropertyPage, RemoteData, RichTextBox, Slider,
StatusBar, TabStrip, TextBox, ToolBar, TreeView, UpDown, UserControl, UserDocument,
VScrollBar, WebBrowser
Beschreibung

Bes c hreibung
...................................................
Das DragDrop-Ereignis signalisiert den Abschluss einer Drag&Drop-Operation – ein Vorgang,
bei dem ein als Quellobjekt bezeichnetes Steuerelement (Source) mit Hilfe der Maus über ein
anderes als Zielobjekt bezeichnetes Steuerelement (Objekt) oder ein Formular (Form, MDIForm)
gezogen und dort abgelegt wird. Da das Zielobjekt dabei eine Objektreferenz auf das Quellob-
jekt erhält, steht es ihm frei, die Aktion nach Belieben zu interpretieren und von den Eigenschaf-
ten und Methoden des Quellobjekts Gebrauch zu machen. Die Parameter X und Y drücken die
Zielkoordinaten des Steuerelements im Koordinatensystem des jeweiligen Zielobjekts aus.
Der Parameter Index gibt den Index des signalisierenden Steuerelements (Zielobjekt) wieder,
wenn es Element eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Im Gegensatz zu OLE-Drag&Drop-Operationen funktionieren Drag&Drop-Operationen nur
innerhalb einer Anwendung (bzw. innerhalb ein und derselben Exe-Datei). Bei einer OLE-

21 8
DragDrop- Ereignis

Drag&Drop-Operation handelt es sich um einen dokumentenorientierten Vorgang, der den


Datentransport zwischen Objekten (Steuerelementen, Komponenten) über DataObject-Objekte
abwickelt, ohne dass das Quellobjekt als solches in Erscheinung tritt. Da sie auch anwendungs-
übergreifend funktioniert – letztlich war genau dies das Ziel, das zu ihrer Entwicklung geführt
hat –, ist ihre Handhabung schwieriger und mit wesentlich mehr Overhead verbunden als die
Handhabung der Drag&Drop-Operation, bei der das Quellobjekt offen zu Tage tritt (weil es
zum gleichen Prozess gehört).
Ein in einer Drag&Drop-Operation befindliches Steuerelement folgt – ohne weiteres Zutun des
Programms – als schwebender Umriss den Mausbewegungen. Gelangt der Mittelpunkt des
Umrisses in den Fensterbereich eines anderen Steuerelements, beginnt dieses mit der Signalisie-
rung von DragOver-Ereignissen. (Das als Parent-Objekt des Steuerelements fungierende Form-

Standardereignisse
Objekt signalisiert somit laufend DragOver-Ereignisse). Ein DragOver-Ereignis übermittelt einen
der Aktionscodes vbEnter (0), vbLeave (1), vbOver (2). Eine Behandlungsroutine für das DragO-
ver-Ereignis wird im Allgemeinen die DragIcon-Eigenschaft des Quellobjekts ändern, um dem
Benutzer anhand der Mauszeigerform zu bedeuten, ob die Operation von Erfolg gekrönt sein
kann oder nicht – zuweilen findet man aber auch das Verhalten, dass das Zielobjekt seine
Anzeige invertiert.
Damit ein Steuerelement eine Drag&Drop-Operation als Quellobjekt eingeht, muss entweder
seine DragMode-Eigenschaft den Wert vbAutomatic (1) aufweisen oder ein expliziter Aufruf seiner
Drag-Methode mit Aktionscode vbBeginDrag erfolgen. Im ersteren Fall leitet das Objekt die
Operation bei Niederdrücken der Maustaste von sich aus ein, so dass man sich als Programmie-
rer eigentlich nur um die Behandlung des DragDrop- sowie gegebenenfalls des DragOver-Ereignis-
ses auf der Zielseite kümmern muss. Wenn als Quelle auch mehrere Steuerelemente zulässig
sein sollen oder die Steuerung des Vorgangs sonstwie durch Programmcode gegeben sein soll
(beispielsweise über Tastaturereignisse oder unter Berücksichtigung von Funktionstasten),
bleibt nicht anderes übrig, als die Eigenschaft DragMode auf vbManual zu belassen und die Opera-
tion explizit mit der Methode Drag unter Angabe des entsprechenden Aktionscodes einzuleiten
(vbBeginDrag), zu beenden (vbEndDrag) oder abzubrechen (vbCancel).
Beispiel

Beis piel
...................................................
Das Beispielprojekt DragDrop demonstriert den typischen Ablauf einer programmseitig einge-
leiteten Drag&Drop-Operation. Das Formular enthält eine Schalfläche Command1 sowie ein Bild-
feld Picture1. Ein Klick auf die Schaltfläche öffnet eine weitere Instanz des Formulars und lädt
ein Bild in das Bildfeld. Das Bild kann nun via Drag&Drop zwischen den Bildfeldern der beiden
Formulare hin und her verschoben werden. Ein Klick auf die Schaltfläche Command1 der zweiten
Instanz öffnet eine dritte Instanz, woraufhin sich das Bild zwischen allen drei Bildfeldern ver-
schieben lässt. Der Code pflegt zudem die DragIcon-Eigenschaft des Quellobjekts, indem er ihm
je nach Situation die Symbole DropOK, NoDrop und Dragging zuordnet. Sie stammen aus der
umfangreichen zu Visual Basic gehörigen Grafiksammlung \Programme\Microsoft Visual Stu-
dio\Common\Graphics. Die folgende Abbildung zeigt die verschiedenen Gesichter des Mauszei-
gers während einer Drag&Drop-Operation (siehe folgende Abbildung).
Für den vorliegenden Code ist es kein Problem, wenn Quell und Zielobjekt übereinstimmen.
Das Steuerelement behandelt dann sozusagen die hausgemachten DragOver- und Drag-Ereig-
nisse. (Das ist auch der Grund, warum man sofort nach Beginn der Operation erst einmal das
DropOK-Symbol sieht.)
' Projekt: DragDrop-Demo
Dim Form2 As New Form1
Public NoDrop As Picture ' Ablegen nicht möglich
Public Dragging As Picture ' Drag&Drop-Operation
Public DropOK As Picture ' Ablegen möglich

21 9
Standardereignisse

Der Mauszeiger ändert sich während einer Drag&Drop- Operation


Standardereignisse

Private Sub Command1_Click()


Picture1 = LoadPicture(App.Path + "\phone.wmf") ' Bild laden
Form2.Left = Left + Width ' Nächstes Formular neben dieses
Form2.Top = Top
Form2.Show
End Sub

Private Sub Command1_DragOver(Source As Control, X As Single, Y As Single, State As Integer)


Static AltesIcon As Picture
Select Case State ' Aktionscode analysieren
Case vbEnter
Set AltesIcon = Source.DragIcon ' Altes Symbol speichern
Source.DragIcon = NoDrop ' Ablegen nicht möglich
Case vbLeave
Source.DragIcon = AltesIcon ' Altes Symbol wiederherstellen
End Select
End Sub

Private Sub Form_Unload(Cancel As Integer)


Unload Form2
End Sub

Private Sub Picture1_DragOver(Source As Control, X As Single, _


Y As Single, State As Integer)
Static AltesIcon As Picture
Select Case State ' Aktionscode analysieren
Case vbEnter
Set AltesIcon = Source.DragIcon ' Altes Symbol speichern
Source.DragIcon = DropOK ' Ablegen möglich
Case vbLeave
Source.DragIcon = AltesIcon ' Altes Symbol wieder herstellen
End Select
End Sub

Private Sub Form_Load()


Set NoDrop = LoadPicture(App.Path + "\noDrop02.cur")
Set Dragging = LoadPicture(App.Path + "\drag1pg.ico")
Set DropOK = LoadPicture(App.Path + "\drop1pg.ico")
End Sub

220
DragOver- Ereignis

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Set Picture1.DragIcon = Dragging ' Symbol für Drag-Operation
Picture1.Drag (vbBeginDrag) ' Drag-Operation starten
End Sub

Private Sub Picture1_DragDrop(Source As Control, X As Single, _


Y As Single)
Dim Bild As Picture ' Da Drag&Drop auf sich
Set Bild = Source.Picture ' selbst möglich, muss

Standardereignisse
Set Source.Picture = Nothing ' Bildreferenz zwischengespeichert
Set Picture1 = Bild ' werden!
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
DragOver, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedBack, OLESetData
Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

DragOver- Ereignis
Sub MDIForm_DragOver(Source As Control, X As Single, Y As Single, _
State As Integer)
Sub Form_DragOver(Source As Control, X As Single, Y As Single, _
State As Integer)
Sub Objekt_DragOver([Index As Integer], Source As Control, _
X As Single, Y As Single, State As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, Coolbar, Data, DataGrid, DataList,
DataRepeater, DateTimePicker, DBCombo, DBGrid, DBList, DirListBox, DriveListBox, File-
ListBox, FlatScrollBar, Form, Frame, Grid, HScrollBar, Image, ImageCombo, Label, List-
Box, ListView, MaskEdBox, MDIForm, MonthView, MSFlexGrid, MSHFlexGrid, OLE, OptionBut-
ton, PictureBox, ProgressBar, PropertyPage, RemoteData, RichTextBox, Slider, StatusBar,
TabStrip, TextBox, ToolBar, TreeView, UpDown, UserControl, UserDocument, VScrollBar,
WebBrowser
Beschreibung

Bes c hreibung
...................................................
Das DragOver-Ereignis signalisiert, dass der Umriss des als Quellobjekt fungierenden Steuerele-
ments Source im Verlauf einer Drag&Drop-Operation gerade über den Fensterbereich von
Objekt (Steuerelement oder Formular) gezogen wird und somit als mögliches Ziel der Opera-
tion in Frage kommt. Da Objekt eine Objektreferenz auf das Quellobjekt erhält, steht es ihm
frei, die Aktion nach Belieben zu interpretieren und von den Eigenschaften und Methoden des
Quellobjekts Gebrauch zu machen – das heißt insbesondere dessen Eigenschaft DragIcon zu
manipulieren, um dem Benutzer ein visuelles Feedback über den möglichen Erfolg oder Misser-
folg der Operation zu geben. Die Parameter X und Y drücken die aktuellen Koordinaten des
Steuerelements im Koordinatensystem von Objekt aus.

221
Standardereignisse

Der Parameter State enthält einen Aktionscode, der über die Tendenz der Operation Auf-
schluss gibt. Sein Wert ist: vbEnter (0), wenn der Mittelpunkt des Umrisses von Source gerade in
den Fensterbereich von Objekt gelangt ist; vbOver (2), wenn der Mittelpunkt des Umrisses von
Source im Fensterbereich von Objekt ist und darin bewegt wird; vbLeave (1), wenn der Mittel-
punkt des Umrisses von Source den Fensterbereich von Objekt verlässt.
Der Parameter Index gibt den Index des signalisierenden Steuerelements (mögliches Zielobjekt
der Operation) wieder, wenn es Element eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Ein in einer Drag&Drop-Operation befindliches Steuerelement folgt – ohne weiteres Zutun des
Standardereignisse

Programms – als schwebender Umriss den Mausbewegungen. Gelangt der Mittelpunkt des
Umrisses in den Fensterbereich eines anderen Steuerelements, beginnt dieses mit der Signalisie-
rung von DragOver-Ereignissen. (Das als Parent-Objekt des Steuerelements fungierende Form-
Objekt signalisiert somit laufend DragOver-Ereignisse). Bei der Behandlung des DragOver-Ereig-
nisses wird meist nur zwischen den Aktionscodes vbEnter (0) und vbLeave (1) unterschieden, um
die Eigenschaft DragIcon des Quellobjekts geeignet zu setzen. Der Aktionscode vbOver kann
dann von Relevanz sein, wenn der Bereich des Steuerelements noch einmal in Unterbereiche
aufgeteilt ist.
Beispiel

Beis piel
...................................................
Die folgende Behandlungsroutine entstammt dem vollständigen Beispiel für das DragDrop-Ereig-
nis. Auf den Aktionscode vbEnter hin speichert die Routine zunächst den Wert von DragIcon
des Quellobjekts und ändert dann die Eigenschaft geeignet. Tritt der Aktionscode vbLeave auf,
stellt die Routine das ursprüngliche Symbol wieder her.
Private Sub Picture1_DragOver(Source As Control, X As Single, _
Y As Single, State As Integer)
Static AltesIcon As Picture
Select Case State ' Aktionscode analysieren
Case vbEnter
Set AltesIcon = Source.DragIcon ' Altes Symbol speichern
Source.DragIcon = DropOK ' Ablegen möglich
' Source.DragIcon = NoDrop ' Ablegen nicht möglich
Case vbLeave
Source.DragIcon = AltesIcon ' Altes Symbol wieder herstellen
End Select
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
DragDrop, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedBack, OLESetData

GotFocus- Ereignis und LostFocus- Ereignis


Sub MDIForm_GotFocus()
Sub Form_GotFocus()
Sub Objekt_GotFocus ([Index As Integer])
Sub MDIForm_LostFocus()
Sub Form_LostFocus()
Sub Objekt_LostFocus ([Index As Integer])

222
GotFocus- Ereignis und LostFocus- Ereignis

Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, DataGrid, DataList, DataRepeater,
DateTimePicker, DBCombo, DBGrid, DBList, DirListBox, DriveListBox, FileListBox, Form,
Grid, ImageCombo, ListBox, ListView, MaskEdBox, MDIForm, MonthView, MSFlexGrid, MSHFlex-
Grid, OLE, OptionButton, PictureBox, PropertyPage, RichTextBox, Slider, TabStrip, Text-
Box, TreeView, UpDown, UserControl, UserDocument, VScrollBar, WebBrowser
Beschreibung

Bes c hreibung
...................................................
Das GotFocus-Ereignis signalisiert einem Objekt, dass es den Eingabefokus erhalten, das LostFo-

Standardereignisse
cus-Ereignis, dass es ihn verloren hat. Der Eingabefokus legt fest, welches Objekt die Tastatur-
eingaben des Benutzers zu sehen bekommt. Mit anderen Worten: Hat ein Objekt den Eingabe-
fokus, erhält es auch die Ereignisse KeyDown usw. Ein Formular erhält den Eingabefokus nur,
wenn es keine Steuerelemente enthält, die diesen erhalten könnten. (Nicht alle Steuerelemente
unterstützen einen Eingabefokus, und gesperrte sowie unsichtbare Steuerelemente nehmen ihn
nicht an.)
Der Parameter Index gibt den Index des Steuerelements wieder, das den Fokus erhalten bzw.
verloren hat, wenn es Element eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Beim Show-Aufruf eines Formulars erhält das Steuerelement den Eingabefokus, das unter allen
in Frage kommenden den niedrigsten TabIndex-Wert besitzt, sprich: in der Tabulatorreihenfolge
möglichst weit am Anfang steht. Den Eingabefokus erhalten können alle Steuerelemente, die
den Eingabefokus unterstützen (das Image-Steuerelement tut das beispielsweise nicht) und deren
Visible- sowie Enabled-Eigenschaften auf True gesetzt sind. Ist ein Steuerelement im Besitz des
Eingabefokus, wird das aus seiner Darstellung ersichtlich: Ein Textfeld zeigt eine blinkende Ein-
gabemarke an, die Beschriftung einer Schaltfläche erhält eine gepunktete Umrahmung usw.
Für die Weitergabe des Eingabefokus kommt eine von drei Ursachen in Betracht. Erstens, der
Benutzer drückt die Taste (Tab) bzw. die Tastenkombination (Umschalt)+(Tab). In diesem
Fall rückt der Eingabefokus unter den in Frage kommenden Steuerelementen entlang der Tabu-
latorreihenfolge vorwärts bzw. rückwärts. Zweitens, der Benutzer klickt mit der Maus auf ein
anderes Steuerelement. Falls das Steuerelement den Eingabefokus annehmen kann, erhält es
ihn, ansonsten verbleibt er bei dem Steuerelement, in dessen Besitz er ist. Drittens, der Fokus
wird einem Steuerelement programmseitig durch Aufruf der SetFocus-Methode des zugehörigen
Objekts explizit zugeordnet. Falls das Steuerelement den Fokus nicht annehmen kann, etwa
weil es gesperrt oder nicht sichtbar ist, kommt es zu einem Laufzeitfehler.
Geht der Eingabefokus von einem ersten Steuerelement auf ein zweites Steuerelement weiter,
signalisieren beide Steuerelemente ein Ereignis: Das erste Steuerelement signalisiert ein LostFo-
cus-Ereignis und das zweite ein GotFocus-Ereignis. Das GotFocus-Ereignis wird in der Regel dazu
benutzt, den für die Eingabe erforderlichen Kontext einzustellen, das heißt, den Zustand ande-
rer Steuerelemente zu aktualisieren, wechselseitige Abhängigkeiten mit anderen Steuerelemen-
ten zu berücksichtigen oder Vorgabewerte bereitzustellen.
Das LostFocus-Ereignis lässt sich dazu benutzen, den Fokus abweichend von der Tabulatorrei-
henfolge explizit einem bestimmten Steuerelement zuzuschanzen, Aktualisierungen anderer
Steuerelemente oder Objekte vorzunehmen, deren Zustände in irgendeiner Form vom Wert des
signalisierenden Steuerelements abhängen, oder Daten zurückzuschreiben bzw. anzufordern.
Kurz gesagt, die Behandlung des LostFocus-Ereignisses ermöglicht es, den aktuellen Wert des
signalisierenden Steuerelements in den Zustand der Anwendung einzuflechten.
Ist die CausesValidation-Eigenschaft sowohl des Steuerelements, das den Fokus verliert, als
auch des Steuerelements, das den Fokus erhält, auf True gesetzt, geht dem LostFocus-Ereignis

223
Standardereignisse

noch das Validate-Ereignis voraus, das eine Gültigkeitsprüfung des Eingabewerts ermöglicht.
Zur Weitergabe des Fokus kommt es in diesem Fall nur, wenn der vom Ereignis übermittelte
ByRef-Parameter Cancel im Verlauf der Validate-Behandlung nicht auf True gesetzt wird.
Warnung

Wa rnung
...................................................
Vom Prinzip her könnte man auch versuchen, eine Gültigkeitsprüfung im Zuge von LostFocus
zu implementieren. Das kann aber Probleme verursachen, da das Steuerelement zu dem Zeit-
punkt, an dem das Ereignis auftritt, den Fokus bereits abgegeben hat. Es wäre also ein SetFo-
cus-Aufruf erforderlich, der aber wiederum dem neuen Inhaber des Fokus diesen sofort wieder
entreißt und ihm das LostFocus-Ereignis beschert. Falls dieses Steuerelement gleichfalls nicht
Standardereignisse

bereit ist, den Fokus herzugeben und seinerseits einen SetFocus-Aufruf durchführt, kommt es zu
einer Ereignisflut, die das System destabilisieren kann. Benutzen Sie für dieses Unterfangen bes-
ser das Validate-Ereignis, das speziell auf diesen Zweck ausgelegt ist.
Tipp

Tipp
...................................................
Um einer anderen Anwendung oder Instanz der gleichen Anwendung den Anwendungsfokus
zuzuschanzen, lässt sich die AppActivate-Anweisung verwenden:

Sub AppActivate (title As String[, wait As Boolean])

Die Parameter der Anweisung sind benannt. Für title gibt man den Fenstertitel der zu aktivie-
renden Anwendung vollständig oder nur die ersten paar signifikanten Zeichen an. Hat der
optionale Parameter wait den Wert True, erfolgt die Aktivierung der im ersten Parameter spezi-
fizierten Anwendung erst, wenn das Programm, das die AppActivate-Anweisung ausführt, selbst
den Anwendungsfokus erhält, ansonsten erfolgt die Fokusweitergabe unabhängig davon, wel-
che der aktuell in Ausführung befindlichen Anwendungen ihn gerade besitzt.
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
Validate, Activate, Deactivate

Initialize- Ereignis
Sub Objekt_Initialize()
Betroffene Objekte

Betro ffene Objekte


...................................................
Class, DataReport, DHTMLPageDesigner, Form, MDIForm, PropertyPage, UserControl, UserDo-
cument, WebClass
Beschreibung

Bes c hreibung
...................................................
Das Initialize-Ereignis ist das erste Ereignis, das ein frisch generiertes Objekt Objekt zu sehen
bekommt. Es geht dem Load-Ereignis voran und gibt dem Objekt die Möglichkeit zur Initialisie-
rung seiner Bestandteile.
Anwendung

Anwendung
...................................................
Im Gegensatz zum Load-Ereignis kann das Initialize-Ereignis nur einmal im Leben eines
Objekts auftreten. Es tritt auf, wenn das Laufzeitsystem eine neue Objektinstanz anlegt, das
heißt bei Ausführung einer impliziten oder expliziten New-Anweisung oder bei Aufruf der Crea-
teObject-Funktion. Es eignet sich dafür, Elemente und Eigenschaften des frisch ins Leben geru-
fenen Objekts zu initialisieren, die keine erneute Initialisierung benötigen, wenn das Fenster des
Objekts (Formular oder Steuerelement) zwischendurch entladen wird. Dazu zählen beispiels-

224
KeyDown- Ereignis und KeyUp- Ereignis

weise auf Modulebene deklarierte Variablen. Einem Formularobjekt untergeordnete Steuerele-


mente sollten ihre Initialisierung im Zuge des Load-Ereignisses erfahren, da sie, wenn eine
Unload-Anweisung mit nachfolgender impliziter oder expliziter Load-Anweisung auftritt, zusam-
men mit dem Formular entladen und wieder geladen werden.
Tipp

Tipp
...................................................
Achten Sie darauf, dass ein Objekt bei Eintreffen des Initialize-Ereignisses zwar existiert, aber
noch nicht ganz fertig konstruiert ist. Insbesondere lassen sich zu diesem Zeitpunkt noch nicht
alle Methoden des Objekts aufrufen. (So kann es beispielsweise in einem Formular mit dem
Print-Aufruf Schwierigkeiten geben.) Nicht zuletzt aus diesem Grund wird der Code für die Ini-

Standardereignisse
tialisierung eines Formulars meist in die Behandlungsroutine für das Load-Ereignis gepackt, das
unmittelbar nach dem Initialize-Ereignis (bzw. während der Behandlung des Initialize-
Ereignisses) auftritt. Der folgende Code liefert beispielsweise eine zunächst einmal verblüffende
Ausgabe:

Kommt das Load-Ereignis etwa vor dem Initialize-Ereignis?

Sub Form_Initialize()
AutoRedraw = True ' Wenn False oder fehlt, Laufzeitfehler!
Print "Initialize"
a = 1
End Sub

Private Sub Form_Load()


Print "Load"
End Sub

Sieht man sich den Programmablauf aber im Einzelschrittmodus (Taste (F8)) des Debuggers an,
stellt man fest, dass das Load-Ereignis im Verlauf von Form_Initialize – nämlich beim Setzen
der AutoRedraw-Eigenschaft – getriggert wird.
Beispiel

Beis piel
...................................................
Private Names() As String
Const StartGrößeNames = 10
Sub Form_Initialize()
Redim Names(StartGrößeNames)
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
Load, Terminate, Unload

KeyDown- Ereignis und KeyUp- Ereignis


Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Sub Objekt_KeyDown([Index As Integer], KeyCode As Integer, _
Shift As Integer)

225
Standardereignisse

Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)


Sub Objekt_KeyUp([Index As Integer], KeyCode As Integer, _
Shift As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, ComboBox, CommandButton, DataCombo, DataGrid, DataList, DBCombo, DBGrid,
DBList, DirListBox, DriveListBox, FileListBox, Form, Grid, ListBox, ListView, MaskEdBox,
MonthView, OLE, OptionButton, PictureBox, PropertyPage, RichTextBox, Slider, TabStrip,
TextBox, TreeView, UserControl, UserDocument, VScrollBar
Standardereignisse

Beschreibung

Bes c hreibung
...................................................
Die Ereignisse KeyDown und KeyUp werden von dem Steuerelement signalisiert, das den Eingabe-
fokus besitzt. KeyDown zeigt an, dass der Benutzer die Taste mit dem Tastaturcode KeyCode nie-
dergedrückt hat, KeyUp, dass der Benutzer die Taste mit dem Tastaturcode KeyCode wieder losge-
lassen hat. Der Aufzählungstyp KeyCodeConstants definiert für die meisten Tasten eine eigene
Konstante nach dem Muster: vbKey0 für die Taste (0), vbKeyA für die Taste (A), vbKeyF1 für die
Taste (F1) usw. Die vollständige Liste finden Sie im Objektkatalog (aufzurufen mit (F2)) der
Visual-Basic-Entwicklungsumgebung. Der Parameter Shift ist ein Bitvektor, dessen gesetzte
Bits 0 bis 2 (vbShiftMask, vbCtrlMask, vbAltMask) anzeigen, ob die Funktionstasten (Umschalt),
(Strg) oder (Alt) bei Auslösung des Ereignisses gedrückt (gesetztes Bit) bzw. nicht gedrückt
(gelöschtes Bit) waren. Hat Shift beispielsweise den Wert 5 (vbShiftMask+vbAltMask), bedeutet
das, dass die Taste in Kombination mit (Umschalt)+(Alt) niedergedrückt bzw. losgelassen
wurde.
Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Wer sich auf die Verarbeitung von Tastatureingaben auf der Ebene der KeyUp- und KeyDown-
Ereignisse einlässt, beweist Mut zum Detail. Da Steuerelemente, die auf diese Ereignisse reagie-
ren, bereits eine fertige Tastaturschnittstelle mitbringen, die festlegt, wie das Steuerelement auf
jede einzelne Taste bzw. Tastenkombination reagiert, besteht wenig Veranlassung für massivere
Eingriffe, die über die Ergänzung oder Änderung spezifischer Tastaturbefehle hinausgehen.
Bei Implementierung eines Benutzersteuerelements wird man dagegen schon eher in die Verle-
genheit geraten, selbst eine Tastaturschnittstelle gestalten zu müssen. Überlegen Sie sich dabei
aber gut, was sie wollen, denn nichts führt schneller in des Teufels Küche als eine naiv drauf-
losprogrammierte Tastaturschnittstelle.
Bereits bei der Konzeption der Schnittstelle gibt es einige Dinge zu beachten: Erstens schlucken
das Betriebssystem und das Laufzeitsystem von Visual Basic gewisse Tastenkombinationen ein-
fach weg, für die bereits auf höherer Ebene eine Interpretation existiert. Da sind schon einmal
die von Windows reservierten Tastenkombinationen für die Zwischenablage ((Strg)+(C),
(Strg)+(V), (Strg)+(X), (Strg)+(Einfg), (Strg)+(Entf), (Umschalt)+(Einfg)) sowie die für
den Schnellstart von Desktop-Objekten auf dem jeweiligen System vereinbarten Tastenkombi-
nationen. Aufseiten des Formulars kommen dann noch die Zugriffstasten für die Steuerele-
mente ((Alt) + unterstrichener Buchstabe in der Beschriftung des Steuerelements) und die
ShortCut-Tasten für die Menü- und Symbolleistenbefehle ((Ctrl) + Buchstabe) hinzu. Ist bei
einem der Steuerelemente auf dem Formular die Eigenschaft Default bzw. Cancel auf True
gesetzt (CommandButton, OLE usw.), löst die Eingabetaste bzw. die Taste (Esc) dessen Click-
Ereignis aus. Nur was da noch übrig bleibt, führt zu einem KeyUp- und/oder KeyDown-Ereignis
und lässt sich individuell verarbeiten.

226
KeyDown- Ereignis und KeyUp- Ereignis

Zweitens: Der von den Ereignissen gelieferte Wert für den Parameter KeyCode ist mitnichten der
ASCII-Code (wie bei dem Ereignis KeyPress), sondern vielmehr der Tastaturcode der gedrück-
ten Taste. Die Unterscheidung zwischen Klein- und Großschreibung ist ebenso anhand des im
Parameter Shift gelieferten Bitvektors zu treffen wie die Abfrage der Funktionstasten Strg und
Alt. Drückt der Benutzer also die Kombination (Umschalt)+(A), ergibt sich für KeyCode der
Wert vbKeyA und für Shift der Wert vbShiftMask.
Auch jede Funktionstaste für sich liefert KeyUp- und KeyDown-Ereignisse. Die Tastaturcodes der
Tasten (Umschalt), (Strg) und (Alt) sind vbKeyShift, vbKeyCtrl und vbKeyAlt. Eine Unter-
scheidung zwischen rechts und links gelegenen Tasten gibt es nicht, auch der Bitvektor Shift
hilft da nicht weiter. Damit nicht genug: Nach einer gewissen Zeit, setzt die Wiederholfunktion
der Tastatur ein, so dass beispielsweise bereits eine etwas länger gehaltene Taste (Umschalt) zu

Standardereignisse
einer Flut von KeyUp- und KeyDown-Ereignissen führt. All das gibt es zu berücksichtigen. Am bes-
ten, Sie sehen sich auf einem leeren Formular selbst an, was passiert:
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Print KeyCode, Shift
End Sub
Hinweis

Hinweis
...................................................
Ein Formularobjekt erhält diese Ereignisse nur, wenn keines seiner Steuerelemente den Eingabe-
fokus hat oder wenn die Eigenschaft KeyPreview auf True gesetzt ist. Im letzteren Fall sieht das
Formularobjekt jedes Tastaturereignis als Erstes (bis auf spezielle Ereignisse, die einzelne Steu-
erelemente wegfangen: ein CommandButton-Steuerelement mit der Default-Eigenschaft True fängt
beispielsweise die Eingabetaste ab und ein ListBox-Steuerelement die Tasten (Oben) und
(Unten)). Sobald das Formularobjekt mit der Behandlung eines Tastaturereignisses fertig ist,
kommt die Behandlungsroutine des Steuerelements, das den Fokus besitzt, zum Aufruf – es sei
denn, das Formularobjekt setzt den ByRef-Parameter KeyCode auf 0, dann unterbleibt der Auf-
ruf. Dieser Fall gilt analog für alle Objekte, die als Container für Steuerelemente fungieren kön-
nen und über die KeyPreview-Eigenschaft verfügen (PropertyPage, UserControl, UserDocument).
Beispiel

Beis piel
...................................................
Das Projekt KeyUpDown zeigt die Implementation einer Tastaturschnittstelle für ein Picture-
Box-Steuerelement. Das Programm ermöglicht es, das Bildfeld Picture1 mittels der Cursortasten
in dem Formular zu bewegen (Pacman lässt grüßen).
Private MaxX, MaxY, StepX, StepY
Private PosX, PosY
Private Sub Form_Load()
Picture1 = LoadPicture(App.Path + "\Phone.wmf")
StepX = Picture1.Width / 10
StepY = Picture1.Height / 10
MaxX = ScaleWidth – Picture1.Width
MaxY = ScaleHeight – Picture1.Height
PosX = Picture1.Left
PosY = Picture1.Top
End Sub

Private Sub Picture1_KeyDown(KeyCode As Integer, Shift As Integer)


Select Case KeyCode
Case vbKeyUp
PosY = PosY – StepX

227
Standardereignisse

If PosY < 0 Then PosY = 0


Case vbKeyDown
PosY = (PosY + StepY) Mod MaxY
Case vbKeyLeft
PosX = PosX – StepX
If PosX < 0 Then PosX = 0
Case vbKeyRight
PosX = (PosX + StepX) Mod MaxX
Case vbKeyHome
PosX = 0: PosY = 0
Standardereignisse

Case vbKeyEnd
PosX = MaxX: PosY = MaxY
End Select
Picture1.Left = PosX
Picture1.Top = PosY
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
KeyPress, MouseDown, MouseUp

KeyPress- Ereignis
Sub Form_KeyPress(KeyAscii As Integer)
Sub Objekt_KeyPress([Index As Integer], KeyAscii As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, ComboBox, CommandButton, DataCombo, DataGrid, DataList, DBCombo, DBGrid,
DBList, DirListBox, DriveListBox, FileListBox, Form, Grid, ListBox, ListView, MaskEdBox,
MonthView, OLE, OptionButton, PictureBox, PropertyPage, RichTextBox, Slider, TabStrip,
TextBox, TreeView, UserControl, UserDocument, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Das Ereignis KeyPress wird von dem Steuerelement signalisiert, das den Eingabefokus besitzt.
Es zeigt an, dass der Benutzer eine Taste der Tastatur gedrückt hat, die das Zeichen mit dem
ANSI-Code KeyAscii generiert. Groß- und Kleinschreibung werden unterschieden.
Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Wofür sich das KeyPress-Ereignis einsetzen lässt, dürfte klar sein: überall da, wo das konkrete
über die Tastatur eingegebene ANSI-Zeichen von Interesse ist. So könnte man etwa auf die
Taste (Esc) hin den ursprünglichen Wert eines TextBox-Steuerelements wieder herstellen:
Private OldText1 As String
Private Sub Text1_GotFocus()
OldText1 = Text1
End Sub

Private Sub Text1_KeyPress(KeyAscii As Integer)


If KeyAscii = vbKeyEscape Then

228
KeyPress- Ereignis

Text1 = OldText1
End If
End Sub

Übrigens, zur Menge der ANSI-Zeichen gehören bekanntlich auch die Tastenkombinationen
(Strg)+(A) bis (Strg)+(Z) mit den ASCII-Codes 1 bis 26. ((Strg)+(V) und (Strg)+(X)
schnappt sich allerdings das Betriebssystem, ebenso (Strg)+(C), wenn ein Bereich markiert ist;
weitere Kombinationen können für Menübefehle vereinbart sein.)
Hinweis

Hinweis
...................................................
Ein Formularobjekt erhält dieses Ereignis nur, wenn keines seiner Steuerelemente den Eingabe-

Standardereignisse
fokus hat oder wenn die Eigenschaft KeyPreview auf True gesetzt ist. Im letzteren Fall sieht das
Formularobjekt jedes Tastaturereignis als Erstes (bis auf spezielle Ereignisse, die einzelne Steu-
erelemente wegfangen: ein CommandButton-Steuerelement mit der Default-Eigenschaft True fängt
beispielsweise die Eingabetaste ab und ein ListBox-Steuerelement die Tasten (Oben) und
(Unten). Sobald das Formularobjekt mit der Behandlung eines Tastaturereignisses fertig ist,
kommt die Behandlungsroutine des Steuerelements, das den Fokus besitzt, zum Aufruf – es sei
denn, das Formularobjekt setzt den ByRef-Parameter KeyCode auf 0, dann unterbleibt der Auf-
ruf. Dieser Fall gilt analog für alle Objekte, die als Container für Steuerelemente fungieren kön-
nen und über die KeyPreview-Eigenschaft verfügen (PropertyPage, UserControl, UserDocument).
Beispiel

Beis piel
...................................................
Der folgende einfache Code dokumentiert den Ablauf der drei Ereignisse KeyDown, KeyUp und
KeyPress im Direktfenster. Die Abbildung zeigt die Ausgabe für die Tastenfolge (Alt)+(A); (A).

Ausgabe im Direktfenster

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)


Debug.Print "KeyDown"; KeyCode; Shift
End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)


Debug.Print "KeyPress"; KeyAscii; Chr(KeyAscii)
End Sub

Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)


Debug.Print "KeyUp"; KeyCode; Shift
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
MouseDown, MouseUp, KeyDown, KeyUp

229
Standardereignisse

LinkClose- Ereignis
Sub Form_LinkClose()
Sub MDIForm_LinkClose()
Sub Objekt_LinkClose([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, Label, MDIForm, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Standardereignisse

Das LinkClose-Ereignis tritt auf beiden Seiten einer bestehenden DDE-Verbindung auf, wenn
die Verbindung von einer der beiden Seiten beendet wird. Da aufseiten der Quelle das als
»Thema« der Verbindung fungierende Objekt (meist ein Formularobjekt) alle Anforderungen
bedient, erhält dieses auch das LinkClose-Ereignis, und nicht das in LinkItem spezifizierte Quell-
objekt.
Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Eine DDE-Verbindung ermöglicht die Verknüpfung von Datenfeldern und die Übermittlung
von Kommandos zwischen einem Ziel und einer Quelle, die jeweils unterschiedlichen Prozessen
(lies: Laufzeitinstanzen von Anwendungen) angehören. Zielobjekt ist ein Steuerelement, Quell-
objekt ein Formular. Das Zielobjekt initiiert den Verbindungsaufbau. Bei einer DDE-Verknüp-
fung liefert gewöhnlich das Quellobjekt den Wert eines seiner Elemente (lies: Steuerelemente)
an das Zielobjekt, obwohl eine Aktualisierung auch in der anderen Richtung möglich ist, wenn
die Methode LinkPoke zum Einsatz kommt. Ein Zielobjekt kann eine bestehende DDE-Verbin-
dung auch für die Übermittlung von Kommandozeichenfolgen an das Quellobjekt nutzen. Ein
Quellobjekt kann mit mehreren Zielobjekten eine DDE-Verbindung unterhalten, ein Zielobjekt
jedoch immer nur mit einem Quellobjekt.
Eine DDE-Verbindung wird beendet, wenn das Zielobjekt oder das Quellobjekt seine Eigen-
schaft LinkMode auf vbLinkNone (0) setzt. Das Quellobjekt kann immer nur alle von ihm gehalte-
nen Verbindungen auf einmal beenden, nicht jedoch gezielt eine einzelne Verbindung zu einem
bestimmten Zielobjekt.
Die gewöhnliche Reaktion auf das LinkClose-Ereignis besteht darin, die Zustandsvariable für
den Verbindungsstatus zu pflegen und gegebenenfalls dem Benutzer die Beendigung der DDE-
Verbindung mitzuteilen oder sonstwie anzuzeigen.
Beispiel

Beis piel
...................................................
' im Modul des Zielobjekts
Private Text1Verbunden As Boolean

...
Text1.LinkMode = vbLinkNone ' DDE-Verbindung beenden
...

Sub Text1_LinkClose()
Text1Verbunden = False
MsgBox "DDE-Verbindung beendet"
End Sub

230
LinkError- Ereignis

LinkError- Ereignis
Sub Form_LinkError(LinkErr As Integer)
Sub MDIForm_LinkError(LinkErr As Integer)
Sub Objekt_LinkError([Index As Integer], LinkErr As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, Label, MDIForm, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................

Standardereignisse
Das LinkError-Ereignis signalisiert der Quelle und dem Ziel einer DDE-Verbindung, dass ein
Fehler während der DDE-Kommunikation aufgetreten ist. Der Parameter LinkErr übermittelt
eine Fehlernummer, die Aufschluss über die Art des Fehlers gibt. Der Aufzählungstyp LinkEr-
rorConstants definiert dafür die folgenden Konstanten:

Fehler Beschreibung
vbWrongFormat (1) Die andere Anwendung hat Daten im falschen Format angefor-
dert. Dieser Fehler kann mehrmals aufeinander folgend auftre-
ten, während Visual Basic versucht, ein Format zu finden, das
von der anderen Anwendung erkannt wird
vbSourceClosed (6) Das Zielobjekt hat versucht, die Kommunikation fortzusetzen,
nachdem die Quelle die Verbindung bereits geschlossen hat.
vbTooManyLinks (7) Die Quelle kann nicht mehr als 128 Verbindungen handhaben.
vbDataTransferFailed (8) Zielobjekt einer automatischen Verknüpfung oder eines explizi-
ten LinkRequest-Aufrufs konnte nicht aktualisiert werden.
Oder: Quellobjekt konnte durch LinkPoke-Aufruf nicht aktuali-
siert werden.

Der Parameter Index gibt den Index des signalisierenden Steuerelements wieder, wenn es Ele-
ment eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Eine DDE-Verbindung ermöglicht die Verknüpfung von Datenfeldern und die Übermittlung
von Kommandos zwischen einem Ziel und einer Quelle, die jeweils unterschiedlichen Prozessen
(lies: Laufzeitinstanzen von Anwendungen) angehören. Zielobjekt ist ein Steuerelement, Quell-
objekt ein Formular. Das Zielobjekt initiiert den Verbindungsaufbau. Bei einer DDE-Verknüp-
fung liefert gewöhnlich das Quellobjekt den Wert eines seiner Elemente (lies: Steuerelemente)
an das Zielobjekt, obwohl eine Aktualisierung auch in der anderen Richtung möglich ist, wenn
die Methode LinkPoke zum Einsatz kommt. Ein Zielobjekt kann eine bestehende DDE-Verbin-
dung auch für die Übermittlung von Kommandozeichenfolgen an das Quellobjekt nutzen. Ein
Quellobjekt kann mit mehreren Zielobjekten eine DDE-Verbindung unterhalten, ein Zielobjekt
jedoch immer nur mit einem Quellobjekt.
Das LinkError-Ereignis sollte eigentlich nicht auftreten, wenn Ziel und Quelle gut aufeinander
abgestimmt sind. Tritt es dennoch auf, ist die Situation nach einer Analyse der Fehlerursache
häufig noch zu retten, etwa indem nicht mehr benötigte Verbindungen geschlossen werden, ein
anderes Datenformat benutzt oder ein Versuch unternommen wird, eine gestorbene Verbin-
dung erneut zu eröffnen.

23 1
Standardereignisse

LinkExecute- Ereignis
Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)
Sub MDIForm_LinkExecute(CmdStr As String, Cancel As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, MDIForm
Beschreibung

Bes c hreibung
...................................................
Das LinkExecute-Ereignis tritt im Verlauf einer DDE-Verbindung aufseiten des Quellobjekts auf
Standardereignisse

und übermittelt eine Kommandozeichenfolge des Zielobjekts.


Anwendung

Anwendung
...................................................
Eine DDE-Verbindung ermöglicht die Verknüpfung von Datenfeldern und die Übermittlung
von Kommandos zwischen einem Ziel und einer Quelle, die jeweils unterschiedlichen Prozessen
(lies: Laufzeitinstanzen von Anwendungen) angehören. Zielobjekt ist ein Steuerelement, Quell-
objekt ein Formular. Das Zielobjekt initiiert den Verbindungsaufbau. Bei einer DDE-Verknüp-
fung liefert gewöhnlich das Quellobjekt den Wert eines seiner Elemente (lies: Steuerelemente)
an das Zielobjekt, obwohl eine Aktualisierung auch in der anderen Richtung möglich ist, wenn
die Methode LinkPoke zum Einsatz kommt. Ein Zielobjekt kann eine bestehende DDE-Verbin-
dung auch für die Übermittlung von Kommandozeichenfolgen an das Quellobjekt nutzen. Ein
Quellobjekt kann mit mehreren Zielobjekten eine DDE-Verbindung unterhalten, ein Zielobjekt
jedoch immer nur mit einem Quellobjekt.
Zum Versand eines DDE-Kommandos ruft das Zielobjekt seine LinkExecute-Methode unter
Angabe einer Kommandozeichenfolge auf. Empfänger des Kommandos ist immer das Quellob-
jekt, nicht das für die Verknüpfung benannte Datenelement. Die gewöhnliche Reaktion auf das
LinkExecute-Ereignis besteht in der Interpretation des Kommandos. Da es keinen feststehenden
Kommandosatz für DDE-Verbindungen gibt, unterliegt die Ausgestaltung der Kommandos
sowie deren Interpretation allein der Fantasie des Programmierers. Wenn die Behandlungsrou-
tine mit dem Kommando etwas anfangen kann, muss sie den Parameter Cancel explizit auf
False setzen, sonst tritt in der Zielanwendung der Laufzeitfehler 285: »Andere Anwendung
führt die DDE-Methode oder -Operation nicht aus« auf.
Beispiel

Beis piel
...................................................
' Im Modul des Zielobjekts
...
Text1.LinkExecute("Beenden")
...

' Im Modul der Quellobjekts


Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)
If CmdStr = "Beenden" Then
Cancel = False ' Kommando erkannt!
Unload Me ' Kommando ausführen
End If
End Sub

232
LinkNotify- Ereignis

LinkNotify- Ereignis
Sub Objekt_LinkNotify([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................
Label, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Das LinkNotify-Ereignis signalisiert dem Zielobjekt einer im Modus »Manuell mit Benachrich-
tigung« aufgebauten DDE-Verknüpfung, dass sich der Inhalt des Datenlieferanten aufseiten der
Quelle geändert hat. Zur Auffrischung seiner Daten kann das Zielobjekt seine Methode LinkRe-

Standardereignisse
quest ausführen.
Anwendung

Anwendung
...................................................
Eine DDE-Verbindung ermöglicht die Verknüpfung von Datenfeldern und die Übermittlung
von Kommandos zwischen einem Ziel und einer Quelle, die jeweils unterschiedlichen Prozessen
(lies: Laufzeitinstanzen von Anwendungen) angehören. Zielobjekt ist ein Steuerelement, Quell-
objekt ein Formular. Das Zielobjekt initiiert den Verbindungsaufbau. Bei einer DDE-Verknüp-
fung liefert gewöhnlich das Quellobjekt den Wert eines seiner Elemente (lies: Steuerelemente)
an das Zielobjekt, obwohl eine Aktualisierung auch in der anderen Richtung möglich ist, wenn
die Methode LinkPoke zum Einsatz kommt. Ein Zielobjekt kann eine bestehende DDE-Verbin-
dung auch für die Übermittlung von Kommandozeichenfolgen an das Quellobjekt nutzen. Ein
Quellobjekt kann mit mehreren Zielobjekten eine DDE-Verbindung unterhalten, ein Zielobjekt
jedoch immer nur mit einem Quellobjekt.
Ein Zielobjekt hat beim Aufbau einer DDE-Verbindung für eine Verknüpfung die Wahl zwi-
schen drei Arbeitsmodi: »Automatisch«, »Manuell« oder »Manuell mit Benachrichtigung«. Im
Modus »Automatisch« findet eine automatische Synchronisation zwischen Quelle und Ziel
statt. Im Modus »Manuell« kann das Zielobjekt die Synchronisation durch explizite Aufrufe
der Methode LinkRequest nach Bedarf aufrechterhalten. Im Modus »Manuell mit Benachrichti-
gung« erhält das Zielobjekt jedes Mal ein LinkNotify-Ereignis, wenn sich der verknüpfte Wert
aufseiten der Quelle ändert. Die Behandlungsroutine für das Ereignis wird im Allgemeinen
einen LinkRequest-Aufruf enthalten, der die Synchronisation betreibt.
Ein Quellobjekt kann durch Aufruf der LinkSend-Methode des als Datenlieferant für eine DDE-
Verknüpfung fungierenden Steuerelementobjekts LinkNotify-Ereignisse auch außer der Reihe
anstoßen, was beispielsweise nach Manipulation der Picture-Eigenschaft eines Bildfelds erfor-
derlich ist.

LinkOpen- Ereignis
Sub Form_LinkOpen(Cancel As Integer)
Sub MDIForm_LinkOpen(Cancel As Integer)
Sub Objekt_LinkOpen([Index As Integer], Cancel As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, Label, MDIForm, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Das LinkOpen-Ereignis signalisiert den Aufbau einer DDE-Verbindung durch das Zielobjekt. Es
tritt auf beiden Seiten der Verbindung auf. Der Ergebnisparameter Cancel hat als Voreinstellung
den Wert 0. Zielobjekt und Quellobjekt haben die Möglichkeit, die Verbindung abzulehnen,
indem sie Cancel auf einen Wert ungleich 0 setzen.

23 3
Standardereignisse

Anwendung

Anwendung
...................................................
Eine DDE-Verbindung ermöglicht die Verknüpfung von Datenfeldern und die Übermittlung
von Kommandos zwischen einem Ziel und einer Quelle, die jeweils unterschiedlichen Prozessen
(lies: Laufzeitinstanzen von Anwendungen) angehören. Zielobjekt ist ein Steuerelement, Quell-
objekt ein Formular. Das Zielobjekt initiiert den Verbindungsaufbau. Bei einer DDE-Verknüp-
fung liefert gewöhnlich das Quellobjekt den Wert eines seiner Elemente (lies: Steuerelemente)
an das Zielobjekt, obwohl eine Aktualisierung auch in der anderen Richtung möglich ist, wenn
die Methode LinkPoke zum Einsatz kommt. Ein Zielobjekt kann eine bestehende DDE-Verbin-
dung auch für die Übermittlung von Kommandozeichenfolgen an das Quellobjekt nutzen. Ein
Quellobjekt kann mit mehreren Zielobjekten eine DDE-Verbindung unterhalten, ein Zielobjekt
Standardereignisse

jedoch immer nur mit einem Quellobjekt.


Voraussetzung für einen erfolgreichen Verbindungsaufbau ist, dass die Eigenschaft LinkMode des
Quellobjekts bereits beim Entwurf auf den Wert vbLinkSource gesetzt wurde. Die Eigenschaften
LinkTopic und LinkItem des Zielobjekts spezifizieren das Quellobjekt sowie das Verknüpfungs-
element. Der Wert für LinkTopic setzt sich aus einem »Anwendungsnamen« und einem
»Thema« zusammen und hat die Syntax:
Objekt.LinkTopic = "Anwendung|Thema"

Der »Anwendungsname« entspricht dem Wert der Eigenschaft App.Title aufseiten der Quelle
und stimmt meist mit dem Namen der EXE-Datei des Programms überein, jedoch nicht immer.
Als »Thema« ist der Wert der LinkTopic-Eigenschaft des Quellobjekts anzugeben, der meist
(jedoch nicht zwingend) mit dem Fenstertitel des Formulars übereinstimmt. Für die Eröffnung
einer reinen Kommandoverbindung reicht es, nur die LinkTopic-Eigenschaft des Zielobjekts
geeignet zu setzen. Für die Eröffnung einer Datenverknüpfung zu einem Steuerelement des
Quellobjekts muss weiterhin die LinkItem-Eigenschaft auf den Bezeichner des Steuerelements
gesetzt werden:
Objekt.LinkItem = "Element"
Um beispielsweise mit dem Steuerelement Text1 des Formulars Form1 (lies: dessen LinkTopic-
Eigenschaft den Wert »Form1« hat) eines Programms, dessen Anwendungsname »DDE-Demo«
ist, eine Verknüpfung aufzubauen, lautet die Verbindungsinformation für das Zielobjekt Ziel-
Element:
ZielElement.LinkTopic = "DDE-Demo|Form1"
ZielElement.LinkItem = "Text1"
Der Verbindungsaufbau erfolgt, sobald die Eigenschaft LinkMode des Zielobjekts auf einen Wert
ungleich 0 gesetzt wird:
ZielElement.LinkMode = vbLinkAutomatic
Umgekehrt erfolgt der Verbindungsabbau, sobald die Eigenschaft LinkMode des Zielobjekts oder
des Quellobjekts auf den Wert 0 gesetzt wird:
ZielElement.LinkMode = vbLinkNone
Über eine bereits bestehende DDE-Verknüpfung lassen sich gleichfalls Kommandos an das
Quellobjekt schicken, meist erfolgt der Versand von Kommandos aber über eine eigene Kom-
mandoverbindung. Aufseiten des Ziels tritt dann ein weiteres Zielobjekt in Aktion, ohne dass
dies an der Logik der Quelle etwas ändert. Reine Kommandoverbindungen werden im Verbin-
dungsmodus »Manuell« oder »Manuell mit Benachrichtigung« geöffnet.

234
LinkOpen- Ereignis

ZielElement.LinkMode = vbLinkManual

oder
ZielElement.LinkMode = vbLinkNotify

Für reine Kommandoverbindungen macht es keinen Unterschied, welcher der beiden Verbin-
dungsmodi benutzt wird, für eine Datenverknüpfung jedoch schon. Im Modus »Manuell« muss
das Zielobjekt einer Datenverknüpfung jede Aktualisierung der Verknüpfungsinformation
explizit durch einen Aufruf der Methode LinkRefresh anleiern, ohne zu wissen, ob sich aufsei-
ten der Quelle etwas geändert hat oder nicht. Im Modus »Manuell mit Benachrichtigung«
schickt das Quellobjekt dem Zielobjekt dagegen bei jeder Änderung das Ereignis LinkNotifiy,

Standardereignisse
woraufhin dieses mit LinkRefresh reagieren kann, aber nicht muss.
Beispiel

Beis piel
...................................................
Das folgende Codefragment zeigt prototypisch den Aufbau einer DDE-Verknüpfung mit einem
Steuerelement in einer anderen Anwendung:
Static ZielementVerbunden As Boolean
...
If Not ZielementVerbunden Then
ZielElement.LinkTopic = "DDE-Demo|Form1" ' Anwendung und Formular
ZielElement.LinkItem = "Text1" ' Quelle festlegen!
On Error GoTo StarteAnwendung
ZielElement.LinkMode = vbLinkAutomatic
ZielElementVerbunden = True
End If
...
Exit Sub

StarteAnwendung:
MsgBox (Err.Description)
...

Hier der gleiche Code, wenn die Verbindung mit der Zelle B5 einer Excel-Tabelle namens
Tabelle1.xls aufgebaut werden soll:
Static ZielementVerbunden As Boolean
...
If Not ZielementVerbunden Then
ZielElement.LinkTopic = "Excel|Tabelle1.xls" ' Anwendung und Formular
ZielElement.LinkItem = "Z2S5" ' Quelle festlegen!
On Error GoTo StarteAnwendung
ZielElement.LinkMode = vbLinkAutomatic
ZielElementVerbunden = True
End If
...
Exit Sub

StarteAnwendung:
If Shell("C:\Microsoft Office\Office\Excel.exe C:\Tabelle1.xls") Then
Resume
Else

23 5
Standardereignisse

Exit Sub
End If
End Sub
Verwandte Themen

Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)

Load- Ereignis
Sub Objekt_Load()
Standardereignisse

Betroffene Objekte

Betro ffene Objekte


...................................................
Form, MDIForm, PropertyPage
Beschreibung

Bes c hreibung
...................................................
Das Load-Ereignis folgt auf das Initialize-Ereignis und tritt als zweites Ereignis im noch jun-
gen Leben eines Formulars auf. Zu diesem Zeitpunkt wird das Formularobjekt zwar noch nicht
angezeigt, ist aber bereits vollständig konstruiert und ermöglicht die sichere Initialisierung von
Steuerelementen und globalen Variablen sowie das Laden von Ressourcen. Im Gegensatz zum
Initialize-Ereignis kann das Load-Ereignis im Leben eines Objekts mehrmals auftreten.
Anwendung

Anwendung
...................................................
Für das Eintreten eines Load-Ereignisses kommen drei Anlässe in Betracht: Erstens, das Formu-
lar ist als Startobjekt einer Anwendung spezifiziert. Zweitens, das Formular wird durch ein
anderes Objekt explizit mittels einer Load-Anweisung geladen. Drittens, ein anderes Objekt
referiert auf ein Element, eine Eigenschaft oder eine Methode des ungeladenen Formulars. Für
den zweiten und dritten Fall muss die verwendete Objektvariable mit dem Schlüsselwort New
deklariert oder zuvor ein Unload-Aufruf für das Formular erfolgt sein. Auch erfolgt keine auto-
matische Anzeige des Formulars. Vielmehr ist es der Show-Aufruf, der ein geladenes oder ungela-
denes Formular zur Anzeige bringt. Es reicht somit zu schreiben:
Private MeinForm As New Form1
...
' in einer Funktion/Prozedur
MeinForm.Show ' Lädt das Formular und zeigt es an
Wird ein Formular geladen, dessen MDIChild-Eigenschaft beim Entwurf auf True gesetzt wurde,
lädt Visual Basic implizit auch das übergeordnete MDI-Formular, falls dieses noch nicht gela-
den ist. Für ein untergeordnetes Formular ist kein Show-Aufruf erforderlich, da dieses nach dem
Load-Ereignis automatisch angezeigt wird.
Hinweis

Hinweis
...................................................
Von MsgBox oder InputBox angezeigte Dialogfelder erfordern weder eine Deklaration noch einen
Load- oder Show-Aufruf.
Beispiel

Beis piel
...................................................
Der folgende Code demonstriert den Unterschied zwischen dem Load- und dem Initialize-
Ereignis, indem es die Ereignisse durch MsgBox-Aufrufe gewissermaßen sichtbar macht. Das For-
mular enthält ein Steuerelement namens Text1 und initialisiert dieses während der Behandlung
von Initialize (!). Beim Start der Anwendung kommen nacheinander das Initialize- und das

236
MouseDown- Ereignis und MouseUp- Ereignis

Load-Ereignis zum Zuge. Ein Klick auf das Formular entlädt dieses zunächst, gibt eine Meldung
aus und lädt es dann gleich wieder. Wie man sieht, hat Text1 danach seine Initialisierung verges-
sen.
' Demo für den Unterschied zwischen dem Load- und Initialize-Ereignis
Private Sub Form_Initialize()
MsgBox "Form_Initialize"
Text1 = "Initialisiert"
End Sub

Private Sub Form_Load()

Standardereignisse
MsgBox "Form_Load"
End Sub

Private Sub Form_Click()


Unload Me
MsgBox "Formular entladen"
Show
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
Initialize, Terminate, Unload

MouseDown- Ereignis und MouseUp- Ereignis


Sub Form_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub MDIForm_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub Objekt_MouseDown([Index As Integer,] Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Sub Form_MouseUp(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub MDIForm_MouseUp (Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub Objekt_MouseUp ([Index As Integer,] Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, CommandButton, DataGrid, DataList, DataRepeater, DateTime-
Picker, DBCombo, DBGrid, DBList, DirListBox, FileListBox, Form, Grid, HScrollBar Image,
ListBox, ListView, MDIForm, MonthView, MSFlexGrid, MSHFlexGrid, OLE, OptionButton, Pic-
tureBox, ProgressBar, PropertyPage, RichTextBox, Slider, StatusBar, TabStrip, TextBox,
UpDown, UserControl, UserDocument, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Das MouseDown-Ereignis signalisiert einem Objekt, dass der Benutzer über seinem Fenster eine
Maustaste niedergedrückt hat, während das MouseUp-Ereignis das Loslassen derselben verkün-

23 7
Standardereignisse

det. Im Gegensatz zu den Ereignissen Click und DblClick übermitteln MouseDown und MouseUp
genügend Informationen, um die aktuelle Mausposition, die verantwortliche Maustaste sowie
auch den Status der Funktionstasten ermitteln zu können.
Der im Parameter Button übergebene Bitvektor identifiziert die benutzte Maustaste. Es ist
immer nur ein Bit gesetzt: Bit 0 steht für die linke Maustaste, Bit 1 für die rechte und Bit 2 für
die mittlere. Der Aufzählungstyp MouseButtonConstants definiert drei Konstanten dafür, die sich
als Masken für die Abfrage der Maustaste benutzen lassen: vbLeftButton (1), vbRightButton (2)
und vbMiddleButton (4).
Durch Auswertung des Shift-Parameters, gleichfalls ein Bitvektor lässt sich ermitteln, ob und
welche Funktionstasten bei Eintritt des Ereignisses gedrückt waren. Bit 0 steht für (Umschalt),
Bit 1 für (Strg) und Bit 2 für (Alt). Der Aufzählungstyp ShiftConstants definiert drei Kon-
Standardereignisse

stanten dafür, die sich als Masken für die Abfrage der Funktionstasten benutzen lassen: vbShift
(1), vbCtrl (2) und vbAlt (4).
Die Werte der Parameter X und Y geben die aktuelle Mausposition zum Zeitpunkt des Ereignis-
ses als Koordinaten im aktuellen Koordinatensystem des Objekts an.
Der Parameter Index gibt den Index des betroffenen Steuerelements wieder, wenn es Element
eines Steuerelemente-Arrays ist.
Anwendung

Anwendung
...................................................
Ein häufiges Problem besteht darin, dass es dem Benutzer möglich sein soll, mit der Maus einen
Bereich auszuwählen oder die Größe eines Elements zu verändern (vgl. Drag&Drop). In diesem
Fall muss die Programmlogik so ausgelegt sein, dass das MouseDown-Ereignis den Start der Ope-
ration, die bis zum MouseUp-Ereignis auftretenden MouseMove-Ereignisse den Verlauf der Opera-
tion und das MouseUp-Ereignis schließlich den Abschluss der Operation steuern. Der Zusammen-
hang lässt sich durch Einsatz einer geeignet zu pflegenden Zustandsvariable herstellen. Reine
Positionsverschiebungen lassen sich auch allein auf Basis des MouseMove-Ereignisses bewerkstel-
ligen.
Drückt der Benutzer mehrere Maustasten gleichzeitig, sieht das Objekt für jede der Maustasten
ein eigenes Ereignis. Wenn es eine Rolle spielt, ob nur eine oder mehrere Maustasten gedrückt
bzw. losgelassen wurden, müssen die Behandlungsroutinen auch in diesem Fall eine Zustands-
variable pflegen. Da in dem Bitvektor Shift mehrere Bits gesetzt sein können, ist zur Abfrage
einer einzelnen Funktionstaste eine And-Operation mit der Maskenkonstanten erforderlich:
If Shift And vbShift Then

Kombinationen von Funktionstasten lassen sich einzeln oder durch Addition der entsprechen-
den Maskenkonstanten ermitteln:
If (Shift And (vbShift + vbAlt)) = (vbShift + vbAlt) Then

bzw.
If (Shift And vbShift) And (Shift And vbAlt) Then

Die Klammerung ist hier wichtig, da And zweimal als bitweiser und einmal als logischer Opera-
tor auftritt.
Warnungen

Wa rnungen
...................................................
Für Verwirrung sorgt oft die Behandlung von Mausereignissen für Steuerelemente. Da Steuer-
elemente ein unveränderliches Koordinatensystem mit Ursprung in der linken oberen Ecke und
der Maßeinheit Twips benutzen, beziehen sich die von den Ereignissen MouseDown und MouseUp
gelieferten Koordinaten auf dieses Koordinatensystem, auch wenn im übergeordneten Formular

238
MouseMove- Ereignis

ein anderes Koordinatensystem herrscht. Für die Umrechnung von Koordinaten zwischen ver-
schiedenen Koordinatensystemen lassen sich die Methoden ScaleX und ScaleY einsetzen.
Das Eintreffen des MouseUp-Ereignisses ist nicht in jedem Falle garantiert. In speziellen Situatio-
nen kann es auch einmal unter den Tisch fallen – beispielsweise im Zuge der Ausführung der
Stop-Anweisung oder wenn die Programmausführung einen Unterbrechungspunkt erreicht.
Hinweis

Hinweis
...................................................
Beachten Sie, dass jedes MouseUp-Ereignis ein Click-Ereignis sowie gegebenenfalls ein DblClick-
Ereignis nach sich zieht.
Tipp

Standardereignisse
Tipp
...................................................
Eine geeignete Logik bei der Behandlung des MouseMove-Ereignisses kann die Behandlung von
MouseDown und MouseUp obsolet machen.
Verwandte Befehle

Verwa ndte Befehle


...................................................
Click, DblClick, KeyDown, KeyUp, MouseMove
Beispiel

Beis piel
...................................................
Vgl. das Beispiel in »MouseMove-Ereignis« (S. 239).
Verwandte Themen

Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)

MouseMove- Ereignis
Sub Form_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub MDIForm_MouseMove(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
Sub Objekt_MouseMove([Index As Integer,] Button As Integer, _
Shift As Integer, X As Single, Y As Single)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, CommandButton, DataGrid, DataList, DataRepeater, DateTime-
Picker, DBCombo, DBGrid, DBList, DirListBox, FileListBox, Form, Grid, HScrollBar Image,
ListBox, ListView, MDIForm, MonthView, MSFlexGrid, MSHFlexGrid, OLE, OptionButton, Pic-
tureBox, ProgressBar, PropertyPage, RichTextBox, Slider, StatusBar, TabStrip, TextBox,
UpDown, UserControl, UserDocument, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Während die Ereignisse MouseDown und MouseUp nur dann auftreten, wenn der Benutzer die
Maustasten betätigt, tritt das MouseMove-Ereignis auf, sobald der Benutzer die Maus im Fenster-
bereich des Objekts bewegt. Im Gegensatz zu den Ereignissen Click und DblClick übermittelt
MouseMove Informationen, die einer Behandlungsroutine Aufschluss über die aktuelle Mausposi-
tion sowie den Status der Maus- und Funktionstasten geben.
Der im Parameter Button übergebene Bitvektor identifiziert die benutzten Maustasten. Es kön-
nen auch mehrere Bits gesetzt sein: Bit 0 steht für die linke Maustaste, Bit 1 für die rechte und
Bit 2 für die mittlere. Der Aufzählungstyp MouseButtonConstants definiert drei Konstanten

23 9
Standardereignisse

dafür, die sich als Masken für die Abfrage der Maustaste benutzen lassen: vbLeftButton (1),
vbRightButton (2), vbMiddleButton (4).
Durch Auswertung des Shift-Parameters, gleichfalls ein Bitvektor lässt sich ermitteln, ob und
welche Funktionstasten bei Eintritt des Ereignisses gedrückt waren. Bit 0 steht für (Umschalt),
Bit 1 für (Strg) und Bit 2 für (Alt). Der Aufzählungstyp ShiftConstants definiert drei Kon-
stanten dafür, die sich als Masken für die Abfrage der Funktionstasten benutzen lassen: vbShift
(1), vbCtrl (2), vbAlt (4).
Die Werte der Parameter X und Y geben die aktuelle Mausposition zum Zeitpunkt des Ereignis-
ses als Koordinaten im aktuellen Koordinatensystem des Objekts an.
Der Parameter Index gibt den Index des betroffenen Steuerelements wieder, wenn es Element
eines Steuerelemente-Arrays ist.
Standardereignisse

Anwendung

Anwendung
...................................................
Eine Behandlung des MouseMove-Ereignisses ist sinnvoll, wenn die Bewegung des Mauszeigers im
Verlauf einer Operation von Interesse ist – zum Beispiel für die Anzeige eines visuellen Feed-
backs für den Benutzer, wenn dieser eine Ziehoperation mit der Maus durchführt.
Tipp

Tipp
...................................................
Da das Formularobjekt (aber auch großflächige Steuerelemente) im Allgemeinen einer ständi-
gen Flut von MouseDown-Ereignissen ausgesetzt ist, sollten Sie bei Implementierung einer Behand-
lungsroutine für dieses Ereignis stets auf gute Laufzeiteigenschaften achten, damit die Reaktivi-
tät der Benutzerschnittstelle keine Beeinträchtigung erfährt. Am besten, Sie fragen gleich zu
Beginn der Routine eine Zustandsvariable ab, deren Wert über die Notwendigkeit einer ernst-
haften Behandlung mit Auswertung der Ereignisparameter entscheidet. Damit vermeiden Sie
vorauseilende Operationen und Berechnungen, deren Ergebnisse ohnehin erst im Verlauf einer
konkreten Mausoperation von Interesse sind.
Beispiel

Beis piel
...................................................
Das folgende kleine Programm wertet die Ereignisse MouseDown, MouseUp und MouseMove aus, um
eine Ziehoperation für ein Steuerelement zu implementieren, bei der das Steuerelement (im
Gegensatz zur Drag&Drop-Operation) sichtbar bleibt. Das Szenario besteht schlicht aus einem
Formular und einem Steuerelement namens figur. Um die Angelegenheit realistischer zu
machen, geht die Implementation erschwerend davon aus, dass in Formular und Steuerelement
unterschiedliche Koordinatensysteme gelten.
Private StartX As Single
Private StartY As Single

Private Sub Form_Load()


ScaleMode = vbPixels
End Sub

Private Sub figur_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
StartX = X ' Startkoordinaten merken, Operation einleiten
StartY = Y
End Sub

Private Sub figur_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)

240
OLECompleteDrag- Ereignis

If StartX Then
figur.Left = figur.Left – ScaleX((StartX – X), vbTwips, vbPixels)
figur.Top = figur.Top – ScaleY((StartY – Y), vbTwips, vbPixels)
End If
End Sub

Private Sub figur_MouseUp(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
If StartX Then ' Steuerelement ablegen
figur.Left = figur.Left – ScaleX((StartX – X), vbTwips, vbPixels)

Standardereignisse
figur.Top = figur.Top – ScaleY((StartY – Y), vbTwips, vbPixels)
StartX = 0
End If
End Sub

Ein Wort zu der nicht ganz trivialen Strategie, die der Code verfolgt. Die globale Variable
StartX nimmt eine Doppelfunktion ein: Sie ist Zustandsvariable für die Steuerung der Mouse-
Move-Behandlung und bunkert gleichzeitig den X-Offset des Mauszeigers relativ zum Ursprung
des Steuerelements. StartY speichert den Y-Offset. Beide Werte beziehen sich auf den Beginn
der Ziehoperation. Da alle von MouseMove gelieferten Koordinaten auf das Koordinatensystem
des Steuerelements bezogen sind, gilt es, bei jedem MouseMove-Ereignis die Position des Steuer-
elements so zu verändern, dass der Offset des Mauszeigers im Steuerelement wieder hergestellt
wird. Die Distanz für die Verschiebung ergibt sich somit als Differenz zwischen dem Offset und
der aktuellen Mausposition im Steuerelement. Da im Formular ein anderes Koordinatensystem
als im Steuerelement gilt, muss die Distanz für die Verschiebung des Steuerelements im Formu-
lar noch in dessen Koordinatensystem umgerechnet werden.
Verwandte Befehle

Verwa ndte Befehle


...................................................
Click, DblClick, KeyDown, KeyUp, MouseDown, MouseUp
Verwandte Themen

Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)

OLECompleteDrag- Ereignis
Private Sub Objekt_OLECompleteDrag(Effect As Long)
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CoolBar, DataList, DateTimePicker, DBCombo, DBList, DirListBox, FileListBox,
FlatScrollBar, Grid, Image, ImageCombo, ListBox, ListView, MaskEdBox, MSChart, MSFlex-
Grid, MSHFlexGrid, OLE, PictureBox, PropertyPage, RichTextBox, SSTab, TabStrip, TextBox,
TreeView, ToolBar, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das OLECompleteDrag-Ereignis tritt als letztes Ereignis in der Ereignisfolge einer OLE-
Drag&Drop-Operation auf, wenn die Quellkomponente im manuellen Modus (OLEDragMode =
vbDragManual) betrieben wird. Es teilt ihr mit, welche Operation die Zielkomponente auf das
OLEDragDrop-Ereignis hin letztlich durchgeführt hat – vorausgesetzt, diese hat den Parameter
Effect entsprechend gepflegt. Vom Wert her ist Effect ein Bitvektor, dessen einzelne Bits für
die möglichen Operationen stehen. Ist kein Bit gesetzt, fand keine Operation statt. Der Aufzäh-
lungstyp OLEDropEffectConstants definiert eine Reihe von Konstanten für die einzelnen Opera-

241
Standardereignisse

tionen: vbDropEffectNone (0) steht für »keine Operation«, vbDropEffectCopy (1) für »Kopier-
operation« und vbDropEffectMove (2) für »Verschiebeoperation«.
Anwendung

Anwendung
...................................................
Zum Abschluss einer OLE-Drag&Drop-Operation kann aufseiten der Quellkomponente eine
Nachbereitung erforderlich sein, beispielsweise wenn eine Verschiebeoperation stattgefunden
hat und die Komponente den verschobenen Inhalt nicht von alleine löscht oder gegebenenfalls
belegte Ressourcen nicht freigibt. Falls die Quellkomponente in einer der Behandlungsroutinen
für OLEDragStart oder OLEGiveFeedBack einen eigenen Mauscursor setzt, um dem Benutzer das
Ergebnis der Operation besser vor Augen zu bringen, muss in jedem Fall eine Behandlung von
Standardereignisse

OLECompleteDrag erfolgen, um den ursprünglichen Mauscursor wieder herzustellen.


Warnung

Wa rnung
...................................................
Auch wenn der Visual Basic Editor das Ereignis bei vielen Steuerelementen und Objekten anbie-
tet (so beispielsweise für Form und MMControl), betrifft es im Allgemeinen nur solche Objekte, die
darauf eingerichtet sind, als Quellkomponente in einer OLE-Drag&Drop-Operation zu fungie-
ren. Zudem tritt das Ereignis auch bei diesen Objekten nur im »manuellen Modus« auf, das
heißt, wenn die Eigenschaft OLEDragMode den Wert vbOLEDragManual (1) hat.
Beispiel

Beis piel
...................................................
Private Sub Quelle_OLECompleteDrag(Effect As Long)
Screen.MouseIcon = AltesScreenIcon ' Alte Form setzen
Screen.MousePointer = AlterScreenPointer ' Alten Zeiger setzen
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLEDragDrop- Ereignis
Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, Y As Single)
Private Sub Objekt_OLEDragDrop([Index As Integer,] Data As DataObject, _
Effect As Long, Button As Integer, Shift As Integer, X As Single, _
Y As Single)
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CheckBox, CommandButton, CoolBar, DataList, DateTimePicker, DBCombo, DBList,
DirListBox, FileListBox, FlatScrollBar, Frame, Form, Grid, Image, ImageCombo, ListBox,
ListView, MaskEdBox, MDIForm, MMControl, MSChart, MSFlexGrid, MSHFlexGrid, OLE, Opti-
onButton, PictureBox, ProgressBar, PropertyPage, RichTextBox, Slider, SSTab, StatusBar,
TabStrip, TextBox, TreeView, ToolBar, UpDown, UserControl, UserDocument

242
OLEDragDrop- Ereignis

Beschreibung

Bes c hreibung
...................................................
Das OLEDragDrop-Ereignis bedeutet der Zielkomponente einer OLE-Drag&Drop-Operation,
dass der Benutzer den Inhalt abgelegt hat und die gewählte Operation ausführen will.
Der Parameter Effect ist ein von der Quellkomponente in Antwort auf OLEStartDrag oder OLE-
GiveFeedback gesetzter Bitvektor, der ausdrückt, welche Operationen diese unterstützt. Der
Aufzählungstyp OLEDropEffectConstants definiert eine Reihe von Konstanten für die einzelnen
Operationen: vbDropEffectNone (0) steht für »keine Operation«, vbDropEffectCopy (1) für
»Kopieroperation« und vbDropEffectMove (2) für »Verschiebeoperation«.
Button ist gleichfalls ein Bitvektor, der den Zustand der Maustasten zum Zeitpunkt des Ereig-
nisses wiedergibt. Der Aufzählungstyp MouseButtonConstants definiert dafür die Maskenkon-

Standardereignisse
stanten vbLeftButton (1), vbRightButton (2) und vbMiddleButton (4).
Auch Shift ist ein Bitvektor, der ausdrückt, welche Funktionstasten der Benutzer zum Zeit-
punkt des Ereignisses gedrückt hält. Der Aufzählungstyp ShiftConstants definiert dafür die
Maskenkonstanten vbShift (1), vbCtrl (2) und vbAlt (4).
X und Y enthalten die aktuelle Position des Mauszeigers zum Zeitpunkt des Ereignisses im Koor-
dinatensystem der Zielkomponente.
Der Parameter Data verweist auf ein Objekt vom Typ DataObject, das als Container für den zu
übermittelnden Inhalt fungiert und Informationen über die unterstützten Inhaltsformate bereit-
stellt.
Anwendung

Anwendung
...................................................
Bevor eine Zielkomponente mit der Ausführung einer OLE-Drag&Drop-Operation beginnen
kann, ist eine genauere Analyse der Situation erforderlich. Erstens gilt es, anhand des Zustands
der Funktions- und Maustasten (Shift und Button) herauszufinden, welche Operation der
Benutzer ausführen will. Zweitens ist zu klären, ob die Quellkomponente diese Operation auch
unterstützt (Effect). Drittens empfiehlt sich eine Analyse des Datenformats (Data.GetFormat), in
dem der übermittelte Inhalt vorliegt – das ist zwar kein Muss, erleichtert aber die Sache, wenn
die Zielkomponente mit mehreren Datenformaten zurechtkommt oder das angebotene Format
nicht unterstützt. Die folgende Tabelle gibt einen Überblick über die von Visual Basic unter-
stützten (teils auch automatisch erkannten) OLE-Formate und die dafür vom Aufzählungstyp
ClipBoardConstants definierten Konstanten.

Formatkonstante Beschreibung des Formats


vbCFText (1) Data enthält Zeichenfolge im Format TXT
vbCFBitmap (2) Data enthält Bitmap im Format BMP
vbCFMetafile (3) Data enthält Grafik im Zwischendateiformat WMF
vbCFEMetafile (14) Data enthält Grafik im erweiterten Zwischendateiformat EMF
vbCFDIB (8) Data enthält geräteunabhängige Bitmap im DIB-Format
vbCFPalette (9) Data enthält Palette im Format PAL
vbCFFiles (15) Data enthält Files-Auflistung
vbCFRTF (-16639) Data enthält Zeichenfolge im RTF-Format
Standardmäßige Datenformate für Inhalte eines DataObject- Objekts

Vom Prinzip her lassen sich auch eigene Formate in einer OLE-Operation übermitteln (mehr
zur Vorgehensweise im Abschnitt »OLE-Drag&Drop«, S. 501, des Praxisteils).

243
Standardereignisse

Wenn die Operation und das Format geklärt sind, kann der Zugriff auf den Inhalt mittels Get-
Data erfolgen. Hat die Quellkomponente das spezifizierte Format nur angemeldet, ohne einen
Inhalt dafür bereitzustellen – der Aufruf dafür sieht so aus:
Data.SetData , Format

stößt der GetData-Aufruf für das Format implizit ein OLESetData-Ereignis aufseiten der Quell-
komponente an, damit diese den Inhalt bereitstellen kann. GetData löst regulär den Laufzeitfeh-
ler 461 aus, wenn die Quellkomponente das durch den Parameter spezifizierte Format zwar
angeblich unterstützt, aber letztlich keinen Inhalt dafür bereitstellen kann.
Wenn der Inhalt erfolgreich entgegengenommen werden konnte, sollte die Zielkomponente der
Quellkomponente über den Parameter Effect die ausgeführte Operation »mitteilen«. Die Mit-
Standardereignisse

teilung erreicht die Quellkomponente schließlich in Form des OLECompleteDrag-Ereignisses, das


unmittelbar auf OLEDragDrop folgt.
Hinweis

Hinweis
...................................................
Manche Steuerelemente deklarieren für den Data-Parameter eine eigene Variante des Datentyps
DataObject. Am Umgang mit dem Parameter ändert das nichts.
Tipp

Tipp
...................................................
Da die Analyse des Maus- und Funktionstastenstatus auch bei der Behandlung des OLEDragOver-
Ereignisses zu gebrauchen ist, empfiehlt es sich, die gesamte Logik dafür in eine eigene Prozedur
zu packen.
Beispiel

Beis piel
...................................................
Das folgende kleine Programm gibt den Inhalt einer Textdatei aus, die aus einem Fenster des
Windows Explorer auf das Formular gezogen wird:
Private Sub Form_Load()
OLEDropMode = vbOLEDropManual
AutoRedraw = True
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, x As Single, Y As Single)
Dim fs As Object
Dim DOF As DataObjectFiles
If (Effect And vbDropEffectCopy > 0) And Data.GetFormat(vbCFFiles) _
Then
Set DOF = Data.Files
If UCase(Right(DOF(1), 4)) = ".TXT" Then
Set fs = CreateObject("Scripting.FileSystemobject")
On Error Resume Next ' Falls Datei inzwischen unbekannt ...
Print fs.OpenTextfile(DOF(1)).ReadAll ' Datei en bloc ausgeben
End If
Effect = vbDropEffectCopy
Else
Effect = vbDropEffectNone
End If
End Sub

244
OLEDragOver- Ereignis

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLECompleteDrag, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLEDragOver- Ereignis
Private Sub Form_OLEDragOver(Data As DataObject, _
Effect As Long, Button As Integer, Shift As Integer, X As Single, _

Standardereignisse
Y As Single, State As Integer)
Private Sub Objekt_OLEDragOver([Index As Integer,] Data As DataObject, _
Effect As Long, Button As Integer, Shift As Integer, X As Single, _
Y As Single, State As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CheckBox, CommandButton, CoolBar, DataList, DateTimePicker, DBCombo, DBList,
DirListBox, FileListBox, FlatScrollBar, Frame, Form, Grid, Image, ImageCombo, ListBox,
ListView, MaskEdBox, MDIForm, MMControl, MSChart, MSFlexGrid, MSHFlexGrid, OLE, Opti-
onButton, PictureBox, ProgressBar, PropertyPage, RichTextBox, Slider, SSTab, StatusBar,
TabStrip, TextBox, TreeView, ToolBar, UpDown, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das OLEDragOver-Ereignis bedeutet einer Komponente, dass sie als mögliches Ziel einer OLE-
Drag&Drop-Operation in Frage kommt oder nicht mehr in Frage kommt. Ursächlich für das
Ereignis ist, dass der Mauscursor im Verlauf einer OLE-Drag&Drop-Operation in den Fenster-
bereich der Komponente eintritt, darin verschoben wird oder den Fensterbereich verlässt.
Der Parameter Effect ist ein von der Quellkomponente in Antwort auf OLEStartDrag oder OLE-
GiveFeedback gesetzter Bitvektor, der ausdrückt, welche Operationen diese unterstützt. Der
Aufzählungstyp OLEDropEffectConstants definiert eine Reihe von Konstanten für die einzelnen
Operationen: vbDropEffectNone (0) steht für »keine Operation«, vbDropEffectCopy (1) für
»Kopieroperation« und vbDropEffectMove (2) für »Verschiebeoperation«.
Button ist gleichfalls ein Bitvektor, der den Zustand der Maustasten zum Zeitpunkt des Ereig-
nisses wiedergibt. Der Aufzählungstyp MouseButtonConstants definiert dafür die Maskenkon-
stanten vbLeftButton (1), vbRightButton (2) und vbMiddleButton (4).
Auch Shift ist ein Bitvektor, der besagt, welche Funktionstasten der Benutzer zum Zeitpunkt
des Ereignisses gedrückt hält. Der Aufzählungstyp ShiftConstants definiert dafür die Masken-
konstanten vbShift (1), vbCtrl (2) und vbAlt (4).
X und Y enthalten die aktuelle Position des Mauszeigers zum Zeitpunkt des Ereignisses im Koor-
dinatensystem der Zielkomponente.
Der Parameter Data verweist auf ein Objekt vom Typ DataObject, das als Container für den zu
übermittelnden Inhalt fungiert und Informationen über die unterstützten Inhaltsformate bereit-
stellt.
State zeigt an, dass die Maus: den Bereich der Komponente eben erst betreten hat (vbEnter);
ihre Position innerhalb des Bereichs verändert hat (vbOver); den Bereich verlässt (vbLeave). Im
letzten Fall haben die Parameter X und Y den Wert 0.

245
Standardereignisse

Anwendung

Anwendung
...................................................
Die Aufgabe bei der Behandlung des OLEDragOver-Ereignisses besteht darin, eine genauere Ana-
lyse der Situation vorzunehmen und der Quellkomponente über den Wert des ByRef-Parameters
Effect mitzuteilen, welche der im Angebot stehenden Operationen der Benutzer voraussichtlich
ausführen wird. (Die Quellkomponente bekommt das Ergebnis mit dem unmittelbar folgenden
OLEGiveFeedback-Ereignis zugestellt.) Die Analyse umfasst: erstens die Zustände der Funktions-
und Maustasten (Shift und Button), über die der Benutzer die Operation auswählt; zweitens die
von der Quellkomponente unterstützten Operationen (Effect); drittens das Datenformat des
Inhalts (Data.GetFormat). Eine Aufstellung der Datenformate finden Sie im Abschnitt
»OLEDragDrop-Ereignis«.
Standardereignisse

In besonderen Fällen wird auch eine Auswertung des State-Parameters nötig sein, beispiels-
weise wenn die Komponente das Betreten und Verlassen ihres Bereichs durch die Maus wie ein
Hot-spot (lies: über eine Veränderung der eigenen Darstellung) anzeigen soll.
Hinweis

Hinweis
...................................................
Manche Steuerelemente deklarieren für den Data-Parameter eine eigene Variante des Datentyps
DataObject. Am Umgang mit dem Wert selbst ändert das nichts.
Warnung

Wa rnung
...................................................
Eine Auswertung des Inhalts sollte auf dieses Ereignis hin tunlichst unterbleiben, da insbeson-
dere bei späterer Bereitstellung des Inhalts im Rahmen von OLESetData der Aufwand beträcht-
lich sein kann und das System unnötig belastet – schließlich kommt ein OLEDragOver-Ereignis
selten allein.
Tipp

Tipp
...................................................
Nachdem die Analyse des Maus- und Funktionstastenstatus auch bei der Behandlung des OLE-
DragDrop-Ereignisses zu gebrauchen ist, empfiehlt es sich, die gesamte Logik dafür in eine eigene
Prozedur zu packen.
Beispiel

Beis piel
...................................................
Private Sub Form_OLEDragOver(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, x As Single, Y As Single, _
State As Integer)
' Stimmt das Datenformat?
If Not (Data.GetFormat(vbCFBitmap) Or Data.GetFormat(vbCFDIB)) Then
Effect = vbDropEffectNone ' leider nicht
Exit Sub
End If
' Hotspot-Darstellung
If State = vbEnter Then InvertiereDarstellung(1)
If State = vbLeave Then
InvertiereDarstellung(0)
Effect = vbDropEffectNone
Exit Sub
End If
' Kopieren?
If Effect And vbDropEffectCopy > 0 And Shift = 0 Then
Effect = vbDropEffectCopy

246
OLEGiveFeedback- Ereignis

End If
' Verschieben?
If Effect And vbDropEffectMove > 0 And Shift = vbShiftMask Then
Effect = vbDropEffectMove
End If
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLECompleteDrag, OLEDragDrop, OLEGiveFeedback, OLESetData, OLEStartDrag
Verwandte Themen

Standardereignisse
Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLEGiveFeedback- Ereignis
Private Sub Objekt_OLEGiveFeedback(Effect As Long, _
DefaultCursors As Boolean)
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CoolBar, DataList, DateTimePicker, DBCombo, DBList, DirListBox, FileListBox,
FlatScrollBar, Grid, Image, ImageCombo, ListBox, ListView, MaskEdBox, MSChart, MSFlex-
Grid, MSHFlexGrid, OLE, PictureBox, PropertyPage, RichTextBox, SSTab, TabStrip, TextBox,
TreeView, ToolBar, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das OLEGiveFeedback-Ereignis tritt nach jedem OLEDragOver-Ereignis aufseiten der Quellkompo-
nente auf, wenn diese im manuellen Modus (OLEDragMode = vbDragManual) betrieben wird.
Der Parameter Effect ist ein von der Zielkomponente nach Auswertung des Maus- und Funk-
tionstastenstatus sowie gegebenenfalls des Inhaltsformats gesetzter Bitvektor, der die anvisierte
Operation ausdrückt. Der Aufzählungstyp OLEDropEffectConstants definiert eine Reihe von
Konstanten für die einzelnen Operationen: vbDropEffectNone (0) steht für »keine Operation«,
vbDropEffectCopy (1) für »Kopieroperation« und vbDropEffectMove (2) für »Verschiebeopera-
tion«.
DefaultCursors ist ein Ausgabeparameter, den die Quellkomponente auf True setzen kann, um
die über die Eigenschaften MouseIcon und MousePointer des Screen-Objekts spezifizierte Maus-
zeigerform einzustellen.
Anwendung

Anwendung
...................................................
Mit diesem Ereignis erhält die Quellkomponente Gelegenheit, dem Benutzer eine geeignete
Rückmeldung für die von ihm anvisierte Operation zukommen zu lassen. Da Komponenten mit
OLE-Unterstützung standardmäßig für jede der möglichen Operationen eine andere, vom Sys-
tem her bereitgestellte Mauszeigerform anzeigen, lohnt sich der Austausch der Mauszeigerform
meist nur in speziellen Fällen. Eine Behandlung des Ereignisses kann aber auch die Ausgabe
einer kurzen Befehlsbeschreibung in der Statusleiste zum Ziel haben oder gar, bei Verwendung
einer One-Shot-Logik, eine akustische Rückmeldung.
Wenn Sie mit eigenen Mauszeigerformen arbeiten, sollten Sie die alte Mauszeigerform auf jeden
Fall speichern und im Zuge der Behandlung von OLEDragComplete wieder herstellen.

247
Standardereignisse

Beispiel

Beis piel
...................................................
Der folgende Code zeigt, wie man für die unterschiedlichen Operationen eigene Cursorformen
zur Anzeige bringt. Er geht davon aus, dass die Formen in den EffectOperationIcon-Variablen
bereitstehen.
Private Sub File1_OLEGiveFeedback(Effect As Long, _
DefaultCursors As Boolean)
Select Case Effect
Case vbDropEffectCopy ' Kopieren
Set Screen.MouseIcon = EffectCopyIcon ' Eigene Form setzen
Standardereignisse

Case vbDropEffectMove ' Verschieben


Set Screen.MouseIcon = EffectMoveIcon ' Eigene Form setzen
Case vbDropEffectNone ' Operation nicht möglich
Set Screen.MouseIcon = EffectNoneIcon ' Eigene Form setzen
Case Else
DefaultCursors = True
End Select
DefaultCursors = False ' Eigene Form verwenden
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLECompleteDrag, OLEDragDrop, OLEDragOver, OLESetData, OLEStartDrag
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLESetData- Ereignis
Private Sub Objekt_OLESetData(Data As DataObject, DataFormat As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CoolBar, DataList, DateTimePicker, DBCombo, DBList, DirListBox, FileListBox,
FlatScrollBar, Grid, Image, ImageCombo, ListBox, ListView, MaskEdBox, MSChart, MSFlex-
Grid, MSHFlexGrid, OLE, PictureBox, PropertyPage, RichTextBox, SSTab, TabStrip, TextBox,
TreeView, ToolBar, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das OLESetData-Ereignis fordert die Quellkomponente einer OLE-Drag&Drop-Operation auf,
den Inhalt in dem Format DataFormat bereitzustellen. Voraussetzung für das Auftreten des
Ereignisses ist allerdings, dass die Quellkomponente das Format zuvor durch einen SetData-
Aufruf ohne Angabe eines Inhalts (Value) gesetzt hat.
Anwendung

Anwendung
...................................................
Vater dieses Ereignisses ist die Strategie der »späten Bereitstellung« von OLE-Inhalten. Diese
Strategie verfolgt das Ziel, den Ressourcenbedarf für eine OLE-Operation so gering wie mög-
lich zu halten. Würde man umfangreiche Inhalte sozusagen »in vorauseilendem Gehorsam«
bereits zu Beginn einer OLE-Drag&Drop-Operation, also auf das OLEDragStart-Ereignis hin, in
allen unterstützten Formaten bereitstellen, wäre das mitunter mit einem erheblichen Speicherbe-
darf verbunden. Da ist es natürlich weitaus sinnvoller, den Inhalt erst dann in einem spezifi-
schen Format bereitzustellen, wenn er in diesem Format tatsächlich benötigt wird.

248
OLESetData- Ereignis

Eine Aufstellung der von Visual Basic für die verschiedenen ActiveX-Steuerelemente direkt
unterstützten Standardformate finden Sie im Abschnitt »OLEDragDrop-Ereignis«. Sie haben aber
auch die Möglichkeit, eigene Formate in OLE-Operationen zu verwenden. Einzelheiten zur
Vorgehensweise entnehmen Sie dem Abschnitt »OLE-Drag&Drop«, S. 501, des Praxisteils.
Warnung

Wa rnung
...................................................
Ein GetData-Aufruf löst bei der Zielkomponente regulär den Laufzeitfehler 461 aus, wenn die
Quellkomponente das spezifizierte Format zwar angeblich unterstützt, aber letztlich keinen
Inhalt dafür bereitstellt.
Beispiel

Standardereignisse
Beis piel
...................................................
Das folgende kleine Programm demonstriert die »späte Bereitstellung« sowie die Abfolge der
Ereignisse. Das verwendete Formular enthält ein Textfeld, dessen Inhalt sich in das Formular
ziehen lässt, dort jedoch in umgekehrter Zeichenfolge ankommt.

Das Textfeld arbeitet mit später Bereitstellung und dreht die Zeichenfolge um

Private Sub Form_Load()


Text1.OLEDragMode = vbOLEDragAutomatic
OLEDropMode = vbOLEDropManual
AutoRedraw = True
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single)
Print "Form_OLEDragDrop"
Print Data.GetData(vbCFText)
End Sub

Private Sub Text1_OLESetData(Data As DataObject, DataFormat As Integer)


Print "Text1_OLESetData"
Data.SetData StrReverse(Text1), vbCFText
End Sub

Private Sub Text1_OLEStartDrag(Data As DataObject, _


AllowedEffects As Long)
Print "Text1_OLEStartDrag"
Data.SetData , vbCFText ' Inhalt wird später bereitgestellt
End Sub

249
Standardereignisse

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLEStartDrag
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLEStartDrag- Ereignis
Sub Objekt_OLEStartDrag(Data As DataObject, AllowedEffects As Long)
Standardereignisse

Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CoolBar, DataList, DateTimePicker, DBCombo, DBList, DirListBox, FileListBox,
FlatScrollBar, Grid, Image, ImageCombo, ListBox, ListView, MaskEdBox, MSChart, MSFlex-
Grid, MSHFlexGrid, OLE, PictureBox, PropertyPage, RichTextBox, SSTab, TabStrip, TextBox,
TreeView, ToolBar, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das OLEStartDrag-Ereignis tritt als erstes Ereignis gleich zu Anfang einer OLE-Drag&Drop-
Operation auf. Es informiert die Quellkomponente über den Beginn der Operation und gibt ihr
Gelegenheit, die unterstützten Operationen sowie Inhalte und Formate zu setzen.
Der Parameter Data verweist auf ein Objekt vom Typ DataObject, das als Container für die zu
übermittelnden Inhalte und die dazugehörigen Formatinformationen fungiert.
Der Ausgabeparameter AllowedEffects kommt bei der Zielkomponente als Effect-Parameter
an und wird dort als Bitvektor interpretiert, dessen gesetzte Bits die möglichen Operationen
anzeigen. Der Aufzählungstyp OLEDropEffectConstants definiert eine Reihe von Konstanten
dafür: vbDropEffectNone (0) steht für »keine Operation«, vbDropEffectCopy (1) für »Kopierope-
ration« und vbDropEffectMove (2) für »Verschiebeoperation«.
Anwendung

Anwendung
...................................................
Die auf OLE basierende Drag&Drop-Operation ermöglicht den dokumentenorientierten Aus-
tausch von Daten zwischen einer Quellkomponente und einer Zielkomponente. Medium des
Austauschs ist aus der Sicht von Visual Basic das DataObject-Objekt, ein im System verankertes
Containerobjekt, dessen Dienste allen OLE-tauglichen Anwendungen für den anwendungsüber-
greifenden, aber auch -internen Transport von Daten zur Verfügung stehen. Grundlegender
Gedanke bei dieser Art von Kommunikation ist, dass die Daten in einem anwendungsunabhän-
gigen Format gehalten sind. Damit kann eine Komponente jederzeit Inhalte von einer anderen
Komponente entgegennehmen, sofern sich beide auf ein gemeinsames Format »einigen« kön-
nen.
Für die wichtigsten Standardformate definiert der Aufzählungstyp ClipBoardConstants Format-
konstanten:

Formatkonstante Beschreibung des Formats


vbCFText (1) Data enthält Zeichenfolge im Format TXT
vbCFBitmap (2) Data enthält Bitmap im Format BMP
vbCFMetafile (3) Data enthält Grafik im Zwischendateiformat WMF
vbCFEMetafile (14) Data enthält Grafik im erweiterten Zwischendateiformat EMF
Standardmäßige Datenformate eines DataObject-Objekts

250
OLEStartDrag- Ereignis

Formatkonstante Beschreibung des Formats


vbCFDIB (8) Data enthält geräteunabhängige Bitmap im DIB-Format
vbCFPalette (9) Data enthält Palette im Format PAL
vbCFFiles (15) Data enthält Files-Auflistung
vbCFRTF (-16639) Data enthält Zeichenfolge im RTF-Format
Standardmäßige Datenformate eines DataObject-Objekts

Das Containerobjekt ist speziell darauf eingerichtet, Inhalte in verschiedenen Formaten entge-

Standardereignisse
gennehmen zu können. Da die Einhaltung der Formate für die sichere Kommunikation eine
wichtige Rolle spielt, sind die Formate mit einer eindeutigen Nummer (Handle) assoziiert und
in der Systemregistrierung niedergelegt. Damit ist es einer Anwendung prinzipiell möglich, die
Nummer für ein registriertes Format in Erfahrung zu bringen und auch eigene Formate zu regis-
trieren. Allerdings bietet Visual Basic dafür keine Funktionen an, so dass man in diesem Fall die
entsprechenden Routinen der Win32-API direkt aufrufen muss (RegisterClipBoardFormat und
GetClipFormatName). Vom Prinzip her lassen sich Inhalte auch in nicht registrierten Formaten
übermitteln, sofern deren Nummern auf beiden Seiten bekannt sind. Das birgt allerdings
gewisse Gefahren, wenn unter einer verwendeten Nummer ein anderes Format registriert ist.
Eine Quellkomponente reagiert auf das OLEStartDrag-Ereignis, indem sie den AllowedEffects-
Parameter mit einem Bitvektor versorgt und für jedes unterstützte Format die SetData-Methode
des DataObject-Objekts aufruft. Falls der Speicherbedarf für die zugehörigen Inhalte erträglich
ist, spricht nichts dagegen, diese bereits in dieser Phase der SetData-Methode über den Value-
Parameter mitzugeben. Ab einer bestimmten Datenmenge empfiehlt es sich jedoch, mit der
Bekanntgabe des Inhalts auf das OLESetData-Ereignis zu warten und die SetData-Methode vor-
erst nur mit einer Formatkonstanten zu versorgen (späte Bereitstellung).
Data.SetData , vbCFBitmap

Im automatischen Modus (OLEDragMode = vbOLEDragAutomatic) überträgt eine Steuerelement-


komponente ihren Standardwert noch vor dem OLEStartDrag-Ereignis in das Containerobjekt –
im manuellen Modus passiert das nicht, und das ist oft auch erwünscht. Um ein DataObject-
Objekt in einen definierten Zustand zu versetzen, rufen Sie die Clear-Methode auf. Sie löscht
alle Formatinformationen und Inhalte. Unterbleibt der SetData-Aufruf, kann Visual Basic von
sich aus zwischen den Formaten BMP, WMF, EMF und TXT unterscheiden, mehr jedoch nicht.
Alle anderen Formate müssen explizit gesetzt werden, damit kein Laufzeitfehler aufseiten der
Zielkomponente auftritt.
Bei Verwendung eines Formats, das nicht zu den von Visual Basic anerkannten Standardforma-
ten zählt, müssen Sie Inhalte in Form von Byte-Arrays bereitstellen. Außerdem sollte jedes
Array Längeninformationen beinhalten, da der OLE-Mechanismus die Daten ohne Längenan-
gabe in einem »hinreichend großen« Puffer übermittelt, der auch größer sein kann als das Array
– und es in der Regel auch ist.
Beispiel

Beis piel
...................................................
Das folgende Beispielprojekt OLEDragStart ist eine etwas kompliziertere Version des Beispiels
zu OLESetData, wenngleich das Szenario (ohne dass dies eine Rolle spielt) recht einfach gewählt
ist: Der Benutzer kann den Inhalt eines Textfelds mittels OLE-Drag&Drop auf das Formular
verschieben. Quell- und Zielkomponente arbeiten jedoch mit zwei unterschiedlichen Formaten:
zum einen mit dem standardmäßigen Format vbCFText, zum anderen mit dem eigenen Format
»Mein Textformat«.

251
Standardereignisse

Nachdem das Textfeld als Quellkomponente seinen Wert bereits von sich aus im vbCFText-For-
mat in das Containerobjekt einfügt, kann sich die OLEDragStart-Behandlungsroutine darauf
beschränken, das eigene Format zu registrieren und zu setzen. Für die Registrierung ist der Auf-
ruf der Win32-API-Funktion RegisterClipboardFormat notwendig, die das Format mit einer
Nummer identifiziert, wie sie der SetData-Aufruf erwartet. Unglücklicherweise besteht SetData
auf einen Wert vom Typ Integer, während das Add-In API-Viewer für die Funktion den Rück-
gabetyp Long deklariert. Die einfachste Lösung besteht darin, den Rückgabetyp manuell auf
Integer zu ändern, was keinerlei weitere Probleme aufwerfen sollte, da das System Formatkon-
stanten als 16-Bit-Werte behandelt.
Das war die Sicht der Quellkomponente. Die Zielkomponente muss nun ihrerseits bei der
Behandlung von OLEDragDrop die Funktion RegisterClipboardFormat aufrufen (im Allgemeinen
Standardereignisse

werden Quelle und Ziel ja nicht demselben Prozess angehören), um die Nummer des Formats in
Erfahrung zu bringen. Der Rest ist zwar nicht elegant, aber doch geradlinig: Da das DataObject-
Objekt bei eigenen Formaten auf Byte-Arrays besteht, liefert die Methode GetData auch ein sol-
ches, was nicht nur aufseiten der Zielkomponente ein gewisses Geschick bei der Konvertierung
erfordert (das Beispiel verzichtet der Einfachheit halber auf die Einarbeitung einer Längeninfor-
mation und bedient sich für die Konvertierung einer Variant-Variablen).
' Formularmodul: OLEDragStart-Demo
Option Explicit
Private Declare Function RegisterClipboardFormat Lib "user32" Alias _
"RegisterClipboardFormatA" (ByVal lpString As String) As Integer
Private MeinFormat As Integer

Private Sub Form_Load()


OLEDropMode = vbOLEDropManual
Text1.OLEDropMode = vbOLEDragAutomatic
AutoRedraw = True
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As


Integer, X As Single, Y As Single)
' Zuerst im gewöhnlichen Textformat
If Data.GetFormat(vbCFText) Then Print Data.GetData(vbCFText)
' Nun im eigenen Format
If Data.GetFormat(RegisterClipboardFormat("Mein Textformat")) Then
Print Data.GetData(MeinFormat)
End If
End Sub

Private Sub Text1_OLESetData(Data As DataObject, DataFormat As Integer)


Dim Daten As Variant ' Zur einfachen Typ-Konversion
Dim ByteArray() As Byte ' Für eigenes Format bei SetData
If DataFormat = MeinFormat Then ' MeinFormat?
Daten = " " + StrReverse(Text1) ' Daten zuerst in Variant
ByteArray = Daten ' Typkonversion
Data.SetData ByteArray, MeinFormat ' Byte-Array als Inhalt setzen
End If
End Sub

252
Paint- Ereignis

Private Sub Text1_OLEStartDrag(Data As DataObject, AllowedEffects _


As Long)
AllowedEffects = vbDropEffectMove
' Eigenes Format registrieren und setzen
MeinFormat = RegisterClipboardFormat("Mein Textformat")
If MeinFormat Then Data.SetData , MeinFormat
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData

Standardereignisse
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

Paint- Ereignis
Sub Form_Paint()
Sub Objekt_Paint([Index As Integer])
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, PropertyPage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das Paint-Ereignis tritt auf, wenn der Fensterbereich des Objekts teilweise oder vollständig neu
gezeichnet werden muss, weil er (teilweise) verdeckt, unsichtbar oder minimiert war respektive
vergrößert oder explizit durch einen Aufruf der Refresh-Methode für ungültig erklärt wurde.
Voraussetzung für das Ereignis ist aber, dass die AutoRedraw-Eigenschaft den Wert False hat.
Durch Behandlung dieses Ereignisses erhält das Objekt Gelegenheit, seinen Fensterbereich auf-
zufrischen oder – gegebenenfalls mit anderem Inhalt – komplett neu zu zeichnen.
Beim Start eines Formulars herrscht die Ereignisreihenfolge: Load, Resize, Paint, GotFocus usw.
Anwendung

Anwendung
...................................................
Ein Objekt, das auf das Paint-Ereignis reagieren kann, verfügt über die beiden Eigenschaften
AutoRedraw und ClipControls. AutoRedraw hat als Voreinstellung den Wert False und ClipCon-
trols den Wert True. Wird AutoRedraw auf True gesetzt, speichert Visual Basic den Fensterinhalt
des Objekts als Bitmap und restauriert ungültig gewordene Bereiche in eigener Regie, wann
immer dies erforderlich ist. Für die meisten Anwendungsfälle dürfte dies die praktischste Ein-
stellung sein, da man sich als Programmierer eigentlich um nichts kümmern muss und an jeder
beliebigen Stelle Ausgaben vornehmen kann. Wie alle Automatismen hat er aber auch Nach-
teile: Er verzehrt Ressourcen, kostet Zeit und lässt einiges an Flexibilität vermissen.
Die Eigenschaft ClipControls wirkt sich nur aus, wenn AutoRedraw auf False gesetzt ist. Sie
regelt, ob Visual Basic für Steuerelemente Bildausschnitte bei der Restaurierung des Objektbe-
reichs berechnet oder nicht. Ohne diese Berechnung ist die Grafikausgabe schneller, es kann
jedoch zu Ungereimtheiten bei der Anzeige sich überlappender Steuerelemente kommen.
Visual Basic unterscheidet beim Zeichnen eines Objekts drei Ebenen:
1. Die hintere Ebene – in dieser Ebene landet die Bitmap, die über die Picture-Eigenschaft des
Objekts festgelegt ist, über die Print-Methode ausgegebener Text sowie alle Ausgaben der
Grafikmethoden Line, Circle und PSet.

253
Standardereignisse

2. Die mittlere Ebene – in dieser Ebene erscheinen fensterlose Steuerelemente, wie das Bezeich-
nungsfeld (Label), die grafischen Steuerelemente (Shape, Line) sowie alle UserControl-Steuer-
elemente, deren Windowless-Eigenschaft auf True gesetzt wurde.
3. Die obere Ebene – in dieser Ebene erscheinen alle Steuerelemente, denen ein eigenes Fenster
zugeordnet ist. Das sind alle Steuerelemente bis auf die unter 2. genannten.
Die folgende Tabelle gibt einen Überblick über die Wirkung der Eigenschaften AutoRedraw und
ClipControls, wenn die Grafikausgabe innerhalb oder außerhalb der Paint-Behandlung statt-
findet.

AutoRedraw ClipControls Effekt


Standardereignisse

True True Paint-Ereignis bleibt aus und die Grafikausgabe unter-


scheidet drei Ebenen.
True False Beschleunigte Grafikausgabe in drei Ebenen, da keine
Bildausschnitte für Steuerelemente berechnet werden.
Platzierte Steuerelemente sollten sich nicht überlappen.
False True Grafikausgabe findet in drei Ebenen statt, sofern Gra-
(Voreinstellung) (Voreinstellung) fikmethoden ausschließlich innerhalb der Paint-Rou-
tine aufgerufen werden. Beim Aufruf von
Grafikmethoden außerhalb von Paint kann das Ergeb-
nis fehlerhaft sein, da die Abfolge beim Zeichnen der
mittleren Ebene nicht mehr garantiert ist.
False False Die Grafikausgabe findet in drei Ebenen statt. Neu
gezeichnet werden nur Rechteckbereiche, die bis zum
Auftreten des nächsten Paint-Ereignisses für ungültig
erklärt wurden, etwa weil sie verdeckt waren. Beim
Aufruf von Grafikmethoden außerhalb von Paint kann
das Ergebnis fehlerhaft sein, da die Abfolge der Ebenen
nicht mehr garantiert ist.

Warnung

...................................................
Wa rnung
Wenn Sie mit einer Paint-Routine arbeiten, sollten alle expliziten Grafikausgaben innerhalb
dieser Routine erfolgen.
Tipp

...................................................
Tipp
Innerhalb einer Ebene legt die Tabulatorordnung fest, in welcher Reihenfolge überlappende
Steuerelemente einander verdecken. Um eine eigene Reihenfolge festzulegen, können Sie die
ZOrder-Methode der beteiligten Steuerelemente aufrufen, um diese nacheinander an die oberste
Position zu bringen. Der folgende Code aus dem Beispielprojekt Schach1 arbeitet mit einem
Array fensterloser Steuerelemente. Nach jeder Verschiebung einer Figur wird die Reihenfolge
wieder hergestellt:
For i = 31 To 0 Step -1
figur(i).ZOrder (0) ' Steuerelement ganz nach oben
Next i

Wenn Sie den Fensterbereich eines Objekts explizit restaurieren wollen, zum Beispiel nach
einem Resize-Ereignis, sollten Sie die Refresh-Methode aufrufen.

254
Paint- Ereignis

Beispiel

Beis piel
...................................................
Der folgende in zwei Varianten vorgestellte Code zeichnet eine Ellipse, die immer exakt den
Client-Bereich des Formulars ausfüllt. Die erste Variante verlässt sich darauf, dass Visual Basic
den Formularbereich automatisch neu zeichnet, die zweite verwendet eine Paint-Routine.
Ändert man die Größe des Formulars, flackert die Anzeige im ersten Fall ein wenig, im zweiten
Fall jedoch nicht.
' Erste Variante
Private Sub Form_Load()
AutoRedraw = True

Standardereignisse
End Sub

Private Sub Form_Resize()


Dim Radius
If ScaleWidth > ScaleHeight Then
Radius = ScaleWidth / 2
Else
Radius = ScaleHeight / 2
End If
Cls
Circle (ScaleWidth / 2, ScaleHeight / 2), Radius, , , , ScaleHeight / ScaleWidth
End Sub

Die Ellipse füllt das Formular in jeder Größe ganz aus

' Zweite Variante


Private Sub Form_Load()
AutoRedraw = False
End Sub

Private Sub Form_Paint()


Dim Radius
If ScaleWidth > ScaleHeight Then
Radius = ScaleWidth / 2
Else
Radius = ScaleHeight / 2
End If
Cls
Circle (ScaleWidth / 2, ScaleHeight / 2), Radius, , , , ScaleHeight / ScaleWidth
End Sub

255
Standardereignisse

Private Sub Form_Resize()


Refresh
End Sub

QueryUnload- Ereignis
Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
MIDForm_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Standardereignisse

Form, MDIForm
Beschreibung

Bes c hreibung
...................................................
Dieses dem Unload-Ereignis vorangehende Ereignis teilt einem Formular mit, dass es geschlossen
werden soll. Falls die gesamte Anwendung beendet werden soll, schickt Windows dieses Ereig-
nis der Reihe nach an alle geöffneten Formulare. QueryUnload stellt eine Anfrage dar, die ein ein-
zelnes Formular (im Namen aller Formulare) auch ablehnen kann, indem es den Ausgabepara-
meter Cancel auf einen Wert ungleich 0 setzt. MDI-Formulare sehen das Ereignis vor ihren
untergeordneten Formularen (beim Unload-Ereignis ist die Reihenfolge dagegen genau anders-
herum).
Der Parameter UnloadMode liefert den Grund für das Ereignis. Die folgende Tabelle gibt einen
Überblick über die verschiedenen Gründe und die über den Aufzählungstyp QueryUnloadCon-
stants dafür definierten Konstanten.

Konstante Grund
vbFormControlMenu (0) Der Benutzer beendet die Anwendung über das Systemmenü.
vbFormCode (1) Eine Unload-Anweisung wurde für das Formular ausgeführt.
vbAppWindows (2) Windows soll heruntergefahren werden.
vbAppTaskManager (3) Der Task-Manager fordert die Anwendung zum Abbrechen auf.
vbFormMDIForm (4) Das übergeordnete MDI-Formular soll geschlossen werden.
vbFormOwner (5) Das übergeordnete Formular soll geschlossen werden.

Anwendung

Anwendung
...................................................
Eine Anwendung kann dieses Ereignis behandeln, um sicherzustellen, dass alle Operationen in
allen Formularen abgeschlossen sind und alle Daten gespeichert wurden. Andernfalls sollte der
Benutzer die Möglichkeit erhalten, dies nachzuholen.
Beispiel

Beis piel
...................................................
Der folgende Code zeigt die typische Reaktion auf QueryUnload.
Private Textgeändert As Boolean
...
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
If Textgeändert Then
Select Case MsgBox("Datei speichern?", vbExclamation + vbYesNoCancel)
Case vbCancel ' Programmabbruch vereiteln
Cancel = True

256
Resize- Ereignis

Case vbYes ' Datei speichern, dann Unload


mnuDateiSpeichern_Click
Cancel = False
Case vbNo
Cancel = False ' Datei nicht speichern, sofort Unload
End Select
End If
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................

Standardereignisse
Unload

Resize- Ereignis
Sub Form_Resize()
Sub Objekt_Resize([HeightNew As Single, WidthNew As Single])
Betroffene Objekte

Betro ffene Objekte


...................................................
CoolBar, Data, DataReport, Form, MDIForm, OLE, PictureBox, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Das Resize-Ereignis zeigt einem Objekt an, dass sich seine Größe geändert hat. Die Ursache
dafür kann entweder eine entsprechende Benutzeraktion wie »Vergrößern«, »Verkleinern«,
»Maximieren« oder »Wiederherstellen« sein, aber auch die Ausführung einer Anweisung, die
Einfluss auf die Größe oder Sichtbarkeit des Objekts hat.
Für ein Formular tritt das Ereignis erstmals nach dem Load-Ereignis auf, wenn es automatisch
gestartet wurde, oder im Zuge eines Show-Aufrufs, der es sichtbar macht. Ansonsten ist es Sei-
teneffekt, wenn eine der Eigenschaften WindowState, Height, Width einen neuen Wert erhält oder
die Visible-Eigenschaft auf True gesetzt wird.
Die Parameter HeightNew und WidthNew geben die neuen Abmessungen im aktuellen Koordina-
tensystem an.
Anwendung

Anwendung
...................................................
Ein Objekt behandelt dieses Ereignis, um auf Größenänderungen reagieren zu können und sei-
nen Bereich gegebenenfalls neu zu zeichnen oder zu organisieren. Häufig wird in einer Resize-
Routine auch das Koordinatensystem via ScaleHeight, ScaleWidth, ScaleLeft, ScaleTop geän-
dert, um die Grafikausgaben von der Bereichsgröße unabhängig zu machen.
Falls die AutoRedraw-Eigenschaft eines Formulars auf False gesetzt wurde, sollte die Resize-
Routine einen Refresh-Aufruf enthalten, wenn sich das Koordinatensystem geändert hat.
Beispiel

Beis piel
...................................................
Die folgende Resize-Routine reagiert auf Änderungen der Formularabmessungen, indem sie
eine Periode der Sinuskurve ausgibt, die immer genau in den Client-Bereich des Formulars ein-
gepasst ist. Der Einfachheit halber ändert der Code das Koordinatensystem, nicht die Parameter
der Kurve.
Private Sub Form_Resize()
Dim Winkel As Single
Dim Pi As Single
Pi = 4 * Atn(1)

257
Standardereignisse

ScaleHeight = -2 ' Positive Koordinaten oben!


Me.ScaleTop = 1 ' Ursprung in die Mitte
ScaleWidth = 2 * Pi ' reicht für eine volle Sinusperiode
Cls ' Bereich löschen
' Sinuskurve zeichnen
For Winkel = 0 To 2.1 * Pi Step Pi / 30
Line -(Winkel, Sin(Winkel))
Next Winkel
End Sub
Verwandte Themen

Verwandte Them en
...................................................
Standardereignisse

Bildlauf – ein kleiner Betrachter für große Bilder (S. 545); HexView – eine schnelle Textan-
sicht für große Dateien (S. 551)

Terminate- Ereignis
Sub Objekt_Terminate()
Betroffene Objekte

Betro ffene Objekte


...................................................
ClassModule, DataReport, DHTMLPageDesigner, Form, MDIForm, PropertyPage, UserControl,
UserDocument, WebClass
Beschreibung

Bes c hreibung
...................................................
Terminate ist das letzte Ereignis, das ein Objekt ereilt. Es tritt ein, sobald keine Verweise auf das
Objekt mehr existieren, das heißt, wenn das Fenster des Objekts entladen wurde und der Gel-
tungsbereich der letzten Objektvariable, die noch auf das Objekt verwiesen hat, erloschen ist
oder auf den Wert Nothing gesetzt wurde. Für Objekte mit eigenem Fenster folgt das Terminate-
Ereignis unmittelbar auf das Unload-Ereignis, nicht jedoch für Objekte, die von einer auf
ClassModule aufsetzenden Klasse abstammen. Für diese Objekte fungiert Terminate als alleiniger
Destruktor.
Anwendung

Anwendung
...................................................
Die Ereignisse Terminate und Initialize treten beide nur ein einziges Mal auf. Aus diesem
Grund sollte eine Terminate-Routine dazu verwendet werden, genau die Ressourcen wieder frei-
zugeben, die während Initialize angefordert wurden.
Warnungen

Wa rnungen
...................................................
Formularvariablen sollten nicht ohne vorherigen Unload-Aufruf auf Nothing gesetzt werden, da
sie sonst geladen bleiben (und ebenso alle Objekte, die dem Formular untergeordnet sind, das
heißt: alle Steuerelemente sowie gegebenenfalls weitere Formulare).
Terminate tritt nicht auf, wenn ein Formular oder die Instanz einer Klasse aus dem Hauptspei-
cher entfernt, weil die Anwendung nicht ordnungsgemäß beendet wurde, oder wenn die
Anwendung durch eine End-Anweisung beendet wird, ohne dass zuvor alle bestehenden Instan-
zen der Klasse oder des Formulars aus dem Hauptspeicher entfernt wurden.
Beispiel

Beis piel
...................................................
Private Sub Form_Terminate
Redim MeinArray(0) ' Arrayelemente freigeben
End Sub

258
Unload- Ereignis

Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
Initialize, Load, Unload

Unload- Ereignis
Sub Objekt_UnLoad(Cancel As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, MDIForm, PropertyPage

Standardereignisse
Beschreibung

Bes c hreibung
...................................................
Das Unload-Ereignis tritt auf, wenn ein Formularobjekt sein Fenster sowie alle darin enthaltenen
Steuerelemente freigibt bzw. entlädt – das Objekt selbst bleibt bestehen. Ursache des Ereignisses
kann eine Unload-Anweisung sein, aber auch eine Benutzeraktion, die das Schließen des Fensters
oder die Beendigung des gesamten Programms zum Ziel hat – beispielsweise ein Klick auf die
Schaltfläche SCHLIEßEN in der Titelleiste des Fensters oder der Aufruf eines entsprechenden
Menübefehls.
Der Ausgabeparameter Cancel lässt sich auf einen Wert ungleich 0 oder auf True setzen, um das
Entladen zu verhindern. Ein Herunterfahren von Windows wird dadurch aber nicht abgebro-
chen, das kann nur bei der Behandlung von QueryUnload geschehen.
Anwendung

Anwendung
...................................................
Erhält ein Objekt das Unload-Ereignis, heißt das noch lange nicht, dass es selbst auch abgebaut
wird. Das ist erst der Fall, wenn ein Terminate-Ereignis folgt. Es zeugt sogar von gutem Pro-
grammierstil, Formulare zwischendurch mit der Unload-Anweisung zu entladen, wenn sie
gerade nicht benötigt werden. Das Objekt selbst bleibt dabei erhalten, und das Fenster lässt sich
jederzeit über einen Load- oder besser Show-Aufruf erneut laden und zur Anzeige bringen, ja, es
reicht auch ein Zugriff auf die Visible-Eigenschaft. Das spart Ressourcen, kann aber zu Verzö-
gerungen bei der erneuten Anzeige des Formulars führen, weil das Fenster sowie alle darauf
befindlichen Steuerelemente neu initialisiert werden müssen.
Warnungen

Wa rnungen
...................................................
Visual Basic entlädt das Fenster eines Formularobjekts nicht automatisch, wenn die letzte Refe-
renz auf das Objekt auf Nothing gesetzt wird. Das Entladen muss explizit durch den Benutzer
oder durch den Programmcode geschehen.
Erfolgt für ein entladenes Formularfenster ein Hide-Aufruf, bringt dieser – entgegen aller Logik
– das Fenster zur Anzeige.
Tipp

Tipp
...................................................
Um ein Fenster verschwinden zu lassen, können Sie auch die Hide-Methode des Formular-
objekts ausführen. In diesem Fall wird das Fenster zwar unsichtbar, bleibt aber geladen. Das
Fenster selbst ist dann inaktiv und kann insbesondere den Fokus nicht erhalten. Um das Fenster
wieder sichtbar zu machen, kann die Visible-Eigenschaft auf True gesetzt werden oder ein Show-
Aufruf erfolgen.
Beispiel

Beis piel
...................................................
Private Sub Form_Unload(Cancel As Integer)
If vbYes = MsgBox("Sind Sie sicher?", vbYesNo, "Fenster schließen") _

259
Standardereignisse

Then
Cancel = 0
Else
Cancel = 1
End If
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
Initialize, Load, Terminate
Standardereignisse

Validate- Ereignis
Sub Objekt_Validate(Cancel As Boolean)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, Data, DataGrid, DataList, DataRe-
peater, DateTimePicker, DBCombo, DBGrid, DBList, DirListBox, DriveListBox, FileListBox,
HScrollBar, ListBox, ListView, MaskEdBox, MMControl, MonthView, MSChart, MSFlexGrid,
MSHFlexGrid, MSTab, OptionButton, PictureBox, PropertyPage, RemoteData, RichTextBox,
Slider, TabStrip, TextBox, TreeView, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Das unmittelbar vor LostFocus eintreffende Validate-Ereignis kündigt einem Steuerelement an,
dass es den Fokus abgeben soll. Setzt das Steuerelement den Ausgabeparameter Cancel auf True,
kann es die Weitergabe des Fokus unterbinden – etwa, wenn sein aktueller Wert gegen eine
Gültigkeitsregel verstößt. Voraussetzung für das Auftreten dieses Ereignisses ist allerdings, dass
die CausesValidation-Eigenschaft sowohl des betroffenen Steuerelements als auch des Steuerele-
ments, auf das der Fokus übergehen soll, den Wert True hat.
Anwendung

Anwendung
...................................................
Die normale Reaktion auf das Validate-Ereignis ist eine Gültigkeitsprüfung des Werts bzw. des
aktuellen Zustands des Steuerelements. Stellt sich der Wert als »ungültig« heraus, ist kein
besonderes Verhalten vorgeschrieben: Die Behandlungsroutine kann eine belehrende Fehlermel-
dung ausgeben und die Fokusabgabe verweigern, sie kann aber auch den Wert schlichtweg kor-
rigieren und der Weitergabe des Fokus nichts in den Weg legen.
Falls auch nur ein Steuerelement auf einem Formular eine Gültigkeitsprüfung durchführt, wird
die CausesValidation-Eigenschaft der anderen als Empfänger des Fokus in Frage kommenden
Steuerelemente im Allgemeinen auf True gesetzt sein. In besonderen Fällen kann es jedoch Vor-
teile bringen, die CausesValidation-Eigenschaft bestimmter Steuerelemente – etwa einer ABBRE-
CHEN- oder HILFE-Schaltfläche – auf False zu setzen. Der Benutzer kann dann den Fokus auf
diese Steuerelemente verschieben, ohne das Validate-Ereignis des verlassenen Steuerelements
auszulösen. Sobald der Fokus jedoch auf ein Steuerelement weitergehen soll, dessen CausesVa-
lidation-Eigenschaft auf True gesetzt wurde, tritt zunächst einmal das Validate-Ereignis des
ursprünglichen Steuerelements auf. Beachten Sie aber, dass dem Benutzer auf diese Weise gege-
benenfalls das Schließen des Formulars möglich werden kann, ohne dass die Gültigkeitsprüfung
des zuletzt verlassenen Steuerelements zum Zuge kommt. Die Unload-Behandlung für das For-
mular sollte daher einen ValidateControls-Aufruf enthalten.
Die Behandlung des Validate-Ereignisses ist angezeigt, wenn der Benutzer ein Datenfeld ausfül-
len muss oder wenn er nur bestimmte Daten in ein Datenfeld eintragen darf.

260
Global- Objekt

Warnung

Wa rnung
...................................................
Vom Prinzip her könnte man auch versuchen, eine Gültigkeitsprüfung im Zuge von LostFocus
zu implementieren. Das kann aber Probleme verursachen, da das Steuerelement zu dem Zeit-
punkt, an dem das Ereignis auftritt, den Fokus bereits abgegeben hat. Es wäre also ein SetFo-
cus-Aufruf erforderlich, der aber wiederum dem neuen Inhaber des Fokus diesen sofort wieder
entreißt und ihm das LostFocus-Ereignis beschert. Falls dieses Steuerelement gleichfalls nicht
bereit ist, den Fokus herzugeben und seinerseits einen SetFocus-Aufruf durchführt, kommt es zu
einer Ereignisflut, die das System destabilisieren kann.
Beispiel

Beis piel
...................................................

Global- Objekt
Private Sub Text1_Validate(Cancel As Boolean)
Cancel = Not IsDate(Text1)
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
LostFocus, GotFocus

Global- Objekt
Die Einbettung der traditionellen Standardfunktionen von Basic in das inzwischen vollkommen
objektorientierte Programmiermodell von Visual Basic geschieht formal gesehen über ein Glo-
bal-Objekt, das den übergeordneten Kontext für alle Module einer Anwendung bereitstellt.
Damit sind die in der Klasse Global definierten Methoden größtenteils »alte Bekannte«, die
(nach wie vor) den operativen Kern der Sprache selbst ausmachen. Mit den Eigenschaften des
Global-Objekts verhält es sich anders; sie sind ihrerseits Objekte und verkapseln die Standard-
umgebung, in die jedes Visual-Basic-Programm sozusagen beim Start »hineingeboren« wird.
Diese Objekte müssen (und können) nicht eigens instanziiert werden, da sie von Visual Basic
automatisch im Verlauf des Programmstarts angelegt werden und ihre Bezeichner global
bekannt sind.
Eine Qualifikation mit dem Bezeichner »Global« ist weder nötig noch möglich.

Eigens c ha ften
...................................................
App, Calendar, ClipBoard, Date, Forms, Now, Printer, Printers, Screen, Time, Timer
Die folgende Tabelle gibt einen Überblick über die nicht an anderer Stelle vorgestellten globalen
Eigenschaften:

Eigenschaft Beschreibung
App App-Objekt, das die aktuelle Laufzeitinstanz repräsentiert
Calendar Integerwert, der den Kalender für alle Datumsfunktionen festlegt. Voreinstel-
lung ist vbCalGreg (0) für den Gregorianischen Kalender. Alternative ist der
Hijri-Kalender: vbCalHijri (1)
ClipBoard ClipBoard-Objekt, das die OLE-Zwischenablage und ihre Operationen reprä-
sentiert
Err ErrObject-Objekt, das den Fehlerkontext der Anwendung repräsentiert

261
Global- Objekt

Eigenschaft Beschreibung
Forms Object-Auflistung aller von der aktuellen Laufzeitinstanz geladenen Formular-
instanzen
Printer Printer-Objekt, das den aktuellen Standarddrucker repräsentiert
Printers Object-Auflistung aller auf dem System installierten Drucker
Screen Screen-Objekt, das die Grafikanzeige auf dem Bildschirm repräsentiert

Methoden
Methoden

...................................................
Global- Objekt

Abs, AppActivate, Asc, AscB, AscW, Atn, Beep, CallByName, CBool, CByte, CCur, CDate,
CDbl, CDec, ChDir, ChDrive, Choose, Chr, ChrB, ChrW, CInt, CLng, Command, Cos, CreateOb-
ject, CSng, CStr, CurDir, CVar, CVDate, CVErr, DateAdd, DateDiff, DatePart, DateSerial,
DateValue, Day, DDB, DeleteSetting, Dir, DoEvents, Environ, EOF, Err, Error, Exp, File-
Attr, FileCopy, FileDateTime, FileLen, Filter, Fix, Format, FormatCurrency, FormatDa-
teTime, FormatNumber, FormatPercent, FreeFile, FV, GetAllSettings, GetAttr, GetObject,
GetSetting, Hex, Hour, IIF, InputBox, InStr, InStrB, InStrRev, Int, IPmt, IRR, IsArray,
IsDate, IsEmpty, IsError, IsMissing, IsNull, IsNumeric, IsObject, Join, Kill, LCase,
Left, LeftB, Len, Load, LoadPicture, LoadResData, LoadResPicture, LoadResString, Loc,
LOF, Log, LTrim, Mid, MidB, Minute, MIRR, MkDir, Month, MonthName, MsgBox, NPer, NPV,
Oct, Partition, Pmt, PPmt, PV, QBColor, Randomize, Rate, Replace, Reset, RGB, Right,
RightB, RmDir, Rnd, Round, RTrim, SavePicture, SaveSetting, Second, Seek, SendKeys,
SetAttr, Sgn, Shell, Sin, SLN, Space, Split, Sqr, Str, StrComp, StrConv, String, StrRe-
verse, Switch, SYD, Tan, TimeSerial, TimeValue, Trim, TypeName, UCase, Unload, Val, Var-
Type, Weekday, WeekdayName, Year
Die folgende Tabelle gibt einen Überblick über die nicht an anderer Stelle vorgestellten Metho-
den. Die Prototypen lauten:
Function CallByName(Object As Object, ProcName As String, _
CallType As VbCallType, Args()) As Variant
Sub CallByName(Object As Object, ProcName As String, _
CallType As VbCallType, Args())
Function Command() As String
Function CreateObject(Class As String, [ServerName As String]) As Object
Sub DeleteSetting(AppName As String, [Section As String], _
[Key As String])
Sub DoEvents()
Function GetAllSettings(AppName As String, Section As String) _
As String()()
Function GetObject([PathName As String], _
[AnwName.ObjektTyp As String]) As Object
Function GetSetting(AppName As String, Section As String, _
Key As String, [Default]) As String
Function InputBox(Prompt, Title, Default, XPos, YPos, HelpFile, _
Context) As String

262
Global- Objekt

Function Load(Object As Object)


Function LoadPicture([FileName], [Size], [ColorDepth], [X], [Y]) _
As Picture
Function LoadResData(Id, ResType As Integer) As Byte()
Function LoadResPicture(Id, ResType As Integer) As Picture
Function LoadResString(Id As Long) As String
Function QBColor(Color As Integer) As Long

Global- Objekt
Function RGB(Red As Integer, Green As Integer, Blue As Integer) As Long
Sub SavePicture(Picture As Picture, FileName As String)
Sub SaveSetting(AppName As String, Section As String, _
Key As String, Setting As String)
Sub SendKeys(String As String, [Wait As Boolean])
Sub Unload(Object)

Methode Beschreibung
CallByName Ermöglicht den Aufruf einer Methode oder Eigenschaft ProcName eines
zur Laufzeit gebundenen Automatisierungsobjekts Object unter Angabe
des Bezeichners ElementName als Zeichenfolge, gefolgt von der Art des
Elements (vbGet, vbLet, vbMethod, vbSet) und der Parameterliste Params,
die auch als Variant-Array übergeben werden kann. Der Aufruf kann in
Funktions- oder Prozedurform erfolgen.
Command Liefert die Kommandozeilenargumente, die beim Aufruf der Anwendung
angegeben wurden
CreateObject Erzeugt eine neue Instanz eines ActiveX-Objekts optional unter Spezifi-
kation eines Servers und liefert einen Verweis darauf zurück
DeleteSetting Löscht persistente Einstellungen eines Programms aus der Systemregist-
rierung. Die Methode wird unter Angabe des Anwendungsnamens als
Schlüssel, eines Abschnittsbezeichners als Unterschlüssel (optional) und
eines Bezeichners (optional) aufgerufen und löscht den entsprechenden
Eintrag, Unterschlüssel oder Schlüssel.
DoEvents Unterbricht die Ausführung der aktuellen Routine, um die Behandlung
gegebenenfalls anstehender Ereignisse zu ermöglichen, und setzt die Rou-
tine danach fort
GetAllSettings Ermittelt persistente Einstellungen eines Programms aus der Systemregis-
trierung. Die Funktion wird unter Angabe des Anwendungsnamens als
Schlüssel sowie eines Abschnittsbezeichners als Unterschlüssel aufgerufen
und liefert ein zweidimensionales String-Array, das in der ersten Dimen-
sion alle in dem Abschnitt gespeicherten Bezeichner und in der zweiten
die dazugehörigen Werte wiedergibt.
GetObject Liefert eine Object-Referenz auf ein ActiveX-Objekt

263
Global- Objekt

Methode Beschreibung
GetSetting Ermittelt eine persistente Einstellung eines Programms aus der Systemre-
gistrierung. Die Funktion wird unter Angabe des Anwendungsnamens als
Schlüssel, eines Abschnittsbezeichners als Unterschlüssel sowie eines
Bezeichners aufgerufen und liefert einen String-Wert, der den unter dem
Bezeichner abgelegten Wert wiedergibt.
InputBox Ruft ein Dialogfeld auf, das den Benutzer zur Eingabe eines String-Werts
auffordert und diesen als Ergebnis liefert
Load Lädt ein Formular oder Steuerelement für die spätere Anzeige in den
Global- Objekt

Hauptspeicher. Die Methode lässt sich insbesondere für die dynamische


Erweiterung von Steuerelemente-Arrays verwenden.
LoadPicture Lädt eine Bitmap aus einer Datei und liefert sie als Objekt vom Typ Pic-
ture. Die Methode unterstützt die gängigen Grafikformate BMP, JPG,
JPEG, GIF, WMF, EMF, ICO und CUR.
LoadResData Lädt eine Ressource aus einer Ressourcendatei (RES) und liefert deren
Daten in Form eines Byte-Arrays
LoadResPicture Lädt eine Bildressource (Bitmap, Cursor, Symbol) aus einer Ressourcen-
datei (RES) und liefert sie als Picture-Objekt
LoadResString Lädt eine Zeichenfolgenressource aus einer Ressourcendatei (RES) und
liefert sie als String-Wert
QBColor Liefert den zu einer QBasic-Farbe gehörigen Farbwert als Long
RGB Komponiert einen Farbwert aus den Farbanteilen Rot, Grün und Blau
und liefert diesen als Long
SavePicture Speichert ein als Picture-Objekt vorliegendes Bild in einer Datei
SaveSetting Speichert persistente Einstellungen des Programms in der Systemregist-
rierung. Die Anweisung wird unter Angabe des Anwendungsnamens,
eines Abschnittsbezeichners, eines Schlüssels sowie eines Schlüsselwerts
aufgerufen.
SendKeys Sendet eine Folge von Tastaturereignissen an das aktive Fenster (Formu-
lar, Steuerelement im Formular) der im Vordergrund ausgeführten
Anwendung und ermöglicht so deren Fernsteuerung
Shell Ermöglicht den Aufruf einer anderen Anwendung und gibt optional
einen Fensterstil dafür vor
Unload Entfernt ein Formular oder Steuerelement Object aus dem Hauptspei-
cher

App- Objekt
Public App As App
Beschreibung

Bes c hreibung
...................................................
Dem App-Objekt liegt als Datentyp die in der Bibliothek VB definierte gleichnamige Klasse App
zugrunde. Visual Basic vereinbart dieses Objekt automatisch in jeder Anwendung mit globalem
Geltungsbereich. Es repräsentiert die Laufzeitinstanz bei Ausführung der Anwendung und spei-
chert eine Reihe von Informationen über die Anwendung, darunter die Versions- und Herstel-

264
App- Objekt

lerinformationen und den Pfad der ausführbaren Datei sowie diverse Informationen über die
konkrete Laufzeitinstanz (so beispielsweise die Tatsache, ob bereits eine weitere Instanz der
gleichen Anwendung in Ausführung ist) sowie über das Verhalten der Anwendung im Zusam-
menspiel mit OLE-Servern.
Eigenschaften

...................................................
Eigens c ha ften
Ein guter Teil der Eigenschaften (insbesondere die zur Laufzeit schreibgeschützten) des App-
Objekts lassen sich interaktiv im Eigenschaftsfenster PROJEKTEIGENSCHAFTEN des zugehörigen
Projekts setzen. Die folgende Tabelle gibt einen Überblick:

Global- Objekt
Eigenschaft Beschreibung
Comments Zur Laufzeit schreibgeschützte Zeichenfolge für Kommentare zur
aktuellen Version
CompanyName Zur Laufzeit schreibgeschützte Zeichenfolge für Firmenname.
Vorbesetzt mit Firmenname aus der Visual-Basic-Lizenz.
EXEName Zur Laufzeit schreibgeschützte Zeichenfolge mit dem Anwen-
dungsnamen ohne Erweiterung
FileDescription Zur Laufzeit schreibgeschützte Zeichenfolge mit Dateibeschrei-
bung
HelpFile Zur Laufzeit schreibgeschützte Zeichenfolge; enthält Pfad für die
zur Anwendung gehörige kontextbezogene Hilfedatei.
hInstance Zur Laufzeit schreibgeschützter Handle der Laufzeitinstanz (für
Aufrufe der Win32-API)
LegalCopyright Zur Laufzeit schreibgeschützte Zeichenfolge mit Copyrightinfor-
mationen
LegalTrademarks Zur Laufzeit schreibgeschützte Zeichenfolge mit Warenzeichenin-
formationen
LogMode Zur Laufzeit schreibgeschützter Protokollmodus; wird von Start-
Logging-Methode gesetzt. Der Wert dieser Eigenschaft ist ein Vek-
tor und kann eine Kombination aus Werten des Aufzählungstyps
LogEventTypeConstants sein:
vbLogAuto (0) – Protokoll wird unter Windows 9x in durch Log-
Path spezifizierte Datei ausgegeben, unter Windows NT in Ereig-
nisprotokoll (Quelle ist »VBRunTime«, Title wird als genauere
Beschreibung der Instanz ausgegeben).
vbLogOff (1) – keine Protokollierung mehr, LogEvent-Aufrufe blei-
ben ohne Effekt
vbLogToFile (2) – Ausgabe in durch LogPath spezifizierte Datei; ein
ungültiger Dateiname erzwingt vbLogOff; falls LogPath leere Zei-
chenfolge, ist vbevents.log die Vorgabe
vbLogToNT (3) – Ausgabe in NT-Ereignisprotokoll; erzwingt
vbLogOff unter Windows 9x
vbLogOverwrite (16) – legt Protokolldatei bei jedem Start neu an
vbLogThreadID (32) – Meldungen werden um Thread-ID ergänzt
(bei Multithreaded-Anwendung); erzwingt vbLogOff bei Single-
threaded-Anwendung

265
Global- Objekt

Eigenschaft Beschreibung
LogPath Zur Laufzeit schreibgeschützte Zeichenfolge mit Namen der Pro-
tokolldatei, wird von StartLogging-Methode gesetzt
Major Zur Laufzeit schreibgeschützter Wert für primäre Versionsnum-
mer
Minor Zur Laufzeit schreibgeschützter Wert für sekundäre Versionsnum-
mer
NonModalAllowed Laufzeiteigenschaft vom Typ Boolean – ungebundene Anzeige
Global- Objekt

OLERequestPen- Laufzeiteigenschaft vom Typ String für die Spezifikation einer


dingMsgText eigenen Meldung im Zusammenhang mit einer Zeitüberschreitung
bei der Bearbeitung einer Anforderung durch einen ActiveX-Ser-
ver (weiteres unter OLEServerBusyRaiseError)
OLERequestPen- Laufzeiteigenschaft für die Anzahl der Millisekunden (Vorgabe-
dingMsgTimeOut wert: 5 Sekunden), welche die Instanz auf die Anwort eines Acti-
veX-Servers wartet; gilt auch für ActiveX-Dokumente, die via
OLE-Container-Steuerelement eingebettet bzw. verknüpft sind
OLERequestPen- Laufzeiteigenschaft vom Typ String; Vorgabewert ist die Title-
dingMsgTitle Eigenschaft des Objekts
OLEServerBusyMsgText Laufzeiteigenschaft vom Typ String für die Spezifikation einer
eigenen Meldung im Zusammenhang mit einer Zeitüberschreitung
bei einer Anforderung an einen ActiveX-Server (Weiteres unter
OLEServerBusyRaiseError)
OLEServerBusyMsgTitle Laufzeiteigenschaft vom Typ String; Vorgabewert ist die Title-
Eigenschaft des Objekts
OLEServerBusyRaiseError Laufzeiteigenschaft vom Typ Boolean – bei Auftreten eines Time-
outs im Verlauf einer Anforderung an einen ActiveX-Server
bestimmt der Vorgabewert True dieser Eigenschaft, dass umge-
hend der Automatisierungsfehler -2147418111 (&H80010001)
ausgelöst werden soll. Bei False erscheint entweder der standard-
mäßige Dialog KOMPONENTE BESCHÄFTIGT (bzw. KOMPO-
NENTENANFORDERUNG WIRD BEARBEITET) oder ein mit den
Werten der Eigenschaften OLEServerBusyMsgText und OLEServerBu-
syMsgTitle (bzw. OLERequestPendingMsgText und OLERequestPen-
dingMsgTitle) zusammengestellter Dialog – je nachdem, ob der
Wert der Eigenschaft OLEServerBusyMsgText (bzw. OLERequestPen-
dingMsgText) die leere Zeichenfolge ist oder nicht. Jeden der Dia-
loge kann der Benutzer mit OK oder mit ABBRECHEN beenden.
Ein Abbruch löst den genannten Automatisierungsfehler aus.
OLEServerBusyRaise- Laufzeiteigenschaft für die Anzahl der Millisekunden (Vorgabe-
TimeOut wert: 10 Sekunden), welche die Instanz auf die Anwort eines Acti-
veX-Servers wartet; gilt auch für ActiveX-Dokumente, die via
OLE-Container-Steuerelement eingebettet bzw. verknüpft sind
Path Zur Laufzeit schreibgeschützte Zeichenfolge, die den vollständi-
gen Pfad der VBP-Projektdatei bzw. der EXE-Datei wiedergibt.

266
App- Objekt

Eigenschaft Beschreibung
PrevInstance Zur Laufzeit schreibgeschützter Boolean-Wert – True besagt, dass
eine andere Instanz der gleichen Anwendung in Ausführung ist,
False das Gegenteil
ProductName Zur Laufzeit schreibgeschützte Zeichenfolge für Produktnamen
RetainedProject Zur Laufzeit schreibgeschützter Boolean-Wert – True besagt, Lauf-
zeitinstanz bleibt im Speicher geladen, False (Vorgabe), das
Gegenteil

Global- Objekt
Revision Zur Laufzeit schreibgeschützter Wert für Revisionsanteil der Ver-
sionsnummer
StartMode Zur Laufzeit schreibgeschützter Wert, der besagt, ob eine Laufzei-
tinstanz im Stand-alone-Modus (vbSModeStandalone = 0) oder als
ActiveX-Komponente (vbSModeAutomation = 1) gestartet wurde
TaskVisible Boolean-Wert, der bestimmt, ob die Laufzeitinstanz in der Task-
liste von Windows als Eintrag erscheint (True) oder nicht (False)
ThreadID Long-Wert mit der Thread-ID der Laufzeitinstanz (für Aufrufe der
Win32-API)
Title String-Wert, der den Namen der Laufzeitinstanz für die Ausgabe
in der Taskliste bestimmt
UnAttendedApp Zur Laufzeit schreibgeschützter Boolean-Wert; wenn False (Vor-
gabe), erhält die Anwendung eine Benutzeroberfläche, sonst nicht

Methoden
Methoden

...................................................
Sub App.StartLogging( _
LogTarget As String = "vbevents.log", LogModes As Long)
Sub App.LogEvent( _
LogBuffer As String, EventType As LogEventTypeConstants)
Die zwei Methoden des App-Objekts dienen der Protokollierung von Ereignissen. Sie verrichten
Ihren Dienst allerdings nur, wenn das Programm als eigenständige Exe-Datei ausgeführt wird –
bei Ausführung der Projektdatei innerhalb der Entwicklungsumgebung sollte die LogEvent-Aus-
gabe laut Spezifikation in das Direktfenster stattfinden, was jedoch in der Version 6.0 (SP3)
nicht passiert.

Methode Beschreibung
StartLogging Legt LogTarget als Protokolldatei und LogModes als Protokollmodus für
die Ereignisaufzeichnung mittels LogEvent fest (vgl. LogModus-Eigenschaft)
LogEvent Protokolliert den in LogBuffer enthaltenen Text als Meldung in der Proto-
kolldatei LogTarget der Anwendung. (Unter Windows NT schreibt die
Methode in das NT-Ereignisprotokoll.) Der Parameter EventType katego-
risiert die Meldung in »Fehler« (vbLogEventTypeError oder 1), »War-
nung« (vbLogEventTypeWarning oder 2) bzw. »Information«
(vbLogEventTypeInformation oder 4).

267
Global- Objekt

Anwendung

Anwendung
...................................................
Als Laufzeitinstanz eines Programms ist das App-Objekt zwar das »Objekt der Objekte«, doch
bei der Programmierung spielt es eher eine untergeordnete Rolle. Am häufigsten dürften die
Eigenschaften PrevInstance und Path von Interesse sein. PrevInstance gibt Aufschluss darüber,
ob bereits eine andere Instanz der Anwendung in Ausführung ist, und Path gibt Aufschluss über
den Pfad der Exe-Datei. (Der Name der Exe-Datei ergibt sich aus der Eigenschaft Title.) Ab
und an sind aber auch die Möglichkeiten der Ereignisprotokollierung des App-Objekts von Nut-
zen, zum Beispiel wenn es darum geht, die Aktivitäten eines Servers zu protokollieren.
Seltener dagegen wird das App-Objekt für die Gestaltung von Time-outs und Abbrüchen bei
Anforderungen an ActiveX-Server herangezogen. (Das Vorgabeverhalten ist hier in den meisten
Global- Objekt

Fällen ausreichend. In speziellen Fällen, etwa wenn ActiveX-Server im Netzwerk verteilt sind,
kann eine explizite Definition der entsprechenden Eigenschaften nötig sein.)
Warnung

Wa rnung
...................................................
Die Time-out-Intervalle des App-Objekts lassen sich zwar beliebig ausdehnen, da die entspre-
chenden Eigenschaften den Typ Long tragen, doch ein zu langes Zeitintervall kann die Anwen-
dung lahmlegen, wenn der kontaktierte Server nicht reagiert. Sollten Sie für eine bestimmte
Aufgabe die Time-outs des App-Objekts ändern müssen, empfiehlt es sich, die Werte nach Erle-
digung der Aufgabe umgehend wieder zu restaurieren, wenn die Anwendung mit mehr als
einem ActiveX-Objekt arbeitet.
Beispiel

Beis piel
...................................................
Der folgende Code verhindert den mehrfachen Start der Anwendung. Die Beschränkung auf
eine Laufzeitinstanz ist im Zusammenhang mit MDI-Anwendungen zwar nicht zwingend, aber
doch weit verbreitet.
Private Sub Form_Load()
If App.PrevInstance Then
MsgBox ("Es gibt eine ältere Instanz der Anwendung")
End
End If
End Sub

Der folgende Codeauszug demonstriert die Ereignisprotokollierung in eine Datei namens


C:\Test.log. (Achtung: Kompilierung erforderlich).
Option Explicit
Dim Nr As Long
Private Sub Form_Load()
App.StartLogging "C:\Test.log", 0
End Sub

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


Nr = Nr + 1
App.LogEvent "Mousedown " + Str(Nr), vbLogEventTypeError
End Sub

Die Ausgabe in die Datei c:\test.log hat folgende Gestalt:


Error Application C:\Test.log: Thread ID: -513437 ,Logged: Mousedown 1
Error Application C:\Test.log: Thread ID: -513437 ,Logged: Mousedown 2

268
CallByName- Methode

CallByName- Methode
Function CallByName(Object As Object, ProcName As String, _
CallType As VbCallType, Args()) As Variant
Sub CallByName(Object As Object, ProcName As String, _
CallType As VbCallType, Args())
Beschreibung

Bes c hreibung
...................................................
Die globale CallByName-Methode ermöglicht den Zugriff auf eine Funktion (Eigenschaft oder
Methode) eines zur Laufzeit gebundenen Automatisierungsobjekts Object. Zur Spezifikation

Global- Objekt
der Funktion ist ihr Bezeichner als Zeichenfolge ProcName anzugeben. Der Parameter CallType
legt fest, ob die Funktion als Get, Set oder Let Property deklariert ist oder als gewöhnliche
Methode. Der Aufzählungstyp VbCallType definiert dafür die Konstanten: vbMethod (1), vbGet
(2), vbLet (4), vbSet (8). Etwaige Argumente für den Aufruf lassen sich über den Args-Parameter
in Form eines Variant-Arrays oder als schlichte Parameterliste übergeben.
Anwendung

Anwendung
...................................................
Der Visual-Basic-Compiler versucht, Objekte nach Möglichkeit bereits zur Übersetzungszeit zu
binden und Verweise auf ihre Eigenschaften und Methoden möglichst umgehend aufzulösen.
Man spricht in diesem Zusammenhang von früher Bindung. Diese Art der Bindung ist aber bei
COM-Objekten nicht immer möglich, etwa wenn das Objekt keine duale Schnittstelle besitzt
(oder die Typbibliothek dafür nicht bekannt ist), sondern nur eine Automatisierungsschnitt-
stelle (IDispatch) anbietet. Für den Zugriff auf das Objekt bleibt dann nur noch die späte Bin-
dung, das heißt, die Bindung zur Laufzeit. Das ist beispielsweise der Fall, wenn der Program-
mierer mit Object-Verweisen hantiert und Automatisierungsobjekte zur Laufzeit via
CreateObject instanziiert. Hinter der CallByName-Methode steckt übrigens nichts weiter als ein
Aufruf der Invoke-Funktion der IDispatch-Schnittstelle des Automatisierungsobjekts.
Die CallByName-Methode ermöglicht es nun, gewissermaßen in letzter Sekunde auf Eigenschaf-
ten eines Objekts zuzugreifen, ohne dass diese bei der Kompilierung des Visual-Basic-Pro-
gramms bekannt waren oder gar existiert haben. Auf diese Weise kann ein Programm mit maxi-
maler Flexibilität vom jeweils aktuellen Dienstangebot des Automatisierungsobjekts
profitieren.
Beispiel

Beis piel
...................................................
Da für das Scripting-Objekt FileSystemObject eine Typbibliothek sowie eine duale Schnitt-
stelle zur Verfügung stehen, kann der Compiler die Methoden des Objekts selbst auflösen. Wer
will, kann aber die Methoden auch über die Automatisierungsschnittstelle mit CallByName
ansprechen. Die folgenden drei Print-Anweisungen leisten genau dasselbe, sie geben den gesam-
ten Inhalt der Textdatei DateiName aus. (Da ReadAll die gesamte Datei ausliest, müssen immer
zwei Print-Anweisungen auskommentiert sein.)
Set fs = CreateObject("Scripting.FileSystemObject")
' Print fs.OpenTextfile(Dateiname).ReadAll ' Datei en bloc ausgeben
' Print CallByName(fs, "OpenTextFile", VbMethod, Dateiname).ReadAll
Print CallByName(CallByName(fs, "OpenTextFile", VbMethod, Dateiname), _
"ReadAll", VbMethod)
Verwandte Methoden

Verwa ndte Metho den


...................................................
CreateObject, GetObject

269
Global- Objekt

Clipboard- Objekt
Public Clipboard As Clipboard
Beschreibung

Bes c hreibung
...................................................
Das Clipboard-Objekt vermittelt den Zugriff auf die von allen Anwendungen gemeinsam für
den Datenaustausch genutzte Zwischenablage des Systems. Es gehört der in der Bibliothek VB
definierten gleichnamigen Klasse an und wird von Visual Basic in jeder Anwendung automa-
tisch als globales Objekt vereinbart. Das Objekt besitzt zwei voneinander unabhängige Puffer,
von denen der eine für den Transport von Zeichenfolgen als Text, Text im RTF-Format oder
DDE-Nachrichten für OLE-Objekte gedacht ist, während der andere die Übermittlung von
Global- Objekt

Daten unterschiedlichen Formats (Grafiken oder Dateien) ermöglicht. Eine zusätzliche Format-
information gibt Aufschluss über die Art der in den Puffern enthaltenen Daten.
Methoden

Metho den
...................................................
Function Clipboard.Clear()
Function Clipboard.GetData( _
Format As ClipBoardConstants) As IPictureDisp
Function Clipboard.GetFormat( _
Format As ClipBoardConstants) As Boolean
Function Clipboard.GetText( _
[Format As ClipBoardConstants = vbCFText]) As String
Sub Clipboard.SetData(Picture As IPictureDisp, _
[Format As ClipBoardConstants])
Sub Clipboard.SetText(Str As String, _
[Format As ClipBoardConstants = vbCFText])
Die sechs Methoden des Clipboard-Objekts ermöglichen Zugriffe und Manipulationen der Zwi-
schenablage (das heißt: der Pufferinhalte sowie der Formatinformationen). Die folgende Tabelle
gibt einen Überblick über die Aufgaben der einzelnen Methoden:

Methode Beschreibung
Clear Löscht alle Inhalte der Zwischenablage
GetData Liefert Grafikdaten aus der Zwischenablage
GetFormat Testet, ob die Zwischenablage Daten eines bestimmten Formats enthält,
und liefert True, wenn die Daten in der Zwischenablage das im Parameter
bezeichnete Format tragen, ansonsten False
GetText Liefert Text (als Zeichenfolge) aus der Zwischenablage
SetData Überträgt Grafikdaten und Formatbeschreibung in die Zwischenablage
SetText Überträgt Text (als Zeichenfolge) in die Zwischenablage

Die folgende Tabelle gibt einen Überblick über die in Visual Basic für das Clipboard-Objekt
definierten Formatkonstanten:

27 0
Clipboard- Objekt

Formatkonstante Wert Beschreibung


vbCFLink &HFFFFBF00 Zwischenablage enthält Informationen für DDE-Ver-
bindung
vbCFRTF &HFFFFBF01 Zwischenablage enthält eine RTF-Datei (Rich Text
Format)
vbCFText 1 Zwischenablage enthält TXT-Datei (ASCII-Text)
vbCFBitmap 2 Zwischenablage enthält eine Grafik vom Typ BMP
(Bitmap)

Global- Objekt
vbCFMetafile 3 Zwischenablage enthält eine Grafik vom Typ WMF
(Windows Metafile = Windows-Zwischendatei)
vbCFDIB 8 Zwischenablage enthält eine Grafik vom Typ DIB
(geräteunabhängige Bitmap)
vbCFPalette 9 Zwischenablage enthält eine Farbpalette
vbCFEMetafile 14 Zwischenablage enthält eine Grafik vom Typ EMF
(Enhanced Windows Metafile = erweiterte Windows-
Zwischendatei)
vbCFFiles 15 Zwischenablage enthält eine Dateiliste des Windows
Explorers (wird vom Clipboard-Objekt zwar als For-
mat angezeigt, jedoch nicht weiter unterstützt)

Anwendung

Anwendung
...................................................
Über den Einsatz der Methode Clear muss man nicht viele Worte verlieren: Sie sollte immer
dann zum Aufruf kommen, wenn der Inhalt der Zwischenablage nicht mehr vonnöten ist. Sie
sorgt für die Freigabe der von dem Objekt belegten Ressourcen (die im Falle von Grafiken
beträchtlich sein können). Die mit dem Ergebnistyp Boolean sicherlich etwas ungeschickt imple-
mentierte Methode GetFormat testet, ob die Daten in der Zwischenablage ein bestimmtes For-
mat tragen. Nachdem die Zwischenablage allen Anwendungen gleichermaßen zur Verfügung
steht, ist eine solche Prüfung in der Praxis unerlässlich, um Laufzeitfehlern aufgrund falscher
Datenformate vorzubeugen.
Die Methoden GetText und SetText dienen dem Transport von Daten im einfachen Textformat
(TXT; Voreinstellung bei fehlendem Parameter Format), im Rich Text Format (RTF) sowie von
Informationen, die im Zusammenhang mit DDE-Verbindungen übertragen werden. Der Im-
und Export von Text ist auf den Datentyp String ausgerichtet.
Die Methoden GetData und SetData dienen dem Transport von Grafiken und binären Daten,
die in verschiedenen Formaten vorliegen können. Der Im- und Export von Bitmaps ist auf den
Datentyp Picture ausgerichtet und die Anzeige erfordert ein Steuerelement mit Picture-Eigen-
schaft. Bei dem im Prototyp der beiden Methoden genannten Datentyp IPictureDisp handelt es
sich um die Automatisierungsschnittstelle des Picture-Objekts. Er stimmt in Visual Basic mit
dem Datentyp Picture überein (diesen Typ liefert die TypeName-Funktion auch als Ergebnistyp
der Methode GetData).
Tipp

Tipp
...................................................
Das Clipboard-Objekt lässt sich auch für die Übermittlung anderer auf dem System registrierter
Datenformate heranziehen. Analoges dazu finden Sie im Abschnitt »OLEStartDrag-Ereignis«
(S. 250). Allerdings unterstützt das Clipboard-Objekt von Visual Basic nicht alle Operationen

27 1
Global- Objekt

der OLE-Zwischenablage. So zeigt es zwar an, wenn in der Zwischenablage Dateien enthalten
sind (vbCFFiles), es besitzt aber keine Methoden für den Austausch, da es (im Gegensatz zu
einem DataObject-Objekt) keine Files-Eigenschaft verfügbar macht. Eine in der Zwischenab-
lage befindliche Datei lässt sich aber in ein RTF-Steuerelement sowie in ein OLE-Container-
Steuerelement als Inhalt einfügen.
Beispiel

Beis piel
...................................................
Das folgende für seinen Funktionsumfang wirklich kurz geratene Projekt ZwischenAblage
demonstriert recht eindrucksvoll den unkomplizierten Einsatz der Zwischenablage. Das Formu-
lar enthält ein RTF-Steuerelement (RICHTX32.OCX) namens RichTextBox, ein Bildausschnitt-
Global- Objekt

Steuerelement (PICCLP32.OCX) namens PicClip1, ein Bildfeld-Steuerelement (PictureBox)


namens Picture1 sowie ein Menü mit den beiden Befehlen EINFÜGEN und KOPIEREN. Importiert
man Text oder Text mit RTF-Format über die Zwischenablage in das Programm, macht der
Befehl EINFÜGEN diesen im RTF-Steuerelement sichtbar. (Da RTF-Steuerelemente aber auch
von sich aus mit der Zwischenablage des Systems interagieren, wenn sie den Fokus haben, ist
eine explizite Implementation der Zwischenablagenfunktionen eher unnötig – zumal der Funk-
tionsumfang des Clipboard-Objekts in Visual Basic Einschränkungen aufweist.) Importiert man
in das Programm dagegen eine Grafik (beispielsweise einen mittels der Taste (Druck) erstellten
Bildschirmabschuss), macht der Befehl EINFÜGEN diese im Bildfeld sichtbar. Der Befehl KOPIE-
REN ist dagegen so implementiert, dass er nur einen Ausschnitt des im Bildausschnitt-Steuerele-
ment gespeicherten Bildes, nämlich 100×100 Bildpunkte von links oben gesehen, in die Zwi-
schenablage überträgt. (Falls das Bild keine 100×100 Bildpunkte hat, wird auf ein Viertel
verkleinert.) EINFÜGEN bringt das Ergebnis dieser Operation zutage.
Private Sub mnuEinfügen_Click()
If Clipboard.GetFormat(vbCFText) Then ' Text?
RichTextBox1.Text = Clipboard.GetText
End If
If Clipboard.GetFormat(vbCFRTF) Then ' RTF-Text?
RichTextBox1.TextRTF = Clipboard.GetText(vbCFRTF)
End If
If Clipboard.GetFormat(vbCFDIB) Then ' Grafik?
PicClip1.Picture = Clipboard.GetData(vbCFDIB)
Picture1 = PicClip1.Picture
End If
End Sub

Private Sub mnuKopieren_Click()


If PicClip1.Picture Then ' Bild zugewiesen?
PicClip1.ClipHeight = 100 ' Bildausschnitt definieren
PicClip1.ClipWidth = 100
Clipboard.SetData PicClip1.Clip, vbCFDIB ' In Zwischenablage
End If
End Sub
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

27 2
Command- Methode

Command- Methode
Public Command As String
Beschreibung

Bes c hreibung
...................................................
Die globale Command-Methode liefert die beim Aufruf der Anwendung angegebenen Kommando-
zeilenparameter als Zeichenfolge.
Anwendung

Anwendung
...................................................
Seit Windows sind die Kommandozeile sowie die darin übergebenen Aufrufparameter zuneh-
mend in den Hintergrund geraten. Von einer MS-DOS-Kommandozeile aus oder über den

Global- Objekt
Befehl AUSFÜHREN im START-Menü von Windows können Sie eine als EXE-Datei vorliegende
Anwendung aber jederzeit unter Angabe zusätzlicher Kommandozeilenparameter, Schalter etc.
aufrufen. Die Kommandozeile lautet:
MeinProgramm.exe Param1 Param2 Param3
Falls das Programm nicht kompiliert ist, lautet der Aufruf für Visual Basic 6.0, der den soforti-
gen Start der Anwendung bewirkt und Kommandozeilenparameter bereitstellt, so:
Vb6 projekt1 /run /cmd Param1 Param2 Param3
Wenn Verzeichnisse für Vb6.Exe und Projekt1.vbp nicht zum Suchpfad von Windows gehören
(vgl. Umgebungsvariable PATH), müssen Sie natürlich die entsprechenden Pfade angeben:
"C:\Programme\Microsoft Visual Studio\VB98\Vb6" (fortgesetzt)
"Vb60 Programme\Projekt1" /run /cmd Param1 Param2 Param3
In jedem der genannten Fälle liefert die Command-Methode als Wert die Zeichenfolge:
"Param1 Param2 Param3"

CreateObject- Methode
Function CreateObject(Class As String, [ServerName As String]) As Object
Beschreibung

Bes c hreibung
...................................................
Die CreateObject-Methode generiert eine neue Instanz des ActiveX-Objekts Class für die Auto-
matisierung und liefert einen Verweis vom Typ Object darauf zurück. Läuft die für das Objekt
zuständige Serveranwendung zum Zeitpunkt des Aufrufs noch nicht, startet die Methode den
Server. Um das Objekt (via DCOM) auf einem bestimmten Server im Netzwerk auszuführen, ist
dessen Name optional über den Parameter ServerName zu spezifizieren.
Anwendung

Anwendung
...................................................
Visual Basic kann mittels CreateObject eine Bindung zur Laufzeit mit allen COM-Objekten her-
stellen, die über eine Automatisierungsschnittstelle verfügen – und daher Automatisierungsob-
jekte genannt werden. Diese Schnittstelle stellt einen standardisierten Mechanismus dar, der es
einer Host-Anwendung (lies: einem Visual-Basic-Programm) ermöglicht, auf eigens für die
Automatisierung exponierte Methoden und Eigenschaften des Objekts zuzugreifen, wobei die
Bindung erst zur Laufzeit erfolgt. Man spricht dann von später Bindung. Späte Bindung hat den
Vorteil, dass zur Übersetzungszeit außer den Bezeichnern für das Objekt, seine Methoden und
Eigenschaften nichts weiter über das Objekt bekannt sein muss – alle Informationen lassen sich
zur Laufzeit ermitteln. Der Nachteil ist allerdings, dass sie einiges an Laufzeit verschlingt.
Dim fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")

27 3
Global- Objekt

Die meisten Automatisierungsobjekte besitzen aber eine duale Schnittstelle und ermöglichen so
auch eine Anbindung über die für die Klasse definierte Standardschnittstelle. Für diese Art der
Bindung, die bereits zur Übersetzungszeit (bis auf einen einzigen Verweis auf eine zentrale Zei-
gertabelle) vollständig vorbereitet werden kann und somit als frühe Bindung bezeichnet wird,
muss dem Compiler allerdings die gesamte Objektdeklaration in Form einer Objektbibliothek
(OLB) vorliegen. Um dem Compiler eine bestimmte Objektbibliothek zugänglich zu machen,
rufen Sie das Dialogfeld VERWEISE über das Menü PROJEKT/VERWEISE auf und setzen ein Häk-
chen vor den gewünschten Objekttyp. Für das Objekt Scripting.FileSystemObject wäre das die
Bibliothek Microsoft Scripting Runtime. Über den Aufbau des Scripting-Moduls, also die darin
definierten Konstanten, Eigenschaften und Methoden, sowie die Objektstruktur der Eigenschaf-
ten, also wiederum deren Konstanten, Eigenschaften und Methoden etc., können Sie sich dann
Global- Objekt

im Objektkatalog (aufzurufen über ANSICHT/OBJEKTKATALOG) bis in alle Einzelheiten infor-


mieren.

Zum Scripting-Modul gehörige Objektbibliothek


Bei Verwendung der frühen Bindung deklarieren Sie die Objektvariable wie gewohnt unter
Angabe eines konkreten Datentyps:
Dim fs As New Scripting.FileSystemObject

Vielfach spielt die Ausführungsgeschwindigkeit aber keine so große Rolle, so dass der geringere
Overhead sowie die große Flexibilität, die CreateObject ermöglicht, nicht zu übersehende Vor-
teile bietet. Visual Basic ermöglicht es auch, eigene ActiveX-Server zu implementieren, um
anderen Anwendungen Automatisierungsobjekte zur Verfügung zu stellen. Hierfür gibt es die
speziellen Projekttypen »ActiveX-DLL« und »ActiveX-EXE«.
Beispiel

Beis piel
...................................................
Der folgende Code gibt den Inhalt einer Textdatei unter Verwendung des FileSystemObject-
Objekts en bloc aus.

27 4
DeleteSetting- Methode

Dim fs As Object
Set fs = CreateObject("Scripting.FileSystemObject")
Print fs.OpenTextfile(DateiName).ReadAll ' Datei en bloc ausgeben
Verwandte Methoden

Verwa ndte Metho den


...................................................
CallByName, GetObject

DeleteSetting- Methode
Sub DeleteSetting(AppName As String, [Section As String], _
[Key As String])

Global- Objekt
Beschreibung

Bes c hreibung
...................................................
Die Methode DeleteSetting ermöglicht es, persistente Einstellungen eines Programms aus der
Systemregistrierung wieder zu entfernen, die mittels der SaveSetting-Methode als Unterschlüs-
sel des Schlüssels

HKEY_CURRENT_USER\Software\VB and VBA Program Settings\

gespeichert wurden. Es gilt: AppName ist Unterschlüssel von "VB and VBA Program Settings" und
steht für den Programmnamen, Section ist Unterschlüssel von AppName und steht für den
Abschnitt und Key ist Bezeichner eines Werts in Section.
Falls der zu löschende Schlüssel, Unterschlüssel oder Wert nicht existiert, löst die Methode den
Laufzeitfehler 5 »Ungültiger Prozeduraufruf oder ungültiges Argument« aus.
Anwendung

Anwendung
...................................................
Früher mussten Windows-Anwendungen ihre persistenten Einstellungen noch in je eigenen INI-
Dateien ablegen. Spätestens seit Windows 95 (aber auch schon zuvor) gibt es eine Systemregist-
rierung, in der sich solche Daten an zentraler Stelle speichern lassen. Für den Zugriff auf die
Systemregistrierung von Visual Basic aus stehen im Wesentlichen vier Methoden zur Verfü-
gung: GetSetting, GetAllSettings, SaveSetting und DeleteSetting, deren Funktion bereits
durch die Bezeichner deutlich wird. Um auf andere Schlüssel zuzugreifen, müssen Sie die ent-
sprechenden Funktionen der Win32-API (RegDeleteKey, RegDeleteValue etc.) benutzen.
Beispiel

Beis piel
...................................................
On Error Resume Next ' Fehler ignorieren
DeleteSetting "MeineAnwendung" ' Alle Einträge des Programms entfernen
DeleteSetting "MeineAnwendung1", "Metrik" ' Abschnitt entfernen
On Error Goto 0'
Verwandte Methoden

Verwa ndte Metho den


...................................................
GetSetting, GetAllSettings, SaveSetting
Verwandte Themen

Verwandte Them en
...................................................
Registrierung (S. 561)

27 5
Global- Objekt

DoEvents- Methode
Sub DoEvents()
Beschreibung

Bes c hreibung
...................................................
Die DoEvents-Methode unterbricht die Ausführung der aktuellen Routine temporär, um die
Behandlung gegebenenfalls anstehender Ereignisse zu ermöglichen, und setzt die Routine
danach wieder fort. Die Methode lässt sich als Prozedur und als Funktion verwenden. Als
Funktion aufgerufen, liefert sie die Anzahl der geöffneten Formulare.
Anwendung

Anwendung
...................................................
Global- Objekt

Die DoEvents-Methode ist in Programmen mit nur einem einzigen Ausführungspfad (Thread)
ein wichtiges Mittel, um die Reaktivität der Benutzerschnittstelle auch im Verlauf länger andau-
ernder Operationen aufrechtzuerhalten. Da die in der Ereigniswarteschlange bereitstehenden
Ereignisse immer nacheinander abgearbeitet werden, kann eine zeitintensive Routine die
Behandlung anderer wartender Ereignisse spürbar (wenn nicht gar ewig) verzögern, was der
Benutzer als »zähe Reaktion« auf seine Aktivitäten zu spüren bekommt. Damit zeitaufwändige
Routinen quasi im Hintergrund ablaufen, fügen Sie an passender Stelle (nicht zu häufig, nicht
zu selten; eine Faustregel ist: ca. jede Zehntelsekunde auf einem durchschnittlichen System)
einen DoEvents-Aufruf ein.
Tipp

Tipp
...................................................
In manchen Fällen lassen sich längere Wartezeiten für den Benutzer nicht vermeiden. Um ihm
aber dennoch das Gefühl zu geben, dass etwas passiert, können Sie eine Fortschrittsleiste anzei-
gen oder zumindest die Mauszeigerform auf »Sanduhr« umschalten.
Warnung

Wa rnung
...................................................
Wenn eine durch DoEvents unterbrochene Routine erneut aufgerufen wird, kommt es zur
Rekursion. Rekursion an sich bereitet keine Probleme, solange Sie bei der Programmierung
darauf achten, dass keine statischen oder globalen Variablen im Spiel sind. Wird die Rekursion
jedoch zu tief, kommt es zum Laufzeitfehler »Stapelüberlauf«. Ein weiteres Problem im Zusam-
menhang mit DoEvents sind die so genannten »Stehaufmännchen«, die auftreten können, wenn
Unload innerhalb einer DoEvents-Unterbrechung zur Ausführung kommt. In diesem Fall wird
Visual Basic das Formularobjekt beim nächsten Zugriff auf eine Eigenschaft oder Methode
automatisch erneut laden, und das ganze Spiel beginnt von vorne. Schlimmer noch: wenn das
einmal passiert ist, lässt sich das Formular nicht mehr beenden, weil jeder Versuch es zu been-
den eine neue Instanz hervorzaubert, selbst wenn keine DoEvents-Unterbrechung mehr vorliegt.
(Wenn Sie es ausprobieren, müssen Sie das Programm über das Entwicklungssystem beenden.)
Sie umgehen das Problem, indem Sie den von DoEvents gelieferten Funktionswert auswerten.
Dieser ist nämlich 0, wenn der Benutzer inzwischen das Formular geschlossen hat, ansonsten
ungleich 0 (detailliertere Informationen dazu entnehmen Sie dem Abschnitt »ApfelmannZoom
– eine Fahrt durch die Mandelbrotmenge«, S. 478 im Praxisteil).
Beispiel

Beis piel
...................................................
Die folgende Routine ist eine Variante des »Apfelmännchens«, die mit regelmäßigen DoEvents-
Aufrufen während der Bildberechnung die Benutzerschnittstelle am »Leben« erhält.
Private Sub Apfel(m_x1, m_x2, m_y1, m_y2, step_x, step_y)
Dim r1 As Double, re As Double, im As Double
Dim zr As Double, zi As Double, it As Integer

27 6
Err- Objekt

For zr = m_x1 To m_x2 Step step_x ' alle Spalten in x-Richtung


For zi = m_y1 To m_y2 Step step_y ' alle Punkte in Spalte zr
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
For it = 0 To cMaxIterat ' Iteration für Punkt
r1 = re * re – im * im + zr
im = 2 * re * im + zi
re = r1
If re < -cGrenze Or re > cGrenze Or _
im < -cGrenze Or im > cGrenze Then

Global- Objekt
PSet (zr, zi), it * 16 ' Punkt ausgeben
Exit For
End If
Next it
Next zi
if DoEvents = 0 Then Exit Sub
Next zr
End Sub

Err- Objekt
Public Err As ErrObject
Beschreibung

Bes c hreibung
...................................................
Für den Umgang mit Laufzeitfehlern besitzt Visual Basic ein altes und eine neues Informations-
konzept. Für das alte steht die Error-Anweisung, für das neue das Err-Objekt. Das von Visual
Basic in jeder Anwendung automatisch als globales Objekt vereinbarte Err-Objekt gehört der
Klasse ErrObject aus der Bibliothek VBA an. Seine Aufgabe besteht darin, Laufzeitfehler zu sig-
nalisieren und spezifische Fehlerinformationen für deren Behandlung bereitzustellen.
Eigenschaften

Eigens c ha ften
...................................................
Das Err-Objekt verfügt über eine Reihe von Eigenschaften für die nähere Spezifikation eines
Fehlers und dessen Behebung. Die folgende Tabelle gibt einen Überblick über alle Eigenschaften
des Objekts:

Eigenschaft Beschreibung
Description Zeichenfolge mit dem aktuellen Fehlertext
HelpContext Zeichenfolge mit der Kontextkennung für das aktuelle Hilfethema
in Hilfedatei. Wenn leer, wird die Kontextkennung über den Wert
von Number ermittelt.
HelpFile Zeichenfolge mit dem Zugriffspfad für die Hilfedatei. Wenn leer,
wird die Visual-Basic-Hilfedatei benutzt.
LastDllError zur Laufzeit schreibgeschützter Long-Wert, der den Rückgabewert
der zuletzt aufgerufenen DLL-Routine übermittelt. Die Bedeutung
des Rückgabewerts ist der Dokumentation der entsprechenden
Funktion zu entnehmen (vgl. »Routinen aus DLLs und der Win-
dows-API einsetzen«, S. 185).
Number Wert vom Typ Long mit der aktuellen Fehlernummer

27 7
Global- Objekt

Eigenschaft Beschreibung
Source Zeichenfolge mit dem Klassennamen des den Fehler signalisieren-
den Objekts (gegebenenfalls Objekt-ID) oder dem Namen des Pro-
grammmoduls; hilfreich, wenn keine modulinterne Behandlung
des Fehlers erfolgt

Ein explizites Setzen der Eigenschaften erübrigt sich, da alle Eigenschaften im Zuge des Raise-
Aufrufs mit einem Wert versorgt werden können.
Methoden

Metho den
...................................................
Global- Objekt

Sub Err.Clear ()
Sub Err.Raise(Number, _
[Source], [Description], [HelpFile], [HelpContext])
Die Methode Clear ermöglicht es, das Err-Objekt in den Grundzustand zurück zu versetzen.
Das ist beispielsweise im Zusammenhang mit der Anweisung On Error Resume Next erforder-
lich, wenn eine Inline-Fehlerbehandlung unmittelbar im Anschluss an eine Anweisung erfolgt.
Die Methode Raise löst einen Laufzeitfehler mit der Nummer Number aus. Die benannten Para-
meter der Methode setzen die gleichnamigen Eigenschaften des Objekts. Der Wertebereich für
Visual-Basic-Fehler liegt zwischen 0 und 65.535, wobei der Bereich zwischen 0 und 512 für
Systemfehler reserviert ist, so dass für benutzerdefinierte Fehler der Bereich zwischen 513 und
65.535 übrig bleibt. In Klassenmodulen arbeitet man mit Fehlernummern, die den Offset vbOb-
jectError haben.
Anwendung

Anwendung
...................................................
Das Err-Objekt stellt gegenüber dem traditionellen Fehlermechanismus von Visual Basic eine
Verfeinerung dar, weil es eine bessere Kontrolle über den Kontext eines Fehlers bietet. Am Feh-
lerbehandlungsmechanismus von Visual Basic ändert das Err-Objekt jedoch nichts (Einzelhei-
ten dazu im Abschnitt »Fehlerbehandlung«, S. 43). Mit Ausnahme der Eigenschaft LastDllEr-
ror, die nur im Zusammenhang mit Aufrufen der Win32-API eine Bedeutung hat, lassen sich
die Eigenschaften des Fehlerobjekts an beliebiger Stelle in einer Funktion/Prozedur setzen. Im
Allgemeinen wird man die Werte für die diese Eigenschaften bei einem Raise-Aufruf bereitstel-
len. Beachten Sie aber, dass die Anweisungen Exit Function, Exit Sub, Exit Property sowie
Resume Next implizit einen Clear-Aufruf des Err-Objekts veranlassen, so dass die Eigenschaften
jedes Mal neu gesetzt werden müssen.
Tipp

Tipp
...................................................
Die Fehlerbehandlung sollte bei der Entwicklung eines Programms von Anfang an einen sehr
hohen Stellenwert haben. Testen Sie Ihre Fehlerroutinen ausgiebig auf alle Spezialfälle und
schließen Sie aus, dass eine Fehlerbehandlungsroutine in die Verlegenheit kommt, Fehler zu
behandeln, für die sie nicht ausgelegt ist.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel zu dem Thema »Fehlerbehandlung« (S. 43)
Verwandte Themen

Verwandte Them en
...................................................
Fehlerbehandlung (S. 43)

27 8
Forms- Auflistung

Forms- Auflistung
Forms As Object
Beschreibung

Bes c hreibung
...................................................
Die nicht mit dem Datentyp Collection kompatible Forms-Auflistung enthält eine Liste der
aktuell von der Anwendung instanziierten Formularobjekte – gewöhnliche Formulare, MDI-
Formulare, MDI-Formularen untergeordnete Formulare. Elementtyp ist der Klassenname (For-
mularname) der jeweiligen Instanz. Einzige Eigenschaft der Auflistung ist Count, über die sich
die Anzahl Listenelemente in Erfahrung bringen lässt. Um die Pflege der Auflistung kümmert
sich das Laufzeitsystem (im Rahmen von Load), so dass sie jederzeit auf dem neuesten Stand ist.

Global- Objekt
Anwendung

Anwendung
...................................................
Sie können die Auflistung Forms mit einem For Each-Konstrukt durchlaufen, um festzustellen,
welche Formulare es gibt, oder um beispielsweise den Anwendungsfokus an ein bestimmtes
Formular weiterzureichen. Als Datentyp für die Laufvariable vereinbaren Sie Object oder besser
Form.
Beispiel

Beis piel
...................................................
Dim Formular As Form
For Each Formular In Forms
Print Formular.Caption
Next
Verwandte Themen

Verwandte Them en
...................................................
Auflistungen und Collection-Objekte (S. 304)

GetAllSettings- Methode
Function GetAllSettings(AppName As String, Section As String) _
As String()()
Beschreibung

Bes c hreibung
...................................................
Die Methode GetAllSettings ermöglicht die Abfrage aller zum Abschnitt (Unterschlüssel) Sec-
tion gehörigen persistenten Einstellungen eines Programms AppName, die mittels der SaveSet-
ting-Methode als Unterschlüssel des Schlüssels

HKEY_CURRENT_USER\Software\VB and VBA Program Settings\

gespeichert wurden.
Die Methode liefert ihr Ergebnis in einem zweidimensionalen Zeichenfolgenarray mit nullba-
siertem Index, wobei in der ersten Dimension die Bezeichner der Werte und in der zweiten
Dimension die Daten zu den Werten enthalten sind.
Falls ein Schüssel nicht existiert oder keine Werte enthält, liefert die Methode den Wert Empty.
Anwendung

Anwendung
...................................................
Früher mussten Windows-Anwendungen ihre persistenten Einstellungen noch in je eigenen INI-
Dateien ablegen. Spätestens seit Windows 95 (aber auch schon zuvor) gibt es eine zentrale Sys-
temregistrierung, in der sich solche Daten an zentraler Stelle speichern lassen. Für den Zugriff
auf die Systemregistrierung von Visual Basic aus stehen im Wesentlichen vier Methoden zur

27 9
Global- Objekt

Verfügung: GetSetting, GetAllSettings, SaveSetting und DeleteSetting, deren Funktion


bereits durch die Bezeichner deutlich wird. Um auf andere Schlüssel zuzugreifen, müssen Sie die
entsprechenden Funktionen der Win32-API (RegOpenKeyEx etc.) benutzen.
Beispiel

Beis piel
...................................................
Der folgende Code fügt vier Werte unter dem Schlüssel »Abschnitt« in die Registrierung ein.
Danach liest er sie wieder mittels GetAllSettings, gibt sie aus und löscht sie schließlich en bloc.
Dim a, i
SaveSetting "MeineAnwendung", "Abschnitt", "Wert", 10
SaveSetting "MeineAnwendung", "Abschnitt", "Wert1", 20
Global- Objekt

SaveSetting "MeineAnwendung", "Abschnitt", "Höhe", 100


SaveSetting "MeineAnwendung", "Abschnitt", "Breite", 100
a = GetAllSettings("MeineAnwendung", "Abschnitt")
If not IsEmpty(a) Then
For i = 0 To UBound(a)
Print a(i, 0) & " = " & a(i, 1)
Next i
End If
DeleteSetting "MeineAnwendung"
Verwandte Methoden

Verwa ndte Metho den


...................................................
DeleteSetting, GetSetting, SaveSetting
Verwandte Themen

Verwandte Them en
...................................................
Registrierung (S. 561)

GetObject- Methode
Function GetObject([PathName As String], _
[AnwName.ObjektTyp As String]) As Object
Beschreibung

Bes c hreibung
...................................................
Die GetObject-Methode liefert die Referenz auf ein ActiveX-Objekt (Automatisierungsobjekt)
mit registrierter Klasse. Existiert das Objekt bereits als Datei, lässt es sich unter Angabe des ent-
sprechenden Dateinamens (PathName) öffnen, was dazu führt, dass die für das Objekt zuständige
(lies: für den Objekttyp registrierte) Serveranwendung automatisch gestartet wird.
Optional lässt sich über den zweiten String-Parameter die Klasse des zu aktivierenden Objekts
noch genauer spezifizieren, falls in der Datei mehrere Objekte enthalten sind. Ist Pathname die
leere Zeichenfolge, muss der zweite Parameter in jedem Fall angegeben sein, da die Methode
dann eine Referenz auf ein neues Objekt dieser Klasse liefert.
Beispiel

Beis piel
...................................................
Der folgende Code organisiert eine Referenz auf ein Word-Dokument sowie auf eine Corel-
DRAW-Zeichnung:
Dim Wdoc As Object, CorelDoc As Object
Set Wdoc = GetObject("\Eigene Dateien\Basic.doc")
Set Wdoc = GetObject("Zeichnung.cdr", "CorelDRAW.Graphic.7")

280
GetSetting- Methode

Einige Anwendungen ermöglichen es auch, einzelne Eigenschaften eines gegebenen Objekts zu


aktivieren. Der Name der Eigenschaft wird dann durch ein Ausrufezeichen abgetrennt hinten
angefügt.

GetSetting- Methode
Function GetSetting(AppName As String, Section As String, _
Key As String, [Default]) As String
Beschreibung

Bes c hreibung
...................................................
Die GetSetting-Methode entspricht von der Funktionalität her der GetAllSettings-Methode,

Global- Objekt
mit dem Unterschied, dass sie nur die Daten zu einem bestimmten Wert Key des Abschnitts
(Unterschlüssels) Section liefert. Als Vorgabe für den Fall, dass der Eintrag Key nicht existiert,
kann der optionale Parameter Default angegeben werden.
Beispiel

Beis piel
...................................................
Print GetSetting ("MeineAnwendung", "Abmessungen", "Breite", 100)
Verwandte Methoden

Verwa ndte Metho den


...................................................
DeleteSetting, GetAllSettings, SaveSetting
Verwandte Themen

Verwandte Them en
...................................................
Registrierung (S. 561)

InputBox- Methode
Function InputBox(Prompt, [Title], [Default], [XPos, YPos], _
[HelpFile], [Context]) As String
Beschreibung

Bes c hreibung
...................................................
Die Methode InputBox ruft ein Dialogfeld mit den Schaltflächen OK und ABBRECHEN auf, in
dessen Client-Bereich die Eingabeaufforderung Prompt sowie ein einzeiliges Textfeld für die
Werteingabe erscheinen. Als Ergebnis liefert Sie den Wert des Textfeldes als Zeichenfolge. Stan-
dardmäßige Beschriftung des Dialogfelds ist der Name der Anwendung, sie lässt sich aber über
den optionalen Parameter Title frei gestalten. Ist ein Wert für Default angegeben, erscheint die-
ser markiert als Vorgabewert im Textfeld des Dialogs. Bricht der Benutzer den Dialog ab, resul-
tiert die leere Zeichenfolge, unabhängig von der Existenz eines Vorgabewerts. Über XPos und
YPos kann die Position des Dialogfelds relativ zum linken oberen Punkt der Bildschirmanzeige
(Screen) gesetzt werden. Fehlen diese Parameter, setzt Windows das Dialogfeld leicht nach oben
verschoben in die Mitte des Bildschirms. Darüber hinaus lassen sich optional ein Hilfethema
HelpFile sowie eine zuständige Hilfedatei Context angeben.
Anwendung

Anwendung
...................................................
Obwohl der Anwendungsbereich der Methode vom Prinzip her den gesamten Bereich der zei-
lenorientierten Benutzereingabe abdeckt, wird sie eigentlich nur in Situationen eingesetzt, wo
sich der Entwurf eines eigenen Dialogfelds nicht lohnt – so in provisorischen Programmentwür-
fen oder wenn bei der Reaktion auf einen Fehler interaktive Eingaben erforderlich sind.

281
Global- Objekt

Beispiel

Beis piel
...................................................
Do
a = InputBox("Bitte eine Zahl zwischen 10 und 100 eingeben", _
"Bereich einstellen")
Loop Until IsNumeric(a) And Val(a) <= 100 And Val(a) >= 10
Verwandte Methoden

Verwa ndte Metho den


...................................................
MsgBox
Global- Objekt

Load- Methode
Function Load(Object As Object)
Beschreibung

Bes c hreibung
...................................................
Die Load-Methode lädt das Objekt Object in den Hautspeicher und initialisiert es, ohne es anzu-
zeigen. Das Objekt kann ein Formular, ein MDI-Formular oder ein Steuerelement sein.
Anwendung

Anwendung
...................................................
Normalerweise ist es unnötig, ein Formular oder ein zur Entwurfszeit eingefügtes Steuerelement
explizit zu laden, denn jeder Verweis auf das Formular (mit Ausnahme von TypeOf- und Set-
Konstrukten) veranlasst Visual Basic dazu, dieses samt aller ihm untergeordneten Steuerele-
mente implizit zu laden. Für ein Formular, das nicht Startobjekt des Projekts ist und somit zum
Programmstart auch nicht automatisch geladen wird, genügt ein Show-Aufruf, um es zu laden
und anzeigen. Die explizite Verwendung von Load vor Show kann aber den Vorteil haben, dass
das Objekt dann, wenn es benötigt wird, bereits geladen ist und nur noch die Visible-Eigen-
schaft mittels Show oder explizit zu setzen ist, um es ohne weitere Wartezeiten anzuzeigen.
Explizit ist der Load-Aufruf eigentlich nur erforderlich, wenn Sie mit einem Steuerelemente-
Array arbeiten und in dieses zur Laufzeit eine neue Instanz des Steuerelements einfügen wollen.
Visual Basic erweitert das Array dann automatisch, initialisiert die Visible-Eigenschaft jedoch
mit False, so dass Sie diese Eigenschaft extra auf True setzen müssen, damit das neue Steuerele-
ment sichtbar wird.
Tipp

Tipp
...................................................
Um Ressourcen zu sparen, können Sie selten benötigte Formulare oder monströse Steuerele-
mente mittels Unload umgehend nach Gebrauch wieder entladen. Das erneute Laden erfolgt
dann implizit mit dem nächsten Show-Aufruf. Diese Technik führt dazu, dass auch alle Steuer-
elemente auf dem Formular neu initialisiert werden – ein Vorgang, der natürlich auf Kosten der
Laufzeit geht.
Beispiel

Beis piel
...................................................
Load Form1
Verwandte Befehle

Verwa ndte Befehle


...................................................
Unload, Show
Verwandte Themen

Verwandte Them en
...................................................
Schach – klare Sicht auf Hintergründliches (S. 607)

282
LoadPicture- Methode

LoadPicture- Methode
Function LoadPicture([FileName As String], _
[Size As LoadPictureSizeConstants], _
[ColorDepth As LoadPictureColorConstants], _
[X], [Y]) _
As Picture
Beschreibung

Bes c hreibung
...................................................
Die LoadPicture-Methode lädt eine Grafikdatei FileName, die in einem der Formate DIB, BMP,
RLE, ICO, CUR, GIF, JPG, WMF oder EMF vorliegt, und liefert eine Referenz vom Typ Pic-

Global- Objekt
ture dafür. Falls die Datei eines der Formate ICO oder CUR trägt, können Sie für den optiona-
len Parameter Size zwischen verschiedenen Symbolgrößen auswählen (sofern in der Datei ver-
fügbar). Der Aufzählungstyp LoadPictureSizeConstants definiert dafür die folgenden
Konstanten:

Konstante Beschreibung
vbLPSmall (0) Kleines Systemsymbol (Voreinstellung)
vbLPLarge (1) Großes Systemsymbol
vbLPSmallShell (2) Größe von »Titelleistensymbol«, wie im Systemdialog EIGEN-
SCHAFTEN VON ANZEIGE auf der Registerkarte DARSTELLUNG
festgelegt
vbLPLargeShell (3) Größe von Symbol, wie im Systemdialog EIGENSCHAFTEN VON
ANZEIGE auf der Registerkarte DARSTELLUNG festgelegt
vbLPCustom (4) Benutzerdefinierte Größe

Für den optionalen Parameter ColorDepth gibt es drei Werte, für die der Aufzählungstyp Load-
PictureColorConstants Konstanten definiert.

Konstante Beschreibung
vbLPDefault (0) System wählt beste Übereinstimmung mit Anzeige
vbLPMonochrom (1) Schwarz/Weiß
vbLPVGAColor (2) 16 Grundfarben
vbLPColor (3) 256 Farben

Wird die Methode ohne Parameter aufgerufen, liefert Sie den Wert Empty und kann dafür
benutzt werden, die Picture-Eigenschaft eines Steuerelements oder Formulars auf »Kein Bild«
zu setzen.
Beispiel

Beis piel
...................................................
Set Picture = LoadPicture(Dateiname)
Set Picture1.Picture = LoadPicture(Dateiname1)

283
Global- Objekt

LoadResData- Methode, LoadResPicture- Methode, LoadResString- Methode


Function LoadResData(Id, ResType As Integer) As Byte()
Function LoadResPicture(Id, ResType As Integer) As Picture
Function LoadResString(Id As Long) As String
Beschreibung

Bes c hreibung
...................................................
Die Methoden LoadResData, LoadResPicture und LoadResString ermöglichen das Laden von
binären Ressourcen, Bildressourcen oder Zeichenfolgenressourcen aus einer Ressourcendatei
(RES). Für den Parameter Id ist die Ressourcenkennung anzugeben, wie im Ressourcen-Editor
Global- Objekt

festgelegt. Die Methoden LoadResData und LoadResPicture erwarten noch einen weiteren Para-
meter, ResType, der den Typ der zu ladenden Ressource genauer spezifiziert. LoadResPicture
akzeptiert für diesen Parameter die drei Werte vbResBitmap (0), vbResIcon (1) vbResCursor (2),
während LoadResData den Zugriff auf alle Arten von Ressourcen (also auch auf Zeichenfolgen
und Bitmaps) ermöglicht, diese aber in Form eines Byte-Arrays zurückliefert. Der Parameter
ResType kann für diese Methode folgende Werte tragen:

Wert für ResType Art der Ressource


1 Cursor
2 Bitmap
3 Symbol
4 Menü
5 Dialogfeld
6 Zeichenfolge
7 Schriftartverzeichnis
8 Schriftart
9 Zugriffstasten (Accelerator)
10 benutzerdefiniert
12 Gruppen-Cursor
14 Gruppensymbol

Printer- Objekt
Public Printer As Printer
Beschreibung

Bes c hreibung
...................................................
Das in jeder Anwendung als globales Objekt bekannte Printer-Objekt entstammt der gleichna-
migen in der Bibliothek VB beheimateten Klasse und ermöglicht Druckerausgaben aus einer
Anwendung heraus. Bei Start einer Anwendung ist das Printer-Objekt auf den aktuellen Stan-
darddrucker des Systems gesetzt, und seine Eigenschaften spiegeln die dafür in der Systemsteue-
rung getroffenen Standardeinstellungen wider. Die Eigenschaften des Printer-Objekts lassen
sich ohne Auswirkungen für andere Anwendungen individuell ändern. Um die Druckerausgabe
gezielt auf einen bestimmten Drucker zu leiten (bzw. über einen bestimmten Druckertreiber
auszugeben), kann dem Printer-Objekt jederzeit ein anderes Element aus der Printers-Auflis-
tung zugewiesen werden. In dieser Auflistung sind alle auf dem jeweiligen System installierten
Drucker enthalten.

284
Printer- Objekt

Eigenschaften

...................................................
Eigens c ha ften
Das Printer-Objekt verfügt über eine stattliche Anzahl von Eigenschaften, auf deren Basis der
für den jeweiligen Drucker installierte Druckertreiber die Druckausgabe durchführt. Da nicht
alle Drucker alle Eigenschaften unterstützen, können einzelne Eigenschaften auch ohne Wir-
kung bleiben oder verschiedene Einstellungen die gleiche Wirkung haben (insbesondere »Trans-
parenz« kann ein Problem sein). Einstellungen außerhalb der zulässigen Wertebereiche können
einen Laufzeitfehler verursachen – müssen aber nicht. Genaue Informationen über die Wirkung
der einzelnen Werte bezogen auf eine spezielle Konstellation aus Drucker und Treiber finden Sie
in den jeweiligen Herstellerdokumentationen.

Global- Objekt
Eigenschaft Beschreibung
ColorMode Wert vom Typ Integer, der den Farbmodus des Druckers wiedergibt
bzw. festlegt. Der Aufzählungstyp PrinterObjectConstants definiert
dafür zwei Konstanten: vbPRCMColor (1) – Ausdruck nach Möglichkeit in
Farbe; vbPRCMMonochrom (2) – Ausdruck in Graustufen.
Copies Wert vom Typ Integer, der die Anzahl der Kopien eines Ausdrucks fest-
legt
CurrentX Werte vom Typ Single, die die aktuelle Position auf der Ausgabefläche
CurrentY für die nächste Zeichenoperation wiedergeben bzw. festlegen. Standard-
mäßig gilt die Einheit Twips, es sei denn, über die Eigenschaft ScaleMode
wurde eine andere Einheit festgelegt.
DeviceName Schreibgeschützter Wert vom Typ String, der den Gerätenamen des dem
Printer-Objekt aktuell zugewiesenen Druckers wiedergibt
DrawMode Wert vom Typ Integer, der den Zeichenmodus für Zeichenoperationen
sowie für das Zeichnen von Figur- und Liniensteuerelementen festlegt.
Der Aufzählungstyp DrawModeConstants definiert dafür eine Reihe von
Konstanten:
vbBlackness (1) Schwarzintensität
vbNotMergePen (2) Stift mischen invers (invers zu 15)
vbMaskNotPen (3) inversen Stift maskieren; Kombination der Farben,
die der Hintergrund mit der invertierten Stiftfarbe
gemeinsam hat
vbNotCopyPen (4) Stift kopieren invers (invers zu 13)
vbMaskPenNot (5) Stift und inverse Anzeige maskieren; Kombination
der Farben, die der Stift mit der invertierten Anzei-
gefarbe gemeinsam hat
vbInvert (6) Anzeigefarbe invers
vbXorPen (7) Stift Xor; Kombination der Farben, die im Stift und
in der Anzeigefarbe, aber nicht in beiden vorhan-
den sind
vbNotMaskPen (8) Stift maskieren invers (invers zu 9)
vbMaskPen (9) Stift maskieren; Kombination der Farben, die Stift
und Anzeigefarbe gemeinsam haben (invers zu 10)
vbNotMaskPen (10) Stift maskieren invers (invers zu 9)

285
Global- Objekt

Eigenschaft Beschreibung
DrawMode (Forts.) vbNop (11) Keine Operation, Stift zeichnet nicht
vbMergeNotPen (12) inversen Stift mischen – Kombination der Anzeige-
farbe und der invertierten Stiftfarbe
vbCopyPen (13) Stift kopieren (Voreinstellung); Stiftfarbe ist durch
Eigenschaft ForeColor gegeben (invers zu 4)
vbMergePenNot (14) Stift und inverse Anzeige mischen; Kombination
der Stiftfarbe und der invertierten Anzeigefarbe
Global- Objekt

vbMergePen (15) Stift mischen; Kombination aus Stift- und Anzeige-


farbe (invers zu 2)
vbWhiteNess (16) Weißintensität
DrawStyle Wert vom Typ Integer, der den Linienstil für Zeichenoperationen fest-
legt. Der Aufzählungstyp DrawStyleConstants definiert dafür eine Reihe
von Konstanten:
vbSolid (0) Durchgezogen (Voreinstellung)
vbDash (1) Gestrichelt
vbDot (2) Gepunktet
vbDashDot (3) Folge aus Strichen und Punkten
vbDashDotDot (4) Folge aus Strichen und zwei Punkten
vbInvisible (5) Transparent
vbInsideSolid (6) Innen ausgefüllt
DrawWidth Wert vom Typ Integer, der die Linienbreite in Bildpunkten für Zeichen-
operationen festlegt. Der Wert kann zwischen 1 (Haarlinie; Voreinstel-
lung) und 32767 liegen. Ist der Wert ungleich 1, erzeugen die Werte 0 bis
4 für die DrawStyle-Eigenschaft eine durchgezogene Linie.
DriverName Zur Laufzeit schreibgeschützter Wert vom Typ String mit dem Geräte-
namen des Druckers
Duplex Wert vom Typ Integer für einseitiges oder beidseitiges Drucken. Der
Aufzählungstyp DrawStyleConstants definiert dafür drei Konstanten:
vbPRDPSimplex (1) Einseitiges Drucken
vbPRDPHorizontal (2) Beidseitiges Drucken mit horizontalem Seiten-
wechsel
vbPRDPVertical (3) Beidseitiges Drucken mit vertikalem Seiten-
wechsel
FillColor Farbwert vom Typ Long, der die Füllfarbe für das Ausmalen von Figuren
angibt. Standardwert ist 0 (vbBlack). Beliebige Farben lassen sich aus
ihren Komponentenanteilen über die Funktion RGB komponieren. Die
Funktion QBColor liefert den Farbwert einer der 16 Grundfarben. Zudem
stehen die Elemente des Aufzählungstyps ColorConstants als vordefi-
nierte Konstanten zur Verfügung.

286
Printer- Objekt

Eigenschaft Beschreibung
FillStyle Wert vom Typ Integer, der das Füllmuster für das Ausmalen von Figu-
ren angibt. Der Aufzählungstyp FillStyleConstants definiert dafür acht
Konstanten:
vbFSSolid (0) Ausgefüllt
vbFSTransparent (1) Transparent (Voreinstellung)
VbHorizontalLine (2) Horizontales Linienmuster
vbVerticalLine (3) Vertikales Linienmuster

Global- Objekt
vbUpwardDiagonal (4) Aufwärtsdiagonales Linienmuster
vbDownwardDiagonal (5) Abwärtsdiagonales Linienmuster
vbCross (6) Kreuzmuster
vbDiagonalCross (7) Diagonalkreuzmuster
Font Objekt vom Typ Font, das die Schrift für Ausgaben auf das Gerät reprä-
sentiert
FontBold Werte vom Typ Boolean, die als Attribute für die Schriftstile Fett, Kursiv,
FontItalic Durchgestrichen und Unterstrichen fungieren
FontStrikethru
FontUnderline
FontCount Schreibgeschützter Wert von Typ Integer, der die Anzahl der dem Prin-
ter-Objekt bekannten Schriften wiedergibt
FontName Wert vom Typ String, der den Namen der aktuell eingestellten Schriftart
wiedergibt bzw. festlegt
FontTransparent Wert vom Typ Boolean, der festlegt, ob die Textausgabe mit durchschei-
nendem Hintergrund oder in einem Kasten mit Hintergrundfarbe erfolgt.
Ein Ändern der Eigenschaft während der Druckerausgabe wirkt sich nur
auf nachfolgende Textausgaben aus.
Fonts Schreibgeschützte Auflistung der dem Printer-Objekt bekannten Schrif-
ten
FontSize Wert vom Typ Single, der die Schriftgröße wiedergibt bzw. festlegt
ForeColor Farbwert vom Typ Long, der die Vordergrundfarbe für Zeichenoperatio-
nen im Modus 13 (vbCopyPen) wiedergibt bzw. festlegt. Beliebige Farben
lassen sich aus ihren Komponentenanteilen über die Funktion RGB kom-
ponieren. Die Funktion QBColor liefert den Farbwert einer der 16 Grund-
farben. Zudem stehen die Elemente des Aufzählungstyps ColorConstants
als vordefinierte Konstanten zur Verfügung.
hDC Zur Laufzeit schreibgeschützter Wert vom Typ Long, der auf den Geräte-
kontext des Ausgabegerätes verweist und nur im Zusammenhang mit
Funktionen der Win32-API benötigt wird
Height Werte vom Typ Long, die die Höhe bzw. Breite der Ausgabefläche in
Width Twips beschreiben. Sie richten sich im Allgemeinen nach der Eigenschaft
PaperSize. Setzt man einen dieser Werte, ändert sich gleichzeitig der
Wert von PaperSize auf 256. (Bei A4 ist die Ausgabefläche
16.834 × 11.909 Twips, was bei 600 dpi 7.014 × 4.962 Bildpunkten ent-
spricht.)

287
Global- Objekt

Eigenschaft Beschreibung
Orientation Wert vom Typ Integer, der die Orientierung des Papiers beim Ausdruck
festlegt. Der Aufzählungstyp PrinterObjectConstants definiert dafür
zwei Konstanten:
vbPRORPortrait (1) Hochformat (Standard)
vbPRORLandscape (2) Querformat
Page Zur Laufzeit schreibgeschützter Wert vom Typ Integer, der die aktuelle
Seitennummer seit dem letzten Aufruf von EndDoc bzw. dem Programm-
start wiedergibt. Der mit 1 initialisierte Wert erhöht sich mit jedem Auf-
Global- Objekt

ruf von NewPage um 1, aber auch, wenn die Print-Methode den unteren
Papierrand erreicht hat.
PaperBin Wert vom Typ Integer, der die Papierzufuhr für die Druckerausgabe
festlegt. Der Aufzählungstyp PrinterObjectConstants definiert dafür fol-
gende Konstanten:
vbPRBNUpper (1) Oberer Behälter
vbPRBNLower (2) Unterer Behälter
vbPRBNMiddle (3) Mittlerer Behälter
vbPRBNManual (4) Manueller Einzug
vbPRBNEnvelope (5) Umschlagspapiereinzug automat.
vbPRBNEnvManual (6) Umschlagspapiereinzug manuell
vbPRBNAuto (7) Standardbehälter (Voreinstellung)
vbPRBNTractor (8) Traktor-Einzug
vbPRBNSmallFmt (9) Kleiner Papierbehälter
vbPRBNLargeFmt (10) Großer Papierbehälter
vbPRBNLargeCapacity (11) Einzug mit großem Papiervorrat
vbPRBNCassette (14) Kassetten-Cartridge
PaperSize Wert vom Typ Integer, der die Papiergröße und damit die Größe der
Ausgabefläche festlegt. Ein Setzen dieses Werts ändert gleichzeitig die
Werte der Eigenschaften Height und Width. Der Aufzählungstyp Printer-
ObjektConstants definiert dafür folgende Konstanten:
vbPRPSLetter (1) US Letter: 8½×11 Zoll
vbPRPSLetterSmall (2) US Letter Small: 8½×11 Zoll
vbPRPSTabloid (3) US Tabloid: 11×17 Zoll
vbPRPSLedger (4) US Ledger: 17×11 Zoll
vbPRPSLegal (5) US Legal: 8½×14 Zoll
vbPRPSStatement (6) US Statement: 5½×8½ Zoll
vbPRPSExecutive (7) Executive: 7½×10½ Zoll
vbPRPSA3 (8) DIN A3: 297×420 mm
vbPRPSA4 (9) DIN A4: 210×297 mm
vbPRPSA4Small (10) DIN A4: 210×297 mm
vbPRPSA5 (11) DIN A5: 148×210 mm

288
Printer- Objekt

Eigenschaft Beschreibung
PaperSize (Forts.) vbPRPSB4 (12) DIN B4: 250×354 mm
vbPRPSB5 (13) DIN B5: 182×257 mm
vbPRPSFolio (14) Folio: 8½×13 Zoll
vbPRPSQuarto (15) Quarto: 215×275 mm
vbPRPS10x14 (16) 10×14 Zoll
vbPRPS11x17 (17) 11×17 Zoll
vbPRPSNote (18) US Note: 8½×11 Zoll

Global- Objekt
vbPRPSEnv9 (19) Umschlag 9: 37/8×87/8 Zoll
vbPRPSEnv10 (20) Umschlag 10: 41/8×9½ Zoll
vbPRPSEnv11 (21) Umschlag 11: 4½×103/8 Zoll
vbPRPSEnv12 (22) Umschlag 12: 4½×11 Zoll
vbPRPSEnv14 (23) Umschlag 14: 5×11½ Zoll
vbPRPSCSheet (24) Blatt in C-Größe
vbPRPSDSheet (25) Blatt in D-Größe
vbPRPSESheet (26) Blatt in E-Größe
vbPRPSEnvDL (27) Umschlag DL: 110×220 mm
vbPRPSEnvC5 (28) Umschlag C5: 162×229 mm
vbPRPSEnvC3 (29) Umschlag C3: 324×458 mm
vbPRPSEnvC4 (30) Umschlag C4: 229×324 mm
vbPRPSEnvC6 (31) Umschlag C6: 114×162 mm
vbPRPSEnvC65 (32) Umschlag C65:114×229 mm
vbPRPSEnvB4 (33) Umschlag B4: 250×353 mm
vbPRPSEnvB5 (34) Umschlag B5: 176×250 mm
vbPRPSEnvB6 (35) Umschlag B: 176×125 mm
vbPRPSEnvItaly (36) Umschlag: 110×230 mm
vbPRPSEnvMonarch (37) Umschlag Monarch: 37/8×7½ Zoll
vbPRPSEnvPersonal (38) Umschlag, 35/8×6½ Zoll
vbPRPSFanfoldUS (39) U.S. Stand. Fanfold: 147/8×11 Zoll
vbPRPSFanfoldStdGerman (40) Standard-Durchschlag: 8½×12 Zoll
vbPRPSFanfoldLglGerman (41) Legal-Durchschlag: 8½×13 Zoll
vbPRPSUser (256) benutzerdefiniert
Port Schreibgeschützter Wert vom Typ String, der den Namen der Schnitt-
stelle (zum Beispiel: »LPT1«) oder Netzwerkfreigabe wiedergibt, über
die die Druckausgabe an den Drucker geleitet wird

289
Global- Objekt

Eigenschaft Beschreibung
PrintQuality Wert vom Typ Integer, der die Auflösung als Qualitätsstufe (negativer
Wert) oder in dpi (positiver Wert, z.B.: 600) wiedergibt bzw. festlegt.
Der Aufzählungstyp PrinterObjectConstants definiert vier Konstanten
für die Wahl der Qualitätsstufe:
vbPRPQDraft (-1) Entwurfsqualität
vbPRPQLow (-2) Geringe Qualität
vbPRPQMedium (-3) Mittlere Qualität
vbPRPQHigh (-4) Hohe Qualität
Global- Objekt

RightToLeft Schreibgeschützter Wert vom Typ Boolean, der angibt, ob das Gerät Aus-
gaben in umgekehrter Leserichtung ermöglicht (nur im Zusammenhang
mit bidirektionalen Systemen von Interesse)
ScaleHeight Werte vom Typ Single, die die Höhe bzw. Breite der für die Druckaus-
ScaleWidth gabe zur Verfügung stehenden Fläche in der jeweils geltenden Maßein-
heit (vgl. ScaleMode) und Vergrößerungsstufe (vgl. Zoom) wiedergeben.
Jede Änderung dieser Werte wirkt sich als Skalierung des logischen
Koordinatensystems aus, die physikalischen Abmessungen der für die
Druckausgabe zur Verfügung stehenden Fläche bleiben dabei unverän-
dert (vgl. PaperSize). Setzt man beispielsweise ScaleHeight auf den Wert
100, ordnet das der physikalischen Höhe der Druckausgabefläche (die
im metrischen System beispielsweise 30 cm beträgt) im logischen Koordi-
natensystem das Maß 100 zu. Jede Wertänderung zieht implizit eine
Änderung der Eigenschaft ScaleMode auf den Wert 0 (benutzerdefiniert)
nach sich.
ScaleLeft Werte vom Typ Single, die die Koordinaten der linken bzw. oberen Ecke
ScaleTop der Druckausgabefläche wiedergeben (vgl. auch ScaleMode und Zoom).
Jede Änderung dieser Werte wirkt sich als Translation des logischen
Koordinatensystems aus. Die physikalischen Abmessungen der für die
Druckausgabe zur Verfügung stehenden Fläche bleiben dabei unverän-
dert (vgl. PaperSize). Setzt man beispielsweise ScaleLeft sowie ScaleTop
auf den Wert -100 und ScaleWidth sowie ScaleHeight auf 200, wird die
Druckausgabefläche durch das von den Punkten (-100, -100) und (100,
100) aufgespannte Rechteck beschrieben.
ScaleMode Wert vom Typ Integer, der das für die Druckausgabe geltende Koordi-
naten- und Maßsystem beschreibt. Ist der Wert ungleich 0, liegt der
Ursprung des Koordinatensystems links oben. Der Aufzählungstyp Sca-
leModeConstants definiert mehrere Konstanten für die Wahl des Maßsys-
tems:
vbUser (0) Benutzerdefiniertes Koordinaten- und Maßsystem
(wird implizit gesetzt, wenn mindestens eine der Ei-
genschaften ScaleHeight, ScaleWidth, ScaleLeft
und ScaleTop einen benutzerdefinierten Wert er-
hält)
vbTwips (1) Maßeinheit ist Twips (567 Twips entsprechen ei-
nem Zentimeter und 1440 Twips einem Zoll)
vbPoints (2) Maßeinheit ist Punkt (72 Punkt entsprechen einem
Zoll)

290
Printer- Objekt

Eigenschaft Beschreibung
ScaleMode (Forts.) vbPixels (3) Maßeinheit ist Bildpunkt (kleinste Einheit, die in
der geltenden Auflösung auf dem Drucker darge-
stellt werden kann)
vbCharacters (4) Maßeinheit ist Zeichen (horizontal: 120 Twips je
Einheit; vertikal: 240 Twips je Einheit)
vbInches (5) Maßeinheit ist Zoll
vbMillimeters (6) Maßeinheit ist Millimeter

Global- Objekt
vbCentimeters (7) Maßeinheit ist Zentimeter
vbHimetric (8) Maßeinheit ist HiMetric (0,01 mm)
TrackDefault Wert von Typ Boolean, der festlegt, ob das Printer-Objekt vonseiten des
Betriebssystems veranlasste Änderungen des Standarddruckers zur Lauf-
zeit des Programms mitmacht (True; Voreinstellung) oder nicht (False).
Eine Änderung dieser Eigenschaft während der Druckausgabe erzwingt
implizit den Aufruf der Methode EndPage.
TwipsPerPixelX Zur Laufzeit schreibgeschützte Werte vom Typ Single, die ausdrücken,
TwipsPerPixelY wie viele Twips bei der aktuell eingestellten Auflösung einem Bildpunkt
in horizontaler (X) und vertikaler Richtung (Y) entsprechen (bei 600 dpi
entsprechen 2,4 Twips einem Bildpunkt)
Width Siehe Height
Zoom Wert vom Typ Long, der den Vergrößerungsfaktor für die Druckausgabe
in Prozent enthält. (Um von A4 auf A5 zu verkleinern, ist beispielsweise
der Vergrößerungsfaktor 71 einzustellen.) Bei Druckern, die keine Ver-
größerung unterstützen, ist dieser Wert 0, Standardvorgabe ist 100.

Methoden
Methoden

...................................................
Sub Printer.Circle (x As Single, y As Single, Radius As Single, _
[Color As Long, Start As Single, End As Single, Aspect As Single]
Sub Printer.EndDoc()
Sub Printer.KillDoc()
Sub Printer.Line (Flags As Integer, X1 As Single, Y1 As Single, _
X2 As Single, Y2 As Single, Color As Long)
Sub Printer.NewPage()
Sub Printer.PaintPicture(pic As Picture, X1 As Single, _
Y1 As Single, [Width1 As Single], [Height1 As Single],
[X2 As Single], [Y2 As Single], [Width2 As Single], _
[Height2 As Single], [Opcode])
Sub Printer.Print (Ausdr1[Trennz [Ausdr2] ... ]])
Sub Printer.PSet( X As Single, Y As Single, Color As Long)
Function Printer.ScaleX(Width As Single, [FromScale], [ToScale]) _
As Single

291
Global- Objekt

Function Printer.ScaleY(Width As Single, [FromScale], [ToScale]) _


As Single
Function Printer.TextHeight(Str As String) As Single
Function Printer.TextWidth(Str As String) As Single
Das Printer-Objekt hat zwölf Methoden mit benannten Argumenten. Drei davon (EndDoc,
NewPage und KillDoc) sind originäre Methoden des Printer-Objekts und dienen der Drucksteu-
erung. Die anderen Methoden finden sich auch bei anderen Objekten, die über einer Ausgabe-
fläche operieren (Form, PictureBox, PropertyPage, UserControl, UserDocument), und ermöglichen
Berechnungen sowie Operationen, die mittelbar oder unmittelbar mit dem Zeichnen im Zusam-
Global- Objekt

menhang stehen. Die Textausgabe erfolgt mit der Print-Anweisung, die Grafikausgabe mit
PaintPicture, und gezeichnet wird mit Line, Circle und PSet.
Die Syntax für den Aufruf der Methoden Circle, Line und PSet ist traditionell spezifisch:
Circle [Step] (x, y), Radius, [Color], [Start], [End], [Aspect]
Line [Step] (x1, y1) – [Step] (x2, y2), [Color], [B[F]]
PSet [Step] (x, y), [Color]
Ist das optionale Schlüsselwort Step angegeben, wird das unmittelbar folgende Koordinaten-
paar als relativer Offset bzgl. der aktuellen Position (CurrentX, CurrentY) interpretiert, ansons-
ten als absolute Position – jeweils bezogen auf das geltende Koordinatensystem. Standardmäßig
zeichnen die Methoden in der durch die Eigenschaft ForeColor spezifizierten Farbe (Standard-
wert ist Schwarz: vbBlack). Beliebige Farben lassen sich aus ihren Komponentenanteilen über
die Funktion RGB zu einem Long-Wert für den optionalen Parameter Color komponieren. Defi-
nierte Farben liefert die Funktion QBColor (16 Grundfarben) sowie der Aufzählungstyp Color-
Constants. Füllfarbe ist FillColor, sofern FillStyle ungleich 1 ist.

Methode Beschreibung
Circle Zeichnet einen Kreis um den Mittelpunkt (x, y) mit Radius Radius und
der optionalen Stiftfarbe Color. Sind die optionalen Parameter Start und
End angegeben, zeichnet die Methode nur einen Teilkreis. Start und End
bezeichnen den Start- und Endwinkel (im Bogenmaß). Ist der Parameter
Aspect mit einem Wert ungleich 1 bzw. -1 angegeben, zeichnet die
Methode eine Ellipse, die dem Kreis einbeschrieben (positive Werte) bzw.
umbeschrieben (negative Werte) ist. Aspect drückt das Verhältnis zwi-
schen Höhe und Breite des begrenzenden Rechtecks aus.
EndDoc Schließt den aktuellen Druckjob ab und gibt gegebenenfalls zuvor noch
die aktuelle Druckseite für den Ausdruck frei, wenn bereits Ausgabeope-
rationen darauf erfolgt sind
KillDoc Bricht den aktuellen Druckjob ab
Line Zeichnet eine Linie zwischen den Punkten (x1, y1) und (x2, y2). Ist der
optionale Zusatz »B« gegeben, zeichnet die Methode das Rechteck, das
die beiden Punkte definieren. Ist der optionale Zusatz »BF« gegeben,
zeichnet die Methode das Rechteck und füllt es mit der Füllfarbe FillCo-
lor aus.
NewPage Schließt die aktuelle Druckseite ab und gibt sie für den Ausdruck frei

292
Printer- Objekt

Methode Beschreibung
PaintPicture Zeichnet das im Datentyp Picture vorliegende Bild pic an der Position
(X1, Y1), die den linken oberen Bildpunkt beschreibt. Alle Werte sind in
der aktuellen Maßeinheit (ScaleMode) anzugeben. Sind die optionalen
Parameter Height1 und Width1 angegeben, wird das Bild auf diese Maße
skaliert, ansonsten errechnet sich die Methode diese Werte selbst und gibt
das Bild in originaler Größe aus. Sind die optionalen Parameter X2 und Y2
sowie Width2 und Height2 vorhanden, beschreiben diese einen Bildaus-
schnitt innerhalb des Bildes, der (nach impliziter Skalierung) in dem
durch X1, Y1, Width1 und Height1 spezifizierten Rechteck ausgegeben

Global- Objekt
wird. (Achtung: die Eigenschaften Height und Width eines Picture-
Objekts sind in der Maßeinheit »HiMetric« gehalten und müssen gegebe-
nenfalls mittels ScaleX und ScaleY in die geltende Maßeinheit – Vorgabe
ist Twips – umgewandelt werden.) Negative Werte für Height und/oder
Width führen zu einer spiegelverkehrten und/oder um 180° gedrehten Aus-
gabe. Koordinaten für Ausschnitte sind auf den Ursprung des aktuellen
Koordinatensystems zu beziehen!
Print Gibt die in der Parameterliste genannten Werte unter Berücksichtigung
etwaiger Trennzeichen (Semikolon, Komma, Tab(n)) in der gegebenen
Schrift (Font-Eigenschaft) als Zeichenfolge an der aktuellen Position aus.
Dabei beschreiben die Eigenschaften CurrentX und CurrentY den linken
oberen Punkt des begrenzenden Rechtecks. Der Platzbedarf lässt sich mit-
tels TextHeight und TextWidth ermitteln.
PSet Zeichnet einen Punkt an der Position (x, y) in der Farbe Color
ScaleX Rechnet die Koordinate Width für die X-Achse (bzw. Y-Achse) vom Koor-
ScaleY dinatensystem FromScale in das Koordinatensystem ToScale um und lie-
fert die neue Koordinate als Single. Fehlt der Parameter für ein
Koordinatensystem, bezieht sich die Methode auf das aktuell geltende
Koordinatensystem. Für die verschiedenen Koordinatensysteme sind
Integer-Konstanten definiert (vgl. »ScaleMode-Eigenschaft«, S. 369)
TextHeight Liefert die für die Ausgabe der Zeichenfolge Str benötigte Höhe in der
aktuellen y-Maßeinheit des aktuellen Koordinatensystems
TextWidth Liefert die für die Ausgabe der Zeichenfolge Str benötigte Breite in der
aktuellen x-Maßeinheit des aktuellen Koordinatensystems

Anwendung

Anwendung
...................................................
Das Druckmodell von Visual Basic ist relativ einfach, erlegt dem Programmierer leider aber
auch gewisse Beschränkungen auf. Ein Visual-Basic-Programm muss damit auskommen, was
auf dem jeweiligen System im Angebot ist, da es weder möglich ist, ein neues Printer-Objekt
ins Leben zu rufen, noch die Printers-Auflistung zu erweitern. Das heißt auch, es kann zu
einem Zeitpunkt immer nur einen Drucker ansprechen, nämlich den, auf den das Printer-
Objekt gesetzt ist. (Die parallele Ausgabe auf mehreren Druckern ist zwar vom Prinzip her
möglich, wenn man direkt auf Funktionen des GDI zurückgreift, die Angelegenheit wird dann
jedoch recht aufwändig. (Vgl. auch den Tipp)
Das Printer-Objekt verfügt über die nötige Ausstattung, die Druckausgabe durchzuführen. Die
Ausgabe selbst ist seitenorientiert: Die Anwendung zeichnet (ohne weitere Vorbereitungen)
jeweils den Inhalt einer Seite unter Verwendung der entsprechenden Methoden des Printer-

293
Global- Objekt

Objekts (darunter: Line, Circle, Print, PSet, Print TextHeight und TextWidth) und gibt diese
Seite dann nach Fertigstellung explizit durch Aufruf der Methode NewPage für den Ausdruck
frei. Die Freigabe der ersten Seite eröffnet einen Druckjob in der Warteschlange des dem Prin-
ter-Objekt zugeordneten Druckers. Nachfolgende Ausgaben erscheinen dann – bis zum nächs-
ten NewPage-Aufruf – auf der nächsten Seite. NewPage pflegt darüber hinaus die Page-Eigenschaft
des Objekts, die somit (beginnend mit 1) immer die aktuelle Seitennummer wiedergibt. Der Zei-
chenvorgang an sich unterscheidet sich nicht vom Zeichnen in ein Formular oder ein Steuerele-
ment. Falls der eingestellte Drucker keine Farben unterstützt, setzt der Druckertreiber die Farb-
werte je nach Voreinstellung im Eigenschaftsfenster in Grauwerte um. Zum Abschluss eines
Druckjobs ist ein Aufruf der Methode EndDoc erforderlich. (Visual Basic führt diesen Aufruf bei
Programmende zwar von sich aus durch, darauf zu bauen, wäre aber schlechter Programmier-
Global- Objekt

stil und würde insbesondere auch den Drucker bis zum Programmende blockieren.) Falls zwi-
schen dem letzten Aufruf von NewPage und EndDoc Ausgaben stattgefunden haben, gibt EndDoc
erst die angefangene Seite zum Ausdruck frei und beendet dann den Druckjob. Mit Beendigung
eines Druckjobs erhält Page wieder den Wert 1. Die Methode KillDoc erlaubt es, einen noch
nicht abgeschlossenen Druckjob unmittelbar abzubrechen (je nach Zustand der Warteschlange
des eingestellten Druckers kann dies auch während des Ausdrucks sein, im Drucker gepufferte
vollständige Seiten kommen aber noch zum Ausdruck).
Zur Gestaltung der Ausgabe können die Eigenschaften des Printer-Objekts jederzeit geändert
werden, etwa um eine andere Schriftart oder Schriftgröße einzustellen oder ein Attribut zu
ändern. Eine Änderung wirkt sich erst für die nächste Ausgabeoperation aus, hat also keinen
Rückbezug auf bereits geschehene Ausgabeoperationen für die jeweilige Seite.
Tipps

...................................................
Tipps
In manchen Fällen ist der mit dem Betriebssystem verbundene und verallgemeinernde Overhead
bei der Druckerausgabe eher eine Last als eine Erleichterung, so beispielsweise, wenn der instal-
lierte Treiber das Ausgabegerät nicht im gewünschten Umfang unterstützt oder wenn Lösungen
für ganz spezifische Problemstellungen gefragt sind. Ein Programm kann einen Drucker (oder
ein sonstiges Ausgabegerät) dann gegebenenfalls direkt über die jeweilige Geräteschnittstelle
ansprechen – die klassische Methode der Druckerausgabe also. Dazu öffnet und schließt man
die Schnittstelle wie eine Datei (Open "LPT1:" For Binary …) und versorgt das Gerät via Print#
mit geeigneten Daten.
Wenn Sie ein Formular ausdrucken wollen, wie es auf dem Bildschirm erscheint, führt an der
Methode PrintForm des jeweiligen Formularobjekts kein Weg vorbei. Diese Methode gibt den
Inhalt des dem Formular untergelegten Fensters als eigenständige Seite auf das Printer-Objekt
(unter Beachtung des aktuellen Zustands) aus – die Ausgabe auf eine bereits angefangene Seite
nötigt das Printer-Objekt, einen Laufzeitfehler auszulösen. Aber Achtung, alle Inhalte müssen
in Steuerelementen untergebracht sein. Wie das Beispielprogramm zeigt, berücksichtigt Print-
Form nämlich nur die auf dem Formular befindlichen Steuerelemente (samt Inhalten), nicht
jedoch sonstige, direkt in das Formular gezeichnete Inhalte, seien es Texte, Grafiken oder Bil-
der. Zur Abhilfe sollte man solche Inhalte in ein PictureBox-Steuerelement zeichnen. Mit die-
sem Steuerelement lässt sich auch eine (allerdings nicht sehr befriedigende) Druckvorschau
implementieren. Man legt ein Formular an, das nichts weiter als ein PictureBox-Steuerelement
enthält, und zeichnet alle auszudruckenden Inhalte in dieses Steuerelement. Zu beachten gilt es
lediglich, dass die AutoRedraw-Eigenschaft des Formularobjekts auf True gesetzt ist. Der Aus-
druck selbst ist dann mit einem einfachen PrintForm-Aufruf erledigt. Leider werden nur die
Inhalte eines Formulars gedruckt, die bei der gegebenen Auflösung auf dem Bildschirm Platz
haben (wenn Teile des Formulars verdeckt sind, spielt das keine Rolle). Zudem lässt die Quali-
tät von Grafiken wegen der kleineren Auflösung des Bildschirms (96 dpi) stark zu wünschen
übrig.

294
Printer- Objekt

Beispiel

Beis piel
...................................................
Das Projekt PrinterDemo zeigt die wichtigsten Aspekte im Umgang mit dem Printer-Objekt.
Der Code initialisiert das Kombinationsfeld-Steuerelement Combo1 (dessen Style-Eigenschaft
beim Entwurf auf 1 oder 2 gesetzt wurde) mit den Namen der auf dem System verfügbaren
Drucker und zeigt den Standarddrucker als aktuelle Auswahl im Kombinationsfeld an. Verliert
das Kombinationsfeld den Fokus, erhält das Printer-Objekt – entsprechend der im Kombina-
tionsfeld getroffenen Auswahl – gegebenenfalls einen neuen Wert. Um den Zustand des Kombi-
nationsfelds mit dem aktuellen Wert des Printer-Objekts zu synchronisieren, bedient sich der
Code der SendMessage-Funktion aus der Win32-API mangels einer geeigneten Methode seitens
des Steuerelements. Diese Funktion ermöglicht es, dem Steuerelement eine Nachricht zu senden,

Global- Objekt
die es anweist, nach einem bestimmten Eintrag zu suchen und dessen Index zu liefern. Die fol-
gende Abbildung zeigt das Fenster der Anwendung:

Formular des Projektes PrinterDemo

Das Formular enthält zwei Schaltflächen: Die eine (cmdDemoAusdruck) demonstriert die Druck-
ausgabe unter Verwendung der verschiedenen Methoden des Printer-Objekts, die andere
(cmdFormularAusdruck) zeigt die Ausgabe des Formulars mittels der PrintForm-Methode des
Form-Objekts.
Option Explicit
' Mit etwas Unterstützung der WinApi ...
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _

295
Global- Objekt

(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _


lParam As Any) As Long
Private Const CB_FINDSTRING = &H14C

Private Sub cmdDemoAusdruck_Click()


Demo Printer
Printer.EndDoc ' Druckjob abschließen
End Sub

Private Sub cmdFormularAusdruck_Click()


Global- Objekt

PrintForm
End Sub

Private Sub Combo1_Lostfocus()


If Printer.DeviceName <> Combo1.Text Then ' Hat sich was geändert?
Set Printer = Printers(Combo1.ListIndex)
End If
End Sub

Private Sub Form_Load()


Dim p As Printer, lIndex As Long
For Each p In Printers ' Kombifeld initialisieren
Combo1.AddItem p.DeviceName
Next
' Standarddrucker auswählen. Suchen lassen
lIndex = SendMessage(Combo1.hwnd, CB_FINDSTRING, -1, _
ByVal Printer.DeviceName)
Combo1.ListIndex = lIndex ' Eintrag auswählen
End Sub

Sub Demo(obj As Object)


Dim x As Single
obj.ScaleMode = vbMillimeters ' Millimeter als Maßeinheit
obj.ScaleLeft = -obj.ScaleWidth / 2 ' Ursprung in die Mitte
obj.ScaleTop = -obj.ScaleHeight / 2

obj.Line (-70, 0)-(70, 0), vbBlack ' Koordinatenkreuz


obj.Line (0, -70)-(0, 70), vbBlack
obj.Line (-70, -70)-(70, 70), vbBlack, B ' Quadrat drum herum
For x = 10 To 70 Step 10
obj.Circle (0, 0), x, vbBlack ' Kreise drum herum
Next x

' Überschrift
obj.FontName = "Times New Roman" ' Schrift für Beschriftung
obj.FontSize = 30
obj.FontBold = True

obj.CurrentX = -obj.TextWidth("Demo-Ausdruck") / 2
obj.CurrentY = -70 – obj.TextHeight("Demo-Ausdruck")
obj.Print "Demo-Ausdruck"

296
Printers- Auflistung

' Beschriftung
obj.FontName = "Courier New" ' Schrift für Beschriftung
obj.FontSize = 8.5

For x = -70 To 70 Step 10


' Skala horizontal
obj.CurrentX = x – obj.TextWidth(CStr(x)) / 2
obj.CurrentY = 0
obj.Print CStr(x)
' Skala vertikal

Global- Objekt
obj.CurrentX = -obj.TextWidth(CStr(x))
obj.CurrentY = x – obj.TextHeight(CStr(x)) / 2
obj.Print CStr(x)
Next x
End Sub

Private Sub Form_Paint()


Demo Me
End Sub

Private Sub Form_Resize()


Refresh
End Sub
Verwandte Objekte

Verwandte Objekte
...................................................
Form, PictureBox
Verwandte Themen

Verwandte Them en
...................................................
Standarddialoge-Steuerelement (CommonDialog) (S. 444)

Printers- Auflistung
Printers As Object
Beschreibung

Bes c hreibung
...................................................
Die nicht mit dem Auflistungstyp Collection kompatible Printers-Auflistung stellt eine Liste
mit allen auf dem System installierten Druckern bereit. Elementdatentyp ist Printer. Einzige
Eigenschaft der Auflistung ist Count, über die sich die Anzahl der Listenelemente in Erfahrung
bringen lässt.
Anwendung

Anwendung
...................................................
Sie können die Auflistung mit einem For Each-Konstrukt und einer Zählvariablen des Typs
Printer durchlaufen. Für den direkten Zugriff auf ein Element verwenden Sie die übliche Array-
Schreibweise unter Angabe eines Index (Zählung beginnt bei 0).
Visual Basic initialisiert das Printer-Objekt grundsätzlich mit dem aktuellen Standarddrucker
des Systems. Um auf einem anderen Drucker Ausgaben anzufertigen, weisen Sie dem Printer-
Objekt das zugehörige Element der Auflistung über eine Set-Anweisung zu.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel zu »Printer-Objekt« (S. 284).

297
Global- Objekt

Verwandte Themen

Verwandte Them en
...................................................
Auflistungen und Collection-Objekte (S. 304); Standarddialoge-Steuerelement
(CommonDialog) (S. 444)

QBColor- Methode
Function QBColor (Color As Integer) As Long
Beschreibung

Bes c hreibung
...................................................
Die QBColor-Funktion liefert die zur Farbnummer Color gehörige RGB-Farbe als Long-Farbwert
Global- Objekt

zurück.
Anwendung

Anwendung
...................................................
Bei älteren noch auf DOS basierenden Basic-Versionen (etwa QBasic), musste sich der Program-
mierer (mittels der Screen-Anweisung) noch explizit um die Steuerung der Grafikanzeige (CGA,
EGA, VGA, PVGA etc.) kümmern und konnte je nach vorhandener Hardware zwischen ver-
schiedenen Bildschirmauflösungen und Farbtiefen wählen. Mit Windows und der Philosophie
der geräteunabhängigen Ausgabe ist die Angelegenheit einfacher geworden: Da die Ausgabe
unter Windows fensterbasiert ist, ist sie gewissermaßen auflösungsunabhängig geworden, und
für die Farbausgabe wird inzwischen einheitlich der TrueColor-Farbraum des 24-Bit-Farb-
modells zugrunde gelegt. Die Farben des 16-farbigen EGA/VGA-Modus spielen aber bei der
Programmierung als Grundfarben nach wie vor eine wichtige Rolle, da sie eine klar zu unter-
scheidende Farbauswahl darstellen.
Da die QBColor-Funktion den indizierten Farbraum des 16-farbigen EGA/VGA-Modus in den
TrueColor-Farbraum des 24-Bit-Farbmodells abbildet, ist sie ein unverzichtbares Werkzeug für
die Umsetzung älterer Basic-Programme nach Visual Basic. Die folgende Tabelle gibt einen
Überblick über die Zuordnung zwischen den Farbnummern und den Farben:

Farbnummer Farbe Farbnummer Farbe


0 Schwarz 8 Grau
1 Blau 9 Hellblau
2 Grün 10 Hellgrün
3 Zyan 11 Hellzyan
4 Rot 12 Hellrot
5 Magenta 13 Hellmagenta
6 Gelb 14 Hellgelb
7 Weiß 15 Leuchtend Weiß

Beispiel

Beis piel
...................................................
Line (0, 0)-(1000, 1000), QBColor(6)
Verwandte Befehle

Verwa ndte Befehle


...................................................
RGB

298
RGB- Methode

RGB- Methode
Function RGB(Red As Integer, Green As Integer, Blue As Integer) As Long
Beschreibung

Bes c hreibung
...................................................
Die RGB-Methode komponiert eine RGB-Farbe für den TrueColor-Farbraum aus den Werten für
die einzelnen Farbkomponenten Rot, Grün und Blau und gibt diese als Long-Farbwert zurück.
Die Funktion unterscheidet die Werte 0 bis 255 für die drei Parameter Red, Green und Blue.
(Größere Werte verursachen keinen Laufzeitfehler, sondern werden auf 255 abgerundet.)
Anwendung

Anwendung
...................................................

Global- Objekt
Der Einsatz der RGB-Methode ist immer dann angesagt, wenn eine Farbe aus dem TrueColor-
Farbraum komponentenweise zusammengestellt werden muss. Die Parameter der Methode drü-
cken die zwischen 0 und 255 abgestuften Helligkeitsanteile der einzelnen Farbkomponenten
aus, so dass der Aufruf RGB(0, 0, 0) den Farbwert für Schwarz und RGB(255, 255, 255) den
Farbwert für Weiß liefert.
Die Methode macht eigentlich nichts weiter, als die Komponentenwerte in die unteren drei
Bytes des Farbwerts umzumünzen nach der Formel
RGBWert = (Rot Mod 256) + (Green Mod 256) * 256 + (Blue Mod 256) * 65536
Beispiel

Beis piel
...................................................
Der folgende Code gibt einen so genannten Graukeil aus:
ScaleMode = vbPixels
For i = 0 To 255
Line (i, 0)-(i, 1000), RGB(i, i, i)
Next i

SavePicture- Methode
Sub SavePicture(Picture As Picture, FileName As String)
Beschreibung

Bes c hreibung
...................................................
Die SavePicture-Methode speichert ein Bild Picture in der Datei FileName. Bilder der Formate
BMP, JPG, und GIF werden dabei unabhängig von ihrem ursprünglichen Format im BMP-For-
mat abgespeichert, während Bilder der Formate ICO, WMF, EMF und CUR ihr ursprüngliches
Format beibehalten.
Anwendung

Anwendung
...................................................
Ein interessanter Einsatzbereich dieser Methode ist das Abspeichern des aktuellen Zustands der
Zeichenfläche eines Formulars, die über die Image-Eigenschaft verfügbar ist.
Beispiel

Beis piel
...................................................
Der folgende Code speichert den von Grafikmethoden (PSet, Circle, Line, Print) gezeichneten
Inhalt eines Formulars im BMP-Format. (Beachten Sie, dass dazu die AutoRedraw-Eigenschaft
des Formulars auf True gesetzt sein muss!)
SavePicture Image, "Forminhalt.bmp"

299
Global- Objekt

SaveSetting- Methode
Sub SaveSetting(AppName As String, Section As String, _
Key As String, Setting As String)
Beschreibung

Bes c hreibung
...................................................
Die Methode SaveSetting ermöglicht es, persistente Einstellungen eines Programms in System-
registrierung persistent als Unterschlüssel des Schlüssels

HKEY_CURRENT_USER\Software\VB and VBA Program Settings\


Global- Objekt

zu speichern. Für den Aufruf gilt: AppName steht für den Anwendungsnamen und ist Unterschlüs-
sel von »VB and VBA Program Settings«; Section steht für den Abschnitt und ist Unterschlüs-
sel von AppName; Key ist Eintrag unter Section und steht für den Namen des zu speichernden
Werts; Setting ist der Key zugeordnete Datenwert.
Anwendung

Anwendung
...................................................
Früher mussten Windows-Anwendungen ihre persistenten Einstellungen noch in je eigenen INI-
Dateien ablegen. Spätestens seit Windows 95 (aber auch schon zuvor) gibt es eine zentrale Sys-
temregistrierung, in der sich solche Daten an zentraler Stelle speichern lassen. Für den Zugriff
auf die Systemregistrierung von Visual Basic aus stehen im Wesentlichen vier Methoden zur
Verfügung: GetSetting, GetAllSettings, SaveSetting und DeleteSetting, deren Funktion
bereits durch die Bezeichner deutlich wird. Um auf andere Schlüssel zuzugreifen, müssen Sie die
entsprechenden Funktionen der Win32-API (RegSaveKey etc.) benutzen.
Beispiel

Beis piel
...................................................
Vgl. »GetAllSettings-Methode« (S. 279).

Screen- Objekt
Public Screen As Screen
Beschreibung

Bes c hreibung
...................................................
Das aus der Bibliothek VB stammende Screen-Objekt ist in jeder Anwendung als globales
Objekt bekannt. Es repräsentiert den gesamten Bildschirm als Ausgabegerät, ohne jedoch selbst
Methoden für die Ausgabe zu besitzen. Seine Eigenschaften geben Aufschluss über die physika-
lische Auflösung sowie die Abmessungen des eingestellten Bildschirmmodus, die auf dem Sys-
tem installierten Schriften und darüber, welches Formular und Steuerelement der Anwendung
gerade aktiv ist (lies: im Besitz des Fokus ist). Weiterhin erlauben sie die Kontrolle über den für
alle Formulare und Steuerelemente der Anwendung geltenden Mauszeiger. Die folgende Tabelle
gibt einen Überblick über die Eigenschaften des Screen-Objekts.

Eigenschaft Beschreibung
ActiveControl Zur Laufzeit schreibgeschützter Wert, der vom System gepflegt
wird und eine Objektreferenz auf das Steuerelement des aktiven
Formulars darstellt, das augenblicklich den Fokus besitzt; der
Datentyp der Objektreferenz richtet sich nach dem Steuerelement
(als Datentyp für die Parameterübergabe ist daher Control zu
wählen)

3 00
Screen- Objekt

Eigenschaft Beschreibung
ActiveForm Zur Laufzeit schreibgeschützter Wert, der vom System gepflegt
wird und eine Objektreferenz auf das aktive Formular darstellt. Ist
ein MDI-Formular aktiv, bezeichnet diese Eigenschaft das aktive,
dem MDI-Formular untergeordnete Unterformular.
FontCount Zur Laufzeit schreibgeschützter Wert vom Typ Integer, der die
Anzahl der auf dem System installierten Schriftarten wiedergibt
Fonts Auflistung mit dem Elementtyp Font und Indexbereich: 0 bis Font-
Count – 1 für die auf dem System installierten Schriftarten

Global- Objekt
Height Zur Laufzeit schreibgeschützte Werte vom Typ Single, die die
Width Höhe bzw. Breite des Bildschirms in Twips ausdrücken
(1 Zentimeter entspricht ca. 567 Twips, 1 Zoll entspricht 1440
Twips)
MouseIcon Wert von Typ Picture. Lässt sich zur Laufzeit auf ein CUR- oder
ICO-Bild (nicht jedoch ANI) setzen. Ermöglicht die Anzeige eines
benutzerdefinierten Mauszeigers im Bereich des aktiven Formu-
lars, wenn MousePointer den Wert 99 hat.
MousePointer Wert vom Typ MousePointerConstants, der festlegt, welcher Maus-
zeiger im Bereich des aktiven Formulars angezeigt wird.
vbDefault (0) objektspezifisch (Voreinstellung)
vbArrow (1) Pfeilsymbol
vbCrosshair (2) Kreuz
vbIbeam (3) I-Symbol
vbIconPointer (4) Symbol (Quadrat in Quadrat)
vbSizePointer (5) Pfeilkreuz Nord/Süd/West/Ost
vbSizeNESW (6) Doppelpfeil Nord-Ost/Süd-West
vbSizeNS (7) Doppelpfeil Nord/Süd
vbSizeNWSE (8) Doppelpfeil Nord-West/Süd-Ost
vbSizeWE (9) Doppelpfeil West/ Ost
vbUpArrow (10) Pfeil aufwärts zeigend
vbHourglass (11) Sanduhr
vbNoDrop (12) nicht ablegen
vbArrowHourglass (13) Sanduhr mit Pfeil
vbArrowQuestion (14) Pfeil mit Fragezeichen
vbSizeAll (15) Größenänderung alle
vbCustom (99) benutzerdefiniertes Symbol, wie in
MouseIcon definiert
TwipsPerPixelX Zur Laufzeit schreibgeschützte Werte vom Typ Single, die aus-
TwipsPerPixelY drücken, wie viele Twips bei der aktuell eingestellten Bildschirm-
auflösung einem Bildpunkt in horizontaler (X) und vertikaler
Richtung (Y) entsprechen

3 01
Global- Objekt

Anwendung

Anwendung
...................................................
Eine wichtige Aufgabe des Screen-Objekts ist die Kontrolle des Mauszeigers für die gesamte
Anwendung. Solange Screen.MousePointer den Wert vbDefault hat, kann jedes Formular und
Steuerelement den Mauszeiger für seinen Fensterbereich individuell über seine eigene Mouse-
Pointer-Eigenschaft kontrollieren. Jeder andere Wert für Screen.MousePointer erklärt den ent-
sprechenden Mauszeiger als allgemeingültig und setzt die objektspezifischen Einstellungen für
die Fenster der Anwendung (temporär) außer Kraft. Auf diese Weise kann eine Anwendung bei-
spielsweise auf die Sanduhr umschalten, wenn eine zeitaufwändige Operation die Reaktivität
der Benutzerschnittstelle beeinträchtigt.
Eine wichtige Informationsquelle für die Bildschirmausgabe ist auch die Fonts-Auflistung des
Global- Objekt

Screen-Objekts. Sie gibt einen Überblick über die auf dem System installierten Schriften.
Beispiel

Beis piel
...................................................
Das folgende Codefragment überträgt die Namen der auf dem System installierten Schriftarten
in die Liste eines Kombinationsfeld-Steuerelements namens Combo1.
Dim f As Integer
For f = 0 To Screen.FontCount -1
Combo1.AddItem Screen.Fonts(f)
Next

Sendkeys- Methode
Sub SendKeys(String As String, [Wait As Boolean])
Beschreibung

Bes c hreibung
...................................................
Die SendKeys-Methode interpretiert den Wert des Parameters String als Tastenfolge und sendet
entsprechende Tastaturereignisse an das aktive Fenster (lies: an das Element, das den Fokus
besitzt), so als ob der Benutzer dort die Tastenfolge per Tastatur eingegeben hätte. Wird der
Parameter Wait mit dem Wert True versorgt, wartet die Anwendung, bis die Tastenfolge von der
Zielanwendung tatsächlich verarbeitet wurde (Synchronbetrieb), ansonsten findet die Verarbei-
tung asynchron statt.
Anwendung

Anwendung
...................................................
Die SendKeys-Methode macht es möglich, das Fenster einer beliebigen Anwendung, das den
Fokus besitzt, durch die Simulation von Tastaturereignissen gewissermaßen »fernzusteuern«. In
der Tat ist dieser einfache Mechanismus seit jeher ein probates Mittel, die Prozessgrenze zu
fremden Anwendungen zu überwinden und deren Steuerung zu übernehmen – eine primitive
Form der Automatisierung also.
Eine einfache Syntax mit einer Reihe von Schlüsselwörtern für die Bildung des Parameterwerts
stellt sicher, dass sich alle Tasten und Tastenkombinationen ausdrücken lassen. Die Sonderzei-
chen »+«, »^« und »%« stehen für die Funktionstasten (Umschalt), (Strg) und (Alt) und wir-
ken sich auf das folgende Zeichen bzw. die folgende durch einfache Klammern ausgezeichnete
Gruppierung aus:
SendKeys "+abs" ' sendet "Abs"
SendKeys "+(abs)" ' sendet "ABS"
Um mehrere Funktionstasten auf ein Zeichen oder eine Zeichengruppe anzuwenden, ist keine
Klammerung erforderlich. Für Zeichen, die sich in Großschreibung notieren lassen, ist die
Angabe von »+« nicht erforderlich – aber auch nicht schädlich:
SendKeys "ABS" ' sendet "ABS"

3 02
Unload- Methode

Zu den weiteren Sonderzeichen zählen »~« für die Eingabetaste sowie die geschweiften Klam-
mern »{Schlüsselwort}« zur Notation der Sonderzeichen »+^%~(){}« in literaler Bedeutung
sowie von Schlüsselwörtern für Tasten, die selbst kein Zeichen hervorbringen.
SendKeys "{{ }" ' sendet "{"
SendKeys "erste Zeile+~zweite Zeile" ' Zeilenwechsel in Multiline-
' Textfeld
SendKeys "nähmlich{Left 5}{Backspace}{Right 4}" ' Eingabe der Zeichen-
' folge "nämlich"

Die folgende Tabelle gibt einen Überblick über alle von der Methode erkannten Schlüsselwörter
und Symbole sowie deren Bedeutung:

Global- Objekt
Symbol Bedeutung Symbol Bedeutung
+ (Umschalt) ^ (Strg)
% (Alt) ~ (Eingabe)
( Zeichengruppierung ) Zeichengruppierung
{ Schlüsselwort folgt } Schlüsselwort zu Ende
{Backspace} (Rücktaste) {Delete} (Entf)
{BS}, {Bksp} {Del}
{Capslock} (Feststelltaste) {Break} (Pause)
{Down} (Unten) {End} (Ende)
{Enter} (Eingabe) {Esc} (Esc)
{Help} (Hilfe) {Home} (Pos1)
{Insert}, {Ins} (Einf) {Left} (Links)
{Numlock} (Num) {PgDn} (BildAb)
{PgUp} (BildAuf) {PrtSc} (Druck)
{Scrolllock} (Rollen) {Tab} (Tab)
{Up} (Oben) {F1} bis {F16} (F1) bis (F16)

Beispiel

Beis piel
...................................................
SendKeys "%{F4}" ' beendet aktives Fenster

Unload- Methode
Sub Unload(Object)
Beschreibung

Bes c hreibung
...................................................
Die Unload-Methode entlädt ein Formular oder ein zuvor mittels Load in ein Steuerelemente-
Array geladenes Steuerelement Object. Der Entladevorgang zerstört zwar das Fenster der
Instanz, nicht jedoch das in der Visual-Basic-Umgebung dafür existierende Objekt. (Dieses wird
erst abgebaut, wenn sein Geltungsbereich erloschen ist und das Terminate-Ereignis eintritt!)
Für ein Formular bewirkt der Unload-Aufruf der Reihe nach die Ereignisse QueryUnload und
Unload. Das Formular kann im Zuge der Behandlung dieser Ereignisse den Entladevorgang
unterbinden, indem es den Cancel-Parameter auf True setzt. In diesem Fall bleibt der Unload-
Aufruf ohne weitere Wirkung.

3 03
Auflistungen und Collection- Objekte

Anwendung

Anwendung
...................................................
Ein einmal entladenes Steuerelement oder Formular kann jederzeit mit Load erneut geladen und
durch Setzen der Visible-Eigenschaft auf True (bzw. einen Show-Aufruf) erneut angezeigt wer-
den. Das Fenster des Objekts wird dann neu initialisiert. Beachten Sie jedoch, dass sich Steuer-
elemente, die bereits zur Entwurfzeit auf einem Formular platziert wurden, nicht entladen las-
sen.
Beispiel

Beis piel
...................................................
Ein Formular enthalte zum Beenden seiner selbst eine Befehlsschaltfläche namens cmdBeenden.
Auflistungen und Collection- Objekte

Der Code dafür ist denkbar einfach:


Private Sub cmdBeenden_Click()
Unload Me
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
Load

Auflistungen und Collection- Objekte


Dim cols As Collection
Objekt.Controls, Printers, Forms, Screen.Fonts, Printer.Fonts, DataObject.Files,
Objekt.ListImages
Beschreibung

Bes c hreibung
...................................................
Bei Auflistungen handelt es sich um spezielle Datentypen, die ähnlich einem dynamischen Array
beliebige Elemente eines Datentyps speichern können und den indexsequenziellen Zugriff
darauf ermöglichen. Trotz der rein – funktional gesehen – engen Verwandtschaft mit dynami-
schen Arrays sind Auflistungen Objekte mit Eigenschaften und Methoden, und der zugehörige
allgemeine Objektdatentyp Collection ist so etwas wie eine »objektorientierte Implementation
dynamischer Arrays«. Wie für jeden Objektdatentyp lassen sich auch für den Typ Collection
Objektvariablen vereinbaren, die auf bestehende Auflistungen verweisen können. Neue Auflis-
tungsobjekte werden wie üblich mit dem New-Operator generiert. Anders als bei dynamischen
Arrays ist der Elementdatentyp einer Auflistung grundsätzlich Variant, so dass Auflistungen als
Elementwerte alles »schlucken«, was sich auch einer Variablen des Typs Variant zuweisen lässt
– Werte mit benutzerdefinierten Datentypen, für die eine Type-Deklaration vorliegt, gehören
somit nicht dazu.
Ein Collection-Objekt besitzt die vier Methoden Add, Remove, Count und Item. Die Methode Add
fügt ein neues Element in die Auflistung ein. Ihr Prototyp lautet:
Sub Liste.Add (Item, [Key As String], [Before As Long], [After As Long])

Der Parameter Item stellt den Wert den neuen Elements. Über den Zeichenfolgenparameter Key
lässt sich optional ein Schlüssel für den assoziativen Zugriff auf das Element festlegen. Er muss
eindeutig sein. Die optionalen Parameter Before bzw. After erlauben die Angabe eines Posi-
tionswerts größer 0, vor bzw. nach dem das Element für den indexsequenziellen Zugriff einge-
fügt wird. Ohne Positionsangabe fügt das Objekt neue Elemente grundsätzlich hinten an.

3 04
Auflistungen und Collection- Objekte

Umgekehrt ermöglicht die Methode Remove das Entfernen eines Elements aus der Auflistung. Sie
wird unter Angabe der Position Index oder des für das Element vereinbarten Schlüssels Key auf-
gerufen:
Sub Liste.Remove (Index As Long | Key As String)

Die parameterlose Methode Count liefert die Anzahl der Elemente in der Auflistung und
zugleich – da Auflistungen 1-basiert sind – die Position des letzten Elements. Solange eine Auf-
listung leer ist, lautet das Ergebnis 0.
Die Methode Item wird unter Angabe eines Positionswerts Index oder Schlüssels Key aufgerufen
und liefert das entsprechende Element. Da es sich bei dieser Methode um die Standardmethode
des Objekts handelt, muss ihr Bezeichner nicht unbedingt notiert werden, der Parameter aber

Auflistungen und Collection- Objekte


sehr wohl. Der Prototyp lautet:
Function Liste[.Item](Index As Long | Key As String)

Äquivalent sind folgende Schreibweisen:


Element = MeineListe.Item(i)
Element = MeineListe(i)

Falls das Element i seinerseits eine Auflistung ist, mutet die reduzierte Schreibweise für den
Zugriff auf deren j-tes Element ein wenig seltsam an, sie ist aber korrekt:
Element = MeineListe(i)(j)
Anwendung

Anwendung
...................................................
Die Bezeichner von Eigenschaften und Variablen, die als Auflistung definiert sind, tragen in
Visual Basic traditionell das Plural-«s« der englischen Sprache. Allerdings ist nicht überall, »wo
Auflistung draufsteht, auch Collection drin«. Das liegt im Wesentlichen daran, dass Windows
selbst eine Reihe verschiedener Objektdatentypen für spezifische Auflistungen verwendet, für
die andere Eigenschaften und Methoden als für Collection definiert sind. Mithin ist es also
nicht möglich, einer Collection-Variablen jede in Visual Basic anzutreffende Auflistung zuzu-
ordnen, so dass in vielen Fällen ein spezieller Typ für die Variable vereinbart oder auf den allge-
meinen Datentypen Object zurückgegriffen werden muss. Als Programmierer bekommt man
hier allerdings schnell den Eindruck des Wildwuchses, denn was hier eindeutig fehlt, ist eine
klare Linie. So ist es beispielsweise nicht gerade sehr instruktiv, dass manche Auflistungen mit
dem Index 0 beginnen, andere dagegen mit dem Index 1, und dass Auflistungen wie Fonts der
Objekte Screen und Printer oder die List-Eigenschaft von Listenfeldern weder einer Objektva-
riablen noch einer Array-Variablen als Wert zugeordnet werden können – mit dem dummen
Effekt, dass sie sich auch nicht als Parameter bei Funktionsaufrufen übergeben lassen.
Immerhin ist die Schreibweise für den Zugriff auf einzelne Elemente einheitlich: Es kann durch-
gehend die Array-Notation unter Angabe eines Positionsindex verwendet werden – was übri-
gens nur deshalb geht, weil Item als Standardmethode für Auflistungen vereinbart ist und nicht
notiert werden muss. Darüber hinaus erweist sich die Möglichkeit, neben dem Positionsindex
auch Bezeichner für die Elemente einer Auflistung zu vereinbaren, als höchst praktisch, wenn es
eine Sortierordnung gibt oder mit einer Fluktuation der Elemente zu rechnen ist. Nachdem die
Remove-Methode dafür sorgt, dass keine Lücken in der fortlaufenden Zählung der Elemente ent-
stehen, verkleinern sich die Positionsindizes aller Elemente nach einem gelöschten Element um
1. Umgekehrt erhöht die Add-Methode die Positionsindizes nachfolgender Elemente um 1, wenn
sie ein Element an einer bestimmten Position einfügt.
Während sich gewöhnliche Arrays elementweise ausschließlich in For-Zählschleifen mit Zählin-
dex durchlaufen lassen, gibt es für Auflistungen als Alternative die For Each-Kontrollstruktur,

3 05
Formulare

die kein Problem damit hat, wenn sich die Anzahl der Elemente während der Aufzählung
ändert, und die auch die Ergebnisse von Add und Remove berücksichtigt, sofern sich diese auf
noch nicht aufgezählte Positionen beziehen.
Dim Drucker As Printer
For Each Drucker In Printers
List1.AddItem Drucker.DeviceName
Next
Beispiel

Beis piel
...................................................
Der folgende Code arbeitet mit drei verschiedenen Auflistungstypen. Er instanziiert ein neues
Formulare

Auflistungsobjekt und fügt die Schriftnamen des zweiten (!) auf dem System installierten Dru-
ckers als Einträge ein.
Dim l As Collection
Set l = New Collection
For i = 0 To Printers(1).FontCount – 1 ' Printers beginnt bei Index 0
l.Add Printers(1).Fonts(i) ' Fonts beginnt bei Index 0
Next
Print TypeName(l(1)) ' Ausgabe: "String"

Formulare
Wenn es so etwas wie einen Standardzugang für die Programmierung mit Visual Basic gibt,
dann ist dies das Formular. Es vereinigt zunächst einmal alles unter sich, was für die Umsetzung
traditioneller Basic-Programme benötigt wird: die zeichenorientierte Ein- und Ausgabe sowie
eine grafische Ausgabefläche in Form eines Fensters. Damit aber nicht genug. Hinzu kommt die
mühelose Integration nicht nur aller klassischen Elemente der Windows-Benutzerschnittstelle:
Menü, Symbolleiste, Statusleiste und der üblichen Steuerelemente (Kontrollkästchen, Options-
feld, Listenfeld, Textfeld, Schaltfläche etc.), sondern auch beliebiger im COM-Standard gehalte-
ner ActiveX-Steuerelemente und -Komponenten.
Wer unter Visual Basic ein neues Projekt anlegt und »Standard EXE« als Projekttyp auswählt,
erhält den Rahmen für ein einfaches im Stand-alone-Betrieb ausführbares Programm, in dem
sich als Vorgabe ein einzelnes Formularmodul mit dem Namen Form1 befindet. Aus Sicht der
objektorientierten Programmierung stellt ein Formularmodul einen eigenständigen Objektda-
tentyp (bzw. Klasse) dar, der auf die Klasse Form aufsetzt und für den sich nach Belieben Instan-
zen ins Leben rufen sowie Objektvariablen vereinbaren lassen. Ist ein Formular (wie für den
Projekttyp »Standard-EXE« bereits voreingestellt) im Dialogfeld PROJEKTEIGENSCHAFTEN auf
der Seite ALLGEMEIN als Startobjekt für das Projekt angegeben, sorgt der Compiler dafür, dass
beim Programmstart implizit eine Instanz dieses Formulars generiert wird, zur Anzeige kommt
und die Kontrolle erhält (lies: initialisiert wird und den Fokus erhält). Ein neues Projekt des
Typs »Standard EXE« lässt sich somit bereits ohne weiteres Zutun des Programmierers sofort
kompilieren und stellt das Gerüst für ein vollständiges Programm im Sinne der Windows-Pro-
grammierung dar: ein Fenster (als visuelle Komponente des Formulars) mit Systemmenü, das
sich vergrößern, verkleinern, verschieben und wieder schließen lässt.
Im Programmiermodell von Windows ist ein Fenster mehr als nur eine Ausgabefläche.
Ausgestattet mit einer Schnittstelle für den Empfang von Nachrichten, die das Fenster über die
Aktivitäten des Benutzers (Mausereignisse, Tastatureingaben) sowie über sonstige Ereignisse
(Initialisierungsphasen, Mitteilungen anderer Fenster) informieren, wird es zu einer Art Kom-

306
Form- Objekt (Basisobjekt für Formulare)

mandozentrale für alle das Fenster als visuellen Bereich (gegebenenfalls mit Binnenstruktur)
und als eigenständige operationale Einheit (Objekt mit untergeordneten Objekten) betreffenden
Vorkommnisse.
In der Dokumentation zu Visual Basic wird selten ein Unterschied zwischen einem Formularob-
jekt und dem dazugehörigen Fenster gemacht – eine Sicht, die in den meisten Fällen wohl aus-
reichend ist, doch vielfach auch Verständnisschwierigkeiten bereitet, was die wahre Natur des
Formulars betrifft. Genau genommen ist ein Fenster nämlich ein vom Betriebssystem als Res-
source zur Verfügung gestelltes Objekt mit visueller Repräsentation und der besagten Nachrich-
tenschnittstelle, während das Formularobjekt eine aufseiten von Visual Basic gelegene Instanz
einer Klasse mit Eigenschaften, Methoden und Ereignissen ist, die das Fenster gewissermaßen
umhüllt. Mithin sollte man also nicht sagen: »ein Formular ist ein Fenster«, sondern: »ein For-

Formulare
mular hat ein Fenster«. (Deutlich wird der Unterschied, wenn man sich vor Augen hält, dass
das Fenster eines Formularobjekts mittels Unload jederzeit abgebaut werden kann, während das
Objekt weiter existiert und sich jederzeit über einen Load- bzw. Show-Aufruf ein neues Fenster
organisieren kann.)
Um das genannte Programmgerüst weiter auszugestalten, fügt man zum einen in den Entwurfs-
bereich des Formulars Steuerelemente ein, die eine geeignete Umsetzung der gewünschten spezi-
fischen Ein-/Ausgabefunktionalität gestatten, und definiert zum anderen im Codefenster des
Formulars geeignete Behandlungsroutinen für die verschiedenen von den Steuerelementen und
dem Fenster signalisierten Ereignisse.
Bei der Programmierung mit Formularen unterscheidet man zwischen SDI-Formularen (Single
Document Interface) und MDI-Formularen (Multiple Document Interface). SDI-Formularen
liegt der Datentyp Form zugrunde. Sie verfügen über eine reichhaltige Ausstattung an Eigen-
schaften und Methoden für die Grafik- und Textausgabe und können als Container für Steuer-
elemente und sonstige Komponenten fungieren, jedoch nicht für weitere Formulare. MDI-For-
mularen liegt hingegen der Datentyp MDIForm zugrunde. Sie kennen keine Grafikmethoden,
erlauben nur die Platzierung von bestimmten Steuerelementen (nämlich solchen, die als Leisten
definiert sind) und sind ansonsten speziell auf die Verwaltung und Darstellung untergeordneter
SDI-Formulare im eigenen Client-Bereich eingerichtet.

Form- Objekt (Basisobjekt für Formulare)


Dim Formular As Form
Beschreibung

Bes c hreibung
...................................................
Der Datentyp Form ist Grundlage aller Formulare und stattet diese mit einer reichhaltigen
Sammlung an Eigenschaften, Methoden und Ereignissen aus. Es lassen sich zwar Variablen die-
ses Datentyps vereinbaren, die Referenzen auf beliebige Formularobjekte (konkrete Instanzen
von Formulardatentypen) enthalten können, das hinter dem Objektdatentyp selbst steckende
Objekt lässt sich jedoch weder instanziieren noch ansprechen. Das liegt daran, dass es sich bei
Form (ebenso wie bei MDIForm, UserControl, UserDocument, PropertyPage und ClassModul) um
einen Schnittstellendatentyp (abstrakte Klasse) handelt, der als Vorlage für konkrete Klassen
fungiert, jedoch nicht dafür gedacht ist, eigenständige Objekte hervorzubringen. Vielmehr tritt
das Form-Objekt als Basisobjekt und somit als invarianter Kern konkreter Formulare auf, die
nicht nur Objekte (nämlich Dialogfelder) hervorbringen können, weil sie eigenständige Daten-
typen bzw. Klassen darstellen, sondern auch in je eigenen Modulen organisiert sind.
Da sich die Eigenschaften, Methoden des Form-Objekts auf die konkreten Formulardatentypen
übertragen und das Form-Objekt dem jeweils umhüllenden konkreten Objekt Ereignisse signali-
siert, die dieses behandeln kann, aber nicht muss, erhält man ein Aggregat, das landläufig als
Formularobjekt bezeichnet wird – ohne dass sprachlich ein Unterschied zwischen dem Formu-
lardatentyp und der konkreten Instanz des Formulardatentyps (dem »Formular«, das als Fens-

3 07
Formulare

ter auf dem Bildschirm erscheint) gemacht wird. Dennoch sollte man sich immer darüber im
Klaren sein, dass zu unterschiedlichen Formularen unterschiedliche Formulardatentypen gehö-
ren, die auf ein und dieselbe Standardschnittstelle Form aufbauen, und dass jeder Formularda-
tentyp beliebig viele Instanzen des gleichen Formulars hervorbringen kann, deren Bildschirm-
darstellungen (Fenster) sich aber je nach Objektzustand erheblich voneinander unterscheiden
können.
Eigenschaften

...................................................
Eigens c ha ften
ActiveControl, Appearance, AutoRedraw, BackColor, BorderStyle, Caption, ClipControls,
ControlBox, Controls, Count, CurrentX, CurrentY, DrawMode, DrawStyle, DrawWidth, Enab-
Formulare

led, FillColor, FillStyle, Font, FontBold, FontItalic, FontName, FontStrikethru, Font-


Transparent, FontUnderline, ForeColor, HasDC, hDC, Height, HelpContextID, hWnd, Icon,
Image, KeyPreview, Left, LinkMode, LinkTopic, MaxButton, MDIChild, MinButton, MouseIcon,
Mousepointer, Moveable, Name, OLEDropMode, Palette, PaletteMode, Picture,RightToLeft,
ScaleHeight, ScaleLeft, ScaleMode, ScaleTop, ScaleWidth, ShowInTaskbar, StartupPosi-
tion, Tag, Top, Visible, WhatsThisButton, WhatsThisHelp, WhatsThisMode, Width, Window-
State
Die folgende Tabelle gibt einen Überblick über die nicht anderer Stelle vorgestellten Eigenschaf-
ten des Formulars:

Eigenschaft Beschreibung
ActiveControl Zur Laufzeit schreibgeschützter Object-Verweis auf das Steuerelement des
Formulars, das im Besitz des Fokus ist; der Wert ist Nothing, wenn kein
Steuerelement, sondern das Formular den Fokus hat
AutoRedraw Boolean-Wert, der bestimmt, ob das Formularobjekt den Client-Bereich
automatisch neu zeichnet oder dazu eine Paint-Routine verwendet (vgl.
»Paint-Ereignis«, S. 253)
ClipControls Boolean-Wert, der bestimmt, ob Visual Basic für Steuerelemente Bildaus-
schnitte bei der Restaurierung des Objektbereichs berechnet oder nicht
ControlBox Zur Laufzeit schreibgeschützter Boolean-Wert, der bestimmt, ob das For-
mularfenster zur Laufzeit ein Systemmenü besitzt.
Controls Schreibgeschützte Object-Auflistung, die alle Steuerelemente des Formulars
als Elemente enthält. Beim Entwurf zuletzt eingefügte Steuerelemente kom-
men zuerst.
Count Schreibgeschützter Integer-Wert, der die Anzahl der in der Controls-Auf-
listung des Formulars befindlichen Steuerelemente wiedergibt.
CurrentX Single-Werte, die die Startkoordinaten für die Zeichenoperationen Print,
CurrentY Circle, Pset, Line im aktuellen Koordinatensystem (vgl. ScaleMode)
beschreiben und von diesen Methoden auch aktualisiert werden
KeyPreview Boolean-Wert, der bestimmt, ob das Formular Tastaturereignisse, die sei-
nen Steuerelementen gelten, gleichfalls behandeln kann (True) – und zwar
vor diesen – oder nicht (False). Diese Eigenschaft ermöglicht beispielsweise
die zentrale Tastatursteuerung auf Formularebene.
MaxButton Boolean-Werte, die bestimmen, ob das Formularfenster die Schaltflächen
MinButton MINIMIEREN, MAXIMIEREN und WIEDERHERSTELLEN anzeigt (True)
oder nicht (False)

308
Form- Objekt (Basisobjekt für Formulare)

Eigenschaft Beschreibung
MDIChild Zur Laufzeit schreibgeschützter Boolean-Wert, der bestimmt, ob das For-
mular einem MDI-Formular untergeordnet ist (True) oder nicht (False)
Moveable Boolean-Wert, der bestimmt, ob der Benutzer das Formular verschieben
kann (True) oder nicht (False)
Palette Picture-Wert, der auf ein Bild mit Palette verweist. Voreinstellung der
Eigenschaft ist ein Verweis auf die Standardpalette des Systems, in der die
unteren und oberen 20 Einträge mit den Systemfarben besetzt sind. Die
Palette definiert einen indizierten Farbraum für die Darstellung von Bil-

Formulare
dern und Grafik in palettenorientierten Anzeigemodi (beispielsweise der
Anzeigemodus »256-Farben«). Die Verwendung der Palette ist vom Wert
der Eigenschaft PaletteMode abhängig
PaletteMode Integer-Wert, der bestimmt, welche Palette das Formular (oder Benutzer-
steuerelement) für die Anzeige seiner Steuerelemente verwendet. Der Auf-
zählungsdatentyp PaletteModeConstants definiert Konstanten für die
verschiedenen zur Auswahl stehenden Paletten:
vbPaletteModeHalftone (0) Systempalette verwenden (Voreinstellung)
vbPaletteModeUseZOrder (1) Palette des zuvorderst gezeichneten Steuerele-
ments verwenden
vbPaletteModeCustom (2) Über Palette-Eigenschaft definierte Palette
verwenden
vbPaletteModeContainer (3) Über Palette-Eigenschaft des Container-Ob-
jekts definierte Palette verwenden, sofern be-
kannt
vbPaletteModeNone (4) Keine Palette verwenden (betrifft nur Benut-
zersteuerelemente)
vbPaletteModeObject (5) Palette des ActiveX-Designers verwenden.
(Betrifft nur ActiveX-Designer, die eine Palet-
te enthalten.)
ShowInTaskbar Boolean-Wert, der bestimmt, ob das Formular in der Taskleiste erscheint
(True) oder nicht (False)
StartupPosition Integer-Wert, der die Position qualitativ beschreibt, an der das Formular
unmittelbar nach dem Laden angezeigt wird. Der Aufzählungsdatentyp
StartupPositionConstants definiert Konstanten für die verschiedenen zur
Auswahl stehenden Positionen:
vbStartupManual (0) Keine Vorgabe, Windows gibt die Positi-
on nach eigenen Kriterien vor
vbStartupOwner (1) Fenstermitte; das Formular erscheint zen-
triert im übergeordneten Fenster (MDI-
Formular)
vbStartUpScreen (2) Bildschirmmitte; das Formular erscheint
zentriert im Fenster des Screen-Objekts
(Bildschirm)
vbStartUpWindowsDefault (3) Das Formular erscheint in der linken obe-
ren Ecke im Fenster des Screen-Objekts
(Bildschirm)

3 09
Formulare

Eigenschaft Beschreibung
WhatsThisButton Boolean-Wert, der bestimmt, ob das Formular die Schaltfläche HILFE in
der Titelleiste erhält (True) oder nicht (False). Achtung: Damit die Anzeige
erfolgen kann, müssen MinButton und MaxButton auf False gesetzt sein.
WindowState Integer-Wert, der den Anzeigezustand des Formularfensters zur Laufzeit
bestimmt – zur Auswahl stehen die Werte: vbNormal (0); vbMinimized (1);
vbMaximized (2).

Methoden
Methoden

...................................................
Formulare

Circle, Cls, Line, Hide, Move, OLEDrag, PaintPicture, Print, Point, PopupMenu, Pset,
PrintForm, Refresh, Scale, ScaleX, ScaleY, SetFocus, Show, TextHeight, TextWidth, Vali-
dateControls, WhatsThisMode, ZOrder
Die folgende Tabelle gibt einen Überblick über die nicht an anderer Stelle vorgestellten Metho-
den des Formulars. Die Prototypen lauten:
Sub Circle [Step] (x, y), r, [color As Long], [start, end], [ratio]
Sub Cls()
Sub Line [Step] (x1, y1) – [Step] (x2, y2), [color As Long], [B[F]]
Sub Hide()
Sub PaintPicture(Pic As Picture, x1, y1, Height1, Width1, x2, y2, _
Height2, Width2)
Function Point(x, y) As Long
Sub PopupMenu(Menu As Object, Flags, x, y, DefaultMenu)
Sub Print Wert1 [,|;] Wert2 [,|;] ...
Sub PrintForm()
Sub PSet [Step] (x, y), [Color As Long]
Sub Scale(x1, y1) – (x2, y2)
Function ScaleX(Width, [FromScale], [ToScale]) As Single
Function ScaleY(Height, [FromScale], [ToScale]) As Single
Sub Show()
Function TextHeight(Str As String) As Single
Function TextWidth(Str As String) As Single
Sub ValidateControls()
Sub WhatsThisMode()

31 0
Form- Objekt (Basisobjekt für Formulare)

Methode Kurzbeschreibung
Circle Zeichnet einen Kreis um den Mittelpunkt (x, y) mit Radius Radius und der
optionalen Stiftfarbe Color. Es gilt das aktuelle Koordinatensystem des
Formulars. Sind die optionalen Parameter Start und End angegeben, zeich-
net die Methode nur einen Teilkreis. Start und End bezeichnen den Start-
und Endwinkel (im Bogenmaß). Ist der Parameter Aspect mit einem Wert
ungleich 1 bzw. -1 angegeben, zeichnet die Methode eine Ellipse, die dem
Kreis einbeschrieben (positive Werte) bzw. umbeschrieben (negative
Werte) ist. Aspect drückt das Verhältnis zwischen Höhe und Breite des
begrenzenden Rechtecks aus.

Formulare
Cls Löscht den Client-Bereich, indem es diesen mit der Hintergrundfarbe Back-
Color füllt
Line Zeichnet eine Linie zwischen den Punkten (x1, y1) und (x2, y2). Ist der
optionale Zusatz »B« gegeben, zeichnet die Methode das Rechteck, das die
beiden Punkte definieren. Ist der optionale Zusatz »BF« gegeben, zeichnet
die Methode das Rechteck und füllt es mit der Füllfarbe FillColor aus.
Hide Setzt die Visible-Eigenschaft auf False und macht das Formular unsicht-
bar
PaintPicture Zeichnet das im Datentyp Picture vorliegende Bild Pic an der Position (x1,
y1), die den linken oberen Bildpunkt beschreibt. Alle Werte sind in der
aktuellen Maßeinheit des für das Formular geltenden Koordinatensystems
(ScaleMode) anzugeben. Sind die optionalen Parameter Height1 und Width1
vorhanden, wird das Bild auf diese Maße skaliert, ansonsten errechnet sich
die Methode diese Werte selbst und gibt das Bild in originaler Größe aus.
Sind die optionalen Parameter x2 und y2 sowie Width2 und Height2 angege-
ben, beschreiben diese einen Bildausschnitt innerhalb des Bildes, der (nach
impliziter Skalierung) in dem durch x1, y1, Width1 und Height1 spezifizier-
ten Rechteck ausgegeben wird. (Achtung, die Eigenschaften Height und
Width eines Picture-Objekts sind in der Maßeinheit »HiMetric« gehalten
und müssen gegebenenfalls mittels ScaleX und ScaleY in die geltende Maß-
einheit – Vorgabe ist Twips – umgewandelt werden.) Negative Werte für
Height und/oder Width führen zu einer spiegelverkehrten und/oder um
180° gedrehten Ausgabe. Koordinaten für Ausschnitte sind auf den
Ursprung des aktuellen Koordinatensystems zu beziehen!
Point Liefert den Farbwert des Punkts mit den Koordinaten (x, y) als Long-Wert
PopupMenu Zeigt das Popup-Menü Menu als Kontextmenü an der aktuellen Mausposi-
tion an. Der optionale Parameter Flags ermöglicht die Angabe eines Bit-
vektors, der die Position sowie das Verhalten des Menüs bestimmt. Für die
einzelnen Bits sind folgende Konstanten definiert.
vbPopupMenuLeftAlign (0) links an der Position (x, y) ausgerichtet (Vor-
einstellung)
vbPopupMenuCenterAlign (4) mittig zur Position (x, y) ausgerichtet
vbPopupMenuRightAlign (8) rechts an der Position (x, y) ausgerichtet
vbPopupMenuLeftButton (0) linke Maustaste aktiviert Menübefehl (Vor-
einstellung)
vbPopupMenuRightButton (2) rechte Maustaste aktiviert Menübefehl

31 1
Formulare

Methode Kurzbeschreibung
PopupMenu Die optionalen Parameter x und y ermöglichen die Angabe einer Position
(Forts.) (x, y) im Koordinatensystem des Formulars, relativ zu der das Menü ausge-
richtet wird. Fehlen beide Parameter, verwendet die Methode die aktuellen
Mauskoordinaten. Über den optionalen Parameter DefaultMenu lässt sich
schließlich der Bezeichner für den als Standard vorgeschlagenen Menü-
befehl spezifizieren. Der entsprechende Befehl erscheint dann im Menü
fett.
Print Gibt die in der Parameterliste befindlichen Werte in textueller Repräsenta-
Formulare

tion an der Position (CurrentX, CurrentY) und mit den aktuellen Schriftein-
stellungen (Font) aus. Als Trennzeichen für die Parameter sind das
Semikolon und das Komma zulässig. Folgt ein Semikolon auf einen Para-
meter, wird der nächste Wert (ggf. auch im Rahmen der nächsten Print-
Anweisung) ohne Zwischenraum dahinter gesetzt. Folgt ein Komma auf
einen Parameter, wird der nächste Wert (ggf. auch im Rahmen der nächs-
ten Print-Anweisung) an der nächsten Tabulatorposition ausgegeben.
Print-Anweisungen, deren Parameterliste nicht mit einem Trennzeichen
endet, bewirken einen Zeilenvorschub. Ein automatischer Zeilenumbruch
findet ansonsten nicht statt.
PrintForm Gibt die auf dem Formular befindlichen Steuerelemente samt Inhalte auf
dem Standarddrucker aus. Direkt in den Client-Bereich des Formulars
gezeichnete Ausgaben werden nicht ausgegeben, auch keine Hintergrund-
bilder (Picture).
PSet Zeichnet einen Punkt an der Position (x, y) in der Farbe Color
Scale Setzt ein Koordinatensystem für den Client-Bereich des Formulars, bei dem
der linke obere Punkt die Koordinaten (x1, y1) und der rechte untere Punkt
die Koordinaten (x2, y2) hat
ScaleX Rechnet die Koordinate Width für die X-Achse (bzw. Y-Achse) vom Koor-
ScaleY dinatensystem FromScale in das Koordinatensystem ToScale um und liefert
die neue Koordinate als Single. Fehlt einer der optionalen Parameter für
ein Koordinatensystem, bezieht sich die Methode auf das aktuell geltende
Koordinatensystem. Für die verschiedenen Koordinatensysteme sind Inte-
ger-Konstanten definiert (vgl. »ScaleMode-Eigenschaft«, S. 369)
Show Die Methode zeigt das Formular an, indem sie die Visible-Eigenschaft auf
True setzt. Falls das Formular noch nicht geladen ist, die Formularvariable
aber unter Angabe von New deklariert wurde, findet implizit ein Load-Auf-
ruf statt.
TextHeight Liefert die für die Ausgabe der Zeichenfolge Str benötigte Höhe in der
aktuellen y-Maßeinheit des aktuellen Koordinatensystems
TextWidth Liefert die für die Ausgabe der Zeichenfolge Str benötigte Breite in der
aktuellen x-Maßeinheit des aktuellen Koordinatensystems
ValidateControls Sorgt dafür, dass die Inhalte aller Steuerelemente auf dem Formular gültig
sind (Validate-Ereignis), bevor das Formular geschlossen wird
WhatsThisMode Aktiviert den Direkthilfemodus (Mauszeiger wird zu Pfeil mit Fragezei-
chen)

31 2
MDIForm- Objekt

Die Syntax für den Aufruf der Methoden Circle, Line und PSet ist traditionell spezifisch: Ist das
optionale Schlüsselwort Step angegeben, wird das unmittelbar folgende Koordinatenpaar als
relativer Offset bzgl. der aktuellen Position (CurrentX, CurrentY) interpretiert, sonst als absolute
Position – jeweils bezogen auf das geltende Koordinatensystem. Standardmäßig zeichnen die
Methoden in der durch die Eigenschaft ForeColor spezifizierten Farbe (Standardwert ist
Schwarz: vbBlack). Beliebige Farben lassen sich aus ihren Komponentenanteilen über die Funk-
tion RGB zu einem Long-Wert für den optionalen Parameter Color komponieren. Definierte Far-
ben liefert die Funktion QBColor (16 Grundfarben) sowie der Aufzählungstyp ColorConstants.
Füllfarbe ist FillColor, sofern FillStyle ungleich 1 ist.
Anwendung

Anwendung
...................................................

Formulare
Die Möglichkeiten und Anlässe für die Anwendung von Formularobjekten sind so vielfältig und
unerschöpflich, dass es wenig Sinn hat, sich darüber im Einzelnen auszulassen. Allein dieses
Buch dürfte um die hundert unterschiedliche Konzeptionen für Formulare bzw. formularba-
sierte Programme vorstellen, und letztlich lässt sich fast der gesamte Text des Buches in dem
Kontext »für den Einsatz auf/mit/in einem Formular« lesen.
Mit dem Objektdatentyp Form verhält es sich anders. Dass es überhaupt möglich ist, Variablen
dieses Typs zu vereinbaren und ihnen Formularinstanzen (wohlgemerkt: Instanzen, nicht For-
mulare) als Wert zuzuordnen, resultiert aus dem von Visual Basic verwendeten Polymorphie-
Konzept. Da die einzelnen Formulardatentypen eines Projekts nichts weiter als spezifische Imp-
lementationen ein und derselben der Form-Schnittstelle darstellen und somit dieselbe Grund-
struktur besitzen, ist es zulässig, den gleichen Zeiger für Referenzen auf unterschiedliche Daten-
typen zu verwenden.
Beispiel

Beis piel
...................................................
Im folgenden Codeauszug vertritt eine Variable des Typs Form Instanzen zweier unterschiedli-
cher Formulare.
Dim f As Form
Dim erstesFormular As New Form1
...
Set f = erstesFormular ' Form1 wird implizit instanziiert!
f.Show ' Instanz wird angezeigt
...
Set f = New Form2 ' Form2 wird explizit instanziiert!
f.Show ' Form2-Instanz wird angezeigt
Verwandte Themen

Verwandte Them en
...................................................
Vollbildanzeige (S. 536); DiaProjektor – SDI-Formulare synchronisieren (S. 511)

MDIForm- Objekt
Dim mdiFormVar As MDIForm
Dim mdiFormTypVar As MDIFormTyp
Beschreibung

Bes c hreibung
...................................................
Was die formale Natur des MDIForm-Objekts als Datentyp betrifft, so gilt das Gleiche wie für das
Form-Objekt (vgl. dort, insbesondere die Klärung zur sprachlichen Verwendung des Wortes
»MDI-Formularobjekt«).

31 3
Formulare

Im Gegensatz zu gewöhnlichen Formularobjekten sind MDI-Formularobjekte in der Lage, For-


mulare in ihrem Client-Bereich anzuzeigen. Zudem bieten sie einen gewissen Komfort für die
Verwaltung untergeordneter Formulare. Methoden für eigene Grafikoperationen (die über ein
Setzen der vorhandenen Picture-Eigenschaft hinausgehen) kennt das MDI-Formular jedoch
nicht. MDI-Formulare werden daher meist als Grundlage für die Implementation von Anwen-
dungen verwendet, die mit mehreren Dokumentenfenstern arbeiten.
Damit ein gewöhnliches Formular einem MDI-Formular untergeordnet werden kann, muss
seine MDIChild-Eigenschaft (bereits zur Entwurfszeit) auf True gesetzt werden.
Neben Formularen lassen sich auf einem MDI-Formular nur solche Steuerelemente platzieren,
die im engeren oder weiteren Sinne als Leiste definiert sind: StatusBar, ProgressBar, Data, Remo-
teData, Adodc, ToolBar und PictureBox (erscheint als Leiste in voller Breite des Client-Bereichs).
Formulare

Darüber hinaus kann ein MDI-Formular ein Menü besitzen und Kontextmenüs zur Anzeige
bringen.
Eigenschaften

...................................................
Eigens c ha ften
ActiveControl, ActiveForm, Appearance, AutoShowChildren, BackColor, Caption, Controls,
Count, Enabled, Height, HelpContextID, hWnd, Icon, Left, LinkMode, LinkTopic, MouseIcon,
Mousepointer, Moveable, Name, NegotiateToolsbars, OLEDropMode, Picture,RightToLeft,
ScaleHeight, ScaleWidth, ScrollBars, StartupPosition, Tag, Top, Visible, Width, Window-
State
Die folgende Tabelle gibt einen Überblick über die nicht anderer Stelle vorgestellten Eigenschaf-
ten des MDI-Formulars (vgl. insbesondere: Form-Objekt):

Eigenschaft Beschreibung
ActiveForm Verweis auf das untergeordnete Formular, das im Besitz des Fokus ist
(Datentyp entspricht dem Objektdatentyp des jeweiligen Formulars)
AutoShowChildren Boolean-Wert, der bestimmt, ob nach dem Load-Aufruf für ein unterge-
ordnetes Formular implizit ein Show-Aufruf erfolgt (True; Voreinstellung)
oder nicht (False)
Controls Schreibgeschützte Object-Auflistung, die alle Steuerelemente (nicht For-
mulare!) des MDI-Formulars als Elemente enthält. Beim Entwurf zuletzt
eingefügte Steuerelemente kommen zuerst. Beachten Sie, dass sich nicht
alle Arten von Steuerelementen in ein MDI-Formular einfügen lassen.
Count Schreibgeschützter Integer-Wert, der die Anzahl der in der Controls-
Auflistung für das Formular geführten Steuerelemente (nicht Formu-
lare!) wiedergibt.
NegotiateToolbars Boolean-Wert, der bestimmt, ob die Symbolleisten eines untergeordneten
Objekts im MDI-Formular angezeigt werden, solange das Objekt aktiv
ist
ScrollBars Boolean-Wert, der bestimmt, ob das MDI-Formular automatisch Bild-
laufleisten anzeigt, wenn der Client-Bereich für die vollständige Anzeige
eines untergeordneten Formulars nicht ausreicht

Methoden

...................................................
Metho den
Arrange, Hide, Move, OLEDrag, PopupMenu, SetFocus, Show, ValidateControls, WhatsThis-
Mode, ZOrder

31 4
MDIForm- Objekt

Die einzige nicht an anderer Stelle vorgestellte Methode des MDI-Formulars ist Arrange. Ihr
Prototyp lautet:
Sub Arrange (Arrange As FormArrangeConstants)
Für den Aufruf der Methode definiert der Aufzählungstyp FormArrangeConstants drei Konstan-
ten:

Konstante Beschreibung
vbCascade (0) Die Methode ordnet alle dem MDI-Formular untergeordneten sichtba-
ren und nicht minimierten Formulare als Kaskade an – das heißt: über-

Formulare
lappend, mit zunehmender Verschiebung von links oben nach rechts
unten, so dass von hinteren Fenstern die Titelleisten lesbar bleiben.
vbTileHorizontal (1) Die Methode ordnet alle dem MDI-Formular untergeordneten sichtba-
ren und nicht minimierten Formulare in einer Reihe untereinander an,
so dass sie den Client-Bereich der Breite und der Höhe nach vollstän-
dig ausfüllen.
vbTileVertical (2) Die Methode ordnet alle dem MDI-Formular untergeordneten sichtba-
ren und nicht minimierten Formulare in einer Reihe nebeneinander an,
so dass sie den Client-Bereich der Breite und der Höhe nach vollstän-
dig ausfüllen.

Anwendung

Anwendung
...................................................
Wer MDI von anderen Programmiersprachen her kennt, wird die von Visual Basic vorgestellte
MDI-Konzeption als denkbar einfach empfinden: Man füge dem Projekt ein neues Modul des
Typs »MDI-Formular« hinzu (wobei je Projekt maximal ein MDI-Formular zulässig ist), das
die Implementation für das MDI-Formular enthalten wird, und füge dem Projekt weiterhin für
jeden dem MDI-Formular untergeordneten Formulartyp ein gewöhnliches Formularmodul
hinzu, in dem die Eigenschaft MDIChild auf True gesetzt ist. Das war bereits alles; den Rest erle-
digt Visual Basic für Sie. Ist ein untergeordnetes Formular im Dialog PROJEKTEIGENSCHAFTEN
als Startobjekt festgelegt, lädt Visual Basic das übergeordnete MDI-Formular automatisch noch
vor dem untergeordneten Formular und zeigt es dann im Client-Bereich des MDI-Formulars an.
Ist dagegen das MDI-Formular als Startobjekt definiert, kommt dieses mit leerem Client-
Bereich zur Anzeige und kann sich (beispielsweise im Rahmen seiner Load-Behandlung) selbst
um die Anzeige untergeordneter Formulare kümmern.
Die Ereignisreihenfolge für ein als Startobjekt festgelegtes MDI-Formular sieht so aus:
Initialize
Load
Resize
Activate
...
QueryLoad
Unload
Terminate

Beim Entladen eines MDI-Formulars trifft das QueryUnload-Ereignis zuerst beim MDI-Formular
und dann der Reihe nach bei den untergeordneten Formularen ein. Falls nur ein einziges
Formular die Cancel-Eigenschaft auf True setzt, unterbricht das den Entladevorgang für alle
Formulare. Ansonsten folgt das Unload-Ereignis, das diesmal zuerst aber alle untergeordneten

31 5
Formulare

Formulare erreicht und erst zum Schluss das MDI-Formular. Falls ein untergeordnetes Formu-
lar bei der Behandlung des Unload-Ereignisses die Cancel-Eigenschaft auf True setzt, unterbricht
das den Entladevorgang für alle folgenden Formulare (und damit auch für das MDI-Formular).
Die Ereignisreihenfolge für ein automatisch über ein untergeordnetes Formular geladenes (und
später wieder geschlossenes) MDI-Formular sieht damit so aus:
Form.Initialize
MDIForm.Initialize
MDIForm.Load
Form.Load
MDIForm.Resize
Formulare

Form.Resize
MDIForm.Activate
Form.Activate
Form.GotFocus
...
MDIForm.QueryLoad
Form.QueryLoad
Form.Unload
MDIForm.Unload
Form.Terminate
MDIForm.Terminate

Untergeordnete Formulare sind im Client-Bereich des MDI-Formulars eingesperrt, lassen sich


darin aber bequem mittels Arrange auf drei verschiedene Arten anordnen. Automatisch vom
MDIForm-Objekt gepflegte Bildlaufleisten sorgen dafür (ScrollBars-Eigenschaft), dass der Benut-
zer auch mit Formularen vernünftig arbeiten kann, die nicht vollständig in den Client-Bereich
passen.
Ein wichtiges Mittel für die Arbeit mit untergeordneten Formularen ist die Eigenschaft Active-
Control. Sie ermöglicht es, Operationen immer auf das Formular zu beziehen, das im Besitz des
Fokus ist, ohne eigens darüber Buch führen zu müssen, welches Formular dies gerade ist. Um
beispielsweise den Namen des aktiven Steuerelements im aktiven Formular zu ermitteln, schrei-
ben Sie:
sName = ActiveForm.ActiveControl.Name

Wie das Beispiel zu diesem Abschnitt zeigt, kann es einem diese Eigenschaft sogar ersparen,
Objektvariablen auf geladene untergeordnete Variablen zu halten. Es versteht sich, dass die
Eigenschaft nur dann einen von Nothing unterschiedlichen Wert aufweist, wenn es ein aktives
untergeordnetes Formular gibt. Da ein Formular weder über eine Container-Eigenschaft noch
über eine Parent-Eigenschaft verfügt, haben untergeordnete Formulare umgekehrt jedoch keine
Information über das MDI-Formular, dem sie angehören.
Beispiel

Beis piel
...................................................
Mit dem Projekt MDIForm liegt die einfache Implementation eines MDI-Formulars vor, das
beliebig viele Bilder in untergeordneten Fenstern anzeigen kann. Das Formular verfügt über
eine Menüleiste mit den beiden Menüs DATEI und ANORDNEN. Ersteres enthält die Komman-
dos ÖFFNEN, um ein weiteres Bild in ein neues Fenster zu laden, SCHLIEßEN, um das aktive
untergeordnete Fenster zu schließen, und BEENDEN, um das MDI-Formular samt aller unter-
geordneter Fenster zu schließen und das Programm zu beenden. Die Routine
mnuDateiÖffnen_Click für die Behandlung von ÖFFNEN speichert das neue Formularobjekt in
einer lokalen Variablen und demonstriert so recht schön, dass das Formularobjekt erhalten

31 6
MDIForm- Objekt

bleibt, obwohl im Programm keine Referenz mehr darauf existiert – allerdings hält das MDI-
Formular implizit noch eine Referenz darauf, nicht zuletzt um im Zuge des Unload-Aufrufs im
Rahmen der Behandlung von BEENDEN automatisch alle untergeordneten Formulare entladen
zu können. Die ebenso elegante wie undurchsichtige Implementation des zweiten Menüs
ANORDNEN profitiert davon, dass die Menüeinträge als Array vereinbart sind. Sie nutzt den
Parameter Index der Behandlungsroutine schlicht als Argument für Arrange. Klickt der Benutzer
in den Client-Bereich des MDI-Formulars, wird dieses Menü auch als Kontextmenü angezeigt.
' Modul MDIForm1: Formular zeigt Bilder in untergeordneten Formularen an
Private Sub MDIForm_Load()
mnuDateiÖffnen_Click ' Erstes Fenster öffnen

Formulare
End Sub

Private Sub MDIForm_Click()


PopupMenu mnuAnordnen
End Sub

Private Sub mnuDateiBeenden_Click()


Unload Me ' Programm beenden
End Sub

Private Sub mnuDateiÖffnen_Click() ' Nächstes Fenster öffnen


Dim SDIForm As New Form1
CommonDialog1.Filter =
"Bilder|*.jpg;*.gif;*.bmp;*.wmf;*.emf;*.ico;*.cur"
CommonDialog1.ShowOpen
If CommonDialog1.filename <> "" Then
SDIForm.ShowPic (CommonDialog1.filename)
End If
End Sub

Private Sub mnuDateiSchließen_Click()


Unload ActiveForm ' Fenster schließen
End Sub

Private Sub mnuOrdnen_Click(Index As Integer)


Arrange (Index) ' Fenster anordnen
End Sub

Das Formularmodul, das den Objektdatentyp für die untergeordneten Formulare definiert, ist
recht geradlinig implementiert. Die Routine ShowPic lädt das Bild und baut ansonsten auf die
Resize-Routine, die das Bild in geeigneter Skalierung zentriert mit Hilfe von PaintPicture in
den Client-Bereich des Formulars zeichnet.
' Modul Form1: Formular lädt Bild und zeigt es in passender Größe an
Private Bild As Picture

Private Sub Form_Resize()


Dim w, h
' Bild geeignet zentrieren
w = Bild.Width: h = Bild.Height
If w < Width Or w > ScaleWidth Then

31 7
Selbst definierte Klassen

w = ScaleWidth
h = h * w / Bild.Width
End If
If h > ScaleHeight Then
h = ScaleHeight
w = Bild.Width * h / Bild.Height
End If
Cls
PaintPicture Bild, (ScaleWidth – w) / 2, (ScaleHeight – h) / 2, w, h
End Sub
Selbst definierte Klassen

Public Sub ShowPic(filename As String)


On Error GoTo Fehler
Set Bild = LoadPicture(filename) ' Bild Laden
On Error GoTo 0
Form_Resize ' Bild zeichnen
Caption = Mid(filename, InStrRev(filename, "\") + 1)
Exit Sub
Fehler:
Print "Dateiformat nicht erkannt"
End Sub

Selbst definierte Klassen


Wer schon das eine oder andere Formular oder gar Benutzersteuerelement implementiert hat,
steckt bereits tiefer in der objektorientierten Programmierung, als er vermutet – und hat vom
Prinzip her eigentlich schon das Wesentliche begriffen, was man für die Implementierung eige-
ner Klassen benötigt. Jedes Formular oder Benutzersteuerelement verkörpert in Visual Basic
nämlich einen eigenständigen Datentyp bzw. eine eigene Klasse, so dass die Programmiertech-
nik für den Umgang mit Formularen und Steuerelementen fundamental die gleiche ist wie für
den Umgang mit Objekten selbst definierter Klassen – und auch die Implementation unterliegt
den gleichen Gesetzmäßigkeiten und Prinzipien. Ja, selbst definierte Klassen sind sogar um eini-
ges »pflegeleichter« als Formulare und Benutzersteuerelemente, da sie zunächst einmal weder
eine visuelle Repräsentation in Form eines Fensters besitzen noch auf eine vergleichbar kom-
plexe Schnittstelle aufsetzen.
Was die Form-Schnittstelle für das Formular und die UserControl-Schnittstelle für das Benutzer-
steuerelement, das ist die ClassModule-Schnittstelle für eine selbst definierte Klasse. Sie stattet
eine Instanz der selbst definierten Klasse mit dem Nötigsten aus, was ein Objekt benötigt: Kon-
struktor und Destruktor. Beide lassen sich als Ereignisbehandlungsroutinen implementieren
und fügen sich somit nahtlos in das ereignisorientierte Programmiermodell ein.
Definition
Für die Definition einer eigenen Klasse fügen Sie dem Projekt über das Menü PROJEKT ein Klas-
senmodul hinzu und legen im Eigenschaftsfenster den Namen der Klasse fest. Die Implementa-
tion nehmen Sie dann wie gewohnt im Codefenster vor. Der erste Schritt bei der Implementa-
tion einer neuen Klasse wird die Definition der Datenstruktur sein, die ein Objekt der Klasse
verkörpern soll – mit anderen Worten: die Deklaration der Datenelemente der Klasse. (Wie im
Abschnitt »Klassen als Datentypen für Objektvariablen«, S. 196, näher ausgeführt, gibt es hier
eine Innensicht und eine Außensicht.) Der nächste Schritt ist die Initialisierung der Datenele-
mente. Sie erfolgt im Konstruktor der Klasse, also im Rahmen der Behandlungsroutine für das
Initialize-Ereignis. Im dritten Schritt implementieren Sie die Eigenschaften der Klasse in Form

31 8
Selbst definierte Klassen

von Property-Methoden (vgl. »Eigenschaften«; S. 201) und die sonstigen Methoden der Klasse.
Im letzten Schritt müssen Sie gegebenenfalls noch für den Abbau aller durch ein Objekt dieser
Klasse angeforderter Ressourcen sorgen, die Visual Basic nicht von sich aus mit dem Objekt
zusammen abbaut – so beispielsweise: Formularinstanzen. Den Code dafür setzen Sie in die
Behandlungsroutine für das Terminate-Ereignis.
Standardeigenschaft
Von der Programmierung mit Steuerelementen her sind Sie es sicher gewohnt: Ein Objekt kann
ein so genanntes Standardelement (Standardeigenschaft) besitzen, das heißt eine Eigenschaft
oder eine Methode, deren Wert bzw. Aufruf sich durch alleinige Notation des Objektbezeich-
ners (also unter Weglassung des zugehörigen Elementbezeichners) ergibt. Um eine Methode
(eine Eigenschaft ist ja nichts anderes als eine Property Get-Methode) als Standardelement zu

Selbst definierte Klassen


vereinbaren, gehen Sie wie folgt vor:
1. Aktivieren Sie das Codefenster der Klasse und öffnen Sie das Dialogfeld PROZEDURATTRIBU-
TE über das Menü EXTRAS/PROZEDURATTRIBUTE.
2. Wählen Sie im Kombinationsfeld NAME den Bezeichner des Elements, das Sie als Standard-
element vereinbaren wollen, und zeigen Sie über die Schaltfläche WEITERE die detaillierte
Form des Dialogfelds an.
3. Wählen Sie im Kombinationsfeld PROZEDUR-ID den Eintrag (Voreinstellung) oder tragen Sie
den Wert 0 als ID ein.

Die Eigenschaft Betrag als Standardeigenschaft festlegen

Von nun an können Sie auf das Standardelement (hier: Betrag) referieren, indem Sie schlicht
den Objektbezeichner notieren – und zwar als Rechtswert oder Linkswert, vorausgesetzt, die
entsprechenden Methoden (meist: Property Set/Let und/oder Property Get) sind vorhanden.
Schnittstellen implementieren
Für die fortgeschrittene Programmierung mit Klassen besteht weiterhin die Möglichkeit, eine
Klasse durch Verwendung des Schlüsselworts Implements als Implementation einer bestimmten
Schnittstelle zu deklarieren. Bei der Schnittstelle kann es sich um eine Standardschnittstelle han-
deln, aber auch um eine selbst definierte sog. abstrakte Klasse, die Methoden als Rümpfe dekla-
riert, ohne eine Implementation dafür bereitzustellen. Letzteres ist dann Aufgabe der Klasse, die
die Schnittstelle implementiert – sie muss für jede in der Schnittstelle deklarierte Methode eine
Implementation bereitstellen.

31 9
Selbst definierte Klassen

Eine ausführlichere Diskussion dieses Konzepts führt jedoch sehr schnell in die komplexe Welt
des COM und der Programmierung von und mit ActiveX-Komponenten.
Beispiel

Beis piel
...................................................
Ein Beispiel für die Implementation einer einfachen selbst definierten Klasse finden Sie im
Abschnitt »Eigenschaften« (S. 201).

ClassModul- Schnittstelle
Bei der ClassModule-Schnittstelle handelt es sich um eine rudimentäre Schnittstelle, die eine
selbst definierte Klasse mit den beiden Ereignissen Initialize und Terminate sowie den Eigen-
Selbst definierte Klassen

schaften DatabindingBehavior und DataSourceBehavior ausstattet. Weitere »Erblasten« gibt es


zunächst einmal nicht.
Anwendung

Anwendung
...................................................
Im Gegensatz zu Schnittstellen wie Form oder UserControl steht ClassModule nicht als Objektda-
tentyp für Objektvariablen zur Verfügung. Wer eine generische Objektvariable benötigt (und
nichts anderes wäre eine Variable des Typs ClassModul) muss also mit dem Datentyp Object
vorlieb nehmen.
Das Initialize-Ereignis tritt für jedes Objekt einer gegebenen selbst definierten Klasse ein ein-
ziges Mal auf, nämlich bei der Instanziierung. Eine Behandlung dieses Ereignisses gibt dem
Objekt Gelegenheit, seine Elemente zu initialisieren, Ressourcen anzufordern usw., kurz gesagt:
sich zu konstruieren. Da die Datenstruktur eines Objekts seinerseits Elemente mit Objektdaten-
typen enthalten kann, stellt sich die Frage nach der Reihenfolge der Initialize-Ereignisse. Die
Antwort lautet: Visual Basic instanziiert Objekte top-down, also zuerst das Objekt und dann
seine Elemente. Das ist nicht verwunderlich, da Visual Basic Objekte generell erst dann kon-
struiert, wenn es (implizit oder explizit) eine New-Anweisung ausführt.
Das Terminate-Ereignis ist das Gegenstück zu Initialize und tritt gleichfalls nur einziges Mal
auf, nämlich beim Ableben des Objekts. Es gibt dem Objekt umgekehrt Gelegenheit, angefor-
derte Ressourcen wieder freizugeben. Ein expliziter Abbau von Elementen mit Objektdatentyp
ist allerdings nicht erforderlich, da Visual Basic diese automatisch abbaut. Die Reihenfolge des
Abbaus ist gleichfalls top-down, das heißt, die Elemente eines Objekts werden nach dem Objekt
abgebaut (was natürlich sinnvoll ist, denn das Objekt sollte bei der Behandlung von Terminate
noch über alle Elemente verfügen).
Die nur zur Entwurfszeit verfügbaren Eigenschaften DatabindingBehavior und DataSourceBeha-
vior legen fest, ob (und wenn ja wie) das Objekt an eine Datenquelle gebunden werden kann
bzw. ob es selbst als Datenquelle für andere Objekte auftreten kann. Sie sind nur von Interesse,
wenn Sie die Klasse für die Implementation von Datenbankverbindungen verwenden.

320
Steuerelemente
Was das Lenkrad, der Tacho, die Instrumente, Schalter, Regler, Hebel und Pedale für ein Auto
oder ein Flugzeug, das sind die Steuerelemente für ein Programm. Steuerelemente sind nach
ergonomischen Gesichtspunkten gestaltete Ein- und Ausgabemedien für die Interaktion zwi-
schen Benutzer und Programm. Dabei vereint jedes Steuerelement (genauer: die meisten Steuer-
elemente) in sich eine visuelle Repräsentation seiner Zustände sowie eine operationale Reprä-
sentation der mit diesen Zuständen verbundenen Befehle und Aktionen.
Gut 80 Prozent der Programmierung mit Visual Basic hat etwas mit Steuerelementen zu tun.
Das ist kein Wunder, denn das Erfolgsrezept von Visual Basic war seit jeher der unkomplizierte
Umgang mit Steuerelementen sowie die Möglichkeit, in kürzester Zeit selbst komplexeste For-
mulare nicht nur zusammenstellen, sondern auch ans Laufen bringen zu können. Während der
visuell orientierte Entwurf von Benutzeroberflächen sehr schnell auch in die Entwicklungsum-
gebungen anderer Programmiersprachen Einzug gehalten hat, ist die mit Visual Basic vorlie-
gende Integration der Codeentwicklung in die interaktive visuelle Gestaltung der Benutzerober-
fläche nach wie vor außerordentlich. Das liegt daran, dass auch für den gesamten modularen
Aufbau eines Programms bzw. einer Komponente das gleiche Baukastenprinzip zur Anwen-
dung kommt: Der Entwickler zieht ein Steuerelement bzw. eine Komponente in den Entwurfs-
bereich eines Formulars (bzw. der zu entwickelnden Komponente) und eröffnet sich damit den
gesamten Funktionsumfang des dahinter steckenden Bibliotheksmoduls. Eine zum Modul gehö-
rige und von der Entwicklungsumgebung automatisch konsultierte Typbibliothek gibt zudem
Auskunft über die Eigenschaften, Methoden und Ereignisse, die für das Steuerelement definiert
sind. (Rufen Sie doch einmal mit (F2) den Objektkatalog auf.)
Ein Steuerelement muss nicht unbedingt als sichtbares Element der Benutzeroberfläche mit eige-
nem Fensterbereich in Erscheinung treten. Visual Basic fasst den Begriff des Steuerelements
wesentlich weiter. Hat man erst einmal verstanden, dass in Visual Basic (fast) alles, was von
»außen« kommt, als Steuerelement auf den Entwurfsbereich eines Formulars oder einer Kom-
ponente platziert wird, lebt es sich leicht: »Sage mir, was Du machen willst, und ich besorge Dir
ein Steuerelement dafür«. Die Sparte VB-Steuerelemente ist inzwischen zu einem Boombereich
auf dem Softwaremarkt geworden, und frei nach dem Motto »es gibt nichts, was es nicht gibt«,
reduziert sich so manches Problem durch Einsatz einer fertigen kommerziellen Komponente zu
einer trivialen Angelegenheit. Umgekehrt steht einem Programmierer aber auch nichts im Wege,
sich seine eigenen Bibliotheken als Benutzersteuerelemente (ActiveX-Steuerelemente oder Acti-
veX-Komponenten) zusammenzustellen und sich gegebenenfalls sogar seine Nische in dem brei-
ten Markt zu erobern.
In der Dokumentation wird selten zwischen einem Steuerelement als Fenster, das einem anderen
Fenster (etwa dem eines Formulars) untergeordnet ist, und einem Steuerelement als Objekt, das
die operationale Repräsentation dieses Fensters innerhalb eines Programms vornimmt, unter-
schieden. Gerade für Anfänger im Bereich der Windows-Programmierung ist diese Unterschei-
dung für ein besseres Verständnis aber sehr wichtig, weil sie die über eine Schnittstelle vermit-
telte Dualität sichtbares GDI-Objekt, als Fensterobjekt einer bei Windows registrierten
Fensterklasse, und operatives Visual-Basic-Objekt, das auf Nachrichten des Fensterobjekts rea-
giert und bemüht ist, seinen Zustand mit dem des Fensterobjekts zu synchronisieren, unter-
streicht. Mit diesem Wissen im Hinterkopf erklärt sich auch, warum ein Formular (und alle
darauf befindlichen Steuerelemente) geladen und wieder entladen werden kann, obwohl das
Formularobjekt (respektive die Steuerelementobjekte) erhalten bleibt.
Einen kleinen Nachteil hatte der visuelle Ansatz, bevor die Version 6.0 eine Lösung anbot: Im
Gegensatz zu anderen Programmiersprachen war es Visual Basic bisher nicht so ohne Weiteres
möglich, ein Steuerelement zur Laufzeit zu generieren, das nicht bereits zur Entwurfszeit
wenigstens in einer Instanz als »Samen« auf dem jeweiligen Formular platziert worden war.
Darüber hinaus mussten dynamisch generierte Steuerelementinstanzen in Steuerelemente-

3 21
Selbst definierte Klassen

Arrays verwaltet werden, was die Bezeichnerwahl natürlich einschränkte. Die Version 6.0
behebt dieses Manko nun mit Mitteln der Automatisierung, indem sie die Möglichkeit bietet,
der Controls-Auflistung eines Formulars über die Methode Add dynamisch neue, noch nicht als
»Samen« existierenden Steuerelemente hinzuzufügen – um den Preis einer späten Bindung zur
Laufzeit.
Mit der Version 4.0 hat Visual Basic nicht nur den Sprung in den 32-Bit-Welt vorgenommen,
sondern sich auch konzeptuell dem COM (Component Object Model) verschrieben. Steuerele-
mente sind seither Komponenten im Sinne des COM. Traditionell gibt es die Unterscheidung
zwischen den Standardsteuerelementen, die den Kern der von Windows unterstützten Steuerele-
mente ausmachen, in der grundlegenden Werkzeugsammlung von Visual Basic zu finden sind
Selbst definierte Klassen

und sich ohne weiteres Zutun sofort einsetzen lassen, und den ActiveX-Steuerelementen, die
über den Menübefehl PROJEKT/KOMPONENTEN ((Strg)+(T)) bei Bedarf explizit in die Werk-
zeugsammlung übernommen werden müssen. Die ActiveX-Steuerelemente zerfallen wiederum
in verschiedene Gruppen, die aber im Allgemeinen die Bibliothekszugehörigkeit widerspiegeln.
Die wichtigsten darunter sind die Standarddialoge (COMDLG32.OCX) und die Windows-
Standardsteuerelemente (MSCOMCTL.OCX, MSCOMCT2.OCX, MSCOM332.OCX). Die
folgende Tabelle gibt einen Überblick, in welchem OCX-Modul welches Steuerelement zu fin-
den ist:

Steuerelement Komponentenname Dateiname


Adodc (ADO Daten- Microsoft ADO Data Control 6.0 MSADODC.OCX
Steuerelement)
MSChart Microsoft Chart Control 5.5 MSCHART.OCX
MSComm Microsoft Comm Control 6.0 MSCOMM32.OCX
CommonDialog Microsoft Common Dialog Control 6.0 COMDLG32.OCX
DBGrid Microsoft Data Bound Grid Control 5.0 DBGRID32.OCX
DBCombo, DBList Microsoft Data Bound List Controls 6.0 DBLIST32.OCX
DataRepeater Microsoft Data Repeater Control 6.0 MSDATREP.OCX
DataGrid Microsoft Data Grid Control 6.0 MSDATGRD.OCX
DataList, DataCombo Microsoft Data List Controls 6.0 MSDATLST.OCX
MSFlexGrid Microsoft FlexGrid Control 6.0 MSFLXGRD.OCX
Grid Microsoft Grid Control GRID32.OCX
MSHFlexGrid Microsoft Hierarchical Flex Grid Control 6.0 MSHFLXGD.OCX
Inet (Internet Trans- Microsoft Internet Transfer Control 6.0 MSINET.OCX
fer-Steuerelement)
MAPIMessages, Microsoft MAPI Controls 6.0 MSMAPI32.OCX
MAPISession
MaskEdBox Microsoft MaskedEdit Control 6.0 MSMASK32.OCX
MMControl Microsoft Multimedia Control 6.0 MCI32.OCX
PictureClip Microsoft PictureClip Control 6.0 PICCLP32.OCX
RemoteData Microsoft RemoteData Control 6.0 MSRDC20.OCX
RichTextBox Microsoft RichTextBox Control 6.0 RICHTX32.OCX
Komponentenzugehörigkeit der ActiveX- Steuerelemente

322
Gemeinsame Eigenschaften

Steuerelement Komponentenname Dateiname


SysInfo Microsoft SysInfo Control 6.0 SYSINFO.OCX
Tab (Microsoft Tab- Microsoft TabbedDialog Control 6.0 TABCTL32.OCX
Steuerelement)
ImageCombo, Image- Microsoft Windows Common Controls 6.0 MSCOMCTL.OCX
List, ListView, (in der Version 5.0:
ProgressBar, Slider, COMCTL32.OCX)
StatusBar, TabStrip,
Toolbar, TreeView

Gemeinsame Eigenschaften
Animation, DTPicker, Microsoft Windows Common Controls-2 6.0 MSCOMCT2.OCX
FlatScrollbar, (in der Version 5.0:
MonthView, UpDown, COMCT232.OCX)
CoolBar Microsoft Windows Common Controls-3 6.0 COMCT332.OCX
WinSock Microsoft Winsock Control 6.0 MSWINSCK.OCX
Komponentenzugehörigkeit der ActiveX- Steuerelemente

Gemeinsame Eigenschaften
Da die Standardsteuerelemente und ActiveX-Steuerelemente viele Eigenschaften mit mehr oder
weniger gleicher Bedeutung – teilweise aber mit unterschiedlichen Wertebereichen – besitzen,
folgt zunächst einmal eine Besprechung der wichtigsten Eigenschaften und Methoden, bevor es
dann mit den einzelnen Steuerelementtypen weitergeht. Die folgende Tabelle gibt einen Über-
blick über die Eigenschaften, die bei der Besprechung der einzelnen Steuerelemente sowie des
Formularobjekts nicht eigens diskutiert werden.

Eigenschaft Beschreibung
Alignment Integer-Wert, der die Ausrichtung des Werts oder der Beschriftung des
Steuerelements im Fensterbereich ausdrückt
Appearance Integer-Wert, der die Darstellungsart des Steuerelements ausdrückt
(2D oder 3D)
AutoSize Boolean-Wert, der bestimmt, ob das Steuerelement seine Bereichsab-
messungen automatisch anpasst, um den Standardwert vollständig
darstellen zu können
BackColor Long-Wert, der die Hintergrundfarbe des Steuerelements ausdrückt
BackStyle Integer-Wert, der ausdrückt, ob der Hintergrund des Steuerelements
durchscheint oder nicht
BorderStyle Integer-Wert, der den Stil der Randlinie des Steuerelements ausdrückt
Caption String-Wert für die Beschriftung des Steuerelements
Container Objektverweis auf das Containerobjekt des Steuerelements
Die wichtigsten gemeinsamen Eigenschaften der Steuerelemente

323
Gemeinsame Eigenschaften

Eigenschaft Beschreibung
CausesValidation Boolean-Wert, der ausdrückt, ob ein Validate-Ereignis bei Fokusver-
lust an ein anderes Steuerelement (mit auf True gesetzter CausesValida-
tion-Eigenschaft) auftritt
DataChanged Boolean-Wert, der ausdrückt, ob sich der Wert des Steuerelements
gegenüber dem Datensatz, an den es gebunden ist, geändert hat.
DataField String-Wert für den Namen des Datenfelds, wenn das Steuerelement
an ein bestimmtes Datenfeld im aktuellen Datensatz gebunden ist
Gemeinsame Eigenschaften

DataFormat DataFormat-Objekt, das die Schnittstelle IStdDataFormatDisp imple-


mentiert und für eine formatierte Darstellung des Steuerelementwerts
sorgt
DataMember String-Wert für den Namen des Datenelements in einer Datenquelle,
wenn das Steuerelement an eine solche gebunden ist
DataSource String-Wert für den Namen der Datenquelle, wenn das Steuerelement
an eine solche gebunden ist
DisabledPicture Picture-Objekt mit Verweis auf Bitmap für die benutzerdefinierte Dar-
stellung des inaktiven Steuerelements
DownPicture Picture-Objekt mit Verweis auf Bitmap für die benutzerdefinierte Dar-
stellung des Steuerelements im angeklickten Zustand
DragIcon Picture-Objekt mit Verweis auf benutzerdefinierten Mauszeiger für
die Anzeige während Drag&Drop-Operationen
DragMode Integer-Wert, der das Verhalten des Steuerelements bei Drag&Drop-
Operationen bestimmt
DrawMode Integer-Wert, der den Zeichenmodus für Zeichenoperationen sowie
für das Zeichnen von Figur- und Liniensteuerelementen festlegt
DrawStyle Integer-Wert, der den Linienstil für Grafikmethoden bestimmt
FillColor Long-Wert, der die Füllfarbe für die Darstellung nichttransparenter
Füllbereiche des Steuerelements ausdrückt
FillStyle Integer-Wert, der den Füllstil für die Darstellung nichttransparenter
Füllbereiche des Steuerelements ausdrückt
Font Font-Objekt, das die Schrift für die Darstellung textorientierter Werte
definiert
FontBold, FontIta- Boolean-Werte für zusätzliche Schriftattribute bei der Darstellung text-
lic, FontStrike- orientierter Werte
thru, FontUnderline
FontName String-Wert, der den Namen der aktuell eingestellten Schrift bestimmt
FontSize Single-Wert, der die Schriftgröße der aktuell eingestellten Schrift
bestimmt
ForeColor Long-Wert, der die Farbe für das Zeichnen von Vordergrundanteilen
des Steuerelements ausdrückt
Die wichtigsten gemeinsamen Eigenschaften der Steuerelemente

324
Gemeinsame Eigenschaften

Eigenschaft Beschreibung
HasDC Schreibgeschützter Boolean-Wert, der angibt, ob das Formular oder
Steuerelement einen eigenen Gerätekontext für die Ausgabe besitzt
Height Single-Wert, der die Höhe des Steuerelements bezogen auf das aktu-
elle Koordinatensystem des Containers bestimmt
HelpContextID Long-Wert, der dem Steuerelement die Nummer eines Thema in der
kontextbezogenen Hilfedatei (App.HelpFile) zuordnet
hDC Zur Laufzeit schreibgeschützter Wert vom Typ Long der auf den Gerä-

Gemeinsame Eigenschaften
tekontext des Ausgabegerätes verweist und nur im Zusammenhang mit
Funktionen der Win32-API benötigt wird.
hWnd Long-Wert, der die Windows-Fensternummer (Handle) des dem Steuer-
element zugeordneten Fensters wiedergibt
Image Zur Laufzeit schreibgeschützter Picture-Wert, der einen Verweis auf
die beständige Bitmap im Gerätekontext des Steuerelements oder For-
mulars darstellt
Index Indexnummer des Steuerelements im Steuerelemente-Array (reine Ent-
wurfseigenschaft)
Left Single-Wert, der die horizontale Position (linker Rand) des Steuerele-
ments im Container bezogen auf das aktuelle Koordinatensystem des
Containers ausdrückt
MaskColor Long-Wert, der die Transparenzfarbe für die Maskierung transparenter
Bereiche des Steuerelements ausdrückt (Verwendung abhängig von
UseMaskColor)
MouseIcon Picture-Objekt mit Verweis auf benutzerdefinierten Mauszeiger (Ver-
wendung abhängig von MousePointer)
MousePointer Integer-Wert, der das für das Steuerelement angezeigte Mauszeiger-
symbol auswählt
MultiLine Boolean-Wert, der bestimmt, ob der Wert des Steuerelements für eine
mehrzeilige Darstellung umbrochen werden kann
Name String-Wert, der den Bezeichner des Steuerelementobjekts wiedergibt
OLEDropAllowed Boolean-Wert, der bestimmt, ob das Steuerelement das Ablegen von
OLE-Objekten im Rahmen von OLE-Drag&Drop-Operationen
zulässt
OLEDropMode Integer-Wert, der das Verhalten des Steuerelements bei OLE-
Drag&Drop-Operationen bestimmt
OLETypeAllowed Integer-Wert, der bestimmt, ob das Steuerelement das Einbetten und/
oder das Verknüpfen von OLE-Objekten unterstützt, die im Rahmen
von OLE-Drag&Drop-Operationen abgelegt werden
Parent Verweis auf das (Formular-)Objekt, dem das Steuerelement unterge-
ordnet ist
Die wichtigsten gemeinsamen Eigenschaften der Steuerelemente

325
Gemeinsame Eigenschaften

Eigenschaft Beschreibung
Picture Picture-Objekt mit Verweis auf das im Bereich des Steuerelements
angezeigte (Hintergrund-)Bild (Aktivierung und grafischer Modus ggf.
erforderlich)
RightToLeft Boolean-Wert, der die Ausrichtung der textorientierten Darstellung auf
bidirektionalen Systemen bestimmt
ScaleLeft Single-Wert, der die Ursprungsverschiebung des Koordinatensystems
in horizontaler Richtung ausdrückt
Gemeinsame Eigenschaften

ScaleMode Integer-Wert, der das Koordinatensystem und die darin geltenden


Maßeinheiten bestimmt
ScaleTop Single-Wert, der die Ursprungsverschiebung des Koordinatensystems
in vertikaler Richtung ausdrückt
ShowTips Boolean-Wert, der die QuickInfo ein- oder ausschaltet
Style Integer-Wert, der Art und/oder Darstellungsform des Steuerelements
ausdrückt
TabIndex Integer-Wert, der dem Steuerelements eine Position in der Tabulator-
reihenfolge für die Fokusweitergabe zuordnet
TabStop Boolean-Wert, der festlegt, ob das Steuerelement den Fokus durch
Betätigung der Tabulatortaste (entlang der Tabulatorordnung) erlan-
gen kann
Tag Variant-Wert für zusätzliche benutzerdefinierte Daten (Eigenschaft
wird von Visual Basic nicht benutzt)
ToolTipText String-Wert mit Hilfetext, der als QuickInfo für das Steuerelement
angezeigt wird, wenn die Maus darüber eine Zeit lang verharrt
Top Single-Wert, der die vertikale Position (oberer Rand) des Steuerele-
ments im Container bezogen auf das aktuelle Koordinatensystem des
Containers ausdrückt
UseMaskColor Boolean-Wert, der bestimmt, ob die in MaskColor festgelegte Farbe für
die transparente Darstellung des Steuerelements benutzt wird
Visible Boolean-Wert, der die Sichtbarkeit des Steuerelements bestimmt
WhatsThisHelpID Long-Wert, der den Index für das Hilfethema der Popup-Direkthilfe
festlegt. Wenn 0, kommt die Windows-Standardhilfe unter Beachtung
von HelpContextID zum Aufruf
WhatsThisHelp Boolean-Wert, der festlegt, ob die Direkthilfe für ein Formular aktiv ist
Width Single-Wert, der die Breite des Steuerelements bezogen auf das aktu-
elle Koordinatensystem des Containers bestimmt.
Die wichtigsten gemeinsamen Eigenschaften der Steuerelemente

326
Alignment- Eigenschaft

Alignment- Eigenschaft
Objekt.Alignment As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
DataGrid, Label, ColumnHeader, Function, CheckBox, OptionButton, Panel, RptFunction,
RptLabel, RptText,TextBox, UpDown
Beschreibung

Bes c hreibung
...................................................
Die Alignment-Eigenschaft bestimmt die Ausrichtung eines Steuerelements in dem ihm zur Ver-
fügung stehenden Bereich. Für Ausrichtung sind für die verschiedenen Steuerelemente in den

Gemeinsame Eigenschaften
jeweiligen Modulen diverse Integer-Konstanten definiert. Die folgende Tabelle gibt einen Über-
blick:

Konstante (Wert) definiert für ... Wirkung


vbLeftJustify (0) TextBox, Label, Wert bzw. Beschriftung wird linksbündig
OptionButton, CheckBox im Bereich des Steuerelements ausgerichtet
(Voreinstellung)
vbRightJustify (1) TextBox, Label, Wert bzw. Beschriftung wird rechtsbündig
OptionButton, CheckBox in Steuerelementbereich ausgerichtet
vbCenterJustify (2) TextBox, Label Wert oder Beschriftung wird zentriert in
Steuerelementbereich ausgerichtet
IvwColumnLeft (0) ColumnHeader Spaltenbeschriftung wird linksbündig aus-
gerichtet (Voreinstellung)
IvwColumnRight (1) ColumnHeader Spaltenbeschriftung wird rechtsbündig aus-
gerichtet
IvwColumnCenter (2) ColumnHeader Spaltenbeschriftung wird zentriert ausge-
richtet
sbrLeft (0), Panel Text erscheint linksbündig rechts neben der
hdrLeft (0) Bitmap (Voreinstellung)
sbrCenter (1), Panel Text erscheint zentriert rechts neben der
hdrCenter (1) Bitmap
sbrLeft (2), Panel Text erscheint rechtsbündig links neben der
hdrLeft (2) Bitmap
cc2AlignmentLeft (0) UpDown AufAb-Steuerelement erscheint links von
Buddy
cc2AlignmentRight (1) UpDown AufAb-Steuerelement erscheint rechts von
Buddy (Voreinstellung)
dbgLeft (0) DataGrid Wert wird linksbündig in Spalte ausgerich-
tet
dbgRight (1) DataGrid Wert wird rechtsbündig in Spalte ausge-
richtet
dbgCenter (2) DataGrid Wert wird zentriert in Spalte ausgerichtet

3 27
Gemeinsame Eigenschaften

Konstante (Wert) definiert für ... Wirkung


dbgGeneral (3) DataGrid Text wird links, Zahlen werden rechts in
Spalte ausgerichtet (Voreinstellung)
rptJustifyLeft (0) RptFunction, RptLabel, Wert wird linksbündig in Bereich ausge-
RptText richtet (Voreinstellung)
rptJustifyRight (1) RptFunction, RptLabel, Wert wird rechtsbündig in Bereich ausge-
RptText richtet
rptJustifyCenter (2) RptFunction, RptLabel, Wert wird zentriert in Bereich ausgerichtet
Gemeinsame Eigenschaften

RptText

Hinweis

Hinweis
...................................................
Entgegen anders lautenden Informationen in der Online-Hilfe zu Visual Basic lässt sich diese
Eigenschaft für Kontrollkästchen, Optionsfelder und Textfelder zur Laufzeit manipulieren.
Auch lassen sich die Inhalte von Textfeldern unabhängig vom Wert der Eigenschaft MultiLine
ausrichten.

Appearance- Eigenschaft
Objekt.Alignment As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, CheckBox, ComboBox, CommandButton, Data, DataCombo, DataList, DirListBox, Drive-
ListBox, FileListBox, FlatScrollBar, Form, Frame, Image, Label, ListBox, MDIForm, OLE,
OptionButton, PictureBox, PropertyPage, RemoteData, TextBox, ToolBar, UserControl,
UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Appearance-Eigenschaft legt fest, ob das Steuerelement oder Formular im 3D-Stil von Win-
dows 9x ausgegeben wird oder im flachen 2D-Stil von Windows 3.x. Die Eigenschaft wirkt sich
nur auf das Objekt selbst und nicht auf untergeordnete Objekte aus – sie ist also für diese
getrennt zu setzen.

Konstante (Wert) Definiert für ... Wirkung


0 Die meisten Komponenten 3D-Darstellung
1 Die meisten Komponenten 2D-Darstellung
fsb3D (0) FlatScrollBar 3D-Darstellung wie Windows-Bildlauf-
leiste
fsbFlat (1) FlatScrollBar Flache 2D-Darstellung (Voreinstellung)
fsbTrack3D (2) FlatScrollBar Bildlaufleiste ist 2D, Bildlaufmarke und
Bildlaufpfeile werden 3D, wenn der Maus-
zeiger darüber steht
cc3D (0) Toolbar, ListView, Tree- 3D-Darstellung
View
ccFlat (1) Toolbar, ListView, Tree- 2D-Darstellung
View

328
AutoSize- Eigenschaft

Hinweis

Hinweis
...................................................
Entgegen anders lautenden Informationen in der Online-Hilfe zu Visual Basic lässt sich diese
Eigenschaft zur Laufzeit ändern. Auch wirkt sich der Wert 3 für die Eigenschaft BorderStyle
nicht auf die Darstellung eines Formulars aus.

AutoSize- Eigenschaft
Objekt.AutoSize As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................

Gemeinsame Eigenschaften
Label, PictureBox
Beschreibung

Bes c hreibung
...................................................
Die AutoSize-Eigenschaft bestimmt, ob ein Steuerelement seinen Bereich automatisch an die für
die vollständige Darstellung seines Standardwerts benötigten Abmessungen anpasst (True) oder
nicht (False; Voreinstellung).
Anwendung

Anwendung
...................................................
Trotz der augenscheinlichen Vorzüge, die der hinter der AutoSize-Eigenschaft steckende Auto-
matismus verspricht, sollte sein Einsatz gut überlegt werden – insbesondere bei Bezeichnungs-
feldern, die mit einem Feld in einer Datenbank oder mit einer DDE-Quelle verbunden sind und
ihren Wert somit automatisch ändern können. (Wie das Beispiel zeigt, ist der Automatismus in
Visual Basic 6.0 zudem nicht sauber implementiert). Wenn ein Steuerelement seine Größe auto-
matisch anpasst, kann es nämlich dazu kommen, dass es nicht mehr auf das Formular passt und
abgeschnitten wird, oder schlimmer noch, sich mit anderen Steuerelementen überlappt, diese
verdeckt oder selbst verdeckt wird. Beim Bildfeld-Steuerelement lässt sich das Ergebnis der
automatischen Bereichsanpassung immerhin durch Behandlung des Resize-Ereignisses noch
kontrollieren und gegebenenfalls nachbessern, beim Bezeichnungsfeld-Steuerelement sind
»Hopfen und Malz verloren«.
Beispiel

Beis piel
...................................................
Das Beispielprojekt FadeOut demonstriert die Tücken der AutoSize-Eigenschaft. Ein Timer ani-
miert ein Bezeichnungsfeld mit automatischer Größenanpassung auf einem Formular mit einem
Fade-out-Effekt. Damit die Bereichsgrenzen gut zu sehen sind, ist der Hintergrund des Bezeich-
nungsfelds weiß. Wenn Sie das Programm starten, werden Sie feststellen, dass die Bereichsan-
passung durch die AutoSize-Eigenschaft nur unvollständig funktioniert und der Bereich immer
breiter wird. Einen Work-around für das Problem bieten die beiden auskommentierten Zeilen.
Dim Texte()
Dim i
Private Sub Form_Load()
Texte = Array("Rauchen", "schadet", "Ihrer", "Gesundheit")
Label1 = Texte(0)
Label1.AutoSize = True
Label1.BackColor = vbWhite ' Hintergrund Weiß
Label1.FontName = "Arial" ' TrueType, wegen Size-Änderung
Timer1.Interval = 40
End Sub

3 29
Gemeinsame Eigenschaften

Private Sub Timer1_Timer()


Label1.Font.Size = Label1.Font.Size + 1.2
If Label1.FontSize > 60 Then
Label1.FontSize = 8
' Label1.Left = Label1.Left + Label1.Width / 2
' Label1.Width = 1
i = (i + 1) Mod (UBound(Texte) + 1)
Label1 = Texte(i)
End If
End Sub
Gemeinsame Eigenschaften

BackColor- Eigenschaft und ForeColor- Eigenschaft


Objekt.BackColor As Long
Objekt.ForeColor As Long
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, AmbientProperties, Animation, Band, CheckBox, ComboBox, CommandButton, CoolBar,
Data, DataCombo, DataList, DirListBox, DriveListBox, FileListBox, Form, Frame, Image,
ImageCombo, ImageList, Label, ListBox, MDIForm, OLE, OptionButton, RptFunction, RptI-
mage, RptLabel, RptText, RptShape, PictureBox, Printer, PropertyPage, RemoteData, Rich-
TextBox, Shape, SSTab, TextBox, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften BackColor und ForeColor sind Farbwerte vom Typ Long, die die Hintergrund-
farbe bzw. die Vordergrundfarbe (oder Stiftfarbe) für ein Objekt festlegen. Die Voreinstellun-
gen dieser Eigenschaften sind je nach Komponententyp verschieden, entsprechen aber den stan-
dardmäßig dafür in der Systemsteuerung festgelegten Systemfarben. Zur Auswahl stehen neben
den Systemfarben auch beliebige andere Farben, die sich entweder zur Entwurfszeit aus der
Palette wählen oder zur Laufzeit über die Funktion RGB komponentenweise zu einem Farbwert
komponieren lassen. Die Funktion QBColor liefert den Farbwert einer der 16 Grundfarben.
Zudem definiert der Aufzählungstyp SystemColorConstants die folgenden Konstanten für die
Systemfarben:

Konstante Wert Systemfarbe für ...


vbScrollBars 0x80000000 Farbe der Bildlaufleiste
vbDesktop 0x80000001 Farbe des Desktop
vbActiveTitleBar 0x80000002 Farbe der Titelleiste des aktiven Fensters
vbInactiveTitleBar 0x80000003 Farbe der Titelleiste des inaktiven Fensters
vbMenuBar 0x80000004 Hintergrundfarbe für Menüs
vbWindowBackground 0x80000005 Hintergrundfarbe für Fenster
vbWindowFrame 0x80000006 Rahmenfarbe für Fenster
vbMenuText 0x80000007 Farbe für Menütext
vbWindowText 0x80000008 Textfarbe in Fenstern
vbTitleBarText 0x80000009 Farbe für Titeltext

330
BackStyle- Eigenschaft

Konstante Wert Systemfarbe für ...


vbActiveBorder 0x8000000A Rahmenfarbe für aktives Fenster
vbInactiveBorder 0x8000000B Rahmenfarbe für inaktives Fenster
vbApplicationWorkspace 0x8000000C Hintergrundfarbe von MDI-Anwendungen
vbHighlight 0x8000000D Hintergrundfarbe für ausgewählte Elemente oder
Bereiche des Steuerelements
vbHighlightText 0x8000000E Textfarbe für ausgewählte Elemente oder Berei-
che des Steuerelements

Gemeinsame Eigenschaften
vbButtonFace 0x8000000F Farbe für Oberfläche von Schaltflächen
vbButtonShadow 0x80000010 Farbe für Schattierung von Schaltflächen
vbGrayText 0x80000011 Textfarbe für deaktiviertes Steuerelement
vbButtonText 0x80000012 Farbe für Schaltflächenbeschriftung
vbInactiveCaptionText 0x80000013 Titeltextfarbe für inaktives Fenster
vb3DHighlight 0x80000014 Farbe für markierten Zustand von 3D-Elementen
vb3DDKShadow 0x80000015 Farbe für dunkelsten Schatten von 3D-Elementen
vb3DLight 0x80000016 Farbe für helle Bereiche in 3D-Elementen
vbInfoText 0x80000017 Textfarbe für QuickInfo
vbInfoBackground 0x80000018 Hintergrundfarbe für QuickInfo

Anwendung

Anwendung
...................................................
Der Wertebereich für RGB-Farben liegt zwischen 0 und 16.777.215 (&H00FFFFFF), so dass
das höchstwertige Byte des Long-Werts immer gleich 0 ist. Die drei niederwertigen Bytes bestim-
men (in aufsteigender Reihenfolge) jeweils den Rot-, Grün- und Blauanteil, dargestellt durch
einen Wert zwischen 0 und 255 (&HFF). Ist das höchstwertige Byte 128 (&H80), drückt das
niederwertige Byte eine der 25 reservierten Systemfarben aus (vgl. Tabelle).
Beispiel

Beis piel
...................................................
Form1.BackColor = RGB(124, 12, 120) ' Lila Hintergrund
Form1.ForeColor = RGB(255, 255, 255) ' Weiße Textfarbe

BackStyle- Eigenschaft
Objekt.Alignment As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, Label, RptFunction, RptImage, RptLabel, RptText, RptShape, OLE, Shape, User-
Control
Beschreibung

Bes c hreibung
...................................................
Die BackStyle-Eigenschaft bestimmt, ob ein Steuerelement mit durchsichtigem Hintergrund
angezeigt wird oder nicht.

331
Gemeinsame Eigenschaften

Konstante (Wert) Definiert für ... Wirkung


0 Label, OLE, Shape, UserControl transparenter Hintergrund
1 Label, OLE, Shape, UserControl Hintergrund in Hinter-
grundfarbe
cc2BackStyle- Animation transparenter Hintergrund
Transparent (0)
cc2BackStyle- Animation Hintergrund in Hinter-
Transparent (1) grundfarbe
Gemeinsame Eigenschaften

rptBkOpaque (0) RptFunction, RptImage, RptLabel, transparenter Hintergrund


RptText, RptShape
rptBkTransparent (1) RptFunction, RptImage, RptLabel, Hintergrund in Hinter-
RptText, RptShape grundfarbe

Hinweis

Hinweis
...................................................
Diese Eigenschaft muss auf den Wert 0 gesetzt sein, damit die Eigenschaft MaskColor ihre Wir-
kung entfalten kann.
Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

BorderStyle- Eigenschaft
Objekt.BorderStyle As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, Frame, Image, Label, Line, ListView, MonthView, MSChart, OLE, ProgessBar, Rpt-
Function, RptImage, RptLabel, RptLine, RptShape, PictureBox, ProgressBar, Shape, Slider,
TextBox, ToolBar, TreeView, UserControl
Beschreibung

Bes c hreibung
...................................................
Für ein Steuerelement bestimmt die BorderStyle-Eigenschaft, mit welchem Linientyp es selbst
oder seine Umrandung gezeichnet wird, und für ein Formular, welchen Fenstertyp dieses erhält.

Konstante (Wert) Definiert für ... Wirkung


vbBSNone (0) Frame, Form, Image, «Keine« – Darstellung ohne Randlinie oder
Label, OLE, Text, Umrandung; bei Formularen fehlt zudem
UserControl eine Titelleiste
vbFixedSingle (1) Frame, Form, Image, «Fest Einfach« – Steuerelemente erhalten
Label, OLE, Text, eine Umrandung; für UserControl-Steuerele-
UserControl mente ist dieser Wert nur definiert, wenn
die Windowless-Eigenschaft auf False
gesetzt ist; bei Formular kann der Benutzer
die Größe nur mittels der Schaltflächen
MINIMIEREN, MAXIMIEREN und WIE-
DERHERSTELLEN ändern

332
BorderStyle- Eigenschaft

Konstante (Wert) Definiert für ... Wirkung


vbSizable (2) Form «Änderbar« (Voreinstellung) – der Benutzer
kann die Größe ändern
vbFixedDouble (3) Form «Fester Dialog« – Formular kann System-
menü, nicht jedoch die Schaltflächen MINI-
MIEREN, MAXIMIEREN und
WIEDERHERSTELLEN enthalten. Die
Größe ist nicht änderbar.
vbFixedToolWindow (4) Form «Festes Werkzeugfenster« – Fenster mit

Gemeinsame Eigenschaften
schmaler Titelleiste, ohne Systemmenü
jedoch mit Schaltfläche SCHLIEßEN. Das
Formular wird nicht in der Taskleiste von
Windows 95 angezeigt und seine Größe ist
nicht änderbar.
vbSizableToolWindow (5) Form «Änderbares Werkzeugfenster« – größen-
veränderliches Fenster mit schmaler Titel-
leiste, ohne Systemmenü, jedoch mit der
Schaltfläche SCHLIEßEN. Das Formular
wird nicht in der Taskleiste von Windows
9x angezeigt.
vbTransparent (0) Line, Shape «Transparent« – keine Linie
vbBSSolid (1) Line, Shape «Ausgefüllt« – durchgezogene Linie
vbBSDash (2) Line, Shape «Strich« – gestrichelte Linie
vbBSDot (3) Line, Shape «Punkt« – gepunktete Linie
vbBSDashDot (4) Line, Shape «Strich-Punkt»
vbBSDashDotDot (5) Line, Shape «Strich-Punkt-Punkt»
vbBSInsideSolid (6) Line, Shape «Innen ausgefüllt« – Randlinie innerhalb
der Bereichsgrenzen
rptBSTransparent (0) RptLine, RptShape Keine Linie
rptBSSolid (1) RptLine, RptShape Durchgezogene Linie
rptBSDashes (2) RptLine, RptShape Gestrichelte Linie
rptBSDots (3) RptLine, RptShape Gepunktete Linie
rptBSDashDot (4) RptLine, RptShape Strich-Punkt-Linie
rptBSDashDotDot (5) RptLine, RptShape Strich-Punkt-Punkt-Linie
cc2None (0) MonthView, ListView, Randlos
ProgressBar, Slider,
ToolBar, TreeView
cc2FixedSingle (1) MonthView, ListView, Umrandet
ProgressBar, Slider,
ToolBar, TreeView
vtStyleNone (0) MSChart Randlos
vbStyleFixedSingle (1) MSChart Umrandet

333
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Für ein Formular legt die BorderStyle-Eigenschaft einen Teil der Ausstattung des Fensters fest.
Der Wert 0 steht für ein rahmenloses Fenster ohne Titelleiste, wie es beispielsweise für eine
Vollbildansicht benötigt wird. Die Werte 1 und 2 stehen für ein Mehrzweckfenster wahlweise
mit Systemmenü (ControlBox) und den Schaltflächen MAXIMIEREN MINIMIEREN und WIEDER-
HERSTELLEN (MaxButton, MinButton). Der Wert 3 (Fester Dialog) steht für das klassische Dialog-
feld, dessen Größe der Benutzer nicht ändern kann. Die Einstellungen 4 (Festes Werkzeugfens-
ter) und 5 (Änderbares Werkzeugfenster) erzeugen Fenster mit der Schaltfläche SCHLIEßEN und
ohne Systemmenü, wie sie gewöhnlich für Werkzeugsammlungen verwendet werden.
Einem MDI-Formular untergeordnete Formulare (MDIChild-Eigenschaft hat den Wert True) mit
Gemeinsame Eigenschaften

der Einstellung 2 (Änderbar) erscheinen innerhalb des MDI-Formulars in einer voreingestellten


Größe, die durch Windows zur Laufzeit festgelegt wird. Bei allen anderen Einstellungen
erscheint das Formular in der zur Entwurfszeit angegebenen Größe.
Hinweise

Hinweis e
...................................................
Entgegen anders lautender Informationen in der Online-Hilfe zu Visual Basic ist diese Eigen-
schaft auch für Textfelder und Formulare zur Laufzeit nicht schreibgeschützt. Eine Änderung
der Eigenschaft zur Laufzeit zeigt für Formulare jedoch keine Wirkung.
Wenn Sie diese Eigenschaft für ein Formular auf eine der Einstellungen 0, 1, 3, 4, 5 setzen,
ändert die Entwicklungsumgebung von Visual Basic zugleich die Eigenschaften MinButton, Max-
Button und ShowInTaskbar ungefragt auf False. Allerdings spielen diese Eigenschaften ohnehin
nur für die Einstellungen 1 und 2 eine Rolle.
Verwandte Themen

Verwandte Them en
...................................................
Vollbildanzeige (S. 536)

Caption- Eigenschaft
Objekt.Caption As String
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, CheckBox, CommandButton, Data, Form, Frame, Label, MDIForm, Menu, OptionButton,
PropertyPage, RemoteData, RptLabel, UserControl
Beschreibung

Bes c hreibung
...................................................
Für ein Formularobjekt bestimmt die Caption-Eigenschaft den Fenstertitel und für ein Steuerele-
ment Objekt dessen Beschriftung. Der Wert der Eigenschaft kann zur Laufzeit jederzeit geändert
werden.
Anwendung

Anwendung
...................................................
Die Entwicklungsumgebung setzt als Voreinstellung für die Caption-Eigenschaft immer den
automatisch vergebenen Bezeichner des Steuerelements bzw. Formulars.
Der Fenstertitel eines Formulars erscheint auch in der Taskleiste sowie im Task-Manager,
sofern die Eigenschaft ShowInTaskBar auf True gesetzt ist.
Beispiel

Beis piel
...................................................
Caption = App.Title & " – " & sDateiname

334
Container- Eigenschaft

Container- Eigenschaft
Objekt.Container As FormularTyp
Objekt.Container As PictureBox
Objekt.Container As Frame
Objekt.Container As SSTab
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Steuerelemente
Beschreibung

Bes c hreibung
...................................................

Gemeinsame Eigenschaften
Die Eigenschaft Container ist eine reine Laufzeiteigenschaft. Ihr Wert verweist auf das Objekt,
das als Container für das Steuerelement fungiert. Als Container kann ein Formularobjekt oder
ein anderes Steuerelement des Typs PictureBox, Frame oder SSTab fungieren.
Hinweis

Hinweis
...................................................
Der Container eines Steuerelements lässt sich zur Laufzeit zwar ändern, jedoch immer nur
innerhalb des gleichen Formulars. Beachten Sie, dass sich die Position eines Steuerelements
immer auf das Koordinatensystem des Containers bezieht. Dies kann sich mit dem Container
ändern. Bei Änderung des Containers rechnet Visual Basic die Positionskoordinaten und
Abmessungen allerdings automatisch um.
Beispiel

Beis piel
...................................................
Set Text1.Container = Form1
Form1.ScaleMode = vbInches ' Koordinatensystem mit Einheit Zoll
Text1.Left = 1
Text1.Top = 1
Set Text3.Container = Picture1 ' Anderen Container setzen
Print Text1.Left ' Ausgabe: 1440
Print Text1.Top ' Ausgabe: 1440

CausesValidation- Eigenschaft
Objekt.CausesValidation As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CommandButton, CheckBox, ComboBox, DataCombo, DataList, DataRepeater,
DirListBox, DriveListBox, FileListBox, ListBox, ListView, MonthView, MSChart, OLE, Opti-
onBox, PictureBox, RichTextBox, Slider, TextBox, TreeView, UpDown, VBControlExtender
Beschreibung

Bes c hreibung
...................................................
Die CausesValidation-Eigenschaft eröffnet einem Steuerelement die Möglichkeit, seinen Wert
durch Behandlung des Validate-Ereignisses einer Gültigkeitsprüfung zu unterziehen, unmittel-
bar bevor es den Fokus abgibt. Damit das Steuerelement allerdings das Validate-Ereignis zu
sehen bekommt, muss nicht nur seine CausesValidation-Eigenschaft auf True gesetzt sein, son-
dern auch die des Steuerelements, auf das der Fokus übergehen soll. Verliert ein Steuerelement
mit gesetzter CausesValidation-Eigenschaft den Fokus an ein Steuerelement, dessen CausesVali-
dation-Eigenschaft auf False gesetzt ist, tritt das Validate-Ereignis nicht sofort auf, sondern
erst, wenn der Fokus wieder in Besitz eines Steuerelements mit gesetzter CausesValidation-

335
Gemeinsame Eigenschaften

Eigenschaft gehen soll. Setzt ein Steuerelement bei der Behandlung des Validate-Ereignisses den
Cancel-Parameter auf True, behält es den Fokus bzw. erhält es diesen zurück.
Anwendung

Anwendung
...................................................
Die CausesValidation-Eigenschaft eines Steuerelements muss immer im Zusammenhang mit
den CausesValidation-Eigenschaften der anderen Steuerelemente auf einem Formular gesehen
werden. Der etwas kompliziert anmutende Mechanismus hat aber seine Vorteile: Der Benutzer
kann während der Eingabe eines Werts in ein Steuerelement mit Gültigkeitsprüfung auf andere
Steuerelemente zugreifen, solange für diese die CausesValidation-Eigenschaft nicht gesetzt ist,
und beispielsweise Hilfe anfordern, seine Eingabe verwerfen oder den Dialog ganz abbrechen.
Gemeinsame Eigenschaften

DataChanged- Eigenschaft
Objekt.Changed As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, Column, ComboBox, DataCombo, DataGrid, DataList, DTPicker, Image, Label, List-
Box, MaskEdBox, MonthView, OLE, PictureBox, RepeaterBinding, RichTextBox, TextBox,
Beschreibung

Bes c hreibung
...................................................
Die DataChanged-Eigenschaft eines Steuerelements drückt aus, ob sich der Wert der Standardei-
genschaft inzwischen (lies: seit DataChanged zuletzt auf False gesetzt wurde) geändert hat (True)
oder nicht (False). Eine besondere Rolle spielt die DataChanged-Eigenschaft, wenn das Steuerele-
ment an eine Datenquelle gebunden ist und von dieser Daten bezieht. Jede Synchronisation des
Steuerelements mit dem aktuellen Datensatz eines Recordsets setzt den Wert dieser Eigenschaft
auf False, Änderungen der Standardeigenschaft durch den Benutzer oder durch Programmcode
setzen ihn dagegen auf True. Im letzteren Fall kann eine automatische Wertübernahme beim
nächsten Datensatzwechsel erfolgen.
Anwendung

Anwendung
...................................................
Ein Programm kann die DataChanged-Eigenschaft im Rahmen der Validate-Behandlung eines
Steuerelements als Kriterium für die Gültigkeitsprüfung auswerten und gegebenenfalls auch auf
False setzen, um Aktualisierungen des aktuellen Datensatzes mit dem Wert der Standardeigen-
schaft zu unterbinden. Nur wenn DataChanged auf True gesetzt ist und über die Edit-Methode
des Recordset-Objekts der Bearbeitungsmodus eingeschaltet wurde, wird der Wert der Stan-
dardeigenschaft beim nächsten Datensatzwechsel oder beim expliziten Aufruf der Update-
Methode in den Datensatz zurückgeschrieben.

DataField- Eigenschaft
Objekt.DataField As String
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, Column, ComboBox, DataCombo, DTPicker, Image, ImageCombo, Label, ListBox,
MonthView, OLE, PictureBox, RepeaterBinding, RptFunction, RptTextBox, RichTextBox,
TextBox,

336
DataField- Eigenschaft

Beschreibung

Bes c hreibung
...................................................
Die DataField-Eigenschaft enthält den Feldnamen eines Datenfelds einer Tabelle oder eines
Recordsets, wenn das Steuerelement Objekt als Datennutzer an eine Datenquelle (DataSource)
bzw. ein Datenelement (DataMember) einer Datenquelle gebunden ist.
Anwendung

Anwendung
...................................................
Das standardmäßige Szenario für den Zugriff auf eine Datenquelle (lies: Datenbank) von Visual
Basic sieht so aus, dass ein Formular oder eine Komponente mit Steuerelementen bestückt ist,
deren Werte über die DataField-Eigenschaft an die Feldwerte eines einzelnen Datensatzes oder

Gemeinsame Eigenschaften
einer Folge von Datensätzen gebunden sind. Die Datensätze entstammen wiederum einer
Tabelle oder einem beliebigen Recordset (lies: Ergebnis einer Abfrage), das ein Datensteuerele-
ment unter Verwendung eines Daten-Providers (lies: einer geeigneten Schnittstelle) bei einem
Datenbanksystem anfordert. Als Datenquellen kommen Objekte wie Data, RemoteData, Adodc
oder DataEnvironment in Frage. Datenquellen, die durch die ersten beiden Steuerelementtypen
repräsentiert werden, müssen bereits zur Entwurfszeit an den Datennutzer gebunden werden,
die anderen beiden Objekttypen lassen sich auch zur Laufzeit binden. Die DataField-Eigen-
schaft kann jedoch ohne Einschränkungen zur Laufzeit gesetzt werden, gleich an welche Art
von Datenquelle ein Steuerelement gebunden ist. Falls das Steuerelement bereits an ein Feld
gebunden ist, sollte die Eigenschaft DataField vor einem Wechsel der Datenquelle oder des
Recordsets in der Datenquelle auf die leere Zeichenfolge gesetzt werden.
Tipp

Tipp
...................................................
Um einem Steuerelement ein in einer Abfrage berechnetes Feld zuzuordnen, muss die Abfrage
einen Alias (alternativen Bezeichner) für dieses Feld vereinbaren.
Beispiel

Beis piel
...................................................
Der folgende Code arbeitet mit einem Textfeld Text1, das zur Entwurfszeit an ein Data-Steuer-
element Data1 als Datenquelle gebunden wurde. Ein Klick auf die Schaltfläche FrachtkostenAn-
zeigen ändert das Recordset der Datenquelle sowie die Datenfeldbindung des Textfeldes.
Const Abfrage1 = "SELECT AVG(Frachtkosten) AS Fracht FROM Bestellungen"
Private Sub FrachtkostenAnzeigen_Click()
Text1.DataField = "" ' weil RecordSource geändert wird
Data1.RecordSource = Abfrage1
Data1.Refresh ' weil RecordSource geändert wurde
Text1.DataField = "Fracht" ' berechnetes Feld
End Sub

ADO-Steuerelemente lassen sich auch zur Laufzeit als Datenquelle setzen. In diesem Fall könnte
die Behandlungsroutine so aussehen:
Private Sub FrachtkostenAnzeigen_Click()
Text1.DataField = "" ' alte Bindung ggf. aufheben
Adodc1.RecordSource = Abfrage1 ' Refresh nicht nötig
Set Text1.DataSource = Adodc1
Text1.DataField = "Fracht" ' berechnetes Feld
End Sub
Da der gemeinsame Einsatz von Data- und Adodc-Steuerelementen im Zusammenhang mit der
Jet-Engine Probleme bereiten kann, ist es besser, sich für die eine oder die andere Gattung zu
entscheiden.

337
Gemeinsame Eigenschaften

Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DataMember, DataFormat, DataSource
Verwandte Themen

Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)

DataFormat- Eigenschaft
Objekt.DataFormat As IStdDataFormatDisp
Gemeinsame Eigenschaften

Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, Column, ComboBox, DataCombo, DataList, DataRepeater, DBList, DBCombo, DTPik-
ker, Image, ImageCombo, Label, ListBox, MonthView, OLE, PictureBox, RepeaterBinding,
RptFunction, RptTextBox, TextBox,
Beschreibung

Bes c hreibung
...................................................
Die DataFormat-Eigenschaft ordnet einem Steuerelement Objekt, das an eine Datenquelle gebun-
den ist, ein Datenformat in Form eines Datenformatobjekts zu. Das wie ein bilateraler Filter
arbeitende Datenformatobjekt stellt die von der Datenquelle gelieferten Daten in dem gewähl-
ten Format dar und übersetzt in diesem Format gehaltene Eingaben auch wieder zurück in die
von der Datenquelle benutzte interne Darstellung.
Anwendung

Anwendung
...................................................
Visual Basic ordnet jedem Steuerelement, das an eine Datenquelle gebunden ist, ein standard-
mäßiges Datenformatobjekt des Typs StdDataFormat zu. Diese Zuordnung ist integraler
Bestandteil der Bindung und sorgt im Allgemeinen automatisch für eine geeignete Anpassung
zwischen dem von der Datenquelle gelieferten und dem von dem Steuerelement erwarteten
Wert. Wenn gefordert ist, dass ein Steuerelement seinen Wert in einem bestimmten Darstel-
lungsformat anzeigt, etwa in einem Währungsformat oder einem bestimmten Datums-/Zeit-
Format, kann dieses zur Entwurfszeit in der Eigenschaftsseite des DataFormat-Objekts ausge-
wählt werden. Der Aufruf der Eigenschaftsseite kann über das Eigenschaftsfenster erfolgen.
Darüber hinaus hat das Datenformatobjekt eine Reihe von Eigenschaften, die sich zur Laufzeit
setzen bzw. abfragen lassen. Die wichtigste davon ist die Format-Eigenschaft vom Typ String,
die eine Zeichenfolge mit der Formatbeschreibung enthält.
Beispiel

Beis piel
...................................................
' Liefert Ausgaben der Art "18:02:04 Uhr, am 5. März 1992"
Text1.DataFormat.Format = "h:mm:ss U\hr, a\m d.mmmm yyyy"
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DataField, DataMember, DataSource
Verwandte Themen

Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)

338
DataMember- Eigenschaft

DataMember- Eigenschaft
Objekt.DataMember As String
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, Column, ComboBox, DataCombo, DataGrid, DataList, DataRepeater, DBList,
DBCombo, DTPicker, Image, ImageCombo, Label, ListBox, MonthView, OLE, PictureBox, Repea-
terBinding, RptFunction, RptTextBox, RichTextBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Die DataMember-Eigenschaft eines gebundenen Steuerelements spezifiziert, welches Datenele-

Gemeinsame Eigenschaften
ment der Datenquelle die Datensätze bereitstellt. Datenelemente sind vom Prinzip her benannte
Recordsets, die in dem als Datenquelle fungierenden Objekt bereits vordefiniert sind und sich
über die DataMember-Eigenschaft auswählen lassen. Hat die DataMember-Eigenschaft die leere
Zeichenfolge als Wert, fungiert das standardmäßige Recordset der Datenquelle als Datenele-
ment.
Anwendung

Anwendung
...................................................
Die DataMember-Eigenschaft spielt für die fortgeschrittene Programmierung mit ADO-Datenob-
jekten (ActiveX Data Objects) ein gewisse Rolle, wenn als Datenquelle eine DataEnvironment-
Komponente (oder eine vergleichbare Komponente) benutzt wird. Einer DataEnvironment-Kom-
ponente lassen sich Befehle (Command-Objekte) und gespeicherte Prozeduren (PreparedCommand-
Objekte) für die Auswahl spezieller Recordsets zuordnen, die sich dann über die DataMember-
Eigenschaft abstrakt auswählen lassen.
Beispiel

Beis piel
...................................................
Text1_DataMember = "Command2"
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DataField, DataFormat, DataSource
Verwandte Themen

Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)

DataSource- Eigenschaft
Objekt_DataSource = DatenquelleObjekt
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, Column, ComboBox, DataCombo, DataGrid, DataList, DataRepeater, DBList,
DBCombo, DTPicker, Image, ImageCombo, Label, ListBox, MaskEdBox, MonthView, OLE, Pictu-
reBox, RepeaterBinding, RptFunction, RptTextBox, RichTextBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Die DataSource-Eigenschaft bindet ein Steuerelement an eine sog. Datenquelle. Bei einer Daten-
quelle handelt es sich um ein Objekt, das eine Datenbankverbindung herstellen und die Reprä-
sentation von Datensatzmengen (Recordset) übernehmen kann. Ist ein Steuerelement an eine
Datenquelle gebunden, zeigt es zum einen den von dieser Datenquelle gelieferten Wert an, kann
zum anderen aber auch Änderungen des Werts zurück an die Datenquelle liefern (sofern das
verwendete Recordset-Objekt dies zulässt; vgl. »Data-Datensteuerelement (Data)«; S. 402).

339
Gemeinsame Eigenschaften

An vordefinierten Datenquellen stehen in die beiden älteren Steuerelemente Data, RemoteData


sowie das neuere ActiveX-Steuerelement Adodc und DataEnvironment-Komponenten zur Verfü-
gung. Datenquellen, die durch die ersten beiden Steuerelementtypen repräsentiert werden, müs-
sen bereits zur Entwurfszeit an den Datennutzer gebunden werden, die anderen beiden Objekt-
typen lassen sich auch zur Laufzeit binden.
Anwendung

Anwendung
...................................................
Die Datenbankanbindung über ein Datensteuerelement kommt der Philosophie von Visual
Basic am weitesten entgegen. Da die gesamte Logik für die Errichtung und Pflege der Daten-
bankverbindung in dem Datensteuerelement verkapselt ist, muss der Programmierer beim Ent-
Gemeinsame Eigenschaften

wurf eines datenbankbasierten Formulars (bzw. Komponente) nichts weiter machen, als ein
Datensteuerelement in den Entwurfsbereich zu ziehen, dieses (zur Entwurfszeit oder zur Lauf-
zeit) geeignet zu initialisieren und es den Steuerelementen, die für die Anzeige der Informa-
tionen aus der Datenbank gedacht sind, über die Eigenschaft DataSource als Datenquelle
bekanntzugeben. Den Rest macht das Datensteuerelement: Es baut die Verbindung mit der
Datenbank auf, wählt eine Datensatzmenge aus, pflegt einen über die Pfeilschaltflächen des
Datensteuerelements gesteuerten Datensatzzeiger und synchronisiert die angebundenen Steuer-
elemente mit dem jeweils aktuellen Datensatz.
Jedes der drei in Visual Basic verfügbaren Datensteuerelemente geht mit einem Datenzugriffs-
modell einher. Die beiden älteren Datensteuerelemente Data und RemoteData sind speziell auf
DAO (Data Access Objects = Datenzugriffsobjekte für den Datenzugriff über die Microsoft Jet
Engine) bzw. auf RDO (Remote Data Objects = Remote-Datenzugriffsobjekte für den Datenzu-
griff über ODBC) ausgelegt. Sie werden inzwischen nur noch der Kompatibilität halber unter-
stützt, da seit Einführung der ActiveX-Datenzugriffsobjekte (ADO = ActiveX Data Objects) mit
Visual Basic 6.0 ein vollständig COM-orientiertes Datenzugriffsmodell existiert.
Für einfache Datenbankanwendungen tut es jedes der drei genannten Datensteuerelemente. Bei
komplexeren Anforderungen an die möglichen Formen des Datenzugriffs sowie an Datenbank-
interaktionen generell empfiehlt sich die Verwendung von Datenumgebungskomponenten
(DataEnvironment), die eine Verkapselung maßgeschneiderter Modelle für die fortgeschrittene
Datenbankinteraktion ermöglichen.
Beispiel

Beis piel
...................................................
Const Abfrage1 = "SELECT AVG(Frachtkosten) AS Fracht FROM Bestellungen"
Private Sub FrachtkostenAnzeigen_Click()
Text1.DataField = "" ' alte Bindung ggf. aufheben
Adodc1.RecordSource = Abfrage1 ' Refresh nicht nötig
Set Text1.DataSource = Adodc1
Text1.DataField = "Fracht" ' berechnetes Feld
End Sub
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DataField, DataFormat, DataMember
Verwandte Themen

Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)

340
DisabledPicture- Eigenschaft

DisabledPicture- Eigenschaft
Objekt.DisabledPicture As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, CommandButton, OptionButton
Beschreibung

Bes c hreibung
...................................................
Die DisabledPicture-Eigenschaft ermöglicht es, eine Bitmap anzugeben, die den inaktiven
Zustand des Steuerelements in der benutzerdefinierten Darstellung zum Ausdruck bringt.
Anwendung

Anwendung

Gemeinsame Eigenschaften
...................................................
Schaltflächen, Optionsfelder und Kontrollkästchen unterstützen anstelle der standardmäßigen
Darstellung auch die Möglichkeit, ihre drei Zustände in Form von benutzerdefinierten Bitmaps
anzuzeigen. Zur Festlegung der Bitmaps sind die Eigenschaften Picture, DownPicture und
DisabledPicture zuständig. Damit ein Steuerelement die Werte dieser Eigenschaften überhaupt
beachtet, muss die zur Laufzeit schreibgeschützte Style-Eigenschaft bereits beim Formularent-
wurf auf vbButtonGraphical (1) gesetzt werden.
Die DisabledPicture-Bitmap kommt immer dann zur Anzeige, wenn das Steuerelement sichtbar
und die Enabled-Eigenschaft auf False gesetzt ist.
Beispiel

Beis piel
...................................................
Der folgende Code entstammt einem Formular, auf dem zwei Schaltflächen Command1 und
Command2 sowie ein Bildausschnitt-Steuerelement PictureClip1 platziert wurden. Er demonst-
riert die benutzerdefinierte Darstellung für Command2. Das Bildausschnitt-Steuerelement liefert
die drei Bitmaps, die für die Unterscheidung der Anzeigezustände notwendig sind. Die Schalt-
fläche Command1 ist dafür da, Command2 abwechselnd zu aktivieren und zu deaktivieren (dritter
Zustand):
Private Sub Command1_Click()
Command2.Enabled = Not Command2.Enabled ' Aktivieren/Deaktivieren
End Sub

Private Sub Form_Load()


Command2.Picture = PictureClip1.GraphicCell(0)
Command2.DownPicture = PictureClip1.GraphicCell(1)
Command2.DisabledPicture = PictureClip1.GraphicCell(2)
End Sub
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DownPicture, Picture

DownPicture- Eigenschaft
Objekt.DownPicture As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, CommandButton, OptionButton
Beschreibung

Bes c hreibung
...................................................
Die DownPicture-Eigenschaft ermöglicht es, eine Bitmap anzugeben, die den gedrückten
Zustand des Steuerelements in der benutzerdefinierten Darstellung zum Ausdruck bringt.

3 41
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Schaltflächen, Optionsfelder und Kontrollkästchen unterstützen anstelle der standardmäßigen
Darstellung auch die Möglichkeit, ihre drei Zustände in Form von benutzerdefinierten Bitmaps
anzuzeigen. Zur Festlegung der Bitmaps sind die Eigenschaften Picture, DownPicture und
DisabledPicture zuständig. Damit ein Steuerelement die Werte dieser Eigenschaften überhaupt
beachtet, muss die zur Laufzeit schreibgeschützte Style-Eigenschaft bereits beim Formularent-
wurf auf vbButtonGraphical (1) gesetzt werden.
Zur Anzeige der DownPicture-Bitmap kommt es, wenn das Steuerelement sichtbar ist, die Enab-
led-Eigenschaft auf True gesetzt ist und der Benutzer mit der Maus oder der Tastatur das Click-
Ereignis des Steuerelements auslöst.
Gemeinsame Eigenschaften

Beispiel

Beis piel
...................................................
Vgl. das Beispiel in »DisabledPicture-Eigenschaft« (S. 341).
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DisabledPicture, Picture

DragIcon- Eigenschaft
Objekt.DragIcon As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
Die meisten Steuerelementtypen
Beschreibung

Bes c hreibung
...................................................
Die DragIcon-Eigenschaft spezifiziert die Mauszeigerform, die zur Anzeige kommt, wenn das
Steuerelement einer Drag&Drop-Operation unterworfen ist. Hat die Eigenschaft den Wert Not-
hing, bleibt die aktuelle Mauszeigerform unverändert, vielmehr erscheint aber der Umriss des
gezogenen Steuerelements als visuelles Feedback.
Anwendung

Anwendung
...................................................
Als Werte für diese Eigenschaft sind nur Verweise auf Bitmaps geeignet, die in einem der Sym-
bolformate CUR oder ICO vorliegen – insbesondere lassen sich also weder gewöhnliche Bilder
(BMP, JPG, WMF etc.) noch animierte Cursorformen (ANI) als Mauszeigerform setzen.
Beispiel

Beis piel
...................................................
Text1.DragIcon = LoadPicture ("MyDragIcon.Ico")
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
MouseIcon, MousePointer
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501); Transparenz und Drag&Drop (S. 606)

342
DragMode- Eigenschaft

DragMode- Eigenschaft
Objekt.DragMode As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Die meisten vordefinierten Steuerelementtypen
Beschreibung

Bes c hreibung
...................................................
Die DragMode-Eigenschaft legt fest, ob ein Steuerelement Drag&Drop-Operationen automatisch
eingehen kann oder durch Aufruf der Drag-Methode dazu »überredet« werden muss. Die folgende
Tabelle gibt einen Überblick über die möglichen Werte der Eigenschaft und deren Wirkung:

Gemeinsame Eigenschaften
Konstante Beschreibung
vbManual (0) Das Steuerelement geht auf Drag&Drop-Operationen nur ein, wenn es
explizit durch Aufruf der Methode Drag dazu veranlasst wird (Voreinstel-
lung).
vbAutomatic (1) Das Steuerelement interpretiert das Drücken der linken Maustaste als
Beginn einer Drag&Drop-Operation. Zudem kann eine Drag&Drop-Ope-
ration auch explizit durch Aufruf der Methode Drag eingeleitet werden.

Anwendung

Anwendung
...................................................
Drag&Drop-Operationen stellen eine auf die Grenzen eines Programms beschränkte Form der
grafisch orientierten Befehlsübermittlung zwischen Steuerelementen untereinander sowie von
Steuerelement zu Formular dar. Im automatischen Modus beginnt der Benutzer eine
Drag&Drop-Operation, indem er mit der linken Maustaste auf ein Steuerelement (Quellobjekt)
klickt und dieses mit gehaltener Maustaste über ein anderes Steuerelement und/oder Formular
zieht und ablegt (Zielobjekt). Das Loslassen der Maustaste steht für das Ablegen des Steuerele-
ments und löst aufseiten des Zielobjekts das DragDrop-Ereignis aus, dessen Behandlung die mit
der Operation verbundene Wirkung hervorruft. Wie die Wirkung im Einzelnen aussieht, dafür
gibt es keine Vorschriften. Da das Zielobjekt eine echte Referenz auf das Quellobjekt erhält,
kann sie von der einfachen Positionsänderung des gezogenen Steuerelements über die Befehls-
auswahl bis hin zur Vernichtung des Quellobjekts (»in einem Papierkorb verschieben«) reichen.
Beispiel

Beis piel
...................................................
Der folgende Code zeigt die Implementation einer manuellen Drag&Drop-Operation. Der
Benutzer kann eine auf dem Formular befindliche Schaltfläche Command1 mit der rechten Maus-
taste verschieben und mit der linken Maustaste weiterhin wie gewohnt das Click-Ereignis aus-
lösen.
Private StartX As Single
Private StartY As Single
Private Sub Command1_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button = vbRightButton Then
StartX = X
StartY = Y
Command1.Drag vbBeginDrag
End If
End Sub

3 43
Gemeinsame Eigenschaften

Private Sub Form_DragDrop(Source As Control, X As Single, Y As Single)


Source.Left = X – StartX
Source.Top = Y – StartY
End Sub
Private Sub Form_Load()
Command1.DragMode = 0
End Sub
Verwandte Ereignisse

Verwandte Ereignis s e
...................................................
DragDrop-Ereignis, DragOver-Ereignis
Gemeinsame Eigenschaften

Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

DrawMode- Eigenschaft
Objekt.DrawMode As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, Line, PictureBox, Printer, PropertyPage, RptLine, RptShape, Shape, UserControl,
UserDocument
Beschreibung

Bes c hreibung
...................................................
Die DrawMode-Eigenschaft legt die Rasteroperation fest, die das Objekt für das Zeichnen von
Linien und Füllbereichen anwendet. Der Aufzählungstyp DrawModeConstants definiert folgende
Konstanten dafür:

Konstante (Wert) Beschreibung


vbBlackness (1) Schwarzintensität
vbNotMergePen (2) Stift mischen invers (invers zu 15)
vbMaskNotPen (3) inversen Stift maskieren; Kombination der Farben, die der Hinter-
grund mit der invertierten Stiftfarbe gemeinsam hat
vbNotCopyPen (4) Stift kopieren invers (invers zu 13)
vbMaskPenNot (5) Stift und inverse Anzeige maskieren; Kombination der Farben, die der
Stift mit der invertierten Anzeigefarbe gemeinsam hat
vbInvert (6) Anzeigefarbe invers
vbXorPen (7) Stift XOR Anzeigefarbe; Kombination der Farben, die im Stift und in
der Anzeigefarbe, aber nicht in beiden vorhanden sind
vbNotMaskPen (8) Stift maskieren invers (invers zu 9)
vbMaskPen (9) Stift maskieren; Kombination der Farben, die Stift und Anzeigefarbe
gemeinsam haben (invers zu 10)
vbNotMaskPen (10) Stift maskieren invers (invers zu 9)
vbNop (11) Keine Operation; Stift zeichnet nicht
vbMergeNotPen (12) Inversen Stift mischen – Kombination der Anzeigefarbe und der inver-
tierten Stiftfarbe

344
DrawMode- Eigenschaft

Konstante (Wert) Beschreibung


vbCopyPen (13) Stift kopieren (Voreinstellung); Stiftfarbe ist durch Eigenschaft Fore-
Color gegeben (invers zu 4)
vbMergePenNot (14) Stift und inverse Anzeige mischen; Kombination der Stiftfarbe und der
invertierten Anzeigefarbe
vbMergePen (15) Stift mischen; Kombination aus Stift- und Anzeigefarbe (invers zu 2)
vbWhiteNess (16) Stift zeichnet mit leuchtendem Weiß

Gemeinsame Eigenschaften
Anwendung

Anwendung
...................................................
Die DrawMode-Eigenschaft ist etwas für spezielle Effekte. So kann eine einfache Änderung der
DrawMode-Eigenschaft recht beachtliche Veränderungen in der Ausgabe hervorrufen. Der vorein-
gestellte Wert vbCopyPen (13) entspricht dem, was man sich landläufig unter »Zeichnen mit
einem deckenden Stift in einer bestimmten Farbe« vorstellt. Die anderen Rasteroperationen ver-
wenden teilweise eine feste oder invertierte Stiftfarbe und/oder mischen bzw. invertieren die
Stiftfarbe mit der Anzeigefarbe (das ist die bestehende Farbe des Bildpunkts) – das Ergebnis ist
also nicht in jedem Fall vorhersehbar, sondern hängt von den farblichen Gegebenheiten und der
Logik der Rasteroperation ab.
Auf Rang zwei in der Beliebtheitsskala der Rasteroperationen, gleich nach vbCopyPen, rangiert
vbXorPen (7). Diese Rasteroperation ist ihre eigene Umkehroperation, das heißt, in diesem
Modus versetzt ein erneuter Aufruf der genau gleichen Grafikoperation den Ausgabebereich in
den Zustand vor dem ersten Aufruf zurück. Ausgaben lassen sich auf diese Weise zurückneh-
men, ohne darunter gelegene Elemente zu zerstören. Diese Technik wird beispielsweise für die
Programmierung mit »Gummibändern« verwendet (vgl. »Gummiband – Bereiche interaktiv
auswählen«, S. 492).
Beispiel

Beis piel
...................................................
Das Beispielprojekt DrawModeDemo zeigt die Auswirkungen der DrawMode-Eigenschaft auf das
Zeichnen von Linien und Füllbereichen sowie für Überlappungen mit bereits gezeichneten Ele-
menten. Die Paint-Routine des Formulars zeichnet den linken Kreis mit der voreingestellten
Rasteroperation vbCopyPen (13) und den rechten mit dem jeweils aktuellen Rasteroperation, die
sich durch einen Klick auf den Formularbereich weiterschalten lässt.
Dim DrawMode1 As Integer
Private Sub Form_Click()
DrawMode1 = (DrawMode1 Mod 16) + 1 ' Weiterschalten
Refresh
End Sub

Private Sub Form_Load()


Height = Width
FillStyle = 0
DrawWidth = 15
DrawMode1 = 13
DrawMode1 = 1
AutoRedraw = False
End Sub

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


Dim p, r, g, b

3 45
Gemeinsame Eigenschaften

p = Point(X, Y)
r = (p And &HFF)
g = (p \ &H100 And &HFF)
b = p \ &H10000
Caption = "DrawMode: " & DrawMode1 & ", Farbe unter Maus: (" _
& r & "," & g & "," & b & ")"
End Sub

Private Sub Form_Paint()


' Linker Kreis wird mit "normalen" Einstellungen gezeichnet
Gemeinsame Eigenschaften

Form_MouseMove 0, 0, 0, 0
Cls
DrawMode = 13
FillColor = RGB(200, 255, 255)
ForeColor = RGB(255, 0, 255)
Me.Circle (ScaleHeight * 0.52, ScaleHeight * 0.5), Height * 0.4
' Rechter Kreis wird mit verändertem Drawmode gezeichnet
DrawMode = DrawMode1
FillColor = RGB(123, 145, 17)
ForeColor = RGB(145, 17, 123)
Me.Circle (ScaleHeight * 0.72, ScaleHeight * 0.5), Height * 0.4
End Sub

Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
BorderStyle, BorderWidth, DrawStyle, DrawWidth
Verwandte Themen

Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)

DrawStyle- Eigenschaft
Objekt.DrawStyle As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, UserControl, UserDocument

346
Enabled- Eigenschaft

Beschreibung

Bes c hreibung
...................................................
Die DrawStyle-Eigenschaft bestimmt einen von sieben Linienstilen für die Zeichenoperationen
eines Objekts. Falls für eine Grafikoperation eine Linienbreite (DrawWidth) größer als 1 einge-
stellt ist, ignoriert das Objekt allerdings die Werte 1 bis 4 der DrawStyle-Eigenschaft und arbei-
tet statt dessen mit der Voreinstellung 0.
Der Aufzählungstyp DrawStyleConstants definiert eine Reihe von Konstanten für die unter-
schiedlichen Linienstile:

Konstante (Wert) Beschreibung

Gemeinsame Eigenschaften
vbSolid (0) Durchgezogen (Voreinstellung)
vbDash (1) Gestrichelt
vbDot (2) Gepunktet
vbDashDot (3) Folge aus Strichen und Punkten
vbDashDotDot (4) Folge aus Strichen und zwei Punkten
vbInvisible (5) Transparent
vbInsideSolid (6) Innen ausgefüllt

Anwendung

Anwendung
...................................................
Aufgrund ihrer Begrenztheit auf Linienbreiten von 1 Bildpunkt lässt sich mit der DrawStyle-
Eigenschaft nicht allzu viel anfangen. Der Unterschied zwischen vbSolid und vbInsideSolid
macht sich nur bemerkbar, wenn eine geschlossene Figur, beispielsweise ein Rechteck oder ein
Kreis, gezeichnet wird. Für gewöhnliche Linien gibt es keinen Unterschied. In geschlossen Figu-
ren sorgt vbInsideSolid dafür, dass die Linie vollständig innerhalb des angegebenen Bereichs
(Höhe, Breite, doppelter Radius) verbleibt, so dass für optimierte Zeichenroutinen (Paint)
jeweils mit den Bereichsgrenzen gerechnet werden kann.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
BorderStyle, BorderWidth, DrawMode, DrawWidth
Verwandte Themen

Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)

Enabled- Eigenschaft
Objekt.Enabled As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Formulare sowie die meisten vordefinierten Steuerelementtypen
Beschreibung

Bes c hreibung
...................................................
Die Enabled-Eigenschaft drückt den Aktivierungszustand von Objekt aus. Lautet ihr Wert
False, ist das Objekt deaktiviert, das heißt, es erhält die Darstellung »deaktiviert« und nimmt
den Fokus nicht mehr entgegen.

3 47
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Die Enabled-Eigenschaft implementiert einen recht brauchbaren Mechanismus, der es ermög-
licht, die Benutzerinteraktionen in Abhängigkeit vom jeweiligen Programmzustand auf die sinn-
vollen bzw. erlaubten Operationen einzuschränken. Da die meisten Steuerelemente ihre Deakti-
vierung auch durch eine entsprechend veränderte Darstellung anzeigen, erhält der Benutzer
gleichzeitig ein visuelles Feedback für seinen Handlungspielraum.

FillColor- Eigenschaft
Objekt.FillColor As Long
Gemeinsame Eigenschaften

Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, Shape, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaft FillColor ist ein Farbwert vom Typ Long, der die Füllfarbe für den Füllbereich
beim Zeichnen geschlossener Figuren festlegt. Voreinstellung für diese Eigenschaft ist die Farbe
»Schwarz« mit dem Wert 0. Zur Auswahl stehen neben den Systemfarben auch beliebige
andere Farben, die sich entweder zur Entwurfszeit aus der Palette wählen oder zur Laufzeit
über die Funktion RGB komponentenweise zu einem Farbwert komponieren lassen. Die Funk-
tion QBColor liefert den Farbwert einer der 16 Grundfarben. Zudem definiert der Aufzäh-
lungstyp SystemColorConstants Konstanten für die Systemfarben (vgl. »BackColor-Eigenschaft
und ForeColor-Eigenschaft«, S. 330).
Voraussetzung für die Anzeige der Füllfarbe ist allerdings, dass die Eigenschaft FillStyle einen
Wert ungleich vbTransparent (1) aufweist.
Anwendung

Anwendung
...................................................
FillColor spielt insbesondere eine Rolle, wenn Sie mit grafischen Methoden wie Circle oder
Line arbeiten. Beim Zeichnen ausgefüllter Rechtecke können Sie wählen, ob Sie den Füllbereich
mit der Vordergrundfarbe (ForeColor) oder mit der Füllfarbe (FillColor) und dem Füllmuster
(FillStyle) zeichnen wollen, indem Sie den optionalen Parameter BF oder nur B angeben.
Beispiel

Beis piel
...................................................
Der folgende Code zeichnet ein gefülltes Rechteck mit taubenblauem diagonal gestreiften Füll-
muster und schwarzem verdickten Rand.
DrawWidth = 3
ForeColor = vbBlack
FillColor = RGB(24, 135, 212)
FillStyle = vbDownwardDiagonal
Line (100, 100)-(1000, 1000), , B
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
BackColor, FillStyle, ForeColor

348
FillStyle- Eigenschaft

FillStyle- Eigenschaft
Objekt.FillStyle As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, Shape, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaft Fillstyle legt ein Füllmuster für Füllbereiche fest, die mit Füllfarbe (FillColor)
gezeichnet werden. Der Aufzählungstyp FillStyleConstants definiert folgende Konstanten für
die verschiedenen Füllmuster:

Gemeinsame Eigenschaften
Konstante (Wert) Beschreibung
vbFSSolid (0) Ausgefüllt
vbFSTransparent (1) Transparent (Voreinstellung)
vbHorizontalLine (2) Horizontale Schraffur
vbVerticalLine (3) Vertikale Schraffur
vbUpwardDiagonal (4) Aufwärtsdiagonale Schraffur
vbDownwardDiagonal (5) Abwärtsdiagonale Schraffur
vbCross (6) Kreuzschraffur
vbDiagonalCross (7) Diagonale Kreuzschraffur

Anwendung

Anwendung
...................................................
Laut Voreinstellung wird die Füllfarbe ignoriert. FillStyle muss daher auf einen Wert ungleich
1 gesetzt werden, damit die Füllfarbe im Füllbereich sichtbar wird.
Beispiel

Beis piel
...................................................
Siehe das Beispiel zu »FillColor-Eigenschaft« (S. 348).
Verwandte Befehle

Verwa ndte Befehle


...................................................
BackColor, FillColor, ForeColor

Font- Eigenschaft
Objekt.Font As Font
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, CheckBoxm, ComboBox, CommandButton, Data, DataCombo, DataGrid, DataList, DataRe-
port, DirListBox, DriveListBox, FileListBox, Form, Frame, Label, MaskEdBox, MonthView,
ImageCombo, ListBox, ListView, OptionButton, PictureBox, Printer, PropertyPage, Remote-
Data, RichTextBox, RptFunction, RptLabel, RptTextBox, Shape, SSTab, StatusBar, TabStrip,
TextBox, TreeView, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Font-Eigenschaft enthält eine Referenz auf ein Font-Objekt, das die Schrift sowie die
Schriftattribute für die Textausgabe genauer spezifiziert.
Font-Objekte

3 49
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Um die für ein Steuerelement geltende Schrift zu verändern, können Sie über die Font-Eigen-
schaft auf das aktuell geltende Font-Objekt zugreifen und dessen Eigenschaften neu setzen. Es
besteht aber auch die Möglichkeit, die Schriftattribute mehrerer Steuerelemente über ein einzel-
nes Font-Objekt zu steuern, indem Sie die Font-Eigenschaften dieser Steuerelemente auf das glei-
che Font-Objekt setzen. Dazu vereinbaren Sie entweder auf Modulebene ein neues Font-Objekt:
Private fntGemeinsam As New StdFont
...
fntGemeinsam.Name = "Arial Black"
Gemeinsame Eigenschaften

fntGemeinsam.Size = 14
...

oder nutzen ein bereits bestehendes Font-Objekt, das zu einem der Steuerelemente gehört. Dann
setzen Sie die Font-Eigenschaften der Steuerelemente auf dieses Objekt.
Set Text1.Font = fntGemeinsam
Set Text2.Font = fntGemeinsam
Set Text3.Font = fntGemeinsam

Änderungen an fntGemeinsam wirken sich nun auf alle betroffenen Steuerelemente aus.
Hinweis

Hinweis
...................................................
Die Schriftattribute »Fett«, »Kursiv«, »Durchgestrichen« oder »Unterstrichen« lassen sich
sowohl über die Eigenschaften FontBold, FontItalic, FontStrikethru, FontUnderline als auch
über die Eigenschaften Bold, Italic, Strikethru und Underline des Font-Objekts setzen. In glei-
cher Weise decken sich die Eigenschaften FontName und FontSize mit den Eigenschaften Name
und Size des Font-Objekts.
Beispiel

Beis piel
...................................................
Text1.Font.Italic = True

ForeColor- Eigenschaft
Siehe »BackColor-Eigenschaft und ForeColor-Eigenschaft«, S. 330.

HasDC- Eigenschaft
Objekt.HasDC As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, MonthView, PictureBox, PropertyPage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die HasDC-Eigenschaft spielt nur im Zusammenhang mit Aufrufen von Funktionen der Win32-
API eine Rolle. Sie beschreibt, ob Objekt über einen eigenen Gerätekontext verfügt (True) oder
nicht (False).
Anwendung

Anwendung
...................................................
Falls ein Objekt keinen eigenen Gerätekontext besitzt, wie das beispielsweise bei fensterlosen
Steuerelementen (vgl. Windowless-Eigenschaft) der Fall ist (unabhängig vom tatsächlichen Wert

350
hDC- Eigenschaft

der HasDC-Eigenschaft), benutzt es für seine Ausgaben den Gerätekontext des übergeordneten
Objekts (Parent). Das kann dann zu Schwierigkeiten bis hin zu hässlichen Abstürzen bei der
Ausführung von Win32-API-Funktionen führen.

hDC- Eigenschaft
Objekt.hDC As Long
Betroffene Objekte

Betro ffene Objekte


...................................................
CommonDialog, Form, MonthView, PictureBox, PropertyPage, UserControl, UserDocument

Gemeinsame Eigenschaften
Beschreibung

Bes c hreibung
...................................................
Die hDC-Eigenschaft spielt nur im Zusammenhang mit Aufrufen von Funktionen der Win32-API
eine Rolle. Ihr Wert ist eine Nummer, die den Gerätekontext von Objekt identifiziert. Eine Aus-
nahme bildet das CommonDialog-Steuerelement: Hier spezifiziert hDC den Gerätekontext des aus-
gewählten Druckers.
Anwendung

Anwendung
...................................................
Ein Gerätekontext ist eine Windows-Datenstruktur, die den Zustand eines Ausgabegerätes
(Drucker, Fenster, Bildschirm) vollständig beschreibt. Er enthält die aktuellen Einstellungen
über die verwendeten Farben, den aktuellen Stift, die Schrift usw. und im Falle des Bildschirm-
kontextes auch noch eine Bitmap (Image-Eigenschaft), die den aktuellen Zustand der Ausgabe
repräsentiert und (bei gesetzter AutoRedraw-Eigenschaft) für die Aktualisierung der Anzeige
benutzt wird.
Falls ein Objekt keinen eigenen Gerätekontext besitzt (HasDC-Eigenschaft), wie das beispiels-
weise bei fensterlosen Steuerelementen (vgl. Windowless-Eigenschaft) der Fall ist (unabhängig
vom tatsächlichen Wert der HasDC-Eigenschaft), benutzt es für seine Ausgaben den Gerätekon-
text des übergeordneten Objekts (Parent). Das kann jedoch zu Schwierigkeiten bis hin zu häss-
lichen Abstürzen bei der Ausführung von Win32-API-Funktionen führen.

Height- Eigenschaft und Width- Eigenschaft


Objekt.Height As Single
Objekt.Width As Single
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Formulararten, Komponenten und Steuerelemente mit sichtbarer Darstellung
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften Height und Width beschreiben die vertikale und horizontale Abmessung eines
Objekts. Bei Form-Objekten, Printer-Objekten und dem Screen-Objekt werden die Werte dieser
Eigenschaften standardmäßig in der Maßeinheit Twips ausgedrückt. Bei Steuerelementen und
Komponenten, die in einem Container (in einem Formular, Bildfeld, Rahmen etc.) platziert
wurden, sind die Abmessungen immer auf die Maßeinheiten bezogen, wie sie aktuell im Koor-
dinatensystem des Containers gelten.
Anwendung

Anwendung
...................................................
Die Abmessungen eines Steuerelements oder eines Formulars lassen sich nicht nur zur Ent-
wurfszeit, sondern auch zur Laufzeit dynamisch anpassen, indem Sie die Eigenschaften Height
und/oder Width auf geeignete Werte setzen. Um bei der Anpassung von Steuerelementen keine

3 51
Gemeinsame Eigenschaften

Überraschungen zu erleben, sollten Sie allerdings im Hinterkopf behalten, dass sich die Maßein-
heiten in einem Containerobjekt jederzeit durch einen Wechsel des Koordinatensystems
(ScaleMode) oder durch eine Skalierung der Koordinatenachsen (ScaleHeight und ScaleWidth)
ändern können.
Bei Formularobjekten, deren BorderStyle-Eigenschaft auf vbSizable (2) gesetzt wurde, können
sich Wertänderungen für Height und Width auch aufgrund von Benutzerinteraktionen ergeben.
Jede Wertänderung dieser Eigenschaften, gleich ob sie vom Programmcode aus oder auf Veran-
lassung des Benutzers geschehen ist, generiert ein Resize-Ereignis.
Es ist wichtig, den Unterschied zwischen den Eigenschaften Height und Width und den Eigen-
schaften ScaleHeight und ScaleWidth zu begreifen. Erstere sind auf die äußeren Abmessungen
Gemeinsame Eigenschaften

des Darstellungsbereichs eines Objekts bezogen, während letztere die Abmessungen des Client-
Bereichs, also die »inneren« Abmessungen des Objekts, ausdrücken. Mehr noch: Wertänderun-
gen bei Height und Width ändern die äußeren und inneren Abmessungen des Objekts, Wertän-
derungen bei ScaleHeight und ScaleWidth dagegen nur die Maßgrundlage und nicht die Abmes-
sungen. Beispielsweise gibt ein neuer Wert für die ScaleHeight-Eigenschaft eines Formulars an,
in wie viele Einheiten der Client-Bereich fortan in vertikaler Richtung unterteilt sein soll; da
dies die Metrik ändert, ändert sich auch die Eigenschaft ScaleMode implizit auf vbUser (0).
Anmerkungen

Anm erkungen
...................................................
Beim Bildausschnittobjekt (PictureClip) sind die Eigenschaften Height und Width schreibge-
schützt. Da das Bildausschnittobjekt selbst keine sichtbare Darstellung hat, drücken diese
Eigenschaften die Abmessungen der dem Objekt zugeordneten Bitmap (in Bildpunkten) aus.
Während die Abmessungen des PictureBox-Objekts (wie alle Steuerelemente) in den Maßeinhei-
ten des Containerobjekts gehalten sind, liegt den Eigenschaften Height und Width eines zugewie-
senen Picture-Objekts immer die Maßeinheit HiMetric (hundertstel Millimeter) zugrunde. Um
ein PictureBox-Objekt an die Abmessungen eines Picture-Objekts anzupassen, müssen die
Maßeinheiten mittels der Methoden ScaleX und ScaleY umgerechnet werden.
Picture1.Width = ScaleX(Picture1.Picture.Height, vbHimetric, vbUser)

Für das Screen-Objekt sind die beiden Eigenschaften schreibgeschützt.


Bei DriveListBox- und ComboBox-Steuerelementen, deren Style-Eigenschaft auf vbComboDropdown
(0) oder auf vbComboDropdownList (2) gesetzt wurde, wird die Height-Eigenschaft vom System
errechnet und ist zur Laufzeit schreibgeschützt.
Beispiel

Beis piel
...................................................
Häufig ergibt sich das Problem, den Client-Bereich eines Formulars auf eine bestimmte Größe
trimmen zu müssen, etwa um ein Bild einzupassen. Auf direktem Wege ist das nicht möglich, da
ScaleHeight und ScaleWidth ja keine Abmessungen, sondern nur Maßeinheiten ändern. Die
Lösung ist simpel – wenn man sie kennt. Angenommen die Variablen sNeueHöhe und sNeuBreite
enthalten die neuen Abmessungen des Client-Bereichs, dann leistet der folgende Code das
Gewünschte:
ScaleMode = vbTwips ' gleiche Maßeinheiten für innen und außen
Height = Height – ScaleHeight + sNeueHöhe
Width = Width – ScaleWidth + sNeueBreite
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
ScaleHeight, ScaleMode, ScaleWidth

352
HelpContextID- Eigenschaft und WhatsThisHelpID- Eigenschaft

HelpContextID- Eigenschaft und WhatsThisHelpID- Eigenschaft


Objekt.HelpContextID As Long
Objekt.WhatsThisHelpID As Long
Betroffene Objekte

Betro ffene Objekte


...................................................
Formulare, Komponenten und Steuerelemente mit sichtbarer Darstellung
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften HelpContextID und WhatsThisHelpID ordnen einem Objekt Hilfethemen in der

Gemeinsame Eigenschaften
zur Anwendung gehörigen Hilfedatei (App.HelpFile) zu. HelpContextID spezifiziert den Index
des Hilfethemas, wenn der Benutzer die kontextbezogene Hilfe (Windows-Hilfesystem) über die
Taste (F1) aktiviert. WhatsThisHelpID spezifiziert den Index des Hilfethemas, wenn der Benut-
zer die Direkthilfe zu einem Steuerelement anfordert.
Hat HelpContextID den Wert 0 (Voreinstellung), bedeutet das, dass für das Objekt kein Thema
in der Allgemeinhilfe definiert ist. In diesem Fall versucht das Laufzeitsystem, das Hilfethema
des Containerobjekts aufzurufen. Falls bis zum obersten Container alle HelpContextID-Eigen-
schaften den Wert 0 haben, kommt die SUCHEN-Funktion des Hilfesystems zum Aufruf.
Hat WhatsThisHelpID den Wert 0 (Voreinstellung), bedeutet das, dass keine Direkthilfe für das
Objekt verfügbar ist. In diesem Fall wird der Direkthilfemodus beendet, ohne dass etwas pas-
siert.
Anwendung

Anwendung
...................................................
Visual Basic unterstützt vier verschiedene Techniken, wie Sie Benutzern Ihrer Anwendungen
Hilfe zukommen lassen können:
1. QuickInfo – blendet den Wert der Eigenschaft ToolTipText eines Steuerelements in einem
kleinen Fensterchen ein, wenn die Maus in den Bereich des Steuerelements gelangt und dort
ca. eine halbe Sekunde verweilt.
2. Statusanzeige – die Behandlungsroutine der MouseMove-Methode gibt bei Eintritt der Maus in
den Steuerelementbereich einen Hilfetext in der Statusleiste (StatusBar) aus.
3. Direkthilfe – bei aktiviertem Direkthilfemodus blendet der nächste Klick auf ein Steuerele-
ment ein Popup-Hilfefenster mit einem Hilfetext zu diesem Steuerelement ein. Der über die
Eigenschaft WhatsThisHelp indizierte Hilfetext entstammt der Datei App.HelpFile. Damit sich
die Direkthilfe überhaupt aktivieren lässt, muss die WhatsThisHelp-Eigenschaft des Contai-
nerformulars auf True gesetzt sein. Die Aktivierung des Direkthilfemodus kann dann durch
Aufruf der WhatsThisMode-Methode des Formulars geschehen oder durch einen Klick auf die
Hilfeschaltfläche in der Titelleiste des Formulars (dazu muss die Eigenschaft WhatsThisButton
des Formulars auf True gesetzt sein, und es dürfen keine MINIMIEREN-/MAXIMIEREN-Schalt-
flächen vorhanden sein).
4. Kontextbezogene Hilfe – die Hilfetaste (F1) aktiviert das Windows-Hilfesystem und bringt
darin den über die Eigenschaft HelpContextID indizierten Hilfetext aus der Datei App.HelpFi-
le zur Anzeige.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
MaxButton, MinButton, ToolTipText, WhatsThisHelp, WhatsThisButton

3 53
Gemeinsame Eigenschaften

hWnd- Eigenschaft
Objekt.hWnd As Long
Betroffene Objekte

Betro ffene Objekte


...................................................
Formulare, Komponenten und Steuerelemente mit sichtbarer Darstellung, nicht jedoch OLE
Beschreibung

Bes c hreibung
...................................................
Die zur Laufzeit schreibgeschützte hWnd-Eigenschaft enthält die Zugriffsnummer für das Fenster
des Objekts – den sog. Fenster-Handle.
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Der Fenster-Handle eines Steuerelements spielt für die Visual-Basic-Programmierung nur dann
eine Rolle, wenn Funktionen der Win32-API zum Aufruf kommen.
Warnung

Wa rnung
...................................................
Der Wert dieser Eigenschaft kann sich zur Laufzeit ändern (etwa im Zuge eines Unload-Auf-
rufs).
Beispiel

Beis piel
...................................................
Vgl. das Beispiel zu »Printer-Objekt« (S. 284).
Verwandte Themen

Verwandte Them en
...................................................
Routinen aus DLLs und der Windows-API einsetzen (S. 185)

Image- Eigenschaft
Image As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
Band, Button, Form, Node, PictureBox, PropertyPage, Tab, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Image-Eigenschaft stellt die Beschreibung einer beständigen im Speicher gelegenen Bitmap
dar. Bei Objekten mit eigenem Gerätekontext (hDC) handelt es sich dabei um die beständige
Bitmap im Gerätekontext.
Die Image-Eigenschaft ist ihrerseits ein Objekt und besitzt fünf Eigenschaften sowie eine
Methode:

Eigenschaft Beschreibung
Handle Long-Wert, der die zugeordnete Bitmap identifiziert
Width, Height Long-Werte, die die Breite und Höhe der Bitmap in der Einheit HiMetric
(0,01 mm) ausdrücken. Die Werte müssen meist mit ScaleX bzw. ScaleY
umgerechnet werden.
hPal Long-Wert, der einen Handle auf die Palette darstellt, die für die Bitmap
verwendet wird (nur für Aufrufe der Win32-API interessant)

354
Image- Eigenschaft

Eigenschaft Beschreibung
Type Integer-Wert, der das Grafikformat der beschriebenen Bitmap wiedergibt.
Die möglichen Werte sind:
vbPicTypeNone (0) Bild ist leer
vbPicTypeBitMap (1) Bild hat BMP-Format
vbPicTypeMetaFile (2) Bild hat WMF-Format
vbPicTypeIcon (3) Bild hat ICO-Format
vbPicTypeEMetaFile (4) Bild hat EMF-Format

Gemeinsame Eigenschaften
Die Methode trägt den Bezeichner Render und hat folgenden Prototyp:
Sub Objekt.Image.Render(hDC As Long, x As Long, y As Long, cx As Long,_
cy As Long, xSrc As Long, ySrc As Long, cxSrc As Long, _
cySrc As Long, prcWBounds As Any)
Die vielen Parameter sind alle erforderlich. In hDC muss der Gerätekontext des Ausgabebereichs
übergeben werden (wenn das Zielobjekt keinen eigenen hat, dann der des Containerobjekts).
Die Parameter x, y, cx, cy beschreiben die Position und Abmessungen des Bildes im Ausgabebe-
reich bezogen auf das darin geltende Koordinatensystem. Die Parameter xSrc, ySrc, cxSrc,
cySrc beschreiben den zu zeichnenden Bildausschnitt (Position und Abmessungen) der über
Handle zugänglichen Quell-Bitmap – als Koordinatensystem gilt hier HiMetric. Für den Parame-
ter prcWBounds ist der Wert 0 anzugeben, wenn die Bitmap nicht im WMF-Format vorliegt –
ansonsten ein Wert des Typs RECTL (eine aus vier Long-Werten bestehende Struktur, die den
linken oberen und rechten unteren Punkt beschreibt), der die Standardabmessungen für die
Vektorgrafik definiert.
Anwendung

Anwendung
...................................................
Die Image-Eigenschaft ermöglicht den Umgang mit Bildern, die in einem Gerätekontext repräsen-
tiert sind. Bei Formularen entscheidet die AutoRedraw-Eigenschaft darüber, ob die über die Image-
Eigenschaft beschriebene Bitmap Ziel der Grafikoperationen Circle, Pset, Line und Print ist und
für die Auffrischung des Client-Bereichs herangezogen wird oder ob die Paint-Routine die Ausga-
ben an der Bitmap des Gerätekontextes vorbei direkt in den Client-Bereich zeichnet. Die bestän-
dige Bitmap des Gerätekontextes existiert in jedem Fall, unabhängig vom Wert der AutoRedraw-
Eigenschaft, nur dass sie im einen Fall sowohl die über die Picture-Eigenschaft bereitgestellte
Bitmap enthält als auch Grafikausgaben und im anderen Fall nur die Bitmap.
Beispiel

Beis piel
...................................................
Der genannte Unterschied lässt sich leicht nachweisen, indem man die Picture-Eigenschaft des
Formulars auf eine Bitmap setzt und etwa einen Kreis darüber zeichnet. Da es möglich ist, die
beständige Bitmap des Gerätekontextes über die Image-Eigenschaft auszulesen, kann man sie
beispielsweise der Picture-Eigenschaft eines Bildfelds als Wert zuweisen. Im ersten Fall
(AutoRedraw = True) sieht man dann die Bitmap samt Kreis und im andern Fall nur den Kreis.
Private Sub Form_Click()
Picture = LoadPicture("Test.bmp")
Circle (400, 400), 400
Refresh
Picture1 = Image ' Bitmap aus Gerätekontext in Bildfeld kopieren
End Sub

3 55
Gemeinsame Eigenschaften

Index- Eigenschaft
Objektarray(Index As Integer) As Objekt
Beschreibung

Bes c hreibung
...................................................
Bei der Index-Eigenschaft handelt es sich um eine reine Entwurfseigenschaft, die zur Laufzeit
nicht als Eigenschaft, sondern gegebenenfalls als Array-Index in Erscheinung tritt. Bleibt im
Eigenschaftsfenster das Feld für ihren Wert leer, legt der Entwurfseditor den unter der Eigen-
schaft Name spezifizierten Bezeichner für das Objekt fest, ohne die Index-Eigenschaft weiter zu
beachten. Trägt man dagegen eine (nicht negative) Ganzzahl als Wert für die Index-Eigenschaft
ein, legt der Entwurfseditor unter dem in der Eigenschaft Name spezifizierten Bezeichner ein
Gemeinsame Eigenschaften

dynamisches Steuerelemente-Array an, dem sich beliebig viele Steuerelemente gleichen Typs zur
Entwurfszeit, aber auch noch zur Laufzeit (via Load) hinzufügen lassen.
Anwendung

Anwendung
...................................................
Der Entwurfseditor schlägt die Einrichtung eines Steuerelemente-Arrays von sich aus vor, wenn
Sie ein Steuerelement mit noch nicht gesetzter Index-Eigenschaft über die Zwischenablage ver-
vielfältigen. Da er in diesem Fall die Index-Eigenschaften der im Array zusammengefassten
Objekte auch pflegt, sei Ihnen diese Vervielfältigungsmethode ans Herz gelegt. Das erste Steuer-
element (von dem die Kopie ausging) erhält den Index 0, das zweite den Index 1 usw. Sie kön-
nen ein dynamisches Steuerelemente-Array aber auch »manuell« anlegen, indem Sie für ein
bereits platziertes Steuerelement einen beliebigen Startindex eintragen und dann zur Entwurfs-
zeit oder zur Laufzeit (mittels Load) weitere Steuerelemente gleichen Typs mit gleichem Namen
in denselben Container platzieren. Obwohl die Zählung üblicherweise bei 0 beginnt, gibt es
keine Vorschriften für den Startindex, er darf nur nicht negativ sein. Auch darf die Zählung
Lücken aufweisen – solange zur Laufzeit (außer in der Load-Anweisung) nicht auf die fehlenden
Indizes verwiesen wird.
Der Einsatz von Steuerelemente-Arrays erfordert zwar ein wenig zusätzliche Logik, führt aber
meist zu einem kompakteren Programmcode. Das Besondere an Steuerelemente-Arrays ist näm-
lich, dass eine Ereignisbehandlungsroutine immer für alle Steuerelemente des Arrays zuständig
ist – ihr Name wird daher auch mit dem Array-Bezeichner gebildet. Ein zusätzlicher Parameter
namens Index in der Parameterliste der Prozedur gibt Auskunft darüber, welchem Steuerele-
ment aus dem Array das Ereignis gilt.
Hinweis

Hinweis
...................................................
Um mit einem Steuerelemente-Array arbeiten zu können, muss mindestens ein Steuerelement
des gewünschten Typs zur Entwurfszeit im Bereich des Formulars (bzw. der Komponente) plat-
ziert werden.
Beispiel

Beis piel
...................................................
Die folgende Routine erweitert ein bestehendes Schaltflächen-Array bei jedem Aufruf um eine
weitere Schaltfläche. Ausgehend von einem Formular, auf dem eine einzelne Schaltfläche mit
dem Namen Command1, der Index-Eigenschaft 1 und der Caption-Eigenschaft "Befehl 1" platziert
wurde, erfolgt der Aufruf der Routine interessanterweise (jedoch, ohne dass dies dem Code
etwas Besonderes verleihen würde), sobald der Benutzer auf eine der bereits existierenden
Schaltflächen klickt.
Private Sub Command1_Click(Index As Integer)
Dim i As Integer
i = Command1.UBound
Load Command1(i + 1)

356
Left- Eigenschaft und Top- Eigenschaft

Command1(i + 1).Top = Command1(i).Top + Command1(i).Height


Command1(i + 1).Caption = "Befehl " & (i + 1)
Command1(i + 1).Visible = True
End Sub

Left- Eigenschaft und Top- Eigenschaft


Objekt.Left As Single
Objekt.Top As Single
Betroffene Objekte

Betro ffene Objekte


...................................................

Gemeinsame Eigenschaften
Formulare, Komponenten und Steuerelemente mit sichtbarer Darstellung
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften Left und Top bestimmen die Position der linken oberen Ecke eines Objekts in
seinem Container. Bei Form-Objekten werden die Werte dieser Eigenschaften standardmäßig in
der Maßeinheit Twips ausgedrückt, wobei der Ursprung des Screen-Objekts in der linken obe-
ren Ecke des Bildschirms liegt. Bei Steuerelementen und Komponenten, die in einem Container
(in einem Formular, Bildfeld, Rahmen etc.) platziert wurden, sind die Werte als Koordinaten im
aktuellen Koordinatensystem des Containerobjekts zu interpretieren (vgl. »ScaleMode-Eigen-
schaft«, S. 369).
Anwendung

Anwendung
...................................................
Die Position eines Steuerelements oder eines Formulars lässt sich nicht nur zur Entwurfszeit,
sondern auch zur Laufzeit dynamisch anpassen, indem Sie die Eigenschaften Left und/oder Top
auf geeignete Werte setzen. Um bei der Positionierung von Steuerelementen keine Überraschun-
gen zu erleben, sollten Sie allerdings im Hinterkopf behalten, dass sich das Koordinatensystem
in einem Containerobjekt, das über die Eigenschaft ScaleMode verfügt, jederzeit ändern kann.
Bei Formularobjekten können sich Wertänderungen für Left und Top auch aufgrund von Benut-
zerinteraktionen ergeben. Beachten Sie auch, dass das Laufzeitsystem zur Entwurfszeit gesetzte
Vorgaben für diese Eigenschaften nur berücksichtigt, wenn die Eigenschaft StartUpPosition auf
vbStartUpManual (0) gesetzt wurde. Bei anderen Einstellungen positioniert Windows das Fenster
entweder frei (nach der internen Logik für die Fensteranordnung) oder mittig, bezogen auf das
übergeordnete Fenster oder den Bildschirm.
Hinweise

Hinweis e
...................................................
Bereits positionierte Steuerelemente behalten bei einem Wechsel des Koordinatensystems (Ska-
lierung oder Verschiebung) ihre physikalischen Positionen und Abmessungen bei, da die Eigen-
schaften Left, Top, Height und Width implizit eine umgekehrte Koordinatentransformation
durchmachen.
Die Eigenschaften ScaleLeft und ScaleTop haben mit der Position eines Objekts nichts zu tun,
sondern mit der Position des Ursprungs des Koordinatensystems. Sie drücken die Koordinaten
der linken oberen Ecke des Client-Bereichs aus – ändert man ihre Werte, bewirkt das eine
Ursprungsverschiebung.
Beispiel

Beis piel
...................................................
Das Beispielprojekt TVTennis erinnert stark an den historischen Vorläufer. Der Ball, ein Image-
Steuerelement, das mit einem Smiley-Bild initialisiert wurde, bewegt sich im Formularbereich
und wird an den Wänden reflektiert. Die Bewegung passt sich an Größenänderungen des For-
mulars an.

3 57
Gemeinsame Eigenschaften

Option Explicit
Private StepX As Integer
Private StepY As Integer

Private Sub Form_Load()


StepX = 400 * Rnd
StepY = 400 * Rnd
End Sub

Private Sub Timer1_Timer()


Gemeinsame Eigenschaften

Image1.Left = (Image1.Left + StepX)


Image1.Top = (Image1.Top + StepY)
If Image1.Left > ScaleWidth – Image1.Width Then
StepX = -StepX
Image1.Left = 2 * ScaleWidth – 2 * Image1.Width – Image1.Left
End If
If Image1.Left < 0 Then
StepX = -StepX
Image1.Left = -Image1.Left
End If
If Image1.Top > ScaleHeight – Image1.Height Then
StepY = -StepY
Image1.Top = 2 * ScaleHeight – 2 * Image1.Height – Image1.Top
End If
If Image1.Top < 0 Then
StepY = -StepY
Image1.Top = -Image1.Top
End If
End Sub
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
Height, ScaleHeight, ScaleLeft, ScaleMode, ScaleTop, ScaleWidth, Width
Verwandte Themen

Verwandte Them en
...................................................
Bildlauf – ein kleiner Betrachter für große Bilder (S. 545), HexView – eine schnelle Textan-
sicht für große Dateien (S. 551)

MaskColor- Eigenschaft
Objekt.MaskColor As Long
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, CommandButton, ImageList, OptionButton, UserControl
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaft MaskColor ist ein Farbwert vom Typ Long, der eine Transparenzfarbe für die
dem Objekt zugeordnete(n) Bitmap(s) festlegt. Zur Auswahl stehen neben den Systemfarben
auch beliebige andere Farben, die sich entweder zur Entwurfszeit aus der Palette wählen oder
zur Laufzeit über die Funktion RGB komponentenweise zu einem Farbwert komponieren lassen.
Die Funktion QBColor liefert den Farbwert einer der 16 Grundfarben. Zudem definiert der Auf-

358
MouseIcon- Eigenschaft

zählungstyp SystemColorConstants Konstanten für die Systemfarben (vgl. »BackColor-Eigen-


schaft und ForeColor-Eigenschaft«, S. 330).
Bei Schaltflächen, Optionsfeldern und Kontrollkästchen erscheinen transparente Bereiche der
Bitmap in der für das Steuerelement gesetzten Hintergrundfarbe (BackColor); bei benutzerdefi-
nierten Steuerelementen scheint in transparenten Bereichen durch, was dahinter liegt – bei-
spielsweise ein anderes Steuerelement oder ein Hintergrundbild des Containers.
Anwendung

Anwendung
...................................................
Für die Beachtung der Transparenzfarbe bei Schaltflächen, Optionsfeldern und Kontrollkäst-
chen gibt es drei Voraussetzungen: Die Eigenschaft Style muss auf vbGraphical (1) gesetzt sein,

Gemeinsame Eigenschaften
die UseMaskColor-Eigenschaft muss auf True gesetzt sein und für die benutzerdefinierte Darstel-
lung der Zustände (Picture, DisabledPicture, DownPicture) müssen Bitmaps angegeben sein,
deren transparente Bereiche in der für MaskColor gesetzten Farbe gehalten sind. Sind diese Vor-
aussetzungen erfüllt, machen sich Änderungen der Hintergrundfarbe des Steuerelements in den
transparenten Bereichen der Bitmaps bemerkbar – es handelt sich hier also um Pseudotranspa-
renz.
Von echter Transparenz spricht man, wenn hinter dem Steuerelement gelegene Bereiche – ein
Hintergrundbild und andere Steuerelemente mit niedrigerer Z-Ordnung – an den transparenten
Stellen zu sehen sind. Sie lässt sich nur mit benutzerdefinierten Steuerelementen, also Kompo-
nenten des Typs UserControl, realisieren und erfordert dreierlei: Setzen der BackStyle-Eigen-
schaft auf vbTransparent (0); Setzen der MaskColor-Eigenschaft auf die Transparenzfarbe; Setzen
der Eigenschaften Picture und MaskPicture auf eine Bitmap, deren transparente Bereiche in der
für MaskColor gesetzten Farbe gehalten sind.
Auch beim ImageList-Steuerelement legt die MaskColor-Eigenschaft eine Transparenzfarbe zur
Erstellung einer Maske für die transparente Anzeige fest. Die Methoden Overlay und Draw arbei-
ten mit dieser Eigenschaft und implizit auch Steuerelemente wie TreeView und ListView (bzw.
ListItem).
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
BackColor, BackStyle, DisabledPicture, DownPicture, MaskPicture, Picture
Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

MouseIcon- Eigenschaft
Objekt.MouseIcon As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Formulare, Komponenten und Steuerelemente mit sichtbarer Darstellung
Beschreibung

Bes c hreibung
...................................................
Die MouseIcon-Eigenschaft spezifiziert eine benutzerdefinierte Mauszeigerform für ein Objekt.
Sie kommt zur Anzeige, sobald der Mauszeiger in den sichtbaren Bereich des Objekts gerät,
unter der Voraussetzung dass die MousePointer-Eigenschaft auf vbCustom (99) gesetzt ist. Hat
die Eigenschaft den Wert Nothing, bleibt die aktuelle Mauszeigerform unverändert.

3 59
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Als Werte für diese Eigenschaft sind nur Verweise auf Bitmaps geeignet, die in einem der Sym-
bolformate CUR oder ICO vorliegen – insbesondere lassen sich also weder gewöhnliche Bilder
(BMP, JPG, WMF etc.) noch animierte Cursorformen (ANI) als Mauszeigerform setzen.
Beispiel

Beis piel
...................................................
Command1.MouseIcon = LoadPicture ("MeinIcon.Ico")
Command1.MousePointer = vbCustom
Verwandte Eigenschaften
Gemeinsame Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
DragIcon, MousePointer

MousePointer- Eigenschaft
Objekt.MousePointer As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Formulare, Komponenten und Steuerelemente mit sichtbarer Darstellung
Beschreibung

Bes c hreibung
...................................................
Die MousePointer-Eigenschaft bestimmt, welche Mauszeigerform zur Anzeige kommt, wenn der
Mauszeiger in den sichtbaren Bereich des Objekts gerät. Zur Auswahl stehen die 16 vom Sys-
tem her zur Verfügung gestellten Mauszeigerformen sowie eine benutzerdefinierte Mauszeiger-
form, wenn die Eigenschaft MouseIcon auf ein geeignetes Symbol verweist. Der Aufzählungstyp
MousePointerConstants definiert Konstanten für die einzelnen Mauszeigerformen.

Konstante (Wert) Beschreibung


vbDefault (0) Wie Containerobjekt (Voreinstellung)
vbArrow (1) Mauspfeil
vbCrosshair (2) Kreuz
vbIbeam (3) I-Form
vbIconPointer (4) Symbol
vbSizePointer (5) Größenänderung (Kreuz mit Pfeilspitzen)
vbSizeNESW (6) Größenänderung aufwärts diagonal
vbSizeNS (7) Größenänderung vertikal
vbSizeNWSE (8) Größenänderung abwärts diagonal
vbSizeWE (9) Größenänderung horizontal
vbUpArrow (10) Aufwärtspfeil
vbHourglass (11) Sanduhr
vbNoDrop (12) »Nicht ablegen« (Verbotsschild)
vbArrowHourglass (13) Mauspfeil mit Sanduhr
vbArrowQuestion (14) Mauspfeil mit Fragezeichen (Hilfepfeil)

360
MultiLine- Eigenschaft

Konstante (Wert) Beschreibung


vbSizeAll (15) Größenänderung alle (Kreuz mit Pfeilspitzen)
vbCustom (99) Benutzerdefinierter Mauszeiger (MouseIcon-Eigenschaft)

Anwendung

Anwendung
...................................................
Indem Sie die Mauszeigerform für ein Objekt zur Laufzeit ändern, können Sie dem Benutzer ein
visuelles Feedback über momentan ablaufende Geschehnisse oder aktivierte Funktionen anzeigen.
Standardoperationen sollten auch durch Standardsymbole (wie in der Tabelle aufgeführt) symbo-

Gemeinsame Eigenschaften
lisiert werden. In speziellen Situationen steht es Ihnen frei, die MousePointer-Eigenschaft auf vbCu-
stom (99) zu setzen und über die MouseIcon-Eigenschaft ein eigenes Symbol bereitzustellen.
Beispiel

Beis piel
...................................................
Command1.MouseIcon = LoadPicture ("MeinIcon.Ico")
Command1.MousePointer = vbCustom

MultiLine- Eigenschaft
Objekt.MultiLine As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
TextBox
Beschreibung

Bes c hreibung
...................................................
Die MultiLine-Eigenschaft bestimmt, ob für den Wert eines Textfeldes nur eine einzelne Zeile
zur Verfügung steht (False) oder ob ein Umbruch auf mehrere Zeilen möglich ist (True). Ist
keine horizontale Bildlaufleiste (ScrollBars) vorhanden, führt das Textfeld im mehrzeiligen
Modus einen dynamischen Zeilenumbruch durch, der sich nach der jeweils aktuellen Breite
(Width) des Objekts richtet.
Hinweis

Hinweis
...................................................
Entgegen anders lautenden Informationen in der Online-Hilfe zu Visual Basic wirkt sich der
Wert der MultiLine-Eigenschaft nicht auf die Ausrichtung des Textes (Alignment) in einem
Textfeld aus. Vielmehr wirkt sich der Wert der Alignment-Eigenschaft auf die Art aus, wie ein
Textfeld den Umbruch vornimmt.
Verwandte Befehle

Verwa ndte Befehle


...................................................
ScrollBars

Name- Eigenschaft
Objekt.Name As String
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Formulare, Komponenten und Steuerelemente
Beschreibung

Bes c hreibung
...................................................
Die zur Laufzeit schreibgeschützte Name-Eigenschaft gibt den im Code verwendeten Bezeichner
eines Objekts als Zeichenfolge wieder.

3 61
Gemeinsame Eigenschaften

Anwendung

Anwendung
...................................................
Der Entwurfseditor von Visual Basic benennt Komponenten, Formulare und Steuerelemente
automatisch nach einem festen Schema: vereinfachte Typbezeichnung plus Ordinalzahl der
Instanzenzählung. Somit erhält das erste Textfeld in einem Formular den Bezeichner »Text1«,
das dritte Optionsfeld den Bezeichner »Option3« usw. Wenn Sie lieber mit aussagekräftigeren
Bezeichnern arbeiten, können Sie den Wert der Name-Eigenschaft zur Entwurfszeit jederzeit auf
einen anderen gültigen Variablenbezeichner setzen. Falls der Bezeichner eines Steuerelements
bereits für ein anderes Steuerelement gleichen Typs vergeben wurde, schlägt Ihnen der Ent-
wurfseditor vor, beide Steuerelemente in einem dynamischen Array zu organisieren, das den
gewählten Bezeichner erhält. Die Unterscheidung der Objekte geschieht dann über die Index-
Gemeinsame Eigenschaften

Eigenschaft.
Zwei Formulare können dagegen zur Entwurfszeit nicht denselben Namen erhalten. Da Visual
Basic ein Formularmodul aber als Datentyp behandelt, können Sie zur Laufzeit beliebig viele
Instanzen davon ins Leben rufen. Wenn es ein Array sein muss, bitte sehr, dann vereinbaren Sie
eben ein Array mit diesem Typ. (Ja, wenn Sie so wollen, können Sie sogar den Typbezeichner
als Array-Namen vereinbaren). Wenn nun noch die erste Laufzeitinstanz des Formulars (die alle
weiteren hervorbringt) zu einem Array-Element machen, haben Sie vom Konstrukt her etwas
Ähnliches wie bei einem Steuerelemente-Array:
' Innerhalb des Moduls Form1 ...
Dim Form1(2) As New Form1 ' Drei Instanzen werden gebraucht
Private Sub Form_Click()
Set Form1(0) = Me ' Vorhandene Instanz eingliedern
Form1(1).Show ' Weitere Instanzen anlegen
Form1(2).Show
End Sub
Hinweis

Hinweis
...................................................
Der Entwurfseditor von Visual Basic verwendet automatisch vergebene Bezeichner auch noch
für einige andere Eigenschaften als Voreinstellung – so für Caption, LinkTopic und Text.
Warnung

Wa rnung
...................................................
Wenn Sie im Nachhinein die Groß-/Kleinschreibung eines Formularbezeichners ändern, das
Formularmodul abspeichern und später erneut für die Bearbeitung öffnen, erhalten Sie eine
Namenskonflikt-Fehlermeldung, die Sie nur wieder loswerden, wenn Sie die alte Schreibweise
des Namens wieder einführen oder gleich einen anderen Bezeichner wählen. Der Fehler kommt
daher, dass Visual Basic Änderungen der Groß-/Kleinschreibung nicht in die Projektdatei über-
nimmt und beim erneuten Laden des Moduls glaubt, einen »falschen« Bezeichner vorzufinden.

OLEDropAllowed- und OLETypeAllowed- Eigenschaften


Objekt.OleDropAllowed As Boolean
Objekt.OleTypeAllowed As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
OLE, UserControl

362
OLEDropMode- Eigenschaft

Beschreibung

Bes c hreibung
...................................................
Die OLEDropAllowed-Eigenschaft bestimmt, ob ein Steuerelement als Ziel einer OLE-
Drag&Drop-Operation das Ablegen eines OLE-Objekts erlaubt (True) oder nicht (False; Vor-
einstellung).
Die OLETypeAllowed-Eigenschaft bestimmt, welche Operation(en) das Steuerelement für das
Ablegen eines OLE-Objekts unterstützt. Der Aufzählungstyp OLEContainerContants definiert
drei Konstanten für die zulässigen Werte dieser Eigenschaft.

Eigenschaft Beschreibung

Gemeinsame Eigenschaften
vbOLELinked (0) Für abgelegtes OLE-Objekt kann nur eine Verknüpfung eingerich-
tet werden
vbOLEEmbedded (1) Abgelegtes OLE-Objekt kann nur eingebettet werden
vbOLEEither (2) Abgelegtes OLE-Objekt kann verknüpft oder eingebettet werden

Anwendung

Anwendung
...................................................
Für OLE-Drag&Drop-Operationen sind zwei Szenarien zu unterscheiden: Das erste beinhaltet
die gewöhnliche Datenübertragung zwischen zwei Steuerelementen oder Komponenten im
Sinne einer Kopier- oder Verschiebeoperation (mehr dazu im Praxisteil unter »OLE-
Drag&Drop«, S. 501). Das zweite beinhaltet das Einbetten oder Verknüpfen eines von einem
OLE-Server stammenden OLE-Objekts in einem OLE-Container. Um das zweite Szenario geht
es hier. Wird ein Objekt, das als OLE-Container fungieren kann und OLE-Drag&Drop-Opera-
tionen zulässt, Ziel einer solchen Operation, kann es sich dafür entscheiden, das Objekt einzu-
betten oder nur eine Verknüpfung auf das Objekt einzurichten. Im ersten Fall verschiebt oder
kopiert ((Umschalt) gedrückt) die Operation das Objekt als solches in den OLE-Container,
und der Container ermöglicht fortan die Bearbeitung des Objekts »vor Ort« – also in seinem
Fenster. Im zweiten Fall verbleibt das OLE-Objekt da, wo es ist, und der OLE-Container spei-
chert nur eine Referenz darauf. In beiden Fällen wird das Objekt im OLE-Container angezeigt
(was übrigens der für das OLE-Objekt zuständige OLE-Server übernimmt), nur gespeichert und
bearbeitet wird es an verschiedenen Stellen.
Lässt ein OLE-Container sowohl das Verknüpfen als auch das Einbetten zu, kann der Benutzer
die Art der Operation mittels Funktionstasten gestalten. Drückt er keine Funktionstaste, wird
das Objekt verschoben und eingebettet; drückt er (Umschalt), wird es kopiert und eingebettet;
drückt er (Umschalt)+(Strg), wird es verknüpft.
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

OLEDropMode- Eigenschaft
Objekt.OleDropMode As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CheckBox, ComboBox, CommandButton, CoolBar, Data, DataCombo, DataList,
DateTimePicker, DirListBox, DriveListBox, FileListBox, Frame, Form, Image, ImageCombo,
Label, ListBox, ListView, MaskEdBox, MDIForm, MMControl, MSChart, MSFlexGrid, MSHFlex-
Grid, OptionButton, PictureBox, ProgressBar, PropertyPage, RichTextBox, Slider, SSTab,
StatusBar, TabStrip, TextBox, TreeView, ToolBar, UpDown, UserControl, UserDocument

3 63
Gemeinsame Eigenschaften

Beschreibung

Bes c hreibung
...................................................
Die OLEDropMode-Eigenschaft bestimmt, wie sich ein Objekt verhält, wenn es Zielobjekt einer
OLE-Drag&Drop-Operation wird. Der Aufzählungstyp OLEDropConstants definiert dafür fol-
gende Konstanten:

Konstante (Wert) Beschreibung


vbDropNone (0), ccDropNone (0) Das Objekt lehnt die Durchführung der Opera-
cc2DropNone (0), cc3DropNone (0) tion ab und zeigt dies durch eine wie ein Ver-
mciDropNone (0) botsschild aussehende Mauszeigerform an.
Gemeinsame Eigenschaften

vbDropManual (1), ccDropManual (1) Das Objekt geht auf den Vorgang ein und löst
cc2DropManual (1), cc3DropManual (1) die OLE-Ereignisse OLEDragOver und OLEDrop für
mciDropManual (1), die weitere Ausgestaltung der Operation aus.
vbDropAutomatic (2) ccDropAutomatic (2) Das Objekt wickelt die Operation automatisch
cc2DropAutomatic (2) cc3DropAutomatic (2) ab, sofern ein Datenformat im Angebot steht,
mciDropAutomatic (2) mit dem es etwas anfangen kann. (Dieser Wert
wird nicht von allen Objekten unterstützt, die
über eine OLEDropMode-Eigenschaft verfügen.)

Anwendung

Anwendung
...................................................
Für die meisten der einfacheren Steuerelemente von Visual Basic (etwa Label, TextBox, Picture-
Box, Image etc.) bietet sich der automatische Modus an, da die den Objektwerten zugrunde lie-
genden Datentypen von den standardmäßigen OLE-Datentypen gut abgedeckt werden. Sollen
die Daten allerdings in einem speziellen Format oder gar in mehreren Formaten bei einer OLE-
Drag&Drop-Operation übertragen werden, ist der manuelle Modus unverzichtbar, weil nur er
die notwendige Handhabe für den programmseitigen Eingriff in die Operation bietet. Komple-
xere Steuerelemente wie Form, ListBox oder TreeView unterstützen gar keinen automatischen
Modus, da er hier auch keinen Sinn ergeben würde.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
OLEDragMode
Verwandte Methoden

Verwa ndte Metho den


...................................................
OLEDragDrop, OLEDragOver
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

Parent- Eigenschaft
Objekt.Parent As Formular
Beschreibung

Bes c hreibung
...................................................
Die zur Laufzeit schreibgeschützte Parent-Eigenschaft eines Objekts enthält einen Verweis auf
das übergeordnete Objekt.

364
Picture- Eigenschaft

Anwendung

Anwendung
...................................................
Während die Container-Eigenschaft eine Aussage darüber macht, in welchem anderen Objekt
ein Steuerelement angeordnet ist, regelt die Parent-Eigenschaft das Besitzverhältnis und lässt
sich als »Ist-Datenfeld-von«-Eigenschaft lesen. So kann ein Textfeld beispielsweise ein Rahmen-
feld (Frame) oder ein Bildfeld (PictureBox) als Container haben, während es einem Formularob-
jekt (Form) untergeordnet ist.
Die Parent-Eigenschaft ist manchmal recht hilfreich, wenn ein Objekt eine Methode oder Eigen-
schaft seines übergeordneten Objekts aufrufen will, ohne dieses mit Namen zu kennen. Ein sol-
che Situation liegt beispielsweise vor, wenn eine Funktion/Prozedur nichts weiter als eine Refe-
renz auf ein bestehendes Objekt übergeben bekommt.

Gemeinsame Eigenschaften
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
Container

Picture- Eigenschaft
Objekt.Picture As Picture
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, CommandButton, Form, MDIForm, Image, OptionButton, OLE, PictureBox, Picture-
Clip, PropertyPage, RptImage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Picture-Eigenschaft legt ein Bild fest, das im Bereich eines Steuerelements oder Formulars
zur Anzeige kommt.
Für das OLE-Container-Steuerelement steht diese Eigenschaft zur Entwurfszeit nicht zur Verfü-
gung und ist zur Laufzeit schreibgeschützt. Sie wird von der Quellanwendung, die für das einge-
bettete Objekt zuständig ist, gepflegt.
Für Kontrollkästchen, Optionsfelder und Schaltflächen gibt die Picture-Eigenschaft die Bitmap
an, die den aktivierten, nichtgedrückten (bzw. nichtmarkierten) Zustand des Steuerelements in
der benutzerdefinierten Darstellung zum Ausdruck bringt.
Anwendung

Anwendung
...................................................
Die Anzeige eines Bildes innerhalb eines Steuerelements oder Formulars ermöglicht die visuell
ansprechende Gestaltung des dem Objekt zur Verfügung stehenden Anzeigebereichs (vgl. auch
»Paint-Ereignis«, S. 253).
Wird die Picture-Eigenschaft (bzw. vergleichbare Eigenschaften) eines Steuerelements bereits
zur Entwurfszeit gesetzt, speichert Visual Basic die entsprechende Bitmap zunächst als binären
Anhang in einer separaten Datei (FRX-Datei für Formulare). Bei Erstellung der kompilierten
Fassung erhält die EXE-Datei dann alle binären Anhänge als Ressourcen, so dass die Quelldatei
generell nicht weiter bereitgestellt werden muss. Anders jedoch, wenn die Bitmap erst zur Lauf-
zeit mittels LoadPicture eingelesen wird. In diesem Fall muss die entsprechende Grafikdatei
natürlich dauerhaft verfügbar sein. Mit dem Bildausschnitt-Steuerelement (PictureClip) sowie
dem Bildliste-Steuerelement (ImageList) stehen sehr leistungsfähige Werkzeuge für den flexiblen
Umgang mit Bildern verschiedenster Formate zur Verfügung.
Für Steuerelemente des Typs Image und PictureBox fungiert die Picture-Eigenschaft als Stan-
dardeigenschaft.
Schaltflächen, Optionsfelder und Kontrollkästchen unterstützen anstelle der standardmäßigen
Darstellung auch die Möglichkeit, ihre drei Zustände in Form von benutzerdefinierten Bitmaps

3 65
Gemeinsame Eigenschaften

anzuzeigen. Zur Festlegung der Bitmaps sind die Eigenschaften Picture, DownPicture und
DisabledPicture zuständig. Damit ein Steuerelement die Werte dieser Eigenschaften überhaupt
beachtet, muss allerdings bereits beim Formularentwurf die zur Laufzeit schreibgeschützte
Style-Eigenschaft auf vbButtonGraphical (1) gesetzt worden sein. Die Picture-Bitmap kommt
beim aktivierten Steuerelement (Enabled-Eigenschaft auf True) im Zustand »Normal« (lies:
weder »gedrückt« noch »markiert«) zur Anzeige.
Beispiel

Beis piel
...................................................
Picture = LoadPicture("Form.jpg") ' Formular
Picture1 = LoadPicture("PicBox.jpg") ' PictureBox-Steuerelement
Gemeinsame Eigenschaften

Image1 = LoadPicture("Image.jpg") ' Image-Steuerelement


Command1.Picture = LoadPicture("Schmiley.jpg") ' ben.def.Schaltfläche
Verwandte Befehle

Verwa ndte Befehle


...................................................
DisabledPicture, DownPicture
Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

RightToLeft- Eigenschaft
Objekt.RightToLeft As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, ComboBox, CommandButton, Form, MDIForm, Label, ListBox, OptionButton, Picture-
Box, PropertyPage, RptTextBox, RptLabel, TextBox, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die RightToLeft-Eigenschaft bestimmt, ob ein Steuerelement auf einem bidirektionalen System
Text von rechts nach links (True) oder von links nach rechts (False; Voreinstellung) anzeigt.
Anwendung

Anwendung
...................................................
Für diese Eigenschaft müssen Sie sich nur interessieren, wenn Sie internationale Anwendungen,
beispielsweise für den arabischen Raum, programmieren, wo die Leserichtung von Text nicht
von links nach rechts, sondern von rechts nach links ist.

ScaleLeft- Eigenschaft und ScaleTop- Eigenschaft


Objekt.ScaleLeft As Single
Objekt.ScaleTop As Single
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften ScaleLeft und ScaleTop beschreiben die Koordinaten des linken oberen Bild-
punkts des Client-Bereichs im aktuellen Koordinatensystem des Objekts.

366
ScaleLeft- Eigenschaft und ScaleTop- Eigenschaft

Anwendung

Anwendung
...................................................
Ändert man die Werte dieser Eigenschaften, bewirkt das eine Ursprungsverschiebung (Transla-
tion) des Koordinatensystems, und als Seiteneffekt erhält die ScaleMode-Eigenschaft den Wert
vbUser (0). In allen vordefinierten Koordinatensystemen liegt der Ursprung in der linken oberen
Ecke des Client-Bereichs, so dass umgekehrt diese Eigenschaften als Seiteneffekt den Wert 0
erhalten, wenn die ScaleMode-Eigenschaft auf einen Wert ungleich vbUser (0) gesetzt wird.
Tipps

Tipps
...................................................
Die richtige Wahl des Koordinatensystems kann so manches Problem vereinfachen und lästige

Gemeinsame Eigenschaften
Umrechnereien ersparen. Da Zeichenoperationen meist auf ein virtuelles Koordinatensystem
bezogen sind, bietet es sich an, den in diesem Koordinatensystem benutzten Ausschnitt so auf
den Ausgabebereich abzubilden, dass die virtuellen Koordinaten mit den Bereichskoordinaten
zusammenfallen. Dazu setzen Sie zunächst die Eigenschaften ScaleHeight, ScaleWidth auf die
Ausdehnung und die Orientierung (Vorzeichen der Werte) des Ausschnitts und verschieben
dann den Ursprung, in dem Sie ScaleLeft, ScaleTop geeignet setzen.
Am einfachsten setzen Sie ein neues Koordinatensystem jedoch mittels der Scale-Methode. Sie
übergeben der Methode einfach den linken oberen und den rechten unteren Punkt des Aus-
schnitts, der im Client-Bereich sichtbar sein soll. Anstelle der im Beispiel verwendeten Befehls-
folge ließe sich somit auch schreiben:
Scale (-2 * Pi, 1) – (2 * Pi, -1)
Beispiel

Beis piel
...................................................
Das folgende einfache Programm gibt die Funktion der dreigliedrigen Sinusreihe für die Appro-
ximation der Rechteckkurve im Intervall [-2π, 2π] aus. Da die Paint-Routine das Koordinaten-
system immer so wählt, dass der Kurvenausschnitt exakt in den Client-Bereich des Formulars
passt, kann der Benutzer die Fenstergröße nach Belieben verändern.
Private Sub Form_Paint()
Dim Pi, x, y
Pi = Atn(1) * 4

ScaleHeight = -2
ScaleWidth = 4 * Pi
ScaleLeft = -2 * Pi
ScaleTop = 1

For x = -2 * Pi To 2 * Pi Step Pi / 200


y = Sin(x) + 1 / 3 * Sin(3 * x) + 1 / 5 * Sin(5 * x)
PSet (x, y)
Next x
End Sub

Private Sub Form_Resize()


Refresh
End Sub
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
ScaleMode, ScaleHeight, ScaleWidth

3 67
Gemeinsame Eigenschaften

Approximation der Rec htec kkurve im Intervall [ - 1 , 1] x[ - 2 π, π


2 ]
Gemeinsame Eigenschaften

Verwandte Methoden

Verwa ndte Metho den


...................................................
Scale, ScaleX, ScaleY

ScaleHeight- Eigenschaft und ScaleWidth- Eigenschaft


Objekt.ScaleHeight As Single
Objekt.ScaleWidth As Single
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die Eigenschaften ScaleHeight und ScaleWidth beschreiben die Abmessungen des Client-
Bereichs des Objekts in Koordinaten des aktuellen Koordinatensystems.
Anwendung

Anwendung
...................................................
Beachten Sie, dass sich über die Scale-Eigenschaften keine Größenänderungen durchführen las-
sen. Ändert man die Werte dieser Eigenschaften, ändert sich lediglich die Maßeinheit für die
jeweilige Richtung. Das heißt, es passiert eine Streckung bzw. Stauchung (Skalierung) der Koor-
dinatenachsen, wobei der linke obere Punkt des Client-Bereichs Fixpunkt ist. Als Seiteneffekt
erhält die ScaleMode-Eigenschaft den Wert vbUser (0). Für die vordefinierten Koordinatensys-
teme sind feste Maßeinheiten definiert, so dass umgekehrt ScaleHeight und ScaleWidth als Sei-
teneffekt neue Werte erhalten, wenn die ScaleMode-Eigenschaft auf einen Wert ungleich vbUser
(0) gesetzt wird.
Standardmäßig ist die vertikale Achse des Koordinatensystems eines Objekts von oben nach
unten und die horizontale Achse von links nach rechts orientiert. Um die Orientierung zu
ändern, müssen Sie der entsprechenden Eigenschaft nur ein anderes Vorzeichen verpassen,
indem Sie ihren Wert mit -1 multiplizieren.
Tipp

Tipp
...................................................
Die richtige Wahl des Koordinatensystems kann so manches Problem vereinfachen und schlim-
mere Rechnereien ersparen. Da Zeichenoperationen meist auf ein virtuelles Koordinatensystem
bezogen sind, bietet es sich an, den in diesem Koordinatensystem benutzten Ausschnitt so auf
den Ausgabebereich abzubilden, dass die virtuellen Koordinaten mit den Bereichskoordinaten
zusammenfallen. Dazu setzen Sie ScaleHeight und ScaleWidth auf die Ausdehnung und Orien-
tierung des Bereichs und verschieben den Ursprung, indem Sie ScaleLeft, ScaleTop auf die
Koordinaten des linken oberen Punkts setzen.

368
ScaleMode- Eigenschaft

Am einfachsten setzen Sie ein neues Koordinatensystem jedoch mittels der Scale-Methode. Sie
übergeben der Methode einfach den linken oberen und den rechten unteren Punkt des Aus-
schnitts, der im Client-Bereich sichtbar sein soll.
Scale (-2 * Pi, 1) – (2 * Pi, -1)
Beispiel

Beis piel
...................................................
Siehe »ScaleHeight-Eigenschaft und ScaleWidth-Eigenschaft«, S. 368.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................

Gemeinsame Eigenschaften
ScaleMode, ScaleLeft, ScaleTop
Verwandte Methoden

Verwa ndte Metho den


...................................................
Scale, ScaleX, ScaleY

ScaleMode- Eigenschaft
Objekt.ScaleMode As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Form, PictureBox, Printer, PropertyPage, UserControl, UserDocument
Beschreibung

Bes c hreibung
...................................................
Die ScaleMode-Eigenschaft bestimmt das Koordinatensystem eines Objekts. Zur Auswahl stehen
elf Koordinatensysteme: ein benutzerdefiniertes sowie zehn vordefinierte. Die vordefinierten
haben allesamt den Ursprung in der linken oberen Ecke des Client-Bereichs, sind in der vertika-
len Richtung von oben nach unten orientiert und unterscheiden sich eigentlich nur in den für
die Koordinatenachsen geltenden Maßeinheiten. Der Aufzählungstyp ScaleModeConstants defi-
niert dafür die folgenden Konstanten:

Konstante (Wert) Beschreibung


vbUser (0) Benutzerdefiniertes Koordinatensystem, das über die Scale-
Methode bzw. über die Eigenschaften ScaleHeight, ScaleLeft, Sca-
leTop, ScaleWidth näher spezifiziert wird
vbTwips (1) Vordefiniertes Koordinatensystem mit der Maßeinheit »Twips«
(Voreinstellung); 56,69286 Twips entsprechen einem Millimeter
und 0,176389 Millimeter einem Twip
vbPoints (2) Vordefiniertes Koordinatensystem mit der Maßeinheit »Punkt«; 1
Punkt entspricht 0,3527781 mm, 2,834643 Punkte entsprechen
einem Millimeter und 72 Punkt einem Zoll
vbPixels (3) Vordefiniertes Koordinatensystem mit der Maßeinheit »Bild-
punkt«; bei einer Auflösung von 1200×1068 entspricht 1 Bild-
punkt logisch 0,2116669 mm, und 4,724405 Bildpunkte
entsprechen einem logischen Millimeter (die physikalischen
Abmessungen hängen von der Geometrie des Bildschirms ab)

3 69
Gemeinsame Eigenschaften

Konstante (Wert) Beschreibung


vbCharacters (4) Vordefiniertes Koordinatensystem mit der Maßeinheit »Zeichen«
(die horizontale und vertikale Skalierung kann hier unterschiedlich
sein und hängt im Allgemeinen von den physikalischen Gegeben-
heiten sowie dem Betriebsmodus des Ausgabegeräts ab)
vbInches (5) Vordefiniertes Koordinatensystem mit der Maßeinheit »Zoll«; 1
Zoll entspricht 25,4 Millimeter und ein Millimeter 0,03937 Zoll
vbMillimeters (6) Vordefiniertes Koordinatensystem mit der Maßeinheit »Millime-
ter»
Gemeinsame Eigenschaften

vbCentimeters (7) Vordefiniertes Koordinatensystem mit der Maßeinheit »Zentime-


ter»
vbHimetric (8) Vordefiniertes Koordinatensystem mit der Maßeinheit »hundertstel
Millimeter«; Visual Basic unterstützt dieses Koordinatensystem
(zur Zeit noch) nicht für Steuerelemente und Formulare! Es ist aber
bei Picture-Objekten (und da ausschließlich) anzutreffen (die
Umrechnung mit ScaleX und ScaleY ist möglich und häufig auch
erforderlich)
vbContainerPosition (9) Wird von Visual Basic (zur Zeit noch) nicht unterstützt
vbContainerSize (10) Wird von Visual Basic (zur Zeit noch) nicht unterstützt

Anwendung

Anwendung
...................................................
Mit einem Wert ungleich 0 für die ScaleMode-Eigenschaft arbeiten Sie, wenn Sie eine bestimmte
Skalierung auf einem Ausgabegerät einführen wollen. So ist beispielsweise die Skalierung Milli-
meter (vbMillimeters) sehr hilfreich, um maßstabsgetreue metrische Zeichnungen auf einem
Drucker auszugeben.
Um ein benutzerdefiniertes Koordinatensystem einzustellen, arbeiten Sie am besten mit der
Methode Scale. Die Methode, die in ihren Parametern eine Beschreibung des sichtbaren Aus-
schnitts in Form eines Koordinatenpaars erwartet, setzt ScaleMode auf den Wert vbUser (0) und
richtet das Koordinatensystem so ein, dass das angegebene Koordinatenpaar auf den linken
oberen und den rechten unteren Punkt im Client-Bereich abgebildet wird.
Tipp

Tipp
...................................................
Da es die Druckwerke einiger Drucker meist nicht so ganz genau mit den Größenverhältnissen
nehmen (Toleranzen im Bereich von 1 % sind normal), lässt sich die Skalierung im Einzelfall
nachbessern, indem man ein Quadrat fester Länge ausgibt (bei A4 ist beispielsweise die Kanten-
länge 190 mm gut geeignet):
Printer.ScaleMode = vbMillimeters
Printer.Line(0,0)-(190, 190)
Printer.EndDoc
dieses dann nachmisst und unter Berücksichtigung von Korrekturfaktoren ein benutzerdefinier-
tes Koordinatensystem einführt:
Printer.ScaleWidth = Printer.ScaleWidth * (MesswertBreiteInMM / 190)
Printer.ScaleHeight = Printer.ScaleHeight * (MesswertHöheInMM / 190)

370
ShowTips- Eigenschaft

Beispiel

Beis piel
...................................................
Der folgende Code gibt den Namen, die Papiergröße und die bedruckbare Fläche (Client-
Bereich) des Standarddruckers aus. Da sich ScaleMode nur auf den Client-Bereich auswirkt,
müssen die Eigenschaften Height und Width mittels der Methoden ScaleX und ScaleY in die gel-
tenden Maßeinheiten umgerechnet werden.
With Printer
.ScaleMode = vbMillimeters
.PaperSize = vbPRPSA4
Print .DeviceName

Gemeinsame Eigenschaften
Print .ScaleX(.Height, vbTwips, vbMillimeters),
Print .ScaleX(.Width, vbTwips, vbMillimeters)
Print .ScaleHeight, .ScaleWidth
End With

Papiergröße und bedruckbarer Bereich des Standarddruckers

Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
ScaleHeight, ScaleWidth, ScaleLeft, ScaleTop
Verwandte Methoden

Verwa ndte Metho den


...................................................
Scale, ScaleX, ScaleY

ShowTips- Eigenschaft
Objekt.ShowTips As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
TabStrip, StatusBar, ToolBar
Beschreibung

Bes c hreibung
...................................................
Die ShowTips-Eigenschaft bestimmt, ob die in der Eigenschaft ToolTipText definierte Zeichen-
folge als QuickInfo für das Steuerelement zur Anzeige kommt (True) oder nicht (False). Das
QuickInfo-Fensterchen erscheint, wenn die Maus in den Bereich des Steuerelements gelangt und
dort ca. eine halbe Sekunde verweilt.
Anwendung

Anwendung
...................................................
Visual Basic unterstützt vier verschiedene Techniken, um für den Benutzer einer Anwendung
Hilfe bereitzustellen: QuickInfo, Statusanzeige, Direkthilfe und kontextbezogene Hilfe. Die ers-
ten beiden Techniken bieten dem Benutzer unaufgefordert und in knapper Form Hilfestellung
für den Umgang mit der Benutzerumgebung. Um eine QuickInfo für ein Steuerelement bereitzu-
stellen, weisen Sie der Eigenschaft ToolTipText eine Zeichenfolge mit dem Hilfetext zu und set-
zen – sofern vorhanden – die ShowTips-Eigenschaft auf True. Die Zeichenfolge sollte nicht zu
lang sein, da die Anzeige einzeilig ist.

371
Gemeinsame Eigenschaften

Style- Eigenschaft
Objekt.Style As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Band, Button, CheckBox, CommandButton, ComboBox, DataCombo, ListBox, OptionButton,
SSTab, StatusBar, TabStrip, TreeView
Beschreibung

Bes c hreibung
...................................................
Die Style-Eigenschaft bestimmt den Darstellungsstil eines Steuerelements. Die Tabelle gibt
einen Überblick über die Konstanten, die für die Stile der einzelnen Steuerelemente definiert
Gemeinsame Eigenschaften

sind.

Konstante (Wert) Gilt für Objekt Beschreibung


cc3BandNormal (0) Band Der Benutzer kann Größe des Bandes ändern
(Voreinstellung).
cc3BandFixedSize (1) Band Die Bandgröße ist unveränderlich.
sbrNormal (0) StatusBar Die Statusleiste enthält mehrere Bereiche in Form
von Panel-Objekten (Voreinstellung).
sbrSimple (1) StatusBar Die Statusleiste enthält nur einen Bereich (Panel-
Objekt) und Text wird durch Setzen der Simple-
Text-Eigenschaft ausgegeben.
sbrText (0) Panel Der Statusleistenbereich kann Text und/oder ein
Bild anzeigen (Voreinstellung).
sbrCaps (1) Panel Der Statusleistenbereich zeigt den Zustand der
Feststellfunktion für (Umschalt) an.
sbrNum (2) Panel Der Statusleistenbereich zeigt den Zustand der
Feststellfunktion für (Num) an.
sbrIns (3) Panel Der Statusleistenbereich zeigt den Zustand der
Funktion Einfügen/Überschreiben an.
sbrScrl (4) Panel Der Statusleistenbereich zeigt den Zustand der
Feststellfunktion für (Rollen) an.
sbrTime (5) Panel Der Statusleistenbereich zeigt die Systemzeit an.
sbrDate (6) Panel Der Statusleistenbereich zeigt das Systemdatum
an.
sbrKana (7) Panel Statusleistenbereich zeigt den Zustand der Fest-
stellfunktion für (Kana) an (nur für japanische
Version des Betriebssystems relevant).
ssStyle_ SSTab Die in den Dialogfeldern mit Registerdarstellung
TabbedDialog (0) erscheinenden Register sehen genauso aus wie in
den Anwendungen von Microsoft Office für
Microsoft Windows 3.1. Die Schrift im Register
der aktiven Registerkarte erscheint fett (Vorein-
stellung).

372
Style- Eigenschaft

Konstante (Wert) Gilt für Objekt Beschreibung


ssStyle_ SSTab Die in den Dialogfeldern erscheinenden Register
PropertyPage (1) sind im Stil von Windows 9x gehalten. Die Tab-
MaxWidth-Eigenschaft wird ignoriert und die
Beschriftung des ausgewählten Registers auch
nicht fett dargestellt.
tabTabs (0) TabStrip Die Registerkarten erscheinen wie Register in
einem Notizbuch (Voreinstellung).
tabButtons (1) TabStrip Die Registerkarten enthalten eine Schaltfläche als

Gemeinsame Eigenschaften
Register.
tabFlatButtons (2) TabStrip Die Registerkarten enthalten eine Schaltfläche als
Register, die nur im gedrückten Zustand in 3D-
Darstellung gezeichnet werden, ansonsten in 2D-
Darstellung.
tbrDefault (0) Button Die Schaltfläche ist Befehlsschaltfläche (Vorein-
stellung).
tbrCheck (1) Button Die Schaltfläche ist Schalter.
tbrButtonGroup (2) Button Die Schaltfläche ist Element einer Schaltergruppe,
in der immer nur ein Schalter »gedrückt« sein
kann.
tbrSeparator (3) Button Die Schaltfläche ist Trennlinie.
tbrPlaceholder (4) Button Die Schaltfläche sieht aus wie eine Trennlinie, ist
aber Platzhalter und von der Breite her veränder-
bar.
tbrDropDown (5) Button Der Schaltfläche ist ein Menü (MenuButton-
Objekte) zugeordnet.
tbrStandard (0) ToolBar Symbolleiste hat standardmäßige Darstellung
(Voreinstellung).
tbrTransparent (1) ToolBar Schaltflächen und Symbolleiste sind durchsichtig,
Schaltfläche enthält Beschriftung unter Bitmap,
und Hot Tracking ist aktiviert.
tbrRight (2) ToolBar Wie tbrTransparent, die Beschriftung erscheint
jedoch rechts neben der Bitmap.
tvwTextOnly (0) TreeView Knotenobjekte (Node) werden als reiner Text
angezeigt.
tvwPictureText (1) TreeView Knotenobjekte (Node) werden als Text mit Bild
angezeigt.
tvwPlusMinusText (2) TreeView Knotenobjekte (Node) werden als Text mit Plus-/
Minussymbol (Teilbaum sichtbar/unsichtbar)
angezeigt.
tvwPlusPicture TreeView Knotenobjekte (Node) werden als Text mit Plus-/
Text (3) Minussymbol und Bild angezeigt.

373
Gemeinsame Eigenschaften

Konstante (Wert) Gilt für Objekt Beschreibung


tvwTreelinesText (4) TreeView Knotenobjekte (Node) werden als Text mit
Abhängigkeitslinien (unter Beachtung der Line-
Style-Eigenschaft) angezeigt.
tvwTreelinesPicture TreeView Knotenobjekte (Node) werden als Text mit Bild
Text (5) und Abhängigkeitslinien (unter Beachtung der
LineStyle-Eigenschaft) angezeigt.
tvwTreelinesPlus TreeView Knotenobjekte (Node) werden als Text mit Plus-/
MinusText (6) Minussymbol und Abhängigkeitslinien (unter
Gemeinsame Eigenschaften

Beachtung der LineStyle-Eigenschaft) angezeigt


tvwTreelinesPlus TreeView Knotenobjekte (Node) werden als Text mit Plus-/
MinusPictureText (7) Minussymbol, Bild und Abhängigkeitslinien
(unter Beachtung der LineStyle-Eigenschaft)
angezeigt.
vbButtonStandard (0) CheckBox, Das Steuerelement wird im Stil von Windows 9x
OptionButton, dargestellt.
CommandButton
vbButtonGraphical (1) CheckBox, Das Steuerelement wird mit benutzerdefinierten
OptionButton, Grafiken (für die Zustände »normal«,
CommandButton »gedrückt« und »inaktiv«) dargestellt.
vbListBoxStandard (0) ListBox Das Listenfeld wird als einfaches Listenfeld mit
Texteinträgen dargestellt.
vbListBoxCheckBox (1) ListBox Das Listenfeld wird als Listenfeld mit ankreuzba-
ren Einträgen (Kontrollkästchen neben den Tex-
teinträgen) dargestellt.
vbComboDropDown (0) ComboBox, Das Kombinationsfeld wird als Textfeld mit
dbcDropDownCombo (0) DataCombo Pfeilschaltfläche dargestellt. Der Benutzer kann
einen Wert in das Textfeld eingeben oder die
anhängende Liste öffnen und einen Eintrag dar-
aus wählen (Voreinstellung).
vbComboSimple (1) ComboBox, Das Kombinationsfeld wird als Textfeld über
dbcSimpleCombo (1) DataCombo einem Listenfeld dargestellt. Die Liste bleibt stän-
dig sichtbar. Ihre Höhe wird durch die Height-
Eigenschaft bestimmt.
vbCombo ComboBox, Das Kombinationsfeld wird als Textfeld mit
DropDownList (2) DataCombo Pfeilschaltfläche dargestellt. Der Benutzer kann
dbcDropDownList (2) keine Eingaben in das Textfeld vornehmen, son-
dern muss einen Eintrag aus der anhängenden
Liste wählen.

Verwandte Eigenschaften

...................................................
Verwa ndte Eigens c ha ften
BorderStyle

37 4
TabIndex- Eigenschaft

TabIndex- Eigenschaft
Objekt.TabIndex As Integer
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle sichtbaren Steuerelemente, nicht jedoch Data, Line, Shape, Menu
Beschreibung

Bes c hreibung
...................................................
Die TabIndex-Eigenschaft ordnet einem Objekt eine Position in der Tabulatorordnung des Con-
tainers zu und regelt insbesondere die Fokusweitergabe bei Verwendung der Tabulatortaste.
Die Zählung beginnt üblicherweise bei 0 kann aber auch mit 1 begonnen werden.

Gemeinsame Eigenschaften
Anwendung

Anwendung
...................................................
Die durch die TabIndex-Eigenschaft festgelegte Tabulatorordnung bestimmt die Aktivierreihen-
folge der Steuerelemente, wenn der Benutzer mit (Tab) bzw. (Umschalt)+(Tab) navigiert. Der
Entwurfseditor von Visual Basic legt die Tabulatorordnung nach der Reihenfolge des Einfügens
der Steuerelemente in das Formular (bzw. in die Komponente) fest und setzt dabei die TabIndex-
Eigenschaft, mit der Zählung von 0 beginnend, auf den entsprechenden Wert. Auch Steuerele-
mente, die den Fokus nicht entgegennehmen können – weil sie nicht dafür konzipiert sind oder
ihre TabStop-Eigenschaft auf False gesetzt ist –, spielen eine wichtige Rolle für die Tabulator-
ordnung, da sie Zugriffstasten definieren können. Eine Zugriffstaste ((Alt) plus unterstrichenes
Zeichen in der Beschriftung) ermöglicht es dem Benutzer, den Fokus per Tastatur auf ein
bestimmtes Steuerelement zu verschieben. Sie definieren eine Zugriffstaste für ein Steuerele-
ment, indem Sie dem entsprechenden Zeichen in der Beschriftung des Steuerelements (Caption-
Eigenschaft) ein »&«-Zeichen voranstellen. Falls ein Steuerelement, das den Fokus erhalten
kann, selbst keine Beschriftung besitzt, sondern auf ein Bezeichnungsfeld (Label) angewiesen ist,
lässt sich die Zugriffstaste über die Caption-Eigenschaft des Bezeichnungsfelds festlegen, sofern
dessen UseMnemonic-Eigenschaft auf True gesetzt ist. Dabei ist es wichtig, dass das Bezeichnungs-
feld in der Tabulatorordnung vor dem besagten Steuerelement kommt, das heißt, dass der Wert
seiner TabIndex-Eigenschaft kleiner ist. (Natürlich sollte in der Tabulatorordnung zwischen dem
Steuerelement und seinem Bezeichnungsfeld kein weiteres Steuerelement sitzen, das den Fokus
annehmen kann). Durch Verwendung mehrerer Bezeichnungsfelder lassen sich so sogar prob-
lemlos mehrere Zugriffstasten für ein und dasselbe Steuerelement definieren. Unsichtbare oder
deaktivierte Steuerelemente verbleiben in der Tabulatorreihenfolge, werden aber bei der Fokus-
weitergabe übersprungen.
Beim Entwurf eines Formulars lohnt es sich, gleich beim Einfügen der Steuerelemente auf die
richtige Reihenfolge zu achten – insbesondere also Bezeichnungsfelder vor den zugehörigen
Steuerelementen zu platzieren. Natürlich lässt sich die TabIndex-Eigenschaft jederzeit auch
nachträglich ändern. Dafür sollten Sie wissen, dass der Entwurfseditor von Visual Basic die
TabIndex-Werte zweier Steuerelemente automatisch austauscht, wenn Sie einem Steuerelement
den Wert eines anderen zuordnen.
In seltenen Fällen werden Sie vielleicht die Aktivierreihenfolge zur Laufzeit ändern wollen – ein
automatischer Austausch findet dann aber nicht statt, so dass Sie die TabIndex-Werte aller Steu-
erelemente neu setzen müssen, die eine andere Position in der Tabulatorordnung erhalten sol-
len. Vom Prinzip her ist es zwar unproblematisch, zwei oder mehreren Steuerelementen den
gleichen TabIndex-Wert zuzuordnen, allerdings wird die Aktivierreihenfolge unter diesen Ele-
menten dann zu einem Produkt des Zufalls. »Mut zur Lücke« bei der Tabulatorordnung wird
zwar nicht bestraft, die Ordnung sollte aber nach Möglichkeit fortlaufend sein (und mit 0 oder
1 beginnen), weil nicht nur der Entwurfseditor, sondern auch das Laufzeitsystem (so beim
Laden einer neuen Steuerelementinstanz mit Load) bemüht ist, eine fortlaufende Ordnung

375
Gemeinsame Eigenschaften

durchzusetzen. Wenn Sie einem Steuerelemente-Array mittels Load ein weiteres Element hinzu-
fügen, erhält dieses vom Laufzeitsystem automatisch die jeweils letzte Position in der Tabula-
torordnung.
Die ZOrder-Methode hat nichts mit der TabIndex-Eigenschaft zu tun. Sie regelt die Zeichenrei-
henfolge der Steuerelemente.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
Caption

TabStop- Eigenschaft
Gemeinsame Eigenschaften

Objekt.TabStop As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, DataCombo, DataGrid, DataList,
DataRepeater, DateTimePicker, DirListBox, DriveListBox, FileListBox, HScrollBar, Image-
Combo, ListView, ListBox, MaskEdBox, MonthView, MSChart, MSFlexGrid, MSHFlexGrid, OLE,
OptionButton, PictureBox, RichTextBox, Slider, SSTab, TabStrip, TextBox, TreeView,
UpDown, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Die TabStop-Eigenschaft bestimmt, ob ein Element den Fokus durch Weiterschaltung mit (Tab)
oder (Umschalt)+(Tab) oder per Zugriffstaste erhalten kann (True; Voreinstellung) oder nicht
(False).
Anwendung

Anwendung
...................................................
Der Benutzer hat mehrere Möglichkeiten, den Eingabefokus auf ein bestimmtes Steuerelement
zu setzen: per Tabulatortaste, per Zugriffstaste, per Mausklick und per Pfeiltasten. Die ersten
beiden Möglichkeiten unterliegen dem Einfluss der TabStop-Eigenschaft, die anderen beiden
nicht. Steuerelemente, deren Visible-Eigenschaft oder Enabled-Eigenschaft auf False gesetzt ist,
können den Fokus überhaupt nicht erhalten.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
Visible, Enabled

Tag- Eigenschaft
Objekt.Tag As String
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Formulare, Komponenten und Steuerelemente
Beschreibung

Bes c hreibung
...................................................
Die Tag-Eigenschaft wird von Visual Basic nicht beachtet und steht daher für benutzerdefinierte
Zwecke zur Verfügung.
Anwendung

Anwendung
...................................................
Die Tag-Eigenschaft ist recht hilfreich, wenn es darum geht, ohne viel Aufwand und ohne den
Wert von Eigenschaften wie Caption zu verändern, zusätzliche Informationen an ein Objekt zu
»heften«. So kann man diese Eigenschaft beispielsweise dafür verwenden, unterschiedliche

37 6
ToolTipText- Eigenschaft

Instanzen eines Formulars unterschiedlich zu benennen, um sie auseinander halten zu können.


Vom Prinzip her würde sich für den Zweck der reinen Unterscheidung auch die hWnd-Eigen-
schaft anbieten, doch diese kann sich zur Laufzeit bekanntlich auch ändern.

ToolTipText- Eigenschaft
Objekt.ToolTipText As String
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, Button, CheckBox, ComboBox, CommandButton, CoolBar, Data, DataCombo,
DataGrid, DataList, DataRepeater, DateTimePicker, DirListBox, DriveListBox, FileList-

Gemeinsame Eigenschaften
Box, FlatScrollBar, Frame, Image, ImageCombo, Label, ListItem, ListSubItem, ListView,
ListBox, MaskEdBox, MMContol, MonthView, MSChart, MSFlexGrid, MSHFlexGrid, OptionBut-
ton, Panel, PictureBox, ProgressBar, RemoteData, RichTextBox, Slider, SSTab, StatusBar,
Tab, TabStrip, TextBox, TreeView, UpDown
Beschreibung

Bes c hreibung
...................................................
Die ToolTipText-Eigenschaft bestimmt den Text für die Anzeige der QuickInfo.
Anwendung

Anwendung
...................................................
Visual Basic unterstützt vier verschiedene Techniken, um für den Benutzer einer Anwendung
Hilfe bereitzustellen: QuickInfo, Statusanzeige, Direkthilfe, und kontextbezogene Hilfe. Die
ersten beiden Techniken bieten dem Benutzer unaufgefordert und in knapper Form Hilfestel-
lung für den Umgang mit der Benutzerumgebung. Um eine QuickInfo für ein Steuerelement
bereitzustellen, weisen Sie der Eigenschaft ToolTipText eine Zeichenfolge mit dem Hilfetext zu
und setzen – sofern vorhanden – die ShowTips-Eigenschaft auf True. Die Zeichenfolge sollte
nicht zu lang sein, da die Anzeige einzeilig ist.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
HelpContextID, ShowTips, WhatsThisButton, WhatsThisHelp, WhatsThisHelpID

UseMaskColor- Eigenschaft
Objekt.UseMaskColor As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
CheckBox, CommandButton, OptionButton, ImageList
Beschreibung

Bes c hreibung
...................................................
Die UseMaskColor-Eigenschaft bestimmt, ob die für die MaskColor-Eigenschaft gesetzte Farbe für
die Maskierung transparenter Bereiche verwendet wird (True) oder nicht (False).
Anwendung

Anwendung
...................................................
Bei Schaltflächen, Optionsfeldern und Kontrollkästchen mit benutzerdefinierter Darstellung
ermöglicht die UseMaskColor-Eigenschaft das Ein- und Ausschalten der Pseudotransparenz (vgl.
»MaskColor-Eigenschaft«, S. 358). Gleiches gilt für Steuerelemente, die anders als die genannten
Steuerelemente standardmäßig mit Bildern eines ImageList-Objekts arbeiten. Sie sind darauf
angewiesen, dass die UseMaskColor-Eigenschaft des ImageList-Objekts gesetzt ist, die sich dann
immer für alle Bilder in der Liste auswirkt.

377
Gemeinsame Eigenschaften

Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
MaskColor

Visible- Eigenschaft
Objekt.Visible As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, Band, Button, ButtonMenu, CheckBox, ComboBox, CommandButton, Data,
DataCombo, DataGrid, DataList, DataRepeater, DateTimePicker, DirListBox, DriveListBox,
Gemeinsame Eigenschaften

FileListBox, FlatScrollBar, Form, Frame, HScrollBar, Image, ImageCombo, Label, Line,


ListView, ListBox, MaskEdBox, MDIForm, MMControl, MonthView, MSChart, MSFlexGrid, MSH-
FlexGrid, Node, OLE, OptionButton, Panel, PictureBox, ProgressBar, RemoteData, RichText-
Box, RptFunction, RptLine, RptImage, RptLabel, RptShape, RptTextBox, RptSection, Shape,
Slider, SSTab, StatusBar, TabStrip, TextBox, ToolBar, TreeView, UpDown, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Die Visible-Eigenschaft bestimmt, ob ein Objekt sichtbar ist (True) oder nicht (False). Unsicht-
bare Objekte können den Fokus nicht erhalten.
Anwendung

Anwendung
...................................................
Um ein Formular aus- oder einzublenden, können Sie wahlweise die Methoden Show und Hide
aufrufen oder die Visible-Eigenschaft auf False bzw. True setzen.
Wenn Sie eine neue Instanz für ein Steuerelemente-Array zur Laufzeit anlegen, »erbt« diese die
meisten Eigenschaften der Instanz mit dem niedrigsten Index. hWnd erhält natürlich einen ande-
ren Wert, und die Visible-Eigenschaft trägt standardmäßig den Wert False.
Verwandte Eigenschaften

Verwa ndte Eigens c ha ften


...................................................
Enabled

WhatsThisHelp- Eigenschaft
Objekt.WhatsThisHelp As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, DataGrid, Form, MDIForm, MSFlexGrid
Beschreibung

Bes c hreibung
...................................................
Die WhatsThisHelp-Eigenschaft bestimmt, ob die Hilfetaste (F1) die Direkthilfe in einem Popup-
Fenster (True) oder die kontextbezogene Hilfe im Windows-Hilfesystem (False) anzeigt.
Anwendung

Anwendung
...................................................
Vgl. »HelpContextID-Eigenschaft und WhatsThisHelpID-Eigenschaft«, S. 353.

WhatsThisHelpID- Eigenschaft
Siehe »HelpContextID-Eigenschaft und WhatsThisHelpID-Eigenschaft«, S. 353.

37 8
Width- Eigenschaft

Width- Eigenschaft
Siehe »Height-Eigenschaft und Width-Eigenschaft«, S. 351.

Gemeinsame Methoden
Auch bei den Methoden haben die Steuerelemente einiges an Gemeinsamkeiten zu bieten, die
meisten Steuerelemente besitzen jedoch ungleich weniger Methoden als Eigenschaften. Natür-
lich relativiert sich diese Aussage, wenn man bedenkt, dass die Eigenschaften COM-konformer
Objekte nicht als schlichte Datenelemente mit öffentlichem Geltungsbereich implementiert sind,
sondern über Property-Methoden, die für den entsprechenden prozeduralen Unterbau sorgen.

Gemeinsame Methoden
Mithin sind Eigenschaften also auch Methoden.
Die folgende Tabelle gibt einen Überblick über die Methoden, die bei der Besprechung der ein-
zelnen Steuerelemente sowie des Formularobjekts nicht extra diskutiert werden:

Methode Beschreibung
Drag Leitet eine Drag&Drop-Operation für das Steuerelement manuell ein
LinkExecute Versendet ein DDE-Kommando an das Quellobjekt einer bestehenden
DDE-Verbindung
LinkPoke Ändert den Wert des als Datenlieferant fungierenden Steuerelements auf-
seiten des Quellobjekts einer bestehenden DDE-Verbindung
LinkRequest Fordert das Quellobjekt einer bestehenden DDE-Verbindung auf, den
Wert des Zielobjekts zu aktualisieren
LinkSend Schickt dem Zielobjekt einer bestehenden DDE-Verbindung ein LinkNo-
tify-Ereignis, damit dieses seine LinkRequest-Methode zur erneuten Syn-
chronisation aufruft
Move Ändert Position und Abmessungen des Objekts innerhalb des Containers
OleDrag Leitet eine OLE-Drag&Drop-Operation für ein Steuerelement ein
Refresh Veranlasst das Objekt, seinen Zustand sowie seine Darstellung zu aktuali-
sieren
SetFocus Fordert den Fokus für das Steuerelement an
ShowWhatsThis Zeigt die Direkthilfe für das Steuerelement an
ZOrder Setzt das Steuerelement an die vorderste oder hinterste Position der Anzei-
gereihenfolge

Drag- Methode
Sub Objekt.Drag(Action As Integer)
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, CoolBar, Data, DataCombo, DataGrid,
DataList, DataRepeater, DateTimePicker, DirListBox, DriveListBox, FileListBox, FlatS-
crollBar, Frame, HScrollBar, Image, ImageCombo, Label, ListView, ListBox, MaskEdBox,
MMControl, MonthView, MSChart, MSFlexGrid, MSHFlexGrid, OLE, OptionButton, PictureBox,
ProgressBar, RemoteData, RichTextBox, Slider, SSTab, StatusBar, TabStrip, TextBox, Tool-
Bar, TreeView, UpDown, VScrollBar

379
Gemeinsame Methoden

Beschreibung

Bes c hreibung
...................................................
Die Drag-Methode dient der codeseitigen Steuerung von Drag&Drop-Operationen für Objekt
im manuellen oder automatischen Modus (vgl. DragMode). Für den Parameter Action sind über
den Aufzählungstyp DragConstants drei Werte definiert: vbBeginDrag (1) startet eine
Drag&Drop-Operation; vbEndDrag (2) beendet die aktuelle Drag&Drop-Operation; vbCancel
(0) bricht die aktuelle Drag&Drop-Operation ab. Wird Drag im Verlauf einer Drag&Drop-
Operation mit dem Wert vbEndDrag aufgerufen, erhält das unter dem Mauszeiger befindliche
Objekt ein DragDrop-Ereignis.
Anwendung

Anwendung
...................................................
Gemeinsame Methoden

Die explizite Steuerung von Drag&Drop-Vorgängen ist im Allgemeinen nur erforderlich, wenn
ein Objekt, dessen DragMode-Eigenschaft auf vbManual (0; Voreinstellung) gesetzt ist, eine
Drag&Drop-Operation eingehen soll. Das kann beispielsweise der Fall sein, wenn eine Steue-
rung der Operation mit der Tastatur oder der rechten Maustaste erwünscht ist.
Beispiel

Beis piel
...................................................
Der folgende Code implementiert Drag&Drop mit der rechten Maustaste für ein Bezeichnungs-
feld:
Private Sub Label1_MouseDown(Button As Integer, Shift As Integer, _
X As Single, Y As Single)
If Button = vbRightButton Then Label1.Drag vbBeginDrag
End Sub
Verwandte Methoden

Verwa ndte Metho den


...................................................
DragDrop, DragIcon, DragMode, DragOver
Verwandte Themen

Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)

LinkExecute- Methode
Sub Objekt.LinkExecute (Command As String) As Boolean
Betroffene Objekte

Betro ffene Objekte


...................................................
Label, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Die Methode LinkExecute ermöglicht es dem Zielobjekt einer bestehenden DDE-Verbindung,
eine Kommandozeichenfolge an das in einer anderen Anwendung gelegene Quellobjekt (For-
mular) zu senden. Aufseiten des Quellobjekts löst die Methode ein LinkExecute-Ereignis aus.
Der erste Parameter des Ereignisses übermittelt die Zeichenfolge, den zweiten Parameter muss
das Quellobjekt bei erfolgreicher Behandlung auf 0 setzen, sonst tritt beim Zielobjekt ein Lauf-
zeitfehler auf.
Anwendung

Anwendung
...................................................
Um die LinkExecute-Methode ausführen zu können, muss zuvor eine DDE-Verbindung mit der
Quellanwendung eröffnet worden sein. Für den Verbindungsaufbau ist es nötig, die Eigenschaft
LinkTopic mit einer geeigneten Verbindungsinformation zu versorgen und danach die Eigen-

380
LinkPoke- Methode

schaft LinkMode auf einen Wert ungleich 0 zu setzen. Falls kein Laufzeitfehler 282 auftritt, kann
das Zielobjekt davon ausgehen, dass die Verbindung besteht, und mit der Übermittlung von
DDE-Kommandos beginnen. Da es keinen feststehenden Kommandosatz für DDE-Verbindun-
gen gibt, unterliegt die Ausgestaltung der Kommandos sowie deren Interpretation allein der
Fantasie des Programmierers.
Beispiel

Beis piel
...................................................
' Im Modul des Zielobjekts
...
Text1.LinkExecute("Beenden")

Gemeinsame Methoden
...

' Im Modul der Quellobjekts


Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)
If CmdStr = "Beenden" Then
Cancel = False ' Kommando erkannt!
Unload Me ' Kommando ausführen
End If
End Sub
Verwandte Methoden

Verwa ndte Metho den


...................................................
LinkClose, LinkError, LinkExecute, LinkItem, LinkMode, LinkNotify, LinkOpen, LinkPoke,
LinkRequest, LinkSend, LinkTopic
Verwandte Themen

Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)

LinkPoke- Methode
Sub Objekt.Poke()
Betroffene Objekte

Betro ffene Objekte


...................................................
Label, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Die Methode LinkPoke ermöglicht es dem Zielobjekt einer bestehenden DDE-Verbindung, den
Wert seiner Standardeigenschaft dem als Datenlieferant fungierenden Steuerelement aufseiten
der Quellanwendung aufzuoktroyieren – lies: eine Synchronisation in umgekehrter Richtung
vorzunehmen.
Anwendung

Anwendung
...................................................
In der Regel übermittelt bei einer DDE-Verbindung der Datenlieferant des Quellobjekts seinen
Wert an das Zielobjekt. In speziellen Situation kann es jedoch erforderlich sein, diese Beziehung
umzukehren und LinkPoke einzusetzen. Beachten sie aber, dass nicht alle DDE-Serveranwen-
dungen den Einsatz von LinkPoke akzeptieren.
Die Standardeigenschaften der betroffenen Steuerelemente sind: Text für das Textfeld, Picture
für das Bildfeld und Caption für das Bezeichnungsfeld.

3 81
Gemeinsame Methoden

Verwandte Methoden

Verwa ndte Metho den


...................................................
LinkClose, LinkError, LinkExecute, LinkItem, LinkMode, LinkNotify, LinkOpen, LinkRe-
quest, LinkSend, LinkTopic
Verwandte Themen

Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)

LinkRequest- Methode
Sub Objekt.LinkRequest()
Gemeinsame Methoden

Betroffene Objekte

Betro ffene Objekte


...................................................
Label, PictureBox, TextBox
Beschreibung

Bes c hreibung
...................................................
Die Methode LinkRequest fordert die Quellanwendung einer bestehenden DDE-Verbindung
auf, den Wert des Zielobjekts mit dem Wert des Datenlieferanten zu synchronisieren.
Anwendung

Anwendung
...................................................
Der Aufruf der LinkRequest-Methode findet im Allgemeinen in Reaktion auf das LinkNotify-
Ereignis statt. Je nach Wert der LinkMode-Eigenschaft des Zielobjekts gibt es verschiedene Sze-
narien für die Synchronisation zwischen Quelle und Ziel. Hat LinkMode den Wert vbLinkAutoma-
tic (1) und handelt es sich bei dem zu synchronisierenden Wert um eine Zeichenfolge, sorgt die
Quellanwendung für die automatische Synchronisation, sobald sich aufseiten der Quelle eine
Wertänderung ergibt – ein Aufruf von LinkRequest ist dann nur erforderlich, wenn der Wert
aufseiten des Zielobjekts etwa durch Benutzeraktivitäten verloren gegangen ist. Wenn es sich
im Automatikmodus bei dem zu synchronisierenden Wert um ein Bild handelt oder LinkMode
den Wert vbLinkNotify (3) hat, schickt die Quellanwendung dem Zielobjekt ein LinkNotify-
Ereignis, damit dieses je nach Bedarf die Synchronisation explizit mittels LinkRequest vorneh-
men kann. Hat LinkMode den Wert vbLinkManual (2), liegt es allein am Zielobjekt, die Synchro-
nisation mit LinkRequest anzustoßen; eine Benachrichtigung über Wertänderungen findet nicht
statt.
Verwandte Methoden

Verwa ndte Metho den


...................................................
LinkClose, LinkError, LinkExecute, LinkItem, LinkMode, LinkNotify, LinkOpen, LinkPoke,
LinkSend, LinkTopic
Verwandte Themen

Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)

LinkSend- Methode
Sub Objekt.LinkSend()
Betroffene Objekte

Betro ffene Objekte


...................................................
Label, PictureBox, TextBox

382
Move- Methode

Beschreibung

Bes c hreibung
...................................................
Die LinkSend-Methode ermöglicht es dem Quellobjekt einer bestehenden DDE-Verbindung, das
Zielobjekt über eine Wertänderung des als Datenlieferant fungierenden Steuerelements zu infor-
mieren. Die Benachrichtigung erfolgt in Form des LinkNotify-Ereignisses.
Anwendung

Anwendung
...................................................
Änderungen in Textwerten signalisiert das Quellobjekt automatisch. Der Einsatz der LinkSend-
Methode ist also nur im Zusammenhang mit Bildern notwendig, deren ständige Synchronisa-
tion nur in seltenen Fällen wirklich erwünscht ist. Das Zielobjekt reagiert auf das von der Link-

Gemeinsame Methoden
Send-Methode ausgelöste LinkNotify-Ereignis bei Bedarf mit einem LinkRequest-Aufruf, der
schließlich die Synchronisation bewirkt.
Verwandte Methoden

Verwa ndte Metho den


...................................................
LinkClose, LinkError, LinkExecute, LinkItem, LinkMode, LinkNotify, LinkOpen, LinkPoke,
LinkSend, LinkTopic
Verwandte Themen

Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)

Move- Methode
Sub Objekt.Move(Left, [Top], [Width], [Height])
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle sichtbaren Steuerelemente und Formularobjekte
Beschreibung

Bes c hreibung
...................................................
Die Move-Methode erlaubt es, die Position sowie die Abmessungen des Steuerelements zu verän-
dern. Der Parameter Left ist obligatorisch, die anderen drei Parameter sind optional.
Anwendung

Anwendung
...................................................
Vom Prinzip her macht es keinen Unterschied, ob Sie die Eigenschaften Left, Top, Width oder
Height explizit auf andere Werte setzen oder die Move-Methode dafür verwenden, die Move-
Methode wird allerdings etwas schneller ausgeführt, wenn mehr als eine Eigenschaft einen
neuen Wert erhalten soll.

OLEDrag- Methode
Sub Objekt.OLEDrag()
Betroffene Objekte

Betro ffene Objekte


...................................................
Animation, CheckBox, ComboBox, CommandButton, CoolBar, Data, DataCombo, DataList,
DateTimePicker, DirListBox, DriveListBox, FileListBox, Form, Frame, Image, ImageCombo,
Label, ListView, ListBox, MaskEdBox, MDIForm, MMControl, MonthView, MSChart, MSFlexGrid,
MSHFlexGrid, OptionButton, PictureBox, ProgressBar, PropertyPage, RichTextBox, Slider,
SSTab, StatusBar, TabStrip, TextBox, ToolBar, TreeView, UpDown, UserControl, UserDocu-
ment

3 83
Gemeinsame Methoden

Beschreibung

Bes c hreibung
...................................................
Die OLEDrag-Methode ermöglicht die codeseitige Einleitung von OLE-Drag&Drop-Operationen
im manuellen oder automatischen Modus (vgl. OLEDragMode) und löst insbesondere aufseiten des
Quellobjekts das OLEStartDrag-Ereignis aus.
Anwendung

Anwendung
...................................................
Im Gegensatz zur Drag-Methode ist der Aufruf von OLEDrag parameterlos, da die weitere Steue-
rung der Operation durch OLE-Ereignisse geschieht und ein Abbruch oder gezieltes Beenden
der Operation vonseiten des Quellobjekts her nicht vorgesehen ist. Das Quellobjekt kann die
Gemeinsame Methoden

Operation allenfalls »sabotieren«, indem es auf das OLESetData-Ereignis hin keine Daten bereit-
stellt. Da eine begonnene OLE-Drag&Drop-Operation durch Loslassen der Maustaste abge-
schlossen wird, dürfte es wenig Sinn machen, OLEDrag in einem anderen Szenario als während
der Behandlung eines MouseDown-Ereignisses aufzurufen – schließlich muss der Benutzer die
Maustaste irgendwann loslassen, was dann den Abschluss der Operation sicherstellt.
Beispiel

Beis piel
...................................................
Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
StatusBar1.SimpleText = "OLE-Drag gestartet"
Text1.OLEDrag
StatusBar1.SimpleText = ""
End Sub
Verwandte Methoden

Verwa ndte Metho den


...................................................
OLECompleteDrag, OLEDragMode, OLEDragOver, OLEDropMode, OLEGiveFeedback, OLESetData,
OLEStartDrag
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

Refresh- Methode
Sub Objekt.Refresh()
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, CheckBox, ComboBox, CommandButton, CoolBar, Data, DataCombo, DataGrid, DataList,
DataRepeater, DataReport, DateTimePicker, DBGrid, DBCombo, DBList, DirListBox, Drive-
ListBox, FlatScrollBar, FileListBox, Form, Frame, HScrollBar, Image, ImageCombo, Label,
Line, ListView, ListBox, MaskEdBox, MMControl, MonthView, MSChart, MSFlexGrid, MSHFlex-
Grid, OLE, OptionButton, PictureBox, ProgressBar, PropertyPage, RemoteData, RichText-
Box, Shape, Slider, StatusBar, TabStrip, TextBox, ToolBar, TreeView, UserControl, User-
Document, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Die Refresh-Methode aktualisiert die Darstellung eines Steuerelements bzw. Formulars. Bei
Datensteuerelementen bewirkt Refresh eine explizite Aktualisierung des Recordset-Objekts
sowie aller abhängigen Steuerelemente.

384
SetFocus- Methode

Anwendung

Anwendung
...................................................
Im Allgemeinen frischen Steuerelemente nach einer Wertänderung ihre Darstellung von selbst
auf, sobald sich die Gelegenheit dafür ergibt. Die Priorität für diesen Vorgang ist allerdings
nicht sehr hoch. Wenn jedoch wichtigere Ereignisse auf Behandlung warten (und das sind fast
alle, außer Timer-Ereignissen) oder die Behandlung des aktuellen Ereignisses noch einiges an
Laufzeit beanspruchen wird, lässt sich mittels Refresh eine umgehende Aktualisierung der Dar-
stellung erreichen.
Bei Formularen, deren AutoRedraw-Eigenschaft nicht auf True gesetzt wurde, bewirkt Refresh
unter anderem die Ausführung der Paint-Routine. Die Methode sollte daher immer zum Aufruf
kommen, wenn der Client-Bereich komplett neu gezeichnet werden soll, beispielsweise nach

Gemeinsame Methoden
einer Änderung des Koordinatensystems oder im Zuge einer Resize-Behandlung.
Für die Datensteuerelemente Data, RemoteData und Adodc sind Refresh-Aufrufe jedes Mal dann
notwendig, wenn sich eine der Eigenschaften DatabaseName, RecordSource, ReadOnly, Exclusive
oder Connect geändert hat und ein neues Recordset erstellt werden muss.
Warnung

Wa rnung
...................................................
Der Einsatz von Refresh innerhalb einer Paint-Routine kann zu endlosen Ereignisketten führen
(zur Rettung eines Projekts für den Fall der Fälle, vgl. »Schleifen«, S. 40).
Beispiel

Beis piel
...................................................
Die folgende Routine demonstriert den Unterschied für ein Listenfeld List1. Wenn Sie den
Refresh-Aufruf auskommentieren, erfolgt die Aktualisierung der Anzeige erst nach Beendigung
der Schleife.
Private Sub Form_Click()
Print Time
For i = 1 To 4
List1.AddItem "Eintrag" & i, 0
Next i
List1.Refresh ' umgehende Anzeige
For i = 1 To 10000000 ' Zeitverzögerung
a = Sqr(1)
Next
Print Time
End Sub

SetFocus- Methode
Sub Objekt.SetFocus()
Betroffene Objekte

Betro ffene Objekte


...................................................
Adodc, Animation, CheckBox, ComboBox, CommandButton, DataCombo, DataGrid, DataList,
DataRepeater, DataReport, DateTimePicker, DBGrid, DBCombo, DBList, DirListBox, Drive-
ListBox, FlatScrollBar, FileListBox, Form, HScrollBar, ImageCombo, ListView, ListBox,
MaskEdBox, MMControl, MonthView, MSChart, MSFlexGrid, MSHFlexGrid, OLE, OptionButton,
PictureBox, PropertyPage, RichTextBox, Slider, TabStrip, TextBox, TreeView, UpDown,
UserControl, UserDocument, VScrollBar

3 85
Gemeinsame Methoden

Beschreibung

Bes c hreibung
...................................................
Die SetFocus-Methode gibt den Fokus ungeachtet der Tabulatorreihenfolge direkt an das
Steuerelement Objekt weiter und löst dabei folgende Ereigniskette aus: Validate (abhängig vom
Wert der CausesValidation-Eigenschaft) und LostFocus bei dem Objekt, das den Fokus verliert,
sowie GotFocus bei Objekt.
Anwendung

Anwendung
...................................................
Das Objekt, das den Fokus abgeben soll, kann die Weitergabe verhindern, indem es bei der
Validate-Behandlung den Cancel-Parameter auf True setzt. Umgekehrt resultiert ein Laufzeit-
Gemeinsame Methoden

fehler, wenn die Enabled-Eigenschaft des Empfängerobjekts auf False gesetzt ist. Beachten Sie
jedoch, dass der Fokusempfang trotz gesetzter Locked-Eigenschaft möglich ist, denn auch wenn
der Benutzer den Wert nicht ändern kann, Markierungen kann er vornehmen.
Warnung

Wa rnung
...................................................
Der unvorsichtige Einsatz von SetFocus kann zu endlosen Ereignisketten führen, wenn sich
Steuerelemente den Fokus wechselseitig im Rahmen der GotFocus-Behandlung zuschanzen. (Zur
Rettung des Projekts für den Fall der Fälle: vgl. »Schleifen«, S. 40.)

ShowWhatsThis- Methode
Sub Objekt.ShowWhatsThis()
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle sichtbaren Steuerelemente
Beschreibung

Bes c hreibung
...................................................
Zeigt die Direkthilfe für das Steuerelement im Popup-Hilfefenster an. Der Hilfetext ist über die
Eigenschaft WhatsThisHelpID indiziert und entstammt der in App.HelpFile spezifizierten Datei.
Damit die Methode in Aktion tritt, muss die WhatsThisHelp-Eigenschaft des Formulars auf True
gesetzt sein.

Verwa ndte Eigens c ha ften


...................................................
HelpContextId, WhatsThisButton, WhatsThisHelp, WhatsThisHelpID, WhatsThisMode,
App.HelpFile
Verwandte Themen

Verwandte Them en
...................................................
HelpContextID-Eigenschaft und WhatsThisHelpID-Eigenschaft (S. 353)

ZOrder- Methode
Sub Objekt.ZOrder([Position])
Betroffene Objekte

Betro ffene Objekte


...................................................
Alle Steuerelemente mit sichtbarer Darstellung, Formulare, MDI-Formulare
Beschreibung

Bes c hreibung
...................................................
Unter Z-Ordnung versteht man die Reihenfolge, in der die Objekte eines Containers innerhalb
der jeweiligen Grafikebene gezeichnet werden. Die ZOrder-Methode setzt Objekt an die oberste
oder unterste Position in der Z-Ordnung des zugehörigen Containers. Fehlt der Parameter

386
Standardsteuerelemente

Position oder ist er 0, platziert die Methode das Objekt ganz nach vorn, so dass es potenziell
andere verdecken kann. Ist der Wert 1, platziert die Methode das Objekt nach hinten, so dass es
potenziell von allen anderen verdeckt werden kann.
Anwendung

Anwendung
...................................................
Für die Steuerelemente eines Formulars sind drei Reihenfolgen zu unterscheiden: die Tabulator-
reihenfolge, die Einfügereihenfolge und die Z-Ordnung oder Anzeigereihenfolge. Die Tabula-
torreihenfolge ergibt sich aus der TabIndex-Eigenschaft der Steuerelemente, die den Fokus erhal-
ten können, und regelt die Weitergabe des Fokus bei Betätigung der Tabulatortaste. Die
Einfügereihenfolge ergibt sich aus der Reihenfolge, in der die Steuerelemente auf dem Formular

Standardsteuerelemente
(Container) platziert wurden, unter Berücksichtigung aller nachträglichen Vertauschungen über
das Menü FORMAT/REIHENFOLGE. Sie bestimmt die Reihenfolge, in der Visual Basic die einzel-
nen Steuerelemente deklariert, und spiegelt sich (umgekehrt) in der Elementreihenfolge der Auf-
listung Controls wider. Die nur zur Laufzeit existierende Z-Ordnung ergibt sich zunächst aus
der Einfügereihenfolge und regelt, in welcher Reihenfolge ein Formular (Container) die Steuer-
elemente zeichnet. Falls sich die Bereiche zweier Steuerelemente überschneiden, wird dasjenige
mit der niedrigeren Z-Ordnung zuerst gezeichnet – und damit von dem anderen ganz oder teil-
weise verdeckt.
Beispiel

Beis piel
...................................................
' Z-Ordnung wiederherstellen
For i = 31 To 0 Step -1
figur(i).ZOrder
Next i
Verwandte Themen

Verwandte Them en
...................................................
Schach – klare Sicht auf Hintergründliches (S. 607)

Standardsteuerelemente
CheckBox, ComboBox, CommandButton, Data, DirListBox, DriveListBox, FileListBox, Frame,
HScrollBar, Image, Label, Line, ListBox, OLE, OptionButton, PictureBox, Shape, TextBox,
Timer, VScrollBar
Beschreibung

Bes c hreibung
...................................................
Die Standardsteuerelemente sind in der standardmäßigen Werkzeugsammlung von Visual Basic
enthalten und lassen sich ohne weitere Vorbereitung direkt für den Entwurf von Formularen,
Benutzersteuerelementen, Eigenschaftsseiten und Benutzerdokumenten einsetzen – vorausge-
setzt, die Werkzeugsammlung wurde über den Menübefehl ANSICHT/WERKZEUGSAMMLUNG
eingeblendet. Um ein Steuerelement in den Entwurfsbereich etwa eines Formulars zu platzieren,
klicken Sie zuerst auf das entsprechende Symbol in der Werkzeugleiste und ziehen dann im Ent-
wurfsfenster mit der Maus einen Bereich auf, den das Steuerelement später einnehmen soll.

Auswahl eines Steuerelementtyps in der Werkzeugsammlung von Visual Basic

387
Standardsteuerelemente

Abgesehen von dem Zeitgeber-Steuerelement (Timer), das zur Laufzeit nicht sichtbar ist, legen
Sie über den Bereich die spätere Größe und Position des Steuerelements fest. Um Größe oder
Position eines bereits eingefügten Steuerelements danach noch einmal zu ändern, klicken Sie das
betreffende Steuerelement einfach an und ziehen den Bereich an die gewünschte Position bzw.
in die gewünschte Größe. Die folgende Abbildung zeigt die Entwurfsansicht eines Formulars,
auf dem (ein wenig wahllos) alle Standardsteuerelemente zu sehen sind.
Standardsteuerelemente

Formular, auf dem (wahllos) alle Standardsteuerelemente platziert wurden

Die Steuerelemente auf dem Formular sind in drei Spalten organisiert. In der linken Spalte sind
zwei Kontrollkästchen (CheckBox) in einem Figur-Steuerelement (Shape) enthalten, darunter drei
Optionsfelder (OptionButton) in einem Rahmensteuerelement (Frame), dann ein Datensteuerele-
ment (Data) und schließlich ein Zeitgeber-Steuerelement (Timer), das zur Laufzeit nicht sichtbar
ist und folglich an beliebiger Stelle platziert sein kann. Die mittlere Spalte beginnt mit zwei
Textfeldern (TextBox), darunter ein Kombinationsfeld (ComboBox) sowie ein Listenfeld (ListBox),
daneben eine vertikale Bildlaufleiste (VScrollBar), darunter eine horizontale Bildlaufleiste
(HScrollBar) und schließlich ein Anzeige-Steuerelement (Image). Die optische Abtrennung der
nächsten Spalte übernimmt ein Liniensteuerelement (Line). Die rechte Spalte beginnt mit einem
Beschriftungssteuerelement (Label) über einem Bildfeld-Steuerelement (PictureBox) neben einer
Schaltfläche (CommandButton) über einem OLE-Container-Steuerelement (OLE). Darunter dann
ein Laufwerklistenfeld (DriveListBox), ein Verzeichnislistenfeld (DirListBox) und schließlich ein
Dateilistenfeld (FileListBox).

Steuerelement Objektdatentyp Beschreibung


Anzeige Image Ermöglicht die Anzeige eines Bildes
Befehlsschaltfläche CommandButton Ermöglicht die Ausführung einer Aktion bzw.
eines Befehls
Bezeichnungsfeld Label Ermöglicht Beschriftungen
Bildfeld PictureBox Stellt ein Fenster für die Anzeige von Bildern
sowie die Ausgabe von Text und Grafik bereit

388
Standardsteuerelemente

Steuerelement Objektdatentyp Beschreibung


Bildlaufleiste horizontal HScrollBar Übernimmt die analoge Darstellung der Posi-
tion und des prozentualen Anteils eines hori-
zontalen Ausschnitts bezogen auf ein größeres
Ganzes und ermöglicht die Veränderung der
horizontalen Position über eine Bildlaufmarke
Bildlaufleiste vertikal VScrollBar übernimmt die analoge Darstellung der Posi-
tion und des prozentualen Anteils eines verti-
kalen Ausschnitts bezogen auf ein größeres

Standardsteuerelemente
Ganzes und ermöglicht die Veränderung der
vertikalen Position über eine Bildlaufmarke
Dateilistenfeld FileListBox Zeigt eine Liste der Dateien im gegebenen Ver-
zeichnis an und ermöglicht die Auswahl
Daten Data Ermöglicht den Datenbankzugriff auf Basis der
Microsoft Jet Engine oder der ODBC-Schnitt-
stelle
Figur Shape Ermöglicht die Anzeige verschiedener geomet-
rischer Figuren – Kreis, Ellipse, Rechteck, Qua-
drat, abgerundetes Rechteck, abgerundetes
Quadrat
Kombinationsfeld ComboBox Kombination aus Textfeld und Listenfeld
Kontrollkästchen CheckBox Ermöglicht die Auswahl einer Option
Laufwerklistenfeld DriveListBox Zeigt eine Liste der logischen Laufwerke des
Systems an und ermöglicht die Auswahl
Linie Line Ermöglicht die Anzeige einer Linie
Listenfeld ListBox Ermöglicht die Anzeige einer Zeichenfolgen-
liste sowie die Auswahl daraus
OLE-Container OLE Ermöglicht die Anzeige und Bearbeitung einge-
betteter oder verknüpfter Objekte anderer
Anwendungen
Optionsfeld OptionButton Ermöglicht die Auswahl einer Option unter
vielen
Rahmen Frame Ermöglicht die sichtbare Gruppierung von
Steuerelementen
Textfeld TextBox Ermöglicht die Ein- und Ausgabe von Text
Verzeichnislistenfeld DirListBox Zeigt das hierarchische Umfeld des eingestell-
ten Verzeichnisses für ein gegebenes Laufwerk
an und ermöglicht die Auswahl eines beliebi-
gen Verzeichnisses auf diesem Laufwerk
Zeitgeber Timer Ermöglicht die zeitgebundene, periodische
Ausführung von Code

Visual Basic vereinbart für jedes Steuerelement implizit ein Objekt und schlägt dafür einen
Bezeichner in der Name-Eigenschaft vor. Sofern das Steuerelement eine Beschriftung oder eine

389
Standardsteuerelemente

Zeichenfolge als Wert hat, setzt Visual Basic den gewählten Bezeichner dafür ein – das zeigt die
Abbildung recht schön. Die meisten Eigenschaften eines Steuerelementobjekts lassen sich bereits
zur Entwurfszeit im Eigenschaftenfenster definieren (viele der Entwurfseigenschaften sind zur
Laufzeit sogar schreibgeschützt), manche aber auch erst zur Laufzeit. Die Abbildung zeigt das
Eigenschaftenfenster eines Textfeldes.
Standardsteuerelemente

Eigenschaftenfenster mit den Entwurfseigenschaften eines Textfeldes

Anzeige- Steuerelement (Image)


Image1 As Image
Beschreibung

Bes c hreibung
...................................................
Das Anzeige-Steuerelement dient der Anzeige von Bildern, die als Bitmap in einem der Formate
BMP, JPG, JPEG, GIF, WMF, EMF, ICO oder CUR vorliegen. Die Standardeigenschaft des
Steuerelements ist Picture.

390
Anzeige- Steuerelement ( Image)

Eigenschaften

Eigens c ha ften
...................................................
Appearance, BorderStyle, Container, DataChanged, DataField, DataFormat, DataMember,
DataSource, DragIcon, DragMode, Enabled, Height, Index, Left, MouseIcon, MousePointer,
Name, OLEDragMode, OLEDropMode, Parent, Picture, Stretch, Tag, ToolTipText, Top, Visi-
ble, WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, ShowWhatsThis, ZOrder
Ereignisseza

Ereignis s e
...................................................

Standardsteuerelemente
Click, DblClick, DragDrop, DragOver, MouseDown, MouseMove, MouseUp, OLECompleteDrag,
OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag
Anwendung

Anwendung
...................................................
Bestimmung dieses Steuerelements ist die ressourcenschonende und schnelle Anzeige von Bil-
dern in verschiedenen Grafikformaten. Hat die Eigenschaft Stretch den Wert False, behält das
Bild seine vordefinierte Größe, und es hängt von der Bereichsgröße des Steuerelements ab, ob es
vollständig oder nur teilweise (von links oben aus gesehen) dargestellt werden kann. Andern-
falls wird das Bild unter Inkaufname einer horizontalen Streckung oder Stauchung in den
Bereich des Steuerelements eingepasst.
Wenn Sie der Eigenschaft Picture zur Entwurfszeit ein Bild zuordnen, speichert Visual Basic
eine Kopie des Bildes als binären Anhang der Programmdatei bzw. in der kompilierten Version
als Teil der ausführbaren Datei. Wenn Sie eine aktuelle Fassung des Bildes zur Laufzeit laden
wollen (Verknüpfung), müssen Sie das Bild mit der LoadPicture-Funktion laden und dem
Anzeige-Steuerelement zuweisen.
Warnung

Wa rnung
...................................................
Den Eigenschaften Height und Width des Datentyps Picture liegt die Maßeinheit vbHiMetric
zugrunde. Wenn Sie die Bereichsgröße eines Anzeige-Steuerelements an die Abmessungen eines
Bildes anpassen wollen, müssen Sie die Methoden ScaleX und ScaleY für die Umrechnung der
Maße in die Maßeinheiten des Containers bemühen.
Beispiel

Beis piel
...................................................
Der folgende Code demonstriert, wie man ein Bild in ein Anzeige-Steuerelement lädt und dessen
Bereichsgröße an die Abmessungen der Bitmap anpasst.
Dim pic As Picture
Set pic = LoadPicture(App.Path + "\MeinBild.bmp")
Image1.Width = ScaleX(pic.Width, vbHimetric, ScaleMode)
Image1.Height = ScaleY(pic.Height, vbHimetric, ScaleMode)
Image1 = pic
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
ImageList, PictureBox, RptImage

3 91
Standardsteuerelemente

Befehlsschaltfläche- Steuerelement (CommandButton)


Command1 As CommandButton

Beschreibung

Bes c hreibung
...................................................
Das Befehlsschaltfläche-Steuerelement ist als Visualisierung für die Funktion des einfachen
Standardsteuerelemente

beschrifteten Tasters gedacht. Klickt der Benutzer darauf oder betätigt er die Schaltfläche mit
der Tastatur, ändert sich für die Zeitdauer der Betätigung seine Darstellung sowie der Wert der
Value-Eigenschaft, und das Click-Ereignis tritt auf.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, CausesValidation, Cancel, Caption, Container, Default, Disabled-
Picture, DownPicture, DragIcon, DragMode, Enabled, Font, FontBold, FontItalic, FontName,
FontSize, FontStrikeThru, FontUnderline, ForeColor, Height, HelpContextID, hWnd, Index,
Left, MaskColor, MouseIcon, MousePointer, Name, OLEDropMode, Parent, Picture, RightTo-
Left, Style, TabIndex, TabStop, Tag, ToolTipText, Top, UseMaskColor, Value, Visible,
WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Click, DragDrop, DragOver, GotFocus, KeyDown, KeyUp, KeyPress, LostFocus, MouseDown,
MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESet-
Data, OLEStartDrag, Validate
Anwendung

Anwendung
...................................................
Für gewöhnlich wird die Befehlsschaltfläche dafür genutzt, Aktionen bzw. Befehle explizit
durch einen Klick mit der Maus auszulösen. So für die Befehle »OK«, »Abbrechen« und »Über-
nehmen« in Dialogfeldern, aber auch für andere formularspezifische Kommandos. Vom Prinzip
her ließen sich dafür natürlich auch andere Steuerelemente verwenden, die eine Click-Behand-
lung ermöglichen, doch die Befehlsschaltfläche ist speziell auf diese Aufgabe zugeschnitten. Ins-
besondere besitzt sie die Eigenschaften Default und Cancel, deren Werte darüber entscheiden,
ob auch die Tasten (Eingabe) oder (Esc) das Click-Ereignis auslösen können. Für die beiden
Eigenschaften gelten folgende Regeln:
1. In einem Formular kann immer nur die Default-Eigenschaft einer einzigen Befehlsschaltflä-
che auf True gesetzt sein. Das macht sie zur Standardschaltfläche. Analoges gilt für die Can-
cel-Eigenschaft.
2. Setzt man die Default-Eigenschaft einer Schaltfläche auf True, wird sie zur Standardschalt-
fläche und gleichzeitig ändert sich die Default-Eigenschaft der bisherigen Standardschaltflä-
che auf False. Analoges gilt für die Cancel-Eigenschaft.
3. Es kann immer nur eine Befehlsschaltfläche in einem Formular auf die Eingabetaste reagie-
ren. Das ist entweder die Schaltfläche, die den Fokus besitzt, oder, falls keine der Schaltflä-
chen in dem Formular den Fokus besitzt, die Standardschaltfläche. Analoges gilt für die

392
Bezeichnungsfeld- Steuerelement (Label)

Cancel-Eigenschaft. Den Fokusbesitz zeigt eine Schaltfläche durch einen zusätzlichen gestri-
chelten Innenrand an. Ist keine der Schaltflächen im Besitz des Fokus, lässt sich die Standard-
schaltfläche an einer verdickten Randlinie (vgl. Abbildung) erkennen.
Die Caption-Eigenschaft ermöglicht die Beschriftung der Schaltfläche. Um eine Zugriffstaste für
das Steuerelement zu vereinbaren, stellen Sie dem entsprechenden Buchstaben in der Beschrif-
tung das Zeichen »&« voran. Er wird zur Laufzeit durch Unterstreichung kenntlich gemacht
(vgl. Abbildung).
Befehlsschaltflächen kennen zwei unterschiedliche Darstellungen: die Standarddarstellung im
Stil von Windows 9x und die benutzerdefinierte Darstellung. Um dem Steuerelement ein benut-
zerdefiniertes Aussehen zu verleihen, können Sie den Eigenschaften Picture und DownPicture

Standardsteuerelemente
sowie gegebenenfalls DisabledPicture geeignete Bilder zuordnen. Falls Sie eine pseudotranspa-
rente Darstellung wünschen, bei der die über eine Transparenzfarbe (MaskColor) definierten
transparenten Bereiche der Bilder in Hintergrundfarbe erscheinen, müssen Sie die Eigenschaft
UseMaskColor auf True setzen. Die Style-Eigenschaft entscheidet darüber, welche der Darstel-
lungen zur Anzeige kommt. (Ein Beispiel dafür findet sich im Abschnitt »DisabledPicture-
Eigenschaft«, S. 341.)
Beispiel

Beis piel
...................................................
Die Click-Routinen der Schaltflächen Abbrechen und Beenden schließen beide das Formular. OK
ist Standardschaltfläche und reagiert auf die Eingabetaste, während Abbrechen auf die Taste
(Esc) reagiert. OK_Click verwertet im Gegensatz zu Abbrechen_Click die Eingaben des Benut-
zers.
...
OK.Default = True
Abbrechen.Cancel = True
...
Private Sub OK_Click()
VerwerteEingaben ' Eingaben des Benutzers verwerten
Unload Me
End Sub

Private Sub Abbrechen_Click()


Unload Me ' Eingaben werden verworfen
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Button, CheckBox, OptionButton

Bezeichnungsfeld- Steuerelement (Label)


Label1 As Label
Beschreibung

Bes c hreibung
...................................................
Das Bezeichnungsfeld-Steuerelement hat als Standardeigenschaft eine Zeichenfolge, die es in
seinem Bereich gegebenenfalls umbrochen anzeigt. Eine Bearbeitung der Zeichenfolge durch
Benutzer ist nicht möglich.

3 93
Standardsteuerelemente

Eigenschaften

Eigens c ha ften
...................................................
Alignment, Appearance, AutoSize, BackColor, BackStyle, BorderStyle, Caption, Container,
DataChanged, DataField, DataFormat, DataMember, DataSource, DragIcon, DragMode, Enab-
led, Font, FontBold, FontItalic, FontName, FontSize, FontStrikeThru, FontUnderline,
ForeColor, Height, Index, Left, LinkItem, LinkMode, LinkTimeout, LinkTopic, MouseIcon,
MousePointer, Name, OLEDropMode, Parent, RightToLeft, TabIndex, Tag, ToolTipText, Top,
UseMnemonic, Visible, WhatsThisHelpID, WordWrap
Methoden

Metho den
...................................................
Standardsteuerelemente

Drag, LinkExecute, LinkPoke, LinkRequest, LinkSend, Move, OLEDrag, Refresh, ShowWhats-


This, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyUp, KeyPress, Link-
Close, Link, Error, LinkNotify, LinkOpen, MouseDown, MouseMove, MouseUp, OLEComplete-
Drag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag
Anwendung

Anwendung
...................................................
Das Bezeichnungsfeld-Steuerelement ist als Mittel für die »externe« Beschriftung von Steuerele-
menten gedacht, wenn diese selbst keine Möglichkeit dafür vorsehen, also keine Caption-Eigen-
schaft besitzen.
Zur Gestaltung der Textausgabe können Sie die Schriftattribute über die jeweiligen Font-Eigen-
schaften setzen. Für die Beschriftung von Bildern (beispielsweise in Image-Steuerelementen)
kann es vorteilhaft sein, einen durchsichtigen Bereichshintergrund für das Bezeichnungsfeld ein-
zustellen. Setzen Sie dazu die Eigenschaft BackStyle auf vbTransparent (0).
Der Wert des Steuerelements lässt sich zur Laufzeit nach Belieben und mit sofortiger Wirkung
durch einfache Zuweisung einer anderen Zeichenfolge ändern. Dies kann auch automatisch
passieren, wenn Sie das Steuerelement über die Link-Eigenschaften zum Ziel einer DDE-Ver-
knüpfung erklären oder es über die Data-Eigenschaften an ein Feld in einer Datenbank binden.
Im Zuge einer Wertänderung kann es allerdings passieren, dass nicht die gesamte Zeichenfolge
im Bereich des Steuerelements darstellbar ist – restliche Zeichen werden dann abgeschnitten,
wenn die AutoResize-Eigenschaft nicht auf True gesetzt ist. Sie müssen den Bereich daher entwe-
der von vornherein großzügig bemessen oder Platz für die automatische Ausdehnung einkalku-
lieren. Zudem lässt sich die WordWrap-Eigenschaft auf True setzen, um einen automatischen
Umbruch zu erhalten. Beachten Sie aber, dass sich der Bereich des Feldes dann in beide Rich-
tungen (nach unten und nach rechts/links, bevorzugt aber nach unten) ausdehnen kann, je
nachdem wie der Umbruch zustande kommt. Oft ist es dann besser, ein Textfeld mit Bildlauf-
leisten zu benutzen. Textfelder lassen sich übrigens hervorragend als Bezeichnungsfelder »ver-
kleiden«, wenn man die Möglichkeit der Bearbeitung mittels der Locked-Eigenschaft unterbin-
det und die Eigenschaften BorderStyle und BackColor geeignet setzt. Nur ein transparenter
Hintergrund lässt sich so nicht realisieren.
Beispiel

Beis piel
...................................................
Das folgende kleine Programm benutzt ein Bezeichnungsfeld Label1 und ein Timer-Steuerele-
ment Timer1 für die animierte Wiedergabe einer Textsequenz mit Fade-out-Effekt. (Das voll-
ständige Beispielprojekt FadeOut wird im Abschnitt »AutoSize-Eigenschaft«, S. 329, disku-
tiert.)

394
Bildfeld- Steuerelement (PictureBox)

Dim Texte()
Dim i
Private Sub Form_Load()
Texte = Array("Rauchen", "schadet", "Ihrer", "Gesundheit")
Label1 = Texte(0)
End Sub

Private Sub Timer1_Timer()


Label1.Font.Size = Label1.Font.Size + 1.1
If Label1.FontSize > 40 Then

Standardsteuerelemente
Label1.FontSize = 8
i = (i + 1) Mod (UBound(Texte) + 1)
Label1 = Texte(i)
End If
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
TextBox, RptLabel, RptTextBox

Bildfeld- Steuerelement (PictureBox)


Picture1 As PictureBox
Beschreibung

Bes c hreibung
...................................................
Die Standardeigenschaft des Bildfeld-Steuerelements ist Picture. Damit ist es für die Anzeige
von Bildern prädestiniert. Neben der Anzeige von Bildern in beliebiger Skalierung (Verzerrung
des Seitenverhältnisses möglich) kennt es aber auch die gleichen Grafikmethoden wie das For-
mular und ermöglicht insbesondere die Ausgabe von Text. Darüber hinaus kann es als Contai-
ner für andere Steuerelemente fungieren.
Eigenschaften

Eigens c ha ften
...................................................
Align, Appearance, AutoRedraw, AutoSize, BackColor, BorderStyle, ClipControls, Causes-
Validation, Container, CurrentX, CurrentY, DataChanged, DataField, DataFormat, DataMem-
ber, DataSource, DragIcon, DragMode, DrawMode, DrawStyle, DrawWidth, Enabled, FillColor,
FillStyle, Font, FontBold, FontItalic, FontName, FontSize, FontStrikeThru, FontTranspa-
rent, FontUnderline, ForeColor, hDC, Height, HelpContextID, hWnd, Image, Index, Left,
LinkItem, LinkMode, LinkTimeout, LinkTopic, MouseIcon, MousePointer, Name, OLEDragMode,
OLEDropMode, Parent, Picture, RightToLeft, ScaleHeight, ScaleLeft, ScaleMode, ScaleTop,
ScaleWidth, TabIndex, TabStop, Tag, ToolTipText, Top, Visible, WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Circle, Cls, Drag, Line, LinkExecute, LinkPoke, LinkRequest, LinkSend, Move, OLEDrag,
PaintPicture, Point, PSet, Print, Refresh, Scale, ScaleX, ScaleY, SetFocus, ShowWhats-
This, TextHeight, TextWith, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyUp, KeyPress, LinkC-
lose, LinkError, LinkNotify, LinkOpen, LostFocus, MouseDown, MouseMove, MouseUp, OLECom-
pleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag, Paint,
Resize, Validate

3 95
Standardsteuerelemente

Anwendung

Anwendung
...................................................
Das Bildfeld-Steuerelement besitzt im Wesentlichen die gleiche Ausstattung wie das Formular –
darunter insbesondere die Methoden für die Ausgabe von Bildern (PaintPicture), Text
(TextHeight, TextWidth, Print) und Grafik (Circle, Line, PSet, Point) sowie natürlich auch ein
eigenes Koordinatensystem (Scale, ScaleX, ScaleY), nicht zu vergessen die Kombination Paint-
Methode und AutoRedraw-Eigenschaft sowie das Modell der Ausgabe auf drei Ebenen (vgl.
»Paint-Ereignis«, S. 253).
Auch kann das Bildfeld als Container für andere Steuerelemente fungieren, etwa für die Grup-
pierung von Optionsfeldern und/oder Kontrollkästchen. Obwohl das Bildfeld wirklich viel vom
Formular hat, bleibt es doch ein Steuerelement und kann als Quelle für OLE-Drag&Drop-Ope-
Standardsteuerelemente

rationen oder DDE-Verbindungen fungieren.


Trotz dieser reichhaltigen Ausstattung ist das Bildfeld aber – wie der Name schon vermuten
lässt – in erster Linie als Steuerelement für die flexible Ausgabe von Bildern gedacht. Während
das Anzeige-Steuerelement (Image) nur auf die reine, dafür aber schnelle und ressourcenscho-
nende Ausgabe von Bildern spezialisiert ist und auf die Möglichkeiten, die sich durch Skalie-
rung, Streckung oder Rasteroperationen eröffnen, verzichten muss, bietet das Bildfeld all diesen
Komfort.
Das Bildfeld-Steuerelement lässt sich als einziges Standardsteuerelement neben dem Daten-
steuerelement (Data) auf einem MDI-Formular platzieren. Es verhält sich dann wie eine Leiste
und klebt zusammen mit anderen Leisten (ToolBar, CoolBar, ProgressBar, nicht jedoch Status-
Bar) in voller Breite am oberen Rand des Client-Bereichs. Sie können es dann beispielsweise
dafür benutzen, sich eine benutzerdefinierte Symbolleiste zu basteln.
Beispiel

Beis piel
...................................................
Das für seinen Leistungsumfang eher zierlich geratene Projekt BilderViewer lässt sich als voll-
wertiger Bildbetrachter verwenden und wartet sogar mit OLE-Funktionalität auf. Im Formular
finden Sie zwei Steuerelemente: ein Bildfeld Picture1, das die zentrierte und – in Bezug auf die
aktuelle Formulargröße – maximierte Bildausgabe übernimmt, und ein Standarddialoge-Steuer-
element CommonDialog1 für die unkomplizierte Eingabe eines Dateinamens. Neue Bilder lassen
sich entweder über den Menübefehl DATEI/ÖFFNEN oder per OLE-Drag&Drop einfügen. Bei
Größenänderungen des Formulars passt sich der Inhalt entsprechend an.
' Projekt: Viewer für Bilder
Dim Pic As Picture
Private Sub Form_Load()
CommonDialog1.Filter = "Bilder (JPG, GIF, BMP)|*.jpg;*.gif;*.bmp"
Picture1.Left = 0
Picture1.Top = 0
Picture1.Width = ScaleWidth
Picture1.Height = ScaleHeight
mnuDateiÖffnen_Click
End Sub

Private Sub Form_Resize()


Picture1.Refresh ' Bildfeld neu einpassen
End Sub

Private Sub mnuDateiÖffnen_Click()


CommonDialog1.ShowOpen ' Bilddatei in Erfahrung bringen
If CommonDialog1.FileName <> "" Then

396
Bildfeld- Steuerelement (PictureBox)

Set Pic = LoadPicture(CommonDialog1.FileName)


Picture1.Refresh ' Bild und Bildfeld einpassen
End If
End Sub

Private Sub Picture1_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single)
' Datei von Explorer-Fenster?
If Data.GetFormat(vbCFFiles) Then
Set Pic = LoadPicture(Data.Files(1))

Standardsteuerelemente
Picture1.Refresh
End If
' Gewöhnliches Bildobjekt?
If Data.GetFormat(vbCFDIB) Or Data.GetFormat(vbCFBitmap) Then
Set Pic = Data.GetData(vbCFDIB)
End If
End Sub

Private Sub Picture1_Paint()


Dim PicWidth, PicHeight
If Not Pic Is Nothing Then
' Bildfeld maximieren und zentrieren und
' Bild in maximaler Größe verzerrungsfrei einpassen
PicWidth = ScaleX(Pic.Width, vbHimetric, vbTwips)
PicHeight = ScaleY(Pic.Height, vbHimetric, vbTwips)
If PicHeight / PicWidth > ScaleHeight / ScaleWidth Then
Picture1.Height = ScaleHeight ' Maximieren
Picture1.Width = ScaleHeight / PicHeight * PicWidth
Picture1.Left = (ScaleWidth – Picture1.Width) / 2 ' Zentrieren
Picture1.Top = 0
Else
Picture1.Width = ScaleWidth
Picture1.Height = ScaleWidth / PicWidth * PicHeight
Picture1.Top = (ScaleHeight – Picture1.Height) / 2
Picture1.Left = 0
End If
' Bild einpassen
Picture1.PaintPicture Pic, 0, 0, Picture1.ScaleWidth, _
Picture1.ScaleHeight
End If
End Sub
Verwandte Steuerelemente

...................................................
Verwandte S teuerelemente
Image, Form, RptImage, UserControl, UserDocument
Verwandte Themen

...................................................
Verwa ndte Them en
Formulare (S. 306)

3 97
Standardsteuerelemente
Standardsteuerelemente

Fenster der Anwendung BilderViewer

Bildlaufleisten- Steuerelemente (HScrollBar, VScrollBar)


VScroll1 As VScrollBar
HScroll1 As HScrollBar
Beschreibung

Bes c hreibung
...................................................
Es gibt eine 16- und eine 32-Implementation der Bildlaufleiste, und Visual Basic 6.0 arbeitet
(leider) noch mit der 16-Bit-Version, was gewisse Einschränkungen mit sich bringt.
Die Bildlaufleisten-Steuerelemente HScrollBar und VScrollBar sind speziell für die analoge
Visualisierung und Manipulation von Ausschnittsdarstellungen eingerichtet. Standardeigen-
schaft der Bildlaufleiste ist die Value-Eigenschaft. Sie ist vom Typ Integer und bestimmt die
aktuelle Position der Bildlaufmarke. Den Wertebereich für die Bildlaufmarke legen die Eigen-
schaften Min und Max fest. Die Eigenschaften sind vom Typ Integer und müssen im Intervall 0
bis 32767 liegen, wobei Min kleiner als Max zu wählen ist. Darüber hinaus gestatten die Eigen-
schaften LargeChange und SmallChange die Definition von Werten für den Vorschub der Bild-
laufmarke alternativ zur Ziehoperation.
LargeChange ist für den Bildvorschub zuständig, der mit den Tasten (Bild-Auf) und (Bild-Ab)
sowie durch Mausklicks in den Schaftbereich der Leiste zwischen Bildlaufmarke und Pfeilsym-
bole ausgelöst wird. SmallChange gibt den Wert für den »kleinen Vorschub« (Zeilenvorschub)
mittels der Pfeiltasten (Auf), (Ab), (Links) und (Rechts) sowie der Pfeilsymbole an. Die Aus-
dehnung der Bildlaufmarke hängt von LargeChange ab, gibt aber das Größenverhältnis zwischen
Ausschnitt und vollem Bereich (leider) nicht proportional wieder.
Während der Benutzer die Bildlaufmarke auf eine andere Position zieht, signalisiert das Steuer-
element Scroll-Ereignisse. Am Ende des Ziehvorgangs sowie bei diskreten Positionsänderungen
per Tastatur oder Mausklick tritt das Change-Ereignis auf.
Eigenschaften

Eigens c ha ften
...................................................
CausesValidation, Container, DragIcon, DragMode, Enabled, Height, HelpContextID, hWnd,
Index, LargeChange, Left, Max, Min, MouseIcon, MousePointer, Name, Parent, RightToLeft,
SmallChange, TabIndex, TabStop, Tag, Top, Value, Visible, WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, Move, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, DragDrop, DragOver, GotFocus, KeyDown, KeyUp, KeyPress, LostFocus, Scroll, Vali-
date

398
Bildlaufleisten- Steuerelemente ( HScrollBar, VScrollBar)

Anwendung

Anwendung
...................................................
Der Einsatz der Bildlaufleiste bietet sich überall da an, wo es um die Auswahl eines Werts aus
einem Wertebereich mit analoger Darstellung geht. Das kann eine Tonhöhe (Frequenzwert aus
einem gegebenen Frequenzbereich) sein, eine Lautstärke oder ein Winkel für die perspektivische
Darstellung. Beachten Sie aber, dass Sie mit dem Schieberegler-Steuerelement (Slider) ein
Steuerelement zur Verfügung haben, das auf Analogregelung spezialisiert ist. Die Bildlaufleiste
hat keine Skala, ist aber im Gegensatz zum Schieberegler in der Lage, die Ausdehnung des ange-
zeigten Teilbereichs über die Breite der Bildlaufmarke zu visualisieren.
Die Programmierung der Bildlaufleiste (gleich ob vertikal oder horizontal) hat mehrere
Aspekte:

Standardsteuerelemente
1. Definition des Wertebereichs – wählen Sie den Wertebereich (über die Eigenschaften Min und
Max) nach Möglichkeit so, dass er den Wertebereich der Problemstellung entweder direkt wie-
dergibt oder zumindest entweder durch reine Translation (lies: Verschiebung) oder durch rei-
ne Skalierung (lies: Streckung/Stauchung) auf den Problembereich abzubilden ist. Skalierung
und Translation sind mit viel Rechnerei verbunden.
2. Definition der Seitengröße – setzen Sie die Eigenschaft LargeChange auf die Breite des sicht-
baren Ausschnitts, oder bei Verwendung des Steuerelements als Schieberegler auf eine geeig-
nete Intervalllänge. Ein guter Wert für SmallChange ist in den meisten Fällen ein Zehntel von
LargeChange.
3. Interpretation des Standardwerts – der Standardwert (Value) drückt die Position der Bild-
laufmarke zwischen Min und Max aus, wobei die Breite der Marke sozusagen »herausgelogen«
wird. Aus diesem Grund müssen Sie für die Definition von Max von der oberen Bereichsgrenze
die Seitengröße LargeChange abziehen! Wird das Steuerelement dagegen wie ein Schieberegler
benutzt, setzen Sie Max auf die obere Bereichsgrenze, ohne etwas abzuziehen.
4. Positionierung und Größenanpassung der Bildlaufleiste – wird die Bildlaufleiste in einer grö-
ßenveränderlichen Komponente platziert, muss sie in den meisten Fällen in der verantwort-
lichen Resize-Routine oder dem entsprechenden Äquivalent gepflegt werden. Bei
Größenänderungen einer Bildlaufleiste (Width und Height) bleibt die Breite der Bildlaufmarke
prozentual erhalten. Insbesondere bleiben die Eigenschaften Min, Max, SmallChange und Lar-
geChange sowie Value unverändert.
5. Pflege des Standardwerts – der Standardwert, der die Position der Bildlaufmarke bestimmt,
wird vom Steuerelement selbst gepflegt. Seine Auswertung geschieht im Rahmen der Change-
Behandlung. Sie können den Wert mit sofortiger Wirkung auch explizit unter Beachtung von
Min und Max setzen (jede Änderung des Werts generiert ein Change-Ereignis), nur nicht inner-
halb der Scroll-Behandlung, da das nächste Scroll-Ereignis das Ergebnis sofort wieder zu-
nichte macht.
Beispiel

Beis piel
...................................................
Die folgende weitgehend dem Projekt HexView entstammende Resize-Routine sorgt dafür, dass
die Bildlaufleisten VScroll1 und HScroll1 am rechten bzw. unteren Rand im Client-Bereich des
Formulars verbleiben und gegebenenfalls ausgeblendet werden, wenn der Client-Bereich für die
Anzeige des Dokuments ausreicht. Die globalen Variablen DocWidth und DocHeight geben hier
die Abmessungen des gesamten Dokuments wieder:
Private Sub Form_Load()
VScroll1.Top = 0 ' oben ankleben
HScroll1.Left = 0 ' links ankleben
...

Private Sub Form_Resize()

3 99
Standardsteuerelemente

If Not WindowState = vbMinimized Then


Height = IIf(Height < 1200, 1200, Height)
Width = IIf(Width < 1000, 1000, Width)
HScroll1.Visible = ScaleWidth < DocWidth ' Sichtbarkeit
VScroll1.Visible = ScaleHeight < DocHeight ' Sichtbarkeit
' Abmessungen der Bildlaufleisten
VScroll1.Left = ScaleLeft + ScaleWidth – VScroll1.Width
VScroll1.Height = ScaleHeight + HScroll1.Height * HScroll1.Visible
HScroll1.Top = ScaleTop + ScaleHeight – HScroll1.Height
HScroll1.Width = ScaleWidth + VScroll1.Width * VScroll1.Visible
Standardsteuerelemente

' vertikale Bildlaufparameter anpassen


If VScroll1.Visible Then
VScroll1.Max = DocHeight – ScaleHeight
VScroll1.LargeChange = ScaleHeight * 0.95
VScroll1.SmallChange = VScroll1.LargeChange / 10
End If
' horizontale Bildlaufparameter anpassen
If HScroll1.Visible Then
HScroll1.Max = DocWidth – ScaleWidth
HScroll1.LargeChange = ScaleWidth * 0.95
HScroll1.SmallChange = HScroll1.LargeChange / 10
End If
Refresh
End If
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Slider, UpDown
Verwandte Themen

Verwandte Them en
...................................................
HexView – eine schnelle Textansicht für große Dateien (S. 551); Bildlauf – ein kleiner
Betrachter für große Bilder (S. 545)

Dateilistenfeld- Steuerelement (FileListBox)


File1 As FileListBox

Beschreibung

Bes c hreibung
...................................................
Bei dem Dateilistenfeld-Steuerelement handelt es sich um ein Listenfeld, das darauf spezialisiert
ist, den Inhalt des über die Path-Eigenschaft spezifizierten Verzeichnisses unter Beachtung eines
Namensfilters (Pattern) sowie der über die Eigenschaften Archive, ReadOnly, System, Hidden und
Normal spezifizierten Attribute in seiner Liste anzuzeigen.
Über die Eigenschaft MultiSelect lässt sich zur Laufzeit festlegen, ob der Benutzer nur einen
einzelnen Dateinamen (vbMultiSelectNone = 0), mehrere Dateinamen in einem Block

400
Dateilistenfeld- Steuerelement ( FileListBox)

(vbMultiSelectSimple = 1) oder mehrere einzelne Dateinamen bzw. Blöcke


(vbMultiSelectExtended = 2) auswählen kann.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, Archive, BackColor, CausesValidation, Container, DragIcon, DragMode, Enab-
led, FileName, Font, FontBold, FontItalic, FontName, FontSize, FontStrikethru, FontUn-
derline, ForeColor, Height, HelpContextID, Hidden, hWnd, Index, Left, List, ListCount,
ListIndex, Locked, MouseIcon, MousePointer, MultiSelect, Name, Normal, OLEDragMode, OLE-
DropMode, Parent, Path, Pattern, ReadOnly, Selected, System, TabIndex, TabStop, Tag,
Top, ToolTipText, TopIndex, Visible, WhatsThisHelpID, Width

Standardsteuerelemente
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyPress, KeyUp, LostFocus,
MouseDown, MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeed-
back, OLESetData, OLEStartDrag, PathChange, PatternChange, Scroll, Validate
Anwendung

Anwendung
...................................................
Das Dateilistenfeld ist wie das Verzeichnislistenfeld (DirListBox) und das Laufwerklistenfeld
(DriveListBox) noch ein Relikt aus der Zeit, als Anwendungen den Benutzer mit eigenen Vari-
anten für Dialoge wie »Datei öffnen«, »Speichern unter« usw. auf die Probe stellten. Inzwi-
schen dürfte es nur noch in ganz besonderen Problemfeldern zum Einsatz kommen, da die seit
Windows 9x vorliegende Implementation der Standarddialoge wenig Wünsche offen lässt, was
die interaktive Dateiauswahl betrifft. Freilich wird eine Anwendung, die sich beispielsweise auf
die Konvertierung von Dateien im Batch-Modus spezialisiert, noch in irgendeiner Form vom
Dateilistenfeld profitieren können. Von der Programmierung eigener Versionen der Standard-
dialoge sei aber eher abgeraten, da es der Benutzer sicher nicht danken wird.
Um die im Listenfeld angezeigte Dateiauswahl zu spezifizieren, setzen Sie zunächst die Eigen-
schaft Path auf das gewünschte Verzeichnis. Dieses muss existieren und wird meist von einem
Verzeichnislistenfeld-Steuerelement geliefert. Im zweiten Schritt setzen Sie die Eigenschaft Pat-
tern auf ein Suchmuster im Stil von »*.bmp« oder »a??0012.dat«. Alternativ können Sie die
komplette Spezifikation (Pfad plus Suchmuster) auch über die Eigenschaft FileName setzen. In
diesem Fall extrahiert das Steuerelement die Werte für Path und Pattern und setzt FileName auf
den Namen der ersten Datei in der Auswahl. Ist die Dateiauswahl jedoch leer, tritt ein Laufzeit-
fehler auf. Jede Änderung von Path bzw. Pattern tut das Steuerelement über die Ereignisse
PathChange bzw. PatternChange kund.
Wenn Sie wollen, dass der Benutzer mehrere Einträge im Listenfeld auswählen kann, setzen Sie
MultiSelect auf 1 oder 2. Die Analyse der Auswahl des Benutzers wird meist im Zuge der
Behandlung von Validate oder LostFocus vorgenommen und beinhaltet die Auswertung des
Boolean-Arrays Selected (Basis 0), das so viele Elemente hat, wie es Einträge im Listenfeld gibt,
und für jedes Element die Zugehörigkeit zur aktuellen Auswahl anzeigt – True bedeutet: das
Element gehört zur Auswahl. Die zugehörigen Einträge lassen sich unter dem jeweiligen Index
über die List-Eigenschaft gewinnen.
Warnung

Wa rnung
...................................................
Der verkapselte Teil der OLESetData-Behandlung durch das Steuerelement ist fehlerhaft imple-
mentiert. Als Quellkomponente in einer OLE-Drag&Drop-Operation setzt die Komponente in

401
Standardsteuerelemente

der Files-Auflistung nämlich einen fehlerhaften Pfad, wenn die Auswahl dem Wurzelverzeich-
nis eines Laufwerks angehört: Aus irgendeinem Grund enthält er einen Schrägstrich zu viel –
zum Beispiel »C:\\«.
Beispiel

Beis piel
...................................................
Der folgende Code demonstriert die Auswertung einer Mehrfachauswahl:
Private Sub Form_Load()
File1.FileName = "c:\Windows\*.dll"
End Sub
Standardsteuerelemente

Private Sub File1_LostFocus()


For i = 0 To File1.ListCount – 1
If File1.Selected(i) Then
Print File1.List(i)
End If
Next
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
CommonDialog, DirListBox, DriveListBox, ListBox
Verwandte Themen

Verwandte Them en
...................................................
Listenfeld-Steuerelement (ListBox) (S. 412)

Data- Datensteuerelement (Data)


Data1 As Data

Beschreibung

Bes c hreibung
...................................................
Das Datensteuerelement Data bildet neben den Steuerelementen RemoteData und Adodc die
Grundlage für automatisierte Verbindungen zwischen Steuerelementen und Datenbanken. Aus
Sicht eines gewöhnlichen Steuerelements kann Data als Datenquelle auftreten, die es automa-
tisch mit Werten aus einer Datenbank versorgt und Eingaben des Benutzers zurück an die
Datenbank leitet.
Data legt ein Datenbankobjekt (Database) an, um die Datenbankverbindung zu öffnen, sowie
ein Recordset-Objekt für die Repräsentation der Datensätze, sobald es für ein anderes Steuer-
element als Datenquelle in Aktion treten muss. Einen Überblick über die für den Datenbankzu-
griff spezifischen Eigenschaften und Ereignisse des Datensteuerelements entnehmen Sie den fol-
genden Tabellen.
Eigenschaften

Eigens c ha ften
...................................................
Align, Appearance, BackColor, BOF, Caption, Connect, Database, DatabaseName, DefaultCur-
sorType, DefaultType, DragIcon, DragMode, EditMode, Enabled, EOF, ForeColor, Exclusive,
Font, FontBold, FontItalic, FontName, FontSize, FontStrikeThru, FontTransparent,
FontUnderline, ForeColor, Height, Index, Left, MouseIcon, MousePointer, Name, OLEDrop-

402
Data- Datensteuerelement (Data)

Mode, Options, Parent, ReadOnly, Recordset, RecordsetType, RecordSource, RightToLeft,


Tag, ToolTipText, Top, Visible, WhatsThisHelpID, Width

Eigenschaft Beschreibung
Database Verweis auf Database-Objekt, das das Steuerelement unter Beachtung
der Eigenschaften DataBaseName, Connect, Exclusive und ReadOnly für
eine Verbindung generiert
DatabaseName Zeichenfolge mit dem Namen der Datenbank
Connect Zeichenfolge mit Informationen über den Datenbanktyp sowie (durch

Standardsteuerelemente
ein Semikolon getrennt) gegebenenfalls erforderliche zusätzliche Para-
meter. Zur Auswahl stehen: "Access" (Voreinstellung), "dBASE III;",
"dBASE IV;", "dBASE 5;", "Excel 3.0;", "Excel 4.0;", "Excel 5.0;",
"Excel 8.0;", "Lotus WK1;", "Lotus WK3;", "Lotus WK4;", "FoxPro 2.0;",
"FoxPro 2.5;", "FoxPro 2.6;", "FoxPro 3.0;", "Paradox 3.x;",
"Paradox 4.x;", "Paradox 5.x;" und "Text;"
BOF Boolean-Wert, der anzeigt, ob die Position des aktuellen Datensatzes vor
dem ersten Datensatz im Recordset-Objekt liegt
EOF Boolean-Wert, der anzeigt, ob die Position des aktuellen Datensatzes
hinter dem letzten Datensatz im Recordset-Objekt liegt
DefaultCursorType Integer-Wert der bestimmt, welchen Cursortyp das Recordset-Objekt
verwendet. Zur Auswahl stehen vbUseDefaultCursor (0; Voreinstellung;
Auswahl bleibt dem Treiber überlassen), vbUseODBC (1; Verwendung der
ODBC-Cursorbibliothek) und vbUseServerSideCursor (2, Verwendung
von Server-Cursorn)
DefaultType Integer-Wert, der bestimmt, ob die Microsoft Jet-Engine oder die
ODBC-Treiber für den Datenzugriff verwendet werden sollen. Vorein-
stellung ist dbUseJet (2). Wenn Sie dbUseODBC (1) einstellen, müssen Sie
die Connect-Eigenschaft auf "Text;" gefolgt von der Verbindungszei-
chenfolge für die ODBC-Verbindung setzen.
EditMode Integer-Wert, der den Bearbeitungsstatus des aktuellen Datensatzes
anzeigt. Folgende Werte stehen zur Auswahl: dbEditNone (0) für »keine
Bearbeitung« (Voreinstellung), dbEditInProgress (1) für »Datensatz
wird bearbeitet« und dbEditAdd (2) für »Datensatz wird gerade hinzuge-
fügt«. Die Eigenschaft ist bei der Behandlung von Gültigkeitsfehlern
nützlich.
Exclusive Boolean-Wert, der bestimmt, ob die Datenbank im exklusiven Einbenut-
zermodus (True) oder im Mehrbenutzermodus (False; Voreinstellung)
geöffnet wird
ReadOnly Boolean-Wert, der bestimmt, ob die Datenbank für den reinen Lesezu-
griff (True) oder für den Schreib-/Lesezugriff (False; Voreinstellung)
geöffnet wird
Recordset Verweis auf das Recordset-Objekt, das die Datensätze für die Daten-
bankverbindung zusammenstellt, verwaltet und repräsentiert
RecordsetType Integer-Wert, der den Typ des Recordset-Objekts bestimmt. Zur Aus-
wahl stehen: vbRSTypeTable (0), vbRCTypeDynaset (1) und vbRSTypeSnap-
shot.

403
Standardsteuerelemente

Eigenschaft Beschreibung
RecordSource Zeichenfolge mit dem Namen der Tabelle, Abfrage oder einer SQL-
Anweisung, die Datensätze für das Recordset-Objekt liefert.

Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, ShowWhatsThis, UpdateControls, UpdateRecord, ZOrder

Methode Beschreibung
Standardsteuerelemente

UpdateControls Überträgt die Werte aus dem aktuellen Datensatz des Recordset-Objekts
in die mit dem Datensteuerelement verbundenen Steuerelemente. Der
explizite Aufruf dieser Methode ermöglicht es, die Steuerelemente auf die
ursprünglichen Werte des Datensatzes zurückzusetzen, wenn die Einga-
ben des Benutzers verworfen werden sollen.
UpdateRecord Überträgt die Werte der mit dem Datensteuerelement verbundenen Steu-
erelemente in den aktuellen Datensatz des Recordset-Objekts und spei-
chert diesen in der Datenbank. Falls das Recordset-Objekt vom Typ
Snapshot ist, kann die Methode die Werte nicht zurück in die Datenbank
schreiben, sondern synchronisiert die Steuerelemente mittels UpdateCon-
trols wieder mit dem ursprünglichen Datensatz.

Ereignisse

Ereignis s e
...................................................
DragDrop, DragOver, Error, MouseDown, MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop,
OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag, Reposition, Resize, Validate

Ereignis Beschreibung
Validate Tritt auf, bevor der Datensatzzeiger des Recordsets auf einen anderen
Datensatz gesetzt wird
Reposition Tritt auf, nachdem der Datensatzzeiger des Recordsets auf einen anderen
Datensatz gesetzt wurde.

Anwendung

Anwendung
...................................................
Im Lauf der Zeit hat Microsoft verschiedene Schnittstellenstandards für die datenbankgestützte
Programmierung vorgestellt: Data Access Objects (DAO), Remote Data Objects (RDO) und
ActiveX Data Objects (ADO). Jede Schnittstelle hat ihre eigene Philosophie, ihre eigene Pro-
grammierwelt und – nicht zuletzt – ihr eigenes Datensteuerelement. Traditionell ist das Data-
Steuerelement für die DAO-Schnittstelle der Microsoft Jet-Engine (bis DAO 3.51) zuständig,
während das RemoteData-Steuerelement den rein SQL-orientierten Datenbankzugriff über die
ODBC-Schnittstellen-Treiber nach dem Client/Server-Modell abwickelt. Seit Einführung der
ActiveX Data Objects und des dazu gehörigen ADO-Steuerelements mit Visual Basic 6.0 emp-
fiehlt Microsoft allerdings die Umstellung auf die ADO-Technologie, da diese nicht nur die
anderen beiden Technologien umfasst, sondern auch weiterentwickelt und künftig sogar erset-
zen soll. Trotz der Zukunftspläne von Microsoft wird das Data-Steuerelement aber so schnell
nicht von der Bildfläche verschwinden; dafür ist es zu bequem und zu weit verbreitet.
Datensteuerelemente stellen gewissermaßen den »Königsweg« für die Entwicklung datenbank-
gestützter Anwendungen dar. Sie können als Datenquellen für andere Steuerelemente (etwa

404
Data- Datensteuerelement (Data)

TextBox, Image oder ListBox) fungieren und ermöglichen die einfache Steuerung der Datensatz-
auswahl. Aus Sicht der Programmierung verkapseln sie alles, was mit Datenbankkommunika-
tion als solches zu tun hat. Sie stellen die Verbindung mit dem Datenbanksystem her und küm-
mern sich um die Abwicklung datenbankbezogener Kommandos. Insbesondere fordern sie
Datensatzmengen (Recordsets) an, pflegen Sperren für Datensätze sowie einen Datensatzzeiger
und betreiben das Zurückschreiben geänderter Datensätze. Von der äußeren Gestalt her neh-
men sich die drei Datensteuerelemente nichts. Von der programmtechnischen Seite her gibt es
aber doch einige Unterschiede.
Ein Data-Steuerelement muss den Steuerelementen, die es versorgt, bereits zur Entwurfszeit als
Datenquelle (DataSource) zugeordnet werden – ein Nachteil, den das ADO-Steuerelement nicht
mehr hat. Damit das Datensteuerelement seinen Dienst aufnehmen kann, benötigt es zum einen

Standardsteuerelemente
in der Eigenschaft DataBaseName den Dateinamen der Datenbank, aus der es seine Datensätze
beziehen soll, und zum anderen in der Eigenschaft RecordSource eine Spezifikation der zusam-
menzustellenden Datensatzmenge – jeweils als Wert vom Typ String. Die Aufgabe der Reprä-
sentation der zusammengestellten Datensatzmenge fällt dem Recordset-Objekt des Steuerele-
ments zu. Es kann einen von drei Typen haben, der über die RecordsetType-Eigenschaft
spezifiziert wird: Tabelle, Dynaset oder Snapshot.
Für ein Recordset-Objekt vom Typ Tabelle setzen Sie RecordsetType auf vbRSTypeTable (0) und
RecordSource auf den Namen einer Tabelle, die in der Datenbank als lokale Tabelle oder als
eingebundene externe Tabelle bekannt ist. Einer der größten Vorteile dieses Objekttyps ist, dass
er die jeweils vorhanden Indizes der Tabellen ausnutzen und damit schneller als die anderen
Typen sortieren und filtern kann. Für die Objekttypen Dynaset und Snapshot setzen Sie Record-
setType auf vbRSTypeDynaset (1; Voreinstellung) bzw. auf vbRSTypeSnapshot (2) und Record-
Source auf den Namen einer in der Datenbank bekannten Abfrage oder auf eine explizite SQL-
Anweisung, die eine Datensatzmenge als Ergebnis liefert. Der Unterschied zwischen diesen bei-
den Objekttypen besteht im Wesentlichen darin, dass ein »Snapshot« eine statische Ansamm-
lung von Datensätzen darstellt, die nach ihrer Zusammenstellung keine Verbindung zu den
untergelegten Tabellen mehr unterhält und somit weder eine Aktualisierung der Tabellen
ermöglicht noch spätere Aktualisierungen der Tabellen widerspiegelt. Ein »Dynaset« hält die
Verbindung mit den untergelegten Tabellen aufrecht und reicht Aktualisierungen (in beiden
Richtungen) durch.
Das Datensteuerelement baut die Datenbankverbindung auf, sobald es der ersten Aktualisie-
rungsanforderung eines mit ihm verbundenen Steuerelements nachkommen muss. Falls die
Datenbankbindung bereits zur Entwurfszeit vollständig spezifiziert wurde, passiert dies gleich
beim Laden des Formulars, auf dem die beiden Steuerelemente platziert wurden. Ansonsten
sorgt ein expliziter Aufruf der Refresh-Methode dafür.
Der weitere Umgang mit dem Datensteuerelement hängt natürlich von der Aufgabenstellung
ab. Er ist unkritisch, solange nichts weiter passiert als die Aktualisierung der verbundenen
Datenfelder (UpdateControls) oder des aktuellen Datensatzes (UpdateRecord) sowie die Durch-
setzung von Gültigkeitsregeln im Rahmen der Validate-Behandlung. Auch eine Änderung des
Recordsets (vgl. Beispiel) oder ein Wechsel der Datenbank zur Laufzeit ist nicht schwierig, führt
aber bereits in das Fahrwasser der DAO-Programmierung. Weitergehende Kenntnisse im
Bereich des Datenbank-Designs sind gefordert, wenn es um die Zusammenstellung von SQL-
Anweisungen geht, die über reine SELECT-Abfragen hinausgehen.
Beispiel

Beis piel
...................................................
Der folgende Code demonstriert den Umgang mit dem Datensteuerelement Data1 anhand des
Textfeldes Text1, das zur Entwurfszeit mit diesem gebunden wurde. Ein Klick auf die Schaltflä-
che FrachtkostenAnzeigen ändert das Recordset der Datenquelle sowie die Datenfeldbindung
des Textfeldes.

405
Standardsteuerelemente

Const Abfrage1 = "SELECT AVG(Frachtkosten) AS Fracht FROM Bestellungen"


Private Sub FrachtkostenAnzeigen_Click()
Text1.DataField = "" ' Weil RecordSource geändert wird
Data1.RecordSource = Abfrage1
Data1.Refresh ' Weil RecordSource geändert wurde
Text1.DataField = "Fracht" ' Berechnetes Feld
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Adodc, RemoteData
Standardsteuerelemente

Figur- Steuerelement (Shape)


Shape1 As Shape

Beschreibung

Bes c hreibung
...................................................
Das Figur-Steuerelement verkörpert ein grafisches Element, das es ermöglicht, Verzierungen in
Form von Steuerelementen auf einem Formular oder Benutzersteuerelement anzubringen. Die
Art der Verzierung wird über die Eigenschaft Shape spezifiziert und kann die Form eines Recht-
ecks, Quadrats, Kreises, Ellipse, Rechtecks mit abgerundeten Ecken oder Quadrats mit abge-
rundeten Ecken haben. Der Aufzählungstyp ShapeConstants definiert dafür die Konstanten:
vbShapeRectangle (0); vbShapeSquare (1); vbShapeCircle (3); vbShapeOval (2); vbShapeRounded-
Rectangle (4); vbShapeRoundedSquare (5). Die Form kann ausgefüllt oder transparent sein und
lässt sich über eine Reihe von Eigenschaften (Linienstil, Linienfarbe, Füllmuster, Füllfarbe etc.)
gestalten.
Unterbrochene Linien, wie sie ein Wert größer 1 für die BorderStyle-Eigenschaft hervorbringt,
zeichnet das Steuerelement allerdings durchgezogen, wenn die BorderWidth-Eigenschaft einen
Wert ungleich 1 hat.
Eigenschaften

Eigens c ha ften
...................................................
BackColor, BackStyle, BorderColor, BorderStyle, BorderWidth, Container, DrawMode, Fill-
Color, FillStyle, ForeColor, Height, Index, Left, Name, Parent, Shape, Tag, Visible,
Width
Methoden

Metho den
...................................................
Move, Refresh, ZOrder
Ereignisse

Ereignis s e
...................................................
Keine
Anwendung

Anwendung
...................................................
Der Umgang mit dem Steuerelement ist unkompliziert, da seine Gestaltung bereits zur Ent-
wurfszeit erfolgen kann und so Ergebnis eines interaktiven Vorgangs ist. Kreise und Rechtecke

406
Kombinationsfeld- Steuerelement ( ComboBox)

könnte man natürlich auch über die Paint-Routine des Parent-Objekts zeichnen, bei den abge-
rundeten Formen wird es bereits etwas schwieriger. In jedem Fall hilft das Steuerelement, den
Code zu reduzieren.
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Line, RptLine, RptShape
Verwandte Themen

Verwandte Them en
...................................................
Paint-Ereignis (S. 253)

Standardsteuerelemente
Kombinationsfeld- Steuerelement (ComboBox)
Combo1 As ComboBox

Beschreibung

Bes c hreibung
...................................................
Bei dem Kombinationsfeld-Steuerelement handelt es sich um ein Textfeld mit anhängendem
Listenfeld. Der Wert des Textfelds (Text) ist gleichzeitig der Standardwert des Steuerelements.
Darstellung und Verhalten des Steuerelements richten sich nach der zur Laufzeit schreibge-
schützten Style-Eigenschaft. Der Aufzählungstyp ComboBoxConstants definiert dafür drei Kon-
stanten:

Konstante (Wert) Beschreibung


vbComboDropdown (0) Dropdown-Kombinationsfeld – der Benutzer muss das Listenfeld
(Voreinstellung) über die Pfeilschaltfläche des Textfelds aufklappen, um darin eine
Auswahl zu treffen. Das Textfeld lässt beliebige Eingaben zu (vgl.
Abbildung links).
vbComboSimple (1) Einfaches Kombinationsfeld – das Listenfeld ist ständig unterhalb
des Textfelds sichtbar, und das Textfeld lässt beliebige Eingaben
zu (vgl. Abbildung: Mitte).
vbComboDropdownList (2) Dropdown-Liste – der Benutzer muss das Listenfeld über die
Pfeilschaltfläche des Textfelds aufklappen, und das Textfeld
nimmt nur Listeneinträge als Eingaben an (vgl. Abbildung rechts).

Vom Textfeld erhält das Steuerelement unter anderem die Eigenschaften DataChanged, Locked,
SelLength, SelStart, SelText sowie insbesondere das Changed-Ereignis, und vom Listenfeld
stammen die Eigenschaften List, ListCount, ListIndex, Sorted, die Methoden AddItem, Clear,
RemoveItem sowie das Scroll-Ereignis – mehr darüber in den Abschnitten »Textfeld-Steuerele-
ment (TextBox)« (S. 427) und »Listenfeld-Steuerelement (ListBox)« (S. 412).

407
Standardsteuerelemente

Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, CausesValidation, Container, DataChanged, DataField, DataFormat,
DataMember, DragIcon, DragMode, DataSource, Enabled, Font, FontBold, FontItalic, Font-
Name, FontSize, FontStrikethru, FontUnderline, ForeColor, Height, HelpContextID, hWnd,
Index, Left, List, ListCount, ListIndex, Locked, MouseIcon, MousePointer, Name,
NewIndex, OLEDragMode, OLEDropMode, Parent, RightToLeft, SelLength, SelStart, SelText,
Sorted, Style, TabIndex, TabStop, Tag, Text, Top, ToolTipText, TopIndex, Visible, Whats-
ThisHelpID, Width
Methoden

Metho den
...................................................
Standardsteuerelemente

AddItem, Clear, Drag, Move, OLEDrag, Refresh, RemoveItem, SetFocus, ShowWhatsThis, ZOr-
der
Ereignisse

Ereignis s e
...................................................
Change, Click, DblClick, DragDrop, DragOver, DropDown, GotFocus, KeyDown, KeyPress,
KeyUp, LostFocus, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESet-
Data, OLEStartDrag, Scroll, Validate
Anwendung

Anwendung
...................................................
Das Einsatzgebiet des Kombinationsfelds ist groß. Wo immer die Eingabe von Text bei vorhan-
dener Nachschlageliste stattfinden soll, ist das Kombinationsfeld die richtige Wahl. Die Pflege
und der Umgang mit der Nachschlageliste sieht nicht anders aus als beim Listenfeld. Gleiches
gilt auch für das Textfeld, mit dem einzigen Unterschied, dass dieses im Stil Dropdown-Liste
jeden Tastenanschlag des Benutzers als Anfangsbuchstabe des auszuwählenden Listeneintrags
interpretiert und den ersten passenden Listeneintrag als Wert übernimmt. Eine Wiederholung
des Tastenanschlags ändert die Auswahl in den gegebenenfalls nächsten passenden Listenein-
trag mit dem gleichen Anfangsbuchstaben.
Das Textfeld sowie die Listeneinträge sind auf eine Länge von 1024 Zeichen beschränkt. Zur
Auswertung der Benutzereingaben implementieren Sie am besten Behandlungsroutinen für die
Ereignisse LostFocus und/oder Validate.
Beispiel

Beis piel
...................................................
Die folgende LostFocus-Behandlung sorgt dafür, dass sich das Kombinationsfeld Combo1 in sei-
ner Liste immer die letzten fünf unterschiedlichen Eingaben merkt.
Const MaxElements = 5
Private Sub Combo1_LostFocus()
For i = 0 To Combo1.ListCount – 1
If Combo1.List(i) = Combo1 Then Exit Sub
Next i
Combo1.AddItem Combo1, 0
If Combo1.ListCount >= MaxElements + 1 Then
Combo1.RemoveItem Combo1.ListCount – 1
End If
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
DirListBox, DriveListbox, ImageCombo, ListBox, TextBox

408
Kontrollkästchen- Steuerelement (CheckBox)

Kontrollkästchen- Steuerelement (CheckBox)


Check1 As CheckBox

Beschreibung

Bes c hreibung
...................................................

Standardsteuerelemente
Das Kontrollkästchen-Steuerelement visualisiert die Funktion eines Schalters. Es besteht aus
einem Kästchen, das sich mit einem Häkchen versehen (»ankreuzen«) lässt, sowie einer
Beschriftung. Für die Standardeigenschaft Value des Objekts sind drei Werte definiert: vbFalse
(0), vbTrue (1) und vbUseDefault (2).
Eigenschaften

Eigens c ha ften
...................................................
Alignment, Appearance, BackColor, Caption, CausesValidation, Container, DataChanged,
DataField, DataFormat, DataMember, DataSource, DisabledPicture, DownPicture, DragIcon,
DragMode, Enabled, Font, FontBold, FontItalic, FontName, FontSize, FontStrikeThru,
FontUnderline, ForeColor, Height, HelpContextID, hWnd, Index, Left, MaskColor, Mouse-
Icon, MousePointer, Name, OLEDragMode,OLEDropMode, Parent, Picture, RightToLeft, Style,
TabIndex, TabStop, Tag, ToolTipText, Top, UseMaskColor, Value, Visible, WhatsThisHelpID,
Width
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Click, DragDrop, DragOver, GotFocus, KeyDown, KeyUp, KeyPress, LostFocus, MouseDown,
MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESet-
Data, OLEStartDrag, Validate
Anwendung

Anwendung
...................................................
Ursprüngliche Bestimmung dieses Steuerelements ist die optische Repräsentation von Werten
des Typs Boolean. Zwischen diesen beiden Werten schaltet das Steuerelement auch hin und her,
wenn der Benutzer mit der Maus darauf klickt. Inzwischen hat sich das Steuerelement durch
Hinzunahme eines dritten Werts zu einem TriState-Steuerelement gemausert. Mit welcher Inter-
pretation Sie den dritten Wert, der nur vom Programmcode aus gesetzt werden kann, versehen,
bleibt Ihnen überlassen. Von der Intuition her steht der dritte Zustand für ein »Jein«. Gängige
Interpretationen sind: »Standardeinstellung wird übernommen«, »Nicht alle abhängigen Opti-
onen sind angekreuzt«, »Zustand hat keine Wirkung«.
Jede Änderung der Value-Eigenschaft, gleich ob mit der Maus oder vom Programmcode aus,
bringt das Click-Ereignis hervor. Da Value die Standardeigenschaft des CheckBox-Objekts ist,
muss nur der Objektbezeichner notiert werden, um diese Eigenschaft anzusprechen. Um eine
Zugriffstaste für das Steuerelement zu vereinbaren, stellen Sie dem entsprechenden Buchstaben
in der Beschriftung (Caption) das Zeichen »&« voran. Er wird zur Laufzeit durch Unterstrei-
chung kenntlich gemacht.
Das Kontrollkästchen kennt zwei unterschiedliche Darstellungen: die Standarddarstellung im
Stil von Windows 9x (vgl. Abbildung) und eine benutzerdefinierte Darstellung. Die Style-

409
Standardsteuerelemente

Eigenschaft entscheidet darüber, welche der Darstellungen zur Anzeige kommt. In der benutzer-
definierten Darstellung sieht das Kontrollkästchen zunächst wie eine Befehlsschaltfläche aus,
hält aber im Gegensatz zu dieser den gedrückten Zustand bis zum nächsten Mausklick. Um
dem Steuerelement ein benutzerdefiniertes Aussehen zu verleihen, können Sie den Eigenschaften
Picture und DownPicture sowie gegebenenfalls DisabledPicture geeignete Bilder zuordnen. Falls
Sie eine pseudotransparente Darstellung wünschen, bei der die über eine Transparenzfarbe
(MaskColor) definierten transparenten Bereiche der Bilder in Hintergrundfarbe erscheinen, müs-
sen Sie die Eigenschaft UseMaskColor auf True setzen. (Ein analoges Beispiel für Schaltflächen
findet sich im Abschnitt »DisabledPicture-Eigenschaft«, S. 341.)
In Datenbankanwendungen lässt sich das Steuerelement über seine Data-Eigenschaften an ein
Feld des Typs Boolean binden.
Standardsteuerelemente

Beispiel

Beis piel
...................................................
Der folgende Code arbeitet mit einer Befehlsschaltfläche Command1 und einem Kontrollkästchen
Check1. Jeder Klick auf die Schaltfläche oder auf das Kontrollkästchen ändert den Zustand des
Kontrollkästchens. Der TriState-Zustand lässt sich nur über die Schaltfläche hervorbringen.
Private Sub Check1_Click()
MsgBox "klicke de klicke de klick"
End Sub

Private Sub Command1_Click()


Check1 = (Check1 + 1) Mod 3
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Button, CommandButton, OptionButton

Laufwerklistenfeld- Steuerelement (DriveListBox)


Drive1 As DriveListBox

Beschreibung

Bes c hreibung
...................................................
Das Laufwerklistenfeld-Steuerelement ermöglicht die Auswahl eines logischen Laufwerks des
Systems. Standardeigenschaft des Steuerelements ist Drive, eine Zeichenfolge, die den ausge-
wählten Texteintrag wiedergibt. Ändert sich die Standardeigenschaft aufgrund einer Benutzer-
interaktion, tritt das Ereignis Change auf.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, CausesValidation, Container, DragIcon, DragMode, Drive, Enabled,
Font, FontBold, FontItalic, FontName, FontSize, FontStrikethru, FontUnderline, ForeCo-
lor, Height, HelpContextID, hWnd, Index, Left, List, ListCount, ListIndex, MouseIcon,
MousePointer, Name, OLEDragMode, OLEDropMode, Parent, TabIndex, TabStop, Tag, Top, Tool-
TipText, TopIndex, Visible, WhatsThisHelpID, Width

41 0
Linie- Steuerelement (Line)

Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, DragDrop, DragOver, DropDown, GotFocus, KeyDown, KeyPress, KeyUp, LostFocus,
OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag,
Scroll, Validate
Anwendung

Anwendung
...................................................
Genau genommen müsste dieses Steuerelement die Bezeichnung »DriveCombo« tragen, da es

Standardsteuerelemente
nicht vom Listenfeld abstammt, sondern vom Kombinationsfeld- bzw. ImageCombo-Steuerele-
ment.
Die Standardeigenschaft Drive lässt sich ohne Nachbearbeitung direkt der Standardeigenschaft
Path eines DirListBox-Steuerelements zuweisen, da dieses Steuerelement (genau wie das Drive-
ListBox-Steuerelement) den Laufwerksbuchstaben automatisch extrahiert (sofern ein Leerzei-
chen und ein Text in eckigen Klammern folgen) und auf das für dieses Laufwerk geltende aktu-
elle Verzeichnis umschaltet. Die Standardeigenschaft Path eines Verzeichnislistenfelds lässt sich
wiederum in die Path-Eigenschaft eines Dateilistenfelds übernehmen, so dass sich die drei Steu-
erelemente über eine einfache Aktualisierungskette bequem synchronisieren lassen.
Beispiel

Beis piel
...................................................
Der folgende Code zeigt, wie einfach die Synchronisation zwischen Laufwerklistenfeld, Ver-
zeichnislistenfeld und Dateilistenfeld ist:
Private Sub Dir1_Change()
File1 = Dir1 ' File1.Path = Dir1.Path
End Sub

Private Sub Drive1_Change()


Dir1 = Drive1 ' Dir1.Path = Drive1.Drive
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
DirListBox, FileListBox, ImageCombo, ListBox, TextBox

Linie- Steuerelement (Line)


Line1 As Line
Beschreibung

Bes c hreibung
...................................................
Das Linie-Steuerelement verkörpert ein grafisches Element, das es ermöglicht, Linienverzierun-
gen auf einem Formular oder Benutzersteuerelement anzubringen. Das Erscheinungsbild der
Linie wird durch die Eigenschaften BorderColor, BorderStyle, BorderWidth und DrawMode
bestimmt, die Endpunkte im Koordinatensystem des Containers durch die Eigenschaften X1, Y1,
X2, Y2.
Unterbrochene Linien, wie sie ein Wert größer 1 für die BorderStyle-Eigenschaft hervorbringt,
kennt das Steuerelement nur, wenn die BorderWidth-Eigenschaft den Wert 1 hat.
Eigenschaften

Eigens c ha ften
...................................................
BorderColor, BorderStyle, BorderWidth, Container, DrawMode, Parent, Tag, Visible, X1,
X2, Y1, Y2

41 1
Standardsteuerelemente

Methoden

Metho den
...................................................
Refresh, ZOrder
Ereignisse

Ereignis s e
...................................................
Keine
Anwendung

Anwendung
...................................................
Der Umgang mit dem Steuerelement ist unkompliziert, da seine Gestaltung bereits zur Ent-
wurfszeit erfolgen kann und so Ergebnis eines interaktiven Vorgangs ist. Natürlich könnte man
Standardsteuerelemente

Linien mit den Eigenschaften des Steuerelements auch über die Paint-Routine des Parent-
Objekts zeichnen, doch die Verwendung des Steuerelements ist zumindest für statische Linien,
die als Verzierung gedacht sind, erheblich einfacher und spart zudem Code.
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
Shape, RptShape
Verwandte Themen

Verwandte Them en
...................................................
Paint-Ereignis (S. 253)

Listenfeld- Steuerelement (ListBox)


List1 As ListBox

Beschreibung

Bes c hreibung
...................................................
Das Listenfeld-Steuerelement zeigt eine Liste mit Texteinträgen an, in der ein Benutzer seine
Auswahl treffen kann. Wird die Sorted-Eigenschaft zur Entwurfszeit auf True gesetzt, fügt das
Steuerelement neue Einträge in aufsteigender alphabetischer Ordnung in die über die List-
Eigenschaft zugängliche Liste ein (und zeigt sie auch so an). Je nach Wert der MultiSelect-
Eigenschaft erlaubt das Listenfeld die Einfach- oder Mehrfachauswahl von Einträgen. Stan-
dardeigenschaft des Steuerelements ist Text. Sie ist vom Typ String und hat immer den Wert
des zuletzt markierten Listenelements. Zur Laufzeit gibt die ListIndex-Eigenschaft immer die
Position des zuletzt markierten Eintrags in der Liste wieder.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, CausesValidation, Columns, Container, DataChanged, DataField,
DataFormat, DataMember, DataSource, DragIcon, DragMode, Enabled, Font, FontBold, Font-
Italic, FontName, FontSize, FontStrikethru, FontUnderline, ForeColor, Height, HelpCon-
textID, hWnd, Index, IntegralHeight, ItemData, Left, List, ListCount, ListIndex, Mouse-
Icon, MousePointer, MultiSelect, Name, NewIndex, OLEDragMode, OLEDropMode, Parent,
RightToLeft, Selected, SelCount, Sorted, Style, TabIndex, TabStop, Tag, Text, Top, Tool-
TipText, TopIndex, Visible, WhatsThisHelpID, Width

41 2
Listenfeld- Steuerelement ( ListBox)

Eigenschaft Beschreibung
Columns Integer-Wert, der bestimmt, welche Art von Bildlauf das Listenfeld unter
Anzeige der entsprechenden Bildlaufleisten durchführt – horizontal oder
vertikal – und in wie viele Spalten es seine Anzeige aufteilt. Voreinstellung
ist der Wert 0 für den vertikalen Bildlauf, jeder andere Wert größer 0 hat
den horizontalen Bildlauf zur Folge und bestimmt die Spaltenanzahl (vgl. in
der Abbildung links und Mitte). Die Eigenschaft kann zur Laufzeit nur ver-
ändert werden, wenn sie zur Entwurfszeit auf einen Wert größer 0 gesetzt
wurde.

Standardsteuerelemente
IntegralHeight Boolean-Wert, der bestimmt, ob das Steuerelement Einträge am unteren
Ende abschneiden kann (False) oder ob es nur vollständige Einträge
anzeigt (True; Voreinstellung)
ItemData Long-Array, das es ermöglicht, jedem Eintrag einen benutzerdefinierten
Long-Wert zuzuordnen – etwa für die Indizierung von Elementen in ande-
ren Listen oder Arrays
List Objekt, das die Listeneinträge speichert und den Zugriff darauf nach dem
Prinzip des Array-Zugriffs ermöglicht. Die Array-Elemente lassen sich als
Rechts- und Linkswerte verwenden, das List-Objekt selbst jedoch weder
noch. Die Methoden AddItem und RemoveItem erweitern bzw. verkürzen die
Liste, und Clear löscht sie.
ListCount Integer-Wert, der ausdrückt, wie viele Einträge die Liste enthält
ListIndex Integer-Wert, der den Index des zuletzt ausgewählten Listeneintrags wie-
dergibt
MultiSelect Zur Laufzeit schreibgeschützter Integer-Wert, der bestimmt, ob der Benut-
zer nur einen einzelnen Eintrag (vbMultiSelectNone = 0), einen Block von
Einträgen (vbMultiSelectSimple = 1) oder mehrere einzelne Einträge bzw.
Blöcke (vbMultiSelectExtended = 2) auswählen kann
NewIndex Zur Laufzeit schreibgeschützter Integer-Wert, der wiedergibt, welches Ele-
ment als letztes in die Liste eingefügt wurde
SelCount Integer-Wert, der ausdrückt, wie viele Einträge der Benutzer markiert hat
Selected Boolean-Array, dessen Elemente den einzelnen Einträgen in der Liste zuge-
ordnet sind und beschreiben, ob der zugehörige Listeneintrag markiert ist
(True) oder nicht (False). Hat Style den Wert vbListBoxCheckBox (1),
bestimmt diese Eigenschaft, ob das Kontrollkästchen des Eintrags ein Häk-
chen enthält.
Sorted Zur Laufzeit schreibgeschützter Boolean-Wert, der bestimmt, ob das Listen-
feld seine Einträge aufsteigend sortiert (True) oder nicht (False). Deutsche
Umlaute werden nicht richtig eingeordnet, da das Steuerelement ungeachtet
der Ländereinstellungen die amerikanische Sortierordnung verwendet.
Beachten Sie auch, dass der Aufruf der AddItem-Methode bei expliziter
Angabe eines Index die Sortierung durcheinander bringen kann.
Style Zur Laufzeit schreibgeschützter Integer-Wert, der bestimmt, ob vor den
Einträgen der Liste Kontrollkästchen erscheinen (vbListBoxStandard = 0;
Voreinstellung) oder nicht (vbListBoxCheckBox = 1). Wenn diese Eigen-
schaft auf 1 gesetzt ist, muss die MultiSelect-Eigenschaft den Wert 0 haben
(vgl. in der Abbildung links und rechts).

41 3
Standardsteuerelemente

Eigenschaft Beschreibung
TopIndex Integer-Wert, der den Index des Eintrags bestimmt, welcher als oberstes
Element in der vertikal orientierten (Columns = 0) Liste erscheint – voraus-
gesetzt, es folgen noch genügend Einträge, die den sichtbaren Teil des Lis-
tenfensters füllen. Hat die Columns-Eigenschaft einen Wert größer 0,
bewirkt die TopIndex-Eigenschaft nur, dass das entsprechende Element
sicher angezeigt wird, es ist im Allgemeinen aber nicht der oberste Eintrag
in der Darstellung.
Standardsteuerelemente

Methoden

Metho den
...................................................
AddItem, Clear, Drag, Move, OLEDrag, Refresh, RemoveItem, SetFocus, ShowWhatsThis, ZOr-
der
Ereignisse

Ereignis s e
...................................................
Click, DblClick, DragDrop, DragOver, GotFocus, ItemCheck, KeyDown, KeyPress, KeyUp,
LostFocus, MouseDown, MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver,
OLEGiveFeedback, OLESetData, OLEStartDrag, Scroll, Validate
Anwendung

Anwendung
...................................................
Das Listenfeld-Steuerelement visualisiert den Inhalt eines Zeichenfolgenarrays und ermöglicht,
je nach Wert der MultiSelect-Eigenschaft, die Auswahl einer oder mehrerer Zeichenfolgen
durch einfaches Markieren mit der Maus oder der Tastatur. Wurde die Style-Eigenschaft beim
Entwurf auf »1 – Kontrollkästchen« gesetzt (was erfordert, dass MultiSelect den Wert 0 hat),
geschieht die Auswahl über das Setzen von Häkchen in die links neben den Listeneinträgen
erscheinenden Kontrollkästchen. Dieser Modus erlaubt grundsätzlich die Mehrfachauswahl.
Um die Liste zu erweitern oder zu verkürzen, benutzen Sie die Methoden AddItem und RemoveI-
tem. Die Clear-Methode löscht die gesamte Liste. Die Prototypen dieser Methoden lauten:
Sub Objekt.AddItem (Eintrag As String[, Index As Integer])
Sub Objekt.RemoveItem (Index As Integer)
Sub Objekt.Clear
Fehlt der Parameter Index beim Aufruf von AddItem, hängt die Methode einen neuen Eintrag in
Abhängigkeit von der Sorted-Eigenschaft als letztes Element an die unsortierte Liste oder sor-
tiert ihn ein. Ist ein Index spezifiziert, fügt die Methode das neue Element an der Position Index
ein und verschiebt die nachfolgenden Einträge um eine Position nach hinten, ohne Rücksicht
auf eine gegebenenfalls bestehende Sortierung. Die Angabe der Position 0 bewirkt, dass der
neue Eintrag zum ersten Element in der Liste wird. Zugänglich werden die Einträge über die
List-Eigenschaft. Der Zugriff erfolgt wie bei einem Zeichenfolgenarray unter Angabe eines
nullbasierten Indexwerts – »en bloc«-Zuweisungen, bei denen die List-Eigenschaft selbst als
Linkswert oder als Rechtswert auftritt, sind jedoch nicht möglich. Über die Eigenschaft List-
Count erfahren Sie, wie viele Elemente die Liste hat.
Laut Voreinstellung hat die MultiSelect-Eigenschaft den Wert »0 – Kein«, so dass der Benutzer
zu einem Zeitpunkt immer nur einen Eintrag markieren kann. Die Reaktion auf Benutzereinga-
ben ist in diesem Fall über die Click-Behandlung möglich, da das Steuerelement dieses Ereignis
grundsätzlich bei jeder Änderung der Markierung signalisiert, gleich ob diese auf das Konto der
Maus oder der Tastatur geht.
Wenn Sie wollen, dass der Benutzer mehrere Einträge im Listenfeld auswählen kann, setzen Sie
MultiSelect auf 1 oder 2. Die Analyse der Auswahl des Benutzers wird dann meist im Zuge der

41 4
OLE- Container- Steuerelement (OLE)

Behandlung von Validate oder LostFocus vorgenommen. Sie beinhaltet die Auswertung des
Boolean-Arrays Selected (Basis 0), das so viele Elemente hat, wie es Einträge im Listenfeld gibt,
und für jedes Element die Zugehörigkeit zur aktuellen Auswahl anzeigt – True bedeutet: das
Element gehört zur Auswahl. Die zugehörigen Einträge lassen sich unter dem jeweiligen Index
über die List-Eigenschaft gewinnen. Der Wert von SelCount informiert darüber, wie viele Ein-
träge markiert sind.
Ein Listenfeld-Steuerelement blendet automatisch eine Bildlaufleiste ein, wenn nicht alle Ein-
träge im Listenfenster auf einmal darstellbar sind (vgl. Abbildung). Wurde die Columns-Eigen-
schaft beim Entwurf auf 0 gesetzt, führt das Steuerelement einen vertikalen Bildlauf durch.
Dabei pflegt es die Eigenschaft TopIndex, so dass deren Wert immer den Index des zuoberst
gelegenen Eintrags wiedergibt. Indem Sie diese Eigenschaft auf die Position eines bestimmten

Standardsteuerelemente
Eintrags setzen, erzwingen Sie einen entsprechenden Bildlauf.
An spezifischen Ereignissen signalisiert das Steuerelement: ItemCheck und Scroll. ItemCheck
kann nur auftreten, wenn die Style-Eigenschaft auf 1 gesetzt wurde. Das Ereignis hat einen
Integer-Parameter, der die Position eines Listeneintrags ausdrückt und besagt, dass der Benut-
zer das Kontrollkästchen des Eintrags gesetzt oder gelöscht hat. Das parameterlose Scroll-
Ereignis tritt auf, wenn der Benutzer oder das Setzen der TopIndex-Eigenschaft einen Bildlauf
verursacht hat.
Beispiel

Beis piel
...................................................
Der folgende Code initialisiert ein Listenfeld List1 mit den Namen der auf dem System instal-
lierten Schriften und zeigt das Bezeichnungsfeld Label1 in der jeweils ausgewählten Schrift an.
Private Sub Form_Load()
For i = 0 To Screen.FontCount
List1.AddItem Screen.Fonts(i)
Next
End Sub

Private Sub List1_Click()


Label1.FontName = List1.Text
End Sub
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
ComboBox, CommonDialog, DirListBox, DriveListBox, ImageCombo, ListView

OLE- Container- Steuerelement (OLE)


OLE1 As OLE
Beschreibung

Bes c hreibung
...................................................
Das OLE-Container-Steuerelement eröffnet einem Visual-Basic-Programm die gesamte Funkti-
onalität OLE-fähiger Anwendungen. Es fungiert als Container für OLE-Objekte und kann ver-
knüpfte oder eingebettete Objekte darstellen und für die Bearbeitung aktivieren.
Bei einem verknüpften Objekt arbeitet das Steuerelement nur mit einem Verweis auf den Spei-
cherort für das Objekt und kommt mit dessen aktuellen Datenstrukturen überhaupt nicht in
Berührung. Für seine Darstellung im Fenster des Steuerelements liefert das Objekt ein im Meta-
file-Format gehaltenes Bild, und die Bearbeitung kann nur in einem Fenster der für das Objekt
zuständigen OLE-Quellanwendung stattfinden. Zudem speichert die Methode SaveToFile nur
die Verknüpfungsinformation, das Objekt selbst muss von der Quellanwendung aus gespeichert
werden.

41 5
Standardsteuerelemente
Standardsteuerelemente

Ein eingebettetes Objekt ist dagegen mit allen seinen Datenstrukturen im OLE-Container ent-
halten und kann von diesem beispielsweise auch komplett mittels SaveToFile gespeichert wer-
den. Für die Bearbeitung des Objekts stehen zwei Modi zur Auswahl: die Bearbeitung in einem
Fenster der OLE-Quellanwendung und die Vorortbearbeitung im Fenster des OLE-Container-
Steuerelements. Im ersten Modus, der mit dem Verb Öffnen (-2) aktiviert wird, erhält der
Benutzer ein neues Fenster der Quellanwendung mit dem Objekt und kann dieses darin bearbei-
ten und gegebenenfalls sogar (ohne Auswirkung auf das Objekt im Steuerelement) als Kopie
extern speichern. Wenn er das Fenster schließt, übernimmt das Steuerelement im Allgemeinen
automatisch alle vorgenommenen Änderungen und zeigt diese auch an. Im zweiten Modus, der
mit dem Verb Bearbeiten (-1) – und meist auch mit dem Standardverb – aktiviert wird, kann
der Benutzer das Objekt vor Ort, das heißt im Fenster des Steuerelements, bearbeiten, wobei
die OLE-Quellanwendung die Kontrolle über das Fenster des Steuerelements übernimmt, sein
Menü im Formular anzeigt usw. (vgl. Abbildung).
Eigenschaften

...................................................
Eigens c ha ften
Action, Appearance, AppIsRunning, AutoActivate, AutoVerbMenu, BackColor, BorderStyle,
CausesValidation, Class, Container, Data, DataChanged, DataField, DataText, Display-
Type, DragIcon, DragMode, Enabled, FileNumber, Format, ForeColor, Height, HelpContextID,
HostName, hWnd, Index, Left, lpOleObject, MiscFlags, MouseIcon, MousePointer, Name,
Object, ObjectAcceptFormats, ObjectAcceptFormatsCount, ObjectGetFormats, ObjectGetFor-
matsCount, ObjectVerbFlags, ObjectVerbs, ObjectVerbsCount, OLEDropAllowed, OLEType,
OLETypeAllowed, Parent, PasteOK, Picture, SizeMode, SourceDoc, SourceItem, TabIndex,
TabStop, Tag, Top, UpdateOptions, Verb, Visible, WhatsThisHelpID, Width

41 6
OLE- Container- Steuerelement (OLE)

Eigenschaft Beschreibung
Action Integer-Wert, der eine Operation des Steuerelements auslöst, sobald er
gesetzt wird. Die Aktivierung von Operationen über die Action-Eigenschaft
unterstützt das Steuerelement nur noch zum Erhalt der Kompatibilität.
Inzwischen steht für jede Operation eine Methode zur Verfügung. Folgende
Werte lösen folgende Operationen aus (in Klammern die äquivalente
Methode):
0 (CreateEmbed) Eingebettetes Objekt erstellen (SourceDoc benennt gege-
benenfalls eine Datei, Class den Objekttyp)

Standardsteuerelemente
1 (CreateLink) Verknüpftes Objekt aus dem Inhalt einer Datei erstellen
(SourceDoc benennt Datei, SourceItem gegebenenfalls
Element/Bereich innerhalb des Objekts)
4 (Copy) Objekt in Zwischenablage kopieren
5 (Paste) Kopie des Objekts in Zwischenablage in Steuerelement
einfügen
6 (Update) Darstellung des Objekts (als Bitmap) im Steuerelement
aktualisieren
7 (DoVerb) Objekt für Operation öffnen (Verb spezifiziert Operati-
on)
9 (Close) Objekt schließen und Verbindung mit OLE-Server-An-
wendung trennen
10 (Delete) Objekt löschen und von diesem belegte Ressourcen frei-
geben
11 (SaveToFile) Objekt in der geöffneten Binärdatei mit der Dateinum-
mer FileNumber speichern
12 (ReadFromFile) Objekt aus der geöffneten Binärdatei mit der Datei-
nummer FileNumber laden
14 (InsertObjDlg) Dialog OBJEKT EINFÜGEN ausführen
15 (PasteSpecialDlg) Dialog EINFÜGEN ausführen
17 (FetchVerbs) ObjectVerbs und ObjectVerbsCount aktualisieren
18 (SaveToOle1File) Objekt im OLE-1.0-Format in geöffneter Binärdatei
mit Dateinummer FileNumber speichern
AppIsRunning Boolean-Wert, der eine Aussage darüber macht, ob die für das im Container
enthaltene OLE-Objekt zuständige Quellanwendung in Ausführung ist (True)
oder nicht (False). Ein Setzen der Eigenschaft bewirkt, dass die Anwendung
explizit gestartet bzw. beendet wird.
AutoActivate Integer-Wert, der bestimmt, auf welche Art das im Container enthaltene
OLE-Objekt (sowie die dafür zuständige Server-Anwendung) aktiviert wird.
Der Aufzählungstyp VBOLEContainerConstants definiert dafür die Konstanten:
vbOLEActivateManual (0) Das Objekt lässt sich nur vom Code aus durch
Aufruf der DoVerb-Methode aktivieren.

41 7
Standardsteuerelemente

Eigenschaft Beschreibung
AutoActivate vbOLEActivateGetFocus (1) Falls das Objekt die Aktivierung per
(Forts.) Mausklick unterstützt, wird es automatisch
aktiviert, sobald das OLE-Steuerelement
den Fokus erhält.
vbOLEActivateDoubleclick (2) (Voreinstellung) Das Objekt wird durch ei-
nen Doppelklick oder (falls das OLE-Steuer-
element den Fokus besitzt) durch die Taste
(Eingabe) aktiviert. Das OLE-Steuerele-
ment sieht das DblClick-Ereignis nicht!
Standardsteuerelemente

vbOLEActivateAuto (3) Das Objekt wird automatisch aktiviert,


wenn das OLE-Steuerelement den Fokus er-
hält oder der Benutzer in das Steuerelement
doppelklickt. (Das OLE-Steuerelement sieht
das DblClick-Ereignis nicht!)
AutoVerbMenu Boolean-Wert, der bestimmt, ob das Objekt auf einen rechten Mausklick hin
ein Kontextmenü mit den für es definierten Verben (lies: Befehlen) anzeigt
(True; Voreinstellung) oder nicht (False)
Class Zeichenfolge, die den Klassennamen des eingebetteten Objekts zurückgibt
Data Long-Wert als Handle für Speicherobjekt, das für die Datenübermittlung im
spezifizierten Format (Format-Eigenschaft) herangezogen wird
DataText Zeichenfolge, die als bidirektionaler Puffer für die textorientierte Kommuni-
kation mit dem OLE-Objekt fungiert
DisplayType Integer-Wert, der angibt, ob das OLE-Objekt als Inhalt
(vbOLEDisplayContent = 0; Voreinstellung) oder als Symbol
(vbOLEDisplayIcon = 1) im Steuerelement angezeigt wird. Der Wert dieser
Eigenschaft bestimmt die Voreinstellung des Kontrollkästchens ALS SYM-
BOL ANZEIGEN in den Dialogfeldern INHALTE EINFÜGEN und OBJEKT
EINFÜGEN, wenn diese zur Laufzeit mittels der Methoden InsertObjDlg bzw.
PasteSpecialDlg angezeigt werden. Falls Sie ein OLE-Objekt mit den Metho-
den CreateEmbed oder CreateLink zur Laufzeit erstellen, legen Sie mit der Dis-
playType-Eigenschaft (unwiderruflich) fest, ob das Objekt als Inhalt oder als
Symbol im Steuerelement angezeigt werden soll.
FileNumber Integer-Wert, der für die Werte 11, 12, 18 der Action-Eigenschaft die Datei-
nummer einer im binären Modus geöffneten Datei spezifiziert. Wird nur von
Action verwendet, die Methoden SaveToFile, ReadFromFile, SaveToOle1
machen davon keinen Gebrauch.
Format Zeichenfolge, die das Datenformat für den Versand oder Erhalt objektspezi-
fischer Daten beschreibt. Die als nullbasierte Zeichenfolgen-Arrays definier-
ten Eigenschaften ObjectAcceptFormats (Empfang) und ObjectGetFormats
(Versand) stellen die von dem jeweiligen Objekttyp unterstützten Formate
zur Auswahl.
HostName Zeichenfolge, die auf den Namen der Visual-Basic-Anwendung gesetzt wer-
den kann, um der OLE-Quellanwendung die Ausgabe dieses Namens in der
Titelleiste zu ermöglichen (was jedoch nicht alle OLE-Server tun)
LpOLEObject Adresse des OLE-Objekts (wird von verschiedenen in ActiveX-DLLs gelege-
nen Routinen verlangt)

41 8
OLE- Container- Steuerelement (OLE)

Eigenschaft Beschreibung
MiscFlags Integer-Wert, der als Bitvektor generelle Verhaltensattribute des OLE-
Objekts steuert. Das Bit vbOLEMiscFlagMemStorage (1) verhindert, dass das
Objekt nur im Hauptspeicher und nicht in einer temporären Datei gespei-
chert wird, und das Bit vbOLEMiscFlagDisableInPlace (2) bewirkt, dass das
Objekt keine Vorortbearbeitung im Fenster des Steuerelements unterstützt.
ObjectAccept- Schreibgeschützter Integer-Wert, der die Elementanzahl der Eigenschaft
FormatsCount ObjectAcceptFormats wiedergibt
ObjectGetFor- Schreibgeschütztes Zeichenfolgen-Array (nullbasiert), dessen Elemente die

Standardsteuerelemente
mats Bezeichnungen der von dem OLE-Objekt lieferbaren Datenformate wieder-
geben. Für ein Bitmap-Objekt sind das beispielsweise:
»CF_METAFILEPICT«, »CF_DIB«; »CF_BITMAP"
ObjectGet- Schreibgeschützter Integer-Wert, der die Elementanzahl der Eigenschaft
FormatsCount ObjectGetFormats wiedergibt
ObjectVerb- Long-Array mit Bitvektoren, die die Anzeigezustände der im Array Object-
Flags Verbs enthaltenen Menüeinträge beschreiben. Der Aufzählungstyp VBOLECon-
tainerConstants definiert dafür die Flags:
vbOLEFlagGrayed (1) Menüelement ist abgeblendet
vbOLEFlagDisabled (2) Menüelement ist deaktiviert
vbOLEFlagChecked (8) Menüelement trägt Häkchen
vbOLEFlagSeparator (2048) Menüelement ist Trennlinie
ObjectVerbs schreibgeschütztes Zeichenfolgen-Array (nullbasiert), dessen Elemente die
Menüeinträge für die von dem Objekt (im jeweiligen Zustand) unterstützten
Verben (lies: Kommandos) darstellen. OLE-Objekte unterstützen darüber
hinaus eine Reihe von Standardverben, die eine Entsprechung durch einen
Menüeintrag haben können, aber nicht müssen. Der Aufzählungstyp VBOLE-
ContainerConstants definiert dafür die Konstanten:
vbOLEPrimary (0) Standardaktion des Objekts
vbOLEShow (-1) Objekt wird zum Bearbeiten angezeigt und akti-
viert (nach Möglichkeit für die Vorortbearbei-
tung)
vbOLEOpen (-2) Öffnet Objekt in separatem Fenster der OLE-
Quellanwendung
vbOLEHide (-3) bei eingebetteten Objekten wird die OLE-Quel-
lanwendung ausgeblendet
vbOLEUIActivate (-4) Aktiviert die Benutzeroberfläche der OLE-Quel-
lanwendung des Objekts (nach Möglichkeit für
die Vorortbearbeitung in der Zielanwendung)
vbOLEInPlaceActivate (-5) Macht das Objekt für die Vorortberarbeitung
verfügbar, so dass der Benutzer in das Objekt
klicken und es sofort bearbeiten kann
vbOLEDiscardUndoState (-6) Bringt die OLE-Quellanwendung des Objekts
dazu, alle gespeicherten Bearbeitungsschritte
rückgängig zu machen

41 9
Standardsteuerelemente

Eigenschaft Beschreibung
ObjectVerbs- Schreibgeschützter Integer-Wert, der die Elementanzahl der Eigenschaft
Count ObjectVerbs wiedergibt
OLEDropAllowed Boolean-Wert, der bestimmt, ob das Steuerelement das Ablegen von Objekten
im Rahmen von OLE-Drag&Drop-Operationen in seinem Fenster erlaubt
(True) oder nicht (False)
OLEType Schreibgeschützter Integer-Wert, der eine Aussage über das im Steuerele-
ment befindliche Objekt macht.
vbOLELinked (0) Objekt ist verknüpft
Standardsteuerelemente

vbOLEEmbedded (1) Objekt ist eingebettet


vbOLENone (3) Steuerelement enthält kein Objekt
OLETypeAllowed Integer-Wert, der bestimmt, welche Art von OLE-Objekten das Steuerele-
ment unterstützt.
vbOLELinked (0) verknüpfte OLE-Objekte
vbOLEEmbedded (1) eingebettete OLE-Objekte
vbOLEEither (2) beide Arten (der Befehl EINFÜGEN sollte mittels
PasteSpecialDlg das Dialogfeld EINFÜGEN aufrufen)
PasteOK Boolean-Wert, der bestimmt, ob der Inhalt der Zwischenablage in das Steuer-
element eingefügt werden kann (True) oder nicht (False) (Der Aktivierungs-
zustand des Menübefehls EINFÜGEN sollte sich nach dem Wert dieser
Eigenschaft richten.)
SizeMode Integer-Wert, der den Zusammenhang zwischen den Abmessungen des
Steuerelements und denen des OLE-Objekts festlegt.
vbOLESizeClip (0) OLE-Objekt wird in der originalen Größe angezeigt,
die Darstellung wird jedoch am Rand des Steuerele-
ments beschnitten (Voreinstellung)
vbOLESizeStretch (1) Darstellung des OLE-Objekts wird gestreckt oder ge-
staucht (und dabei gegebenenfalls verzerrt), damit sie
den Fensterbereich des Steuerelements vollständig
ausfüllt
vbOLESizeAutoSize (2) Abmessungen des Steuerelements werden automatisch
an die orignale Größe des OLE-Objekts angepasst
(das Steuerelement-Objekt erhält ein Resize-Ereignis!)
vbOLESizeZoom (3) Darstellung des OLE-Objekts wird gestreckt oder ge-
staucht (dabei jedoch nicht verzerrt), damit sie den
Fensterbereich des Steuerelements möglichst vollstän-
dig ausfüllt
SourceDoc Zeichenfolge, die für den Wert 1 der Action-Eigenschaft (Objekt verknüpfen)
den Dateinamen der Verknüpfung bereitstellt und für den Wert 0 (Objekt
einbetten) den Dateinamen der Datei mit dem einzubettenden OLE-Objekt.
Im Zusammenhang mit den inzwischen verfügbaren Methoden CreateLink
bzw. CreateEmbed hat der Wert von SourceDoc jedoch keine Bedeutung mehr.
Zur Laufzeit gibt die SourceItem-Eigenschaft eine leere Zeichenfolge zurück,
während die SourceDoc-Eigenschaft den vollständigen Pfad zu der verknüpf-
ten Datei, gefolgt von einem Ausrufezeichen (!) und dem Wert des Source-
Item-Parameters enthält. Beispiel: "C:\MeinText!Textmarke1"

420
OLE- Container- Steuerelement (OLE)

Eigenschaft Beschreibung
SourceItem Zeichenfolge, die für den Wert 1 der Action-Eigenschaft (Objekt verknüpfen)
das einzufügende Element (bzw. Elementbereich) des Objekts benennt,
ansonsten (insbesondere im Zusammenhang mit den inzwischen verfügbaren
Methoden CreateLink bzw. CreateEmbed) jedoch keine Funktion mehr hat
(vgl. SourceDoc)
UpdateOptions Integer-Wert, der bestimmt, wie ein verknüpftes Objekt aktualisiert wird,
wenn sich seine Daten aufgrund von Fremdeinwirkungen ändern:
vbOLEAutomatic (0) Automatisch (Voreinstellung). Die Darstellung des Ob-

Standardsteuerelemente
jekts wird sofort aktualisiert, sobald sich die verknüpf-
ten Daten ändern
vbOLEFrozen (1) Die Darstellung des Objekts ist gegenüber Änderungen
des Objektzustands eingefroren. Eine Aktualisierung
findet nur statt, wenn das Objekt von der Quellanwen-
dung aus gespeichert wird
vbOLEManual (2) Für die Aktualisierung der Darstellung des Objekts ist
ein Aufruf der Update-Methode erforderlich
Verb Integer-Wert, der für den Wert 7 der Action-Eigenschaft die auszuführende
Operation angibt; wird von DoVerb ignoriert und dient nur noch dem Erhalt
der Kompatibilität

Methoden
Methoden

...................................................
Close, Copy, CreateEmbed, CreateLink, Delete, DoVerb, Drag, FetchVerbs, InsertObjDlg,
Move, Paste, PasteSpecialDlg, ReadFromFile, Refresh, SaveToFile, SaveToOle1File, SetFo-
cus, ShowWhatsThis, Update, ZOrder
Die Prototypen der nicht an anderer Stelle vorgestellten Methoden des Steuerelements sind:
Sub Objekt.Copy()
Sub Objekt.CreateEmbed(SourceDoc As String, [Class As String])
Sub Objekt.CreateLink(SourceDoc As String, [SourceItem As String])
Sub Objekt.Delete()
Sub Objekt.DoVerb(Verb As Integer)
Sub Objekt.FetchVerbs
Sub Objekt.InsertObjDlg
Sub Objekt.Paste
Sub Objekt.PasteSpecialDlg
Sub Objekt.ReadFromFile (FileNumber As Integer)
Sub Objekt.SaveToFile (FileNumber As Integer)

Methode Beschreibung
Copy Fügt eine Kopie des in der Zwischenablage befindlichen Objekts als OLE-
Objekt in das Steuerelement ein

421
Standardsteuerelemente

Methode Beschreibung
CreateEmbed Fügt ein OLE-Objekt als eingebettetes Objekt in das Steuerelement ein.
Der obligatorische Parameter SourceDoc spezifiziert die Dokumentdatei, in
der das Objekt gespeichert ist. Um ein neues Objekt anzulegen, erhält
SourceDoc beim Aufruf die leere Zeichenfolge und der Class-Parameter den
Namen der dem Objekt zugrunde zu legenden (registrierten) OLE-Klasse.
CreateLink Fügt das in der Dokumentdatei mit dem Namen SourceDoc befindliche
Objekt als verknüpftes Objekt in das Steuerelement ein. Über den optiona-
len Parameter SourceItem lässt sich das Objekt auf eines seiner Elemente
Standardsteuerelemente

bzw. einen Elementbereich einschränken. Nach dem erfolgreichen Öffnen


des Objekts hinterlegt die Methode die vollständige Verknüpfungsinfor-
mation in der Eigenschaft SourceDoc nach dem Muster "C:\TEXT.DOC!MAR-
KE1" für ein Word-Dokument oder "C:\TABS\LOHN.XLS!Z2S1:Z22S5" für
eine Excel-Tabelle. Der Darstellung des Objekts im Steuerelement liegt das
Metafile-Format zugrunde, da die Quelldaten dafür nicht verfügbar sind.
Gespeichert wird nicht das Objekt selbst (dieses kann nur im Bearbeitungs-
modus über die Quellanwendung gespeichert werden), sondern nur die in
der Eigenschaft SourceDoc enthaltene Verknüpfungsinformation.
Delete Löscht das dem Steuerelement zugeordnete OLE-Objekt explizit und gibt
insbesondere die von diesem belegten Ressourcen frei. Erfolgt der Delete-
Aufruf für das Objekt nicht, wird es zusammen mit dem Steuerelementob-
jekt beim Schließen des Formulars abgebaut.
DoVerb Weist das Objekt an, die Aktion Verb auszuführen. Als Werte für Verb ste-
hen die Standardverben sowie die zu dem jeweiligen Objekt (und seinem
aktuellen Zustand) gehörigen Verben zur Verfügung (vgl. ObjectVerbs).
Verben aus dem ObjectVerbs-Array sind über ihren Index anzugeben.
FetchVerbs Aktualisiert die Eigenschaft ObjectVerbs
InsertObjDlg Ruft das Dialogfeld OBJEKT EINFÜGEN auf, das es dem Benutzer ermög-
licht, interaktiv ein OLE-Objekt als verknüpftes oder eingebettetes Objekt
in das Steuerelement einzufügen. Der Funktionsumfang des Dialogfelds
richtet sich nach dem Wert der Eigenschaft OLETypeAllowed.
Paste Kopiert das in dem Steuerelement enthaltene OLE-Objekt in die Zwischen-
ablage
PasteSpecialDlg Ruft das Dialogfeld EINFÜGEN auf, das es ermöglicht, den Inhalt der
OLE-Zwischenablage als eingebettetes oder verknüpftes OLE-Objekt in
das Steuerelement einzufügen. Der Funktionsumfang des Dialogfelds rich-
tet sich nach dem Wert der Eigenschaft OLETypeAllowed.
ReadFromFile Liest ein OLE-Objekt aus der bereits mit der Dateinummer FileNumber
geöffneten Binärdatei und fügt es in das Steuerelement als eingebettetes
oder verknüpftes Objekt ein. Das Objekt muss zuvor (mit der Methode
SaveToFile) im OLE-Format in der Binärdatei gespeichert worden sein,
sonst kommt es zu einem Laufzeitfehler.

422
OLE- Container- Steuerelement (OLE)

Methode Beschreibung
SaveToFile Speichert das im Steuerelement enthaltene OLE-Objekt in einer zuvor im
binären Modus geöffneten Datei mit der Dateinummer FileNumber. Wenn
es sich bei dem Objekt um ein verknüpftes Objekt handelt (OLEType = 0),
speichert die Methode nur den in der Eigenschaft SourceDoc enthaltenen
Verweis auf das Objekt.
SaveToOle1File Wie SaveToFile, speichert das Objekt jedoch im OLE 1.0-Format

Ereignisse

Ereignis s e
...................................................

Standardsteuerelemente
Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyPress, KeyUp, LostFocus,
MouseDown, MouseMove, MouseUp, ObjectMove, Resize, Updated
Private Sub Objekt_ObjectMove(Left As Single, Top As Single, _
Width As Single, Height As Single)
Das Ereignis ObjectMove tritt auf, wenn der Benutzer eine Größenänderung beim aktiviertem
OLE-Objekt vornimmt. Sie können das Ereignis behandeln, um die Größe des Steuerelements
an die des Objekts anzupassen. Falls keine Behandlungsroutine existiert oder diese nicht die
vom Objekt angeforderten Abmessungen einstellt, passt das Objekt seine Abmessungen wieder
an die des Steuerelements an.
Anwendung

Anwendung
...................................................
Das OLE-Container-Steuerelement zählt zu den anspruchsvolleren Steuerelementen, deren
Möglichkeiten schon beinahe ins Unerschöpfliche gehen, weil es einem Visual-Basic-Programm
gewissermaßen die gesamte Welt des OLE 2.0 erschließt. Der Zugang zu diesem Steuerelement
ist dennoch einfach. Platziert man es im Entwurfsmodus beispielsweise auf einem Formular,
konfrontiert einen Visual Basic (nach einer kurzen »Bedenkzeit«) mit dem Dialogfeld OBJEKT
EINFÜGEN, das eine Auswahl des für das Steuerelement vorgesehenen verknüpften Objekts bzw.
des Typs für ein neu zu erstellendes eingebettetes Objekt gestattet. Sie können den Dialog auch
abbrechen, wenn Sie vorhaben, dem Steuerelement erst zur Laufzeit ein OLE-Objekt zuzuord-
nen – etwa über die Zwischenablage.
Um dem Steuerelement zur Laufzeit ein OLE-Objekt zuzuordnen, haben Sie verschiedene Mög-
lichkeiten. Zunächst einmal können Sie den alten, von Microsoft jedoch nicht mehr empfohle-
nen Weg über die Action-Eigenschaft gehen: Setzen Sie dazu im ersten Schritt die Eigenschaften
SourceDoc, SourceItem sowie erforderlichenfalls Class auf geeignete Werte. Im zweiten Schritt
setzen Sie die Action-Eigenschaft auf den Wert 0, um ein eingebettetes OLE-Objekt aus der
Datei SourceDoc zu laden bzw. ein neues Objekt des Typs Class zu generieren, oder auf den
Wert 1, um ein verknüpftes OLE-Objekt einzufügen, das in der Datei SourceDoc gespeichert und
gegebenenfalls durch SourceItem genauer spezifiziert ist. Der von Microsoft empfohlene Weg
sieht dagegen den Aufruf der Methoden CreateEmbed und CreateLink vor, deren Parameter die
gleichen Namen wie die von Action benutzten Eigenschaften tragen und auch die gleichen
Funktionen haben, so dass die Eigenschaften unbeachtet bleiben. Einen dritten Weg eröffnet die
Methode InsertObjDlg (respektive der Code 14 für die Action-Eigenschaft). Sie ruft das (bereits
vom Entwurfsmodus her bekannte) Dialogfeld OBJEKT EINFÜGEN auf, in dem der Benutzer das
OLE-Objekt interaktiv als eingebettetes oder verknüpftes Objekte genauer spezifizieren kann.
Um zu erfahren, welche Art von Objekt der Benutzer in dem Dialog eingefügt hat, empfiehlt
sich eine Auswertung der OLEType-Eigenschaft.
Ein anderer Weg, wie ein OLE-Steuerelement zu einem OLE-Objekt kommt, ist der über die
Zwischenablage. Wenn Sie den Kopiervorgang mit der Paste-Methode (im Standardformat)

423
Standardsteuerelemente

abwickeln wollen, sollten Sie prüfen, ob der Aufruf erfolgreich sein kann. Dazu stellen Sie erst
einmal klar, ob die Zwischenablage das gewünschte Format liefern kann (vgl. ClipBoard-
Objekt), setzen dann die OLETypeAllowed-Eigenschaft auf die gewünschte Objektart und rufen
schließlich Paste in Abhängigkeit vom Wert der Eigenschaft PasteOK auf. Sie können aber auch
die Methode PasteDlgSpecial aufrufen, um dem Benutzer im Rahmen des Dialogfelds EINFÜ-
GEN die Wahl zu überlassen, in welcher Form (und gegebenenfalls in welchem Format) er das
Objekt einfügen möchte. Umgekehrt können Sie mittels Copy natürlich auch eine Kopie des
OLE-Objekts in die Zwischenablage übertragen.
Völlig automatisch geht die Geschichte, wenn der Benutzer das Objekt im Rahmen einer OLE-
Drag&Drop-Operation in das Steuerelement zieht. Einzige Voraussetzung: OLEDropAllowed
muss True sein.
Standardsteuerelemente

Zu guter Letzt können Sie das Objekt aber auch mittels ReadFromFile direkt aus einer bereits im
binären Modus geöffneten Datei einlesen. Die Kombination SaveToFile und ReadFromFile
ermöglicht es, OLE-Objekte in eigenen Dateien zu speichern, um diese gegebenenfalls in einer
späteren Sitzung wieder einzulesen.
Um dem OLE-Objekt ein Kommando aus der Liste der Standardverben sowie seiner eigenen
Verben (ObjectVerbs) zu übermitteln, benutzen Sie die Methode DoVerb. Wenn Sie das OLE-
Objekt des Steuerelements OLE1 beispielsweise für die Vorortbearbeitung aktivieren wollen,
schreiben Sie:
OLE1.DoVerb -4

Anstelle von -4 könnten Sie auch den Index des Befehls »Bearbeiten« im Kontextmenü des
Objekts (ObjectVerbs) angeben. Dieser ist meist 0, da er im Allgemeinen die Standardoperation
des Objekts darstellt. Natürlich kann der Benutzer die Aktivierung auch wie üblich auch per
Doppelklick vornehmen (vgl. AutoActivate)
Beispiel

Beis piel
...................................................
OLE1.AutoActivate = 3
OLE1.OLETypeAllowed = vbOLEEmbedded ' nur einbetten
If OLE1.PasteOK Then OLE1.PasteSpecialDlg ' Aus Zwischenablage ...
...
If OLE1.OLEType <> 3 Then OLE1.DoVerb -4 ' Objekt vorort bearbeiten

Verwandte Objekte
...................................................
ClipBoard
Verwandte Themen

Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)

Optionsfeld- Steuerelement (OptionButton)


Option1 As OptionButton

424
Optionsfeld- Steuerelement (OptionButton)

Beschreibung

Bes c hreibung
...................................................
Das Optionsfeld-Steuerelement visualisiert die Auswahl einer spezifischen Option unter mehre-
ren möglichen Optionen. Im selben Container situierte Optionsfelder bilden automatisch eine
Optionsgruppe, in der sich die Mitglieder gegenseitig auslösen, so dass maximal immer nur ein
Optionsfeld markiert und damit auch ausgewählt sein kann. Standardeigenschaft des Options-
felds ist Value, ein Boolean-Wert mit der Voreinstellung False.
Eigenschaften

Eigens c ha ften
...................................................
Alignment, Appearance, BackColor, Caption, CausesValidation, Container, DataFormat,

Standardsteuerelemente
DisabledPicture, DownPicture, DragIcon, DragMode, Enabled, Font, FontBold, FontItalic,
FontName, FontSize, FontStrikethru, FontUnderline, ForeColor, Height, HelpContextID,
hWnd, Index, Left, MaskColor, MouseIcon, MousePointer, Name, OLEDropMode, Parent, Right-
ToLeft, Style, TabIndex, TabStop, Tag, Top, ToolTipText, UseMaskColor, Value, Visible,
WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyPress, KeyUp, LostFocus,
MouseDown, MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeed-
back, OLESetData, OLEStartDrag, Validate
Anwendung

Anwendung
...................................................
Das Optionsfeld bildet aus logischer Sicht das Gegenstück zum Kontrollkästchen. Während
letzteres als Schalter für logisch voneinander unabhängige Attribute fungiert, ist das Options-
feld für die Darstellung sich gegenseitig ausschließender Attribute konzipiert. Es hat daher
wenig Sinn, einzelne Optionsfelder isoliert zu verwenden. Vielmehr werden Optionsfelder
immer gruppiert. Falls ein Formular oder eine Komponente mehrere logisch voneinander unab-
hängige Gruppierungen anzeigen soll, müssen die Gruppierungen in je eigenen Container-
Steuerelementen (Frame, PictureBox, SSTab) platziert sein (vgl. Abbildung). Je Gruppierung soll-
ten Sie eine Standardoption festlegen, ein Optionsfeld, dessen Value-Eigenschaft Sie am besten
bereits zur Entwurfszeit auf True setzen.
Jede Änderung der Value-Eigenschaft, gleich ob mit der Maus, mit einer Zugriffstaste oder vom
Programmcode aus, bringt das Click-Ereignis hervor. Da Value die Standardeigenschaft des
OptionButton-Objekts ist, muss nur der Objektbezeichner notiert werden, um diese Eigenschaft
anzusprechen. Um eine Zugriffstaste für das Steuerelement zu vereinbaren, stellen Sie dem ent-
sprechenden Buchstaben in der Beschriftung (Caption) das Zeichen »&« voran. Er erscheint zur
Laufzeit unterstrichen.
Zur einfachen Auswertung vereinbaren Sie Optionsfeldgruppen am besten als Steuerelemente-
Arrays. Der Index-Parameter des Click-Ereignisses liefert dann nämlich vorteilhafterweise den
Array-Index des betroffenen Optionsfelds:
Option1_Click(Index As Integer)
Select Case Index
Case 0: ' Erstes Attribut ...
Case 1: ' Zweites Attribut ...
End Select
End Sub

425
Standardsteuerelemente

Das Optionsfeld kennt zwei unterschiedliche Darstellungen: die Standarddarstellung im Stile


von Windows 9x (vgl. Abbildung) und eine benutzerdefinierte Darstellung. Die Style-Eigen-
schaft entscheidet darüber, welche der Darstellungen zur Anzeige kommt. In der benutzerdefi-
nierten Darstellung sieht das Optionsfeld zunächst wie eine Befehlsschaltfläche aus, hält aber
im Gegensatz zu dieser den gedrückten Zustand, bis es von einem anderen Optionsfeld ausge-
löst wird. Um dem Steuerelement ein benutzerdefiniertes Aussehen zu verleihen, können Sie den
Eigenschaften Picture und DownPicture sowie gegebenenfalls DisabledPicture geeignete Bilder
zuordnen. Falls Sie eine pseudotransparente Darstellung wünschen, bei der die über eine Trans-
parenzfarbe (MaskColor) definierten transparenten Bereiche der Bilder in Hintergrundfarbe
erscheinen, müssen Sie die Eigenschaft UseMaskColor auf True setzen. (Ein analoges Beispiel für
Schaltflächen findet sich im Abschnitt »DisabledPicture-Eigenschaft«, S. 341.)
Standardsteuerelemente

Beispiel

Beis piel
...................................................
Im folgenden Beispiel dient eine Optionsfeldgruppe zur Auswahl der Form für das Figur-Steuer-
element Shape1.
Private Sub Option1_Click(Index As Integer)
Shape1.Shape = Index
End Sub

Verwandte Befehle

Verwa ndte Befehle


...................................................
Button, CheckBox, CommandButton

Rahmen- Steuerelement (Frame)


Frame1 As Frame
Beschreibung

Bes c hreibung
...................................................
Das Rahmen-Steuerelement ist eines der drei Steuerelemente, die als Container für andere Steu-
erelemente auftreten können. Die beiden anderen sind: PictureBox und SSTab. Es kann daher
nicht nur für die visuelle, sondern insbesondere auch für die funktionelle Gruppierung anderer
Steuerelemente benutzt werden. Standardeigenschaft des Steuerelements ist die Caption-Eigen-
schaft, die der Entwurfseditor mit dem automatisch generierten Namen des Steuerelements vor-
besetzt.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, Caption, ClipControls, Container, DragIcon, DragMode, Enabled, Font,
FontBold, FontItalic, FontName, FontSize, FontStrikethru, FontUnderline, ForeColor, Height,
HelpContextID, hWnd, Index, Left, MouseIcon, MousePointer, Name, OLEDropMode, Parent, Right-
ToLeft, TabIndex, Tag, Top, ToolTipText, Visible, WhatsThisHelpID, Width

426
Textfeld- Steuerelement ( TextBox)

Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, ShowWhatsThis, Refresh, ZOrder
Ereignisse

Ereignis s e
...................................................
Click, DblClick, DragDrop, DragOver, MouseDown, MouseMove, MouseUp, OLECompleteDrag,
OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag
Anwendung

Anwendung
...................................................
Eine der Regeln, die der Entwurfseditor auferlegt, lautet: Ein Steuerelement kann seinen Con-

Standardsteuerelemente
tainer nicht wechseln. Um ein Steuerelement in einem Rahmen zu platzieren, müssen Sie das
Steuerelement also bereits im Rahmen anlegen. Zur Laufzeit sieht das anders aus: Indem Sie die
Container-Eigenschaft eines Steuerelement auf ein Frame-Objekt setzen, platzieren Sie es in des-
sen Rahmen (beachten Sie aber, dass sich dadurch das für das Steuerelement geltende Koordi-
natensystem ändern kann).
Die Hauptanwendung des Rahmen-Steuerelements ist und bleibt aber die Gruppierung von
Optionsfeldern. Da in einem Container immer nur ein Optionsfeld markiert sein kann, weil sich
alle in einem Container befindlichen Optionsfelder gegenseitig auslösen, müssen funktional
voneinander unabhängige Gruppierungen auf verschiedene Container verteilt werden. Unter
den verfügbaren Container-Steuerelementen ist das Rahmen-Steuerelement die perfekte Wahl,
weil es zudem eine passende Beschriftung der Gruppierung ermöglicht.
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
PictureBox, SSTab

Textfeld- Steuerelement (TextBox)


Text1 As TextBox
Beschreibung

Bes c hreibung
...................................................
Das Textfeld-Steuerelement ist auf die interaktive Ein- und Ausgabe von Text eingerichtet. Die
Standardeigenschaft Text des Steuerelements ist vom Typ String und kann (nahezu) beliebig
lange Zeichenfolgen enthalten. Um die Länge zu beschränken, lässt sich über die MaxLength-
Eigenschaft eine maximale Zeichenanzahl setzen. Mittels der Locked-Eigenschaft lässt sich das
Steuerelement für Benutzereingaben sperren. Neben der voreingestellten einzeiligen Anzeige
unterstützt das Steuerelement auch die mehrzeilige Anzeige mit automatischem Umbruch auf
der Basis von Leerzeichen. Dazu ist die MultiLine-Eigenschaft beim Entwurf auf True zu setzen.
Falls der Fensterbereich des Textfelds für die Anzeige des Werts nicht ausreicht, lassen sich zur
besseren Navigation über die ScrollBars-Eigenschaft Bildlaufleisten hinzufügen.
In einer eingeschränkten Fassung ist das Textfeld auch als Bestandteil der Steuerelemente Com-
boBox, DBCombo, DataGrid sowie als »Partner« (Buddy) des UpDown-Steuerelements anzutreffen.
Über seine Link-Eigenschaften, -Methoden und -Ereignisse kann das Steuerelement als Quell-
oder Zielsteuerelement für DDE-Verbindungen benutzt werden – mehr dazu unter den entspre-
chenden Eigenschaften und Ereignissen. Die Data-Eigenschaften ermöglichen die Anbindung des
Textfelds an ein Datenbankfeld – mehr dazu unter »Data-Datensteuerelement (Data)«, S. 402.

Eigenschaft Beschreibung
HideSelection Boolean-Wert, der bestimmt, ob eine Markierung bei Fokusverlust sichtbar
bleibt (False) oder nicht (True; Voreinstellung)

427
Standardsteuerelemente

Eigenschaft Beschreibung
Locked Boolean-Wert, der bestimmt, ob der Benutzer Eingaben in das Textfeld
vornehmen kann (False; Voreinstellung) oder nicht (True). Ein für die Ein-
gabe gesperrtes Textfeld nimmt zwar den Fokus an und erlaubt die Navi-
gation im Text, reagiert aber nicht auf Tastatureingaben, die den aktuellen
Wert ändern würden.
MaxLength Long-Wert, der bestimmt, wie viele Zeichen der Wert des Textfelds maxi-
mal enthalten darf. Wird die Eigenschaft auf dem voreingestellten Wert 0
belassen, kann Text wie jeder andere Wert vom Typ String (nahezu) belie-
Standardsteuerelemente

big lang werden. Wird die MaxLength-Eigenschaft im Nachhinein kleiner als


die Länge des aktuellen Text-Werts gesetzt, ändert dies die Anzeige nicht,
und der Benutzer kann nach wie vor den gesamten Wert bearbeiten. Die
neue Beschränkung tritt jedoch alsbald in Kraft, wenn der Benutzer Zei-
chen löscht.
MultiLine Zur Laufzeit schreibgeschützter Boolean-Wert, der bestimmt, ob die Dar-
stellung des Standardwerts auf eine Zeile beschränkt bleibt (False; Vorein-
stellung) oder auch mehrere Zeilen umfassen kann. Falls das Textfeld eine
horizontale Bildlaufleiste besitzt (ScrollBars-Eigenschaft), richtet sich der
Umbruch nach dem Vorkommen von Zeilenvorschubzeichen (vbCrLf),
ansonsten führt das Steuerelement einen automatischen Umbruch auf der
Basis von Leerzeichen durch.
PasswordChar String-Wert der Länge 1, der das Platzhalterzeichen für die Kennwortein-
gabe bestimmt. Wird die Eigenschaft auf einen Wert ungleich der leeren
Zeichenfolge (Voreinstellung) gesetzt, aktiviert dies den Modus »Kenn-
worteingabe«: Der Benutzer sieht dann für jedes eingegebene Zeichen ein
Platzhalterzeichen und kann den Wert nicht mehr in die Zwischenablage
übernehmen. Das Textfeld ignoriert diese Eigenschaft allerdings bei mehr-
zeiliger Anzeige (vgl. MultiLine).
ScrollBars Integer-Wert, der bestimmt, ob das Textfeld im mehrzeiligen Modus (vgl.
MultiLine) Bildlaufleisten anzeigt und automatisch verwaltet. Der Aufzäh-
lungstyp ScrollBarConstants definiert dafür die Konstanten: vbSBNone (0)
für keine Bildlaufleisten; vbHorizontal (1) für waagrechte Bildlaufleiste;
vbVertical (2) für senkrechte Bildlaufleiste; vbBoth (3) für waagrechte und
senkrechte Bildlaufleiste. Bei Anzeige der waagrechten Bildlaufleiste erfolgt
kein automatischer Umbruch auf der Basis von Leerzeichen.
SelLength Long-Wert, der die Länge der Markierung ab der Position SelStart
beschreibt. Ist der Wert größer als die Anzahl der restlichen Zeichen ab
SelLength, korrigiert das Steuerelement den Wert auf die Anzahl der restli-
chen Zeichen.
SelStart Long-Wert, der die Position des Zeichens in Text beschreibt, an der die
Markierung beginnt. Ein Ändern dieser Eigenschaft setzt SelLength auf 0.
Ist der neue Wert für SelStart größer als die Länge von Text, korrigiert ihn
das Steuerelement auf die aktuelle Länge des Textes, so dass er auf die
Position hinter dem letzten Zeichen verweist.

428
Textfeld- Steuerelement ( TextBox)

Eigenschaft Beschreibung
SelText String-Wert, der den markierten Teil von Text wiedergibt oder neu defi-
niert. Setzt man diese Eigenschaft, passiert Folgendes: Ist die aktuelle
Länge der Markierung 0 (SelLength), wird der neue Wert an der Position
SelStart eingefügt. Ansonsten ersetzt der neue Wert die Markierung, ohne
dass die Längen eine Rolle spielen.

Eigenschaften

Eigens c ha ften
...................................................
Alignment, Appearance, BackColor, BorderStyle, CausesValidation, Container, DataChan-

Standardsteuerelemente
ged, DataField, DataFormat, DataMember, DataSource, DragIcon, DragMode, Enabled, Font,
FontBold, FontItalic, FontName, FontSize, FontStrikethru, FontUnderline, ForeColor,
Height, HelpContextID, HideSelection, hWnd, Index, Left, LinkItem, LinkMode, LinkTime-
out, LinkTopic, Locked, MaxLength, MouseIcon, MousePointer, MultiLine, Name, OLEDrag-
Mode, OLEDropMode, Parent, PasswordChar, RightToLeft, ScrollBars, SelLength, SelStart,
SelText, TabIndex, TabStop, Tag, Text, Top, ToolTipText, Visible, WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, LinkExecute, LinkPoke, LinkRequest, LinkSend, Move, OLEDrag, Refresh, SetFocus,
ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, Click, DblClick, DragDrop, DragOver, GotFocus, KeyDown, KeyPress, KeyUp, LinkC-
lose, LinkError, LinkNotify, LinkOpen, LostFocus, MouseDown, MouseMove, MouseUp, OLECom-
pleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback, OLESetData, OLEStartDrag, Vali-
date
Anwendung

Anwendung
...................................................
Das Textfeld-Steuerelement ersetzt die klassische Input-Anweisung von Basic. Es eignet sich für
die Ein- und Ausgabe beliebiger Werte mit String-Repräsentation und erfreut durch eine
brauchbare Implementation der Tastaturschnittstelle.
Um den Wert des Textfelds zu setzen oder abzufragen, genügt es, den Bezeichner des Textfeld-
objekts zu notieren. Visual Basic nimmt nach Möglichkeit eine automatische Typumwandlung
vor. Mit jeder Änderung von Text tritt das Change-Ereignis auf. Es zeigt an, dass eine Tastatur-
eingabe, eine DDE-Aktualisierung, eine Datensatzaktualisierung oder eine Wertänderung vom
Programmcode aus geschehen ist. Wenn Sie eine Gültigkeitsprüfung für den Fall des Fokusver-
lusts etablieren wollen, behandeln Sie das Validate-Ereignis. Dazu muss jedoch die CausesVali-
dation-Eigenschaft nicht nur des Textfelds, sondern auch des Steuerelements, das den Fokus
erhält, auf True gesetzt sein.
Wenn Sie ein Textfeld für die Kennworteingabe verwenden wollen, setzen Sie die Eigenschaft
PasswordChar auf ein Zeichen, das als Platzhalterzeichen für eingegebene Zeichen erscheinen
soll.
Tipp

Tipp
...................................................
Anstelle eines Textfelds können Sie einmalige Eingaben auch über die InputBox-Funktion abwi-
ckeln:
a$ = InputBox ("Bitte Startwert eingeben")

429
Standardsteuerelemente

Beispiel

Beis piel
...................................................
Das Beispielprojekt EuroDMTestProjekt zeigt die Implementation eines Benutzersteuerelements
mit zwei Textfeldern, die sich gegenseitig im Rahmen ihrer Change-Behandlung aktualisieren.
Der Zweck der auf Modulebene vereinbarten Zustandsvariable Changing besteht darin, einer
endlosen Rekursion vorzubeugen, die ansonsten aufgrund der gegenseitigen Wertänderung der
Steuerelemente resultieren würde.
Standardsteuerelemente

Fenster eines Formulars, auf dem das Benutz ersteuerelement EuroDM platz iert wurde

' Projekt: Euro/DM-TestProjekt


Const sKurs = 1.95583
Dim Changing As Boolean
Property Let Euro(Value As Currency)
tfEuro = Value
End Property
Property Get Euro() As Currency
Euro = tfEuro
End Property
Property Let DM(Value As Currency)
tfDM = Value
End Property
Property Get DM() As Currency
DM = tfDM
End Property

Private Sub tfDM_Change()


If Not Changing Then
Changing = True
tfEuro = Round(Val(tfDM) / sKurs, 2)
Else
Changing = False
End If
End Sub

Private Sub tfEuro_Change()


If Not Changing Then
Changing = True
tfDM = Round(Val(tfEuro) * sKurs, 2)
Else
Changing = False
End If
End Sub

430
Verzeichnislistenfeld- Steuerelement ( DirListBox)

Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
ComboBox, DataList, DBCombo, MaskEDBox, RichTextBox, RptTextBox

Verzeichnislistenfeld- Steuerelement (DirListBox)


Dir1 As DirListBox

Standardsteuerelemente
Beschreibung

Bes c hreibung
...................................................
Das Verzeichnislistenfeld-Steuerelement visualisiert die hierarchische Einbettung eines Ver-
zeichnisses im Verzeichnisbaum des jeweiligem Laufwerks und bietet die Möglichkeit der inter-
aktiven Auswahl eines jeden beliebigen Verzeichnisses auf dem gegebenen Laufwerk. Standard-
eigenschaft des Steuerelements ist Path.
Eigenschaften

Eigens c ha ften
...................................................
Appearance, BackColor, CausesValidation, Container, DragIcon, DragMode, Enabled, Font,
FontBold, FontItalic, FontName, FontSize, FontStrikethru, FontUnderline, ForeColor,
Height, HelpContextID, hWnd, Index, Left, List, ListCount, ListIndex, MouseIcon, Mouse-
Pointer, MultiSelect, Name, OLEDragMode, OLEDropMode, Parent, Path, TabIndex, TabStop,
Tag, Top, ToolTipText, TopIndex, Visible, WhatsThisHelpID, Width
Methoden

Metho den
...................................................
Drag, Move, OLEDrag, Refresh, SetFocus, ShowWhatsThis, ZOrder
Ereignisse

Ereignis s e
...................................................
Change, Click, DragDrop, DragOver, GotFocus, KeyDown, KeyPress, KeyUp, LostFocus, Mouse-
Down, MouseMove, MouseUp, OLECompleteDrag, OLEDragDrop, OLEDragOver, OLEGiveFeedback,
OLESetData, OLEStartDrag, Scroll, Validate
Anwendung

Anwendung
...................................................
Das Verzeichnislistenfeld (DirListBox) ist wie das Dateilistenfeld und das Laufwerklistenfeld
(DriveListBox) noch ein Relikt aus der Zeit, als Anwendungen den Benutzer mit eigenen Vari-
anten für Dialoge wie »Datei öffnen«, »Speichern unter« usw. auf die Probe stellen mussten,
weil es die Standarddialoge (CommonDialog) noch nicht gab. Seine aktuelle Daseinsberechtigung
bezieht das Verzeichnislistenfeld allerdings aus der Tatsache, dass das Standarddialoge-Steuer-
element (COMLDG32.OCX) den Benutzer dazu zwingt, eine Datei auszuwählen, und die reine
Verzeichnisauswahl nicht zulässt.
Visual Basic initialisiert die Path-Eigenschaft des Steuerelements mit dem aktuellen standardmä-
ßigen Arbeitsverzeichnis, das im Allgemeinen mit App.Path übereinstimmt, beim Aufruf aber
auch explizit gesetzt worden sein kann (vgl. auch »CurDir-Funktion«, S. 134). Der Laufwerks-
anteil von Path lässt sich nur mit Programmcode ändern. Sie können den Wert wahlweise als
Laufwerkspfad oder als UNC-Pfad angeben, um Netzwerkressourcen ohne Laufwerkszuord-
nung darzustellen. Sehr weit kommt man damit jedoch nicht, da es schwierig ist, in Visual Basic

43 1
Standardsteuerelemente

Netzwerkfreigaben in Erfahrung zu bringen, die keinem Netzlaufwerk zugeordnet sind – ein


Grund mehr, letztlich doch mit den Standarddialogen zu arbeiten.
Um dem Benutzer die Möglichkeit der interaktiven Änderung zu geben, können Sie in der Nähe
des Verzeichnislistenfelds zusätzlich ein Laufwerklistenfeld (DriveBox) platzieren und dessen
Change-Behandlung die Path-Eigenschaft des Verzeichnislistenfelds ändern lassen. Die Imple-
mentation der Steuerelemente ist aufeinander abgestimmt, so dass die geklammerte Volumenbe-
zeichnung des Laufwerks im Wert von Drive herausgefiltert wird.
Private Sub Drive1_Change()
Dir1 = Drive1 ' Volumenbezeichnung wird gefiltert
End Sub
Standardsteuerelemente

Eine Möglichkeit für das Herausfiltern von Verzeichnissen mit bestimmten Attributen bietet
das Steuerelement nicht. Da über die Eigenschaften List, ListCount, ListIndex jedoch alle Ein-
träge für die angezeigten Verzeichnisse in Form absoluter Pfade verfügbar sind, lassen sich die
Attribute recht einfach gesondert über die Funktion GetAttr ermitteln.
Mit dem Unterschied, dass die List-Eigenschaft schreibgeschützt ist und auch sonst keine Mög-
lichkeiten gegeben sind, die Einträge des Listenfelds zu ändern, verhält sich das Laufwerklisten-
feld ansonsten wie ein gewöhnliches Listenfeld, insbesondere was die Mehrfachauswahl
(MultiSelect) und den Bildlauf betrifft. Änderungen im Verzeichnissystem spiegelt das Steuer-
element nicht automatisch wider, vielmehr ist ein Refesh-Aufruf dafür erforderlich.
Warnung

Wa rnung
...................................................
Der Wert "\\." für Path bringt das Steuerelement sowie die gesamte Entwicklungsumgebung
von Visual Basic sicher zum Absturz.
Beispiel

Beis piel
...................................................
Private Sub Dir1_Change()
CurDir = Dir1 ' standardmäßiges Arbeitsverzeichnis setzen
End Sub
Verwandte Befehle

Verwa ndte Befehle


...................................................
DriveListBox, FileListbox, ListBox, ListView

Zeitgeber- Steuerelement (Timer)


Timer1 As Timer
Beschreibung

Bes c hreibung
...................................................
Unter den Standardsteuerelementen ist das Zeitgeber-Steuerelement das einzige, das keine sicht-
bare Darstellung besitzt. Vielmehr implementiert das Steuerelement einen einfachen Mechanis-
mus, der periodisch das Timer-Ereignis produzieren kann. Die Periodendauer wird über die
Eigenschaft Interval gesetzt. Hat diese Eigenschaft den Wert 0, löst das Steuerelement keine
Timer-Ereignisse aus, ansonsten legt der Wert die Anzahl der Millisekunden zwischen zwei
Timer-Ereignissen fest.
Eigenschaften

Eigens c ha ften
...................................................
Enabled, Index, Interval, Name, Parent, Tag

432
ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente

Methoden

Metho den
...................................................
Keine
Ereignisse

Ereignis s e
...................................................
Timer
Anwendung

Anwendung
...................................................
Die Anwendungsmöglichkeiten des Zeitgeber-Steuerelements sind so vielseitig, wie die Prob-
lemstellungen, die etwas mit Zeit und periodischen Aufgaben zu tun haben. Erwarten Sie aber

ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente


nicht zu viel von dem Steuerelement. Zunächst einmal ist das Zeitintervall nicht sehr genau.
Das liegt zum einen daran, dass das Steuerelement als Zeitbasis den Systemzeitgeber verwendet,
der unter Windows 9x nur 18,2-mal pro Sekunde und unter Windows NT 50-mal pro Sekunde
tickt, eine Altlast aus der Zeit von MS-DOS. (Es hat also wenig Sinn, den Wert kleiner als 6
unter Windows 9x bzw. kleiner als 2 unter Windows NT zu setzen.) Zum anderen können sich
Timer-Ereignisse verspäten oder auch verloren gehen, da Windows anderen Ereignissen gegen-
über Timer-Ereignissen einen gewissen Vorrang einräumt und Timer-Ereignisse sich grundsätz-
lich nicht ansammeln. Zum dritten: Obwohl die Eigenschaft Interval vom Typ Long ist, akzep-
tiert das Steuerelement dafür keine Werte größer als 65.535 (16 Bit), was das maximale
Zeitintervall auf ca. 65 Sekunden beschränkt. Um längere Zeiträume zu implementieren, müs-
sen Sie eine Logik verwenden, bei der die Timer-Routine in regelmäßigen Abständen die System-
zeit ausliest oder ihre eigenen Aufrufe zählt. Ein Beispiel dafür finden Sie im Abschnitt »Long-
Timer – der Timer mit Ausdauer« (S. 599) des Praxisteils.
Beispiel

Beis piel
...................................................
Vgl. das Beispiel in »AutoSize-Eigenschaft« (S. 329).
Verwandte Themen

Verwandte Them en
...................................................
Date-Funktion und Date-Anweisung (S. 116); Time-Funktion und Time-Anweisung (S. 123);
Timer-Funktion (S. 124)

ActiveX- Steuerelemente (OCX) – Windows-


Standardsteuerelemente
Beschreibung

Bes c hreibung
...................................................
Die Standardsteuerelemente stellen einen durchaus geglückten Versuch von Microsoft dar, die
Benutzeroberflächen und -schnittstellen von Windows-Anwendungen weitgehend zu standardi-
sieren. Bei den Windows-Standardsteuerelementen (Common Controls) handelt es sich gewis-
sermaßen um den zweiten Aufguss, der inzwischen (seit Windows 95) nicht nur in 32-Bit-Imp-
lementation vorliegt und komplett an das Design von Windows 9x angepasst wurde, sondern
auch mit dem Component Object Model (COM) kompatibel ist. Windows-Standardsteuerele-
mente sind somit echte ActiveX-Steuerelemente – während die Standardsteuerelemente schlicht
ein Teil von Windows sind. Da die Benutzeroberfläche von Windows, der Explorer, der Inter-
net-Explorer, alle Systemprogramme sowie die gesamte Palette der Microsoft-Produkte massiv
von diesen Steuerelementen Gebrauch machen, sind sie gewissermaßen zum unverzichtbaren
Bestandteil für die gesamte Welt der Windows-Programmierung geworden – frei nach dem
Motto, »sag's mit Steuerelementen«. Kopieraktionen oder andere zeitaufwändige Operationen

43 3
ActiveX- Steuerelemente ( OCX) – Windows- Standardsteuerelemente

verkürzen dem Benutzer die Wartezeit durch Animationen und Fortschrittsanzeigen. Listenan-
sichten und Strukturansichten standardisieren die Darstellung komplexer Informationen und
ihrer Zusammenhänge. Statusleisten und Symbolleisten dürfen inzwischen in ernstzunehmen-
den Programmen ebenso wenig fehlen wie Eigenschaftsdialoge.
Da ist es nicht verwunderlich, dass Microsoft in regelmäßigen Abständen Aktualisierungen an
der Implementation sowie im Design der Steuerelemente vorstellt und die Sammlung zuneh-
mend erweitert. Unter Visual Basic 6.0 sind die Windows-Standardsteuerelemente aktuell in
zwei unterschiedlichen Versionen vertreten: in der Version 5.0 sowie in der Version 6.0. Der
Grund dafür liegt natürlich an der Aufrechterhaltung der Kompatibilität mit älteren Anwen-
dungen und Projekten. Für neue Projekte sollten Sie ausschließlich mit der neueren Version
arbeiten. Wenn Sie ein älteres, noch mit Visual Basic 5.0 erstelltes Projekt laden, legt Ihnen
ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente

Visual Basic 6.0 die automatische Aktualisierung der Windows-Standardsteuerelemente ans


Herz – ein Vorgang, der problemfrei über die Bühne geht. Die Aktualisierungsaufforderung
unterbleibt, wenn im Eigenschaftsfenster des Projekts EIGENSCHAFTEN VON Projektname das
Kontrollkästen ACTIVEX-STEUERELEMENTE AKTUALISIEREN deaktiviert ist. Um zu prüfen, wel-
che Version der Steuerelemente ein Projekt verwendet, rufen Sie das Dialogfeld KOMPONENTEN
über den Menübefehl PROJEKT/KOMPONENTEN auf und schauen, welche Komponenten ein
Häkchen auf der Registerkarte STEUERELEMENTE haben.
Um einzelne Windows-Standardsteuerelemente in einem neuen Projekt nutzen zu können, rufen
Sie das Dialogfeld KOMPONENTEN über den Menübefehl PROJEKT/KOMPONENTEN auf und set-
zen auf der Registerkarte STEUERELEMENTE vor die entsprechende Komponente ein Häkchen.
(Beachten Sie den OCX-Dateinamen der Komponente unterhalb des Listenfelds für die mar-
kierte Komponente.)

Auswahl der Windows- Standardsteuerelemente

Sie müssen nicht alle drei Komponenten auswählen. Wenn Sie beispielsweise nur mit dem Cool-
Bar-Steuerelement arbeiten wollen, reicht die Auswahl des Eintrags Microsoft Windows Com-
mon Controls-3 6.0 (SP3). Nachdem Sie die Auswahl übernommen bzw. das Dialogfeld
geschlossen haben, finden Sie für jedes Steuerelement eine zusätzliche Schaltfläche in der Werk-
zeugleiste und können damit genauso wie mit den Standardsteuerelementen von Visual Basic
arbeiten.

43 4
ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente

Werkzeugsammlung nac h Auswahl der Windows- Standardsteuerelemente

In der Version 5.0 waren zehn Windows-Standardsteuerelemente im Angebot, die in zwei


OCX-Dateien (ComCtl32.ocx, ComCt232.ocx) enthalten waren und die Unterstützung einer
DLL (ComCtl32.dll) benötigten. In der Version 6.0 sind es bereits 15 Steuerelemente, die sich

ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente


auf drei OCX-Dateien (MsComctl.ocx, MsComct2.ocx, MsComct3.ocx) verteilen, und eine
DLL ist nicht mehr erforderlich. Die folgende Tabelle gibt einen Überblick über die Steuerele-
mente.

Steuerelement Komponentendatei (Version) Bestimmung des Steuerelements


ImageList COMCTL32.OCX (5.0) Abbildungsliste, die anderen Steuerelemen-
MSCOMCTL.OCX (6.0) ten (beispielsweise ImageCombo, TreeView,
ToolBar) Bilder für die Anzeige bereitstellt
Animation COMCT232.OCX (5.0) Spielt unkomprimierte AVI-Dateien ohne
MSCOMCTL2.OCX (6.0) Ton ab
CoolBar MSCOMCTL3.OCX (6.0) Konfigurierbare Symbolleiste im Stile des
Internet Explorer (erfordert Installation des
Internet Explorer mindestens in der Ver-
sion 3.0)
DTPicker MSCOMCTL2.OCX (6.0) Ermöglicht die interaktive Datums-/Zeit-
auswahl
UpDown COMCT232.OCX (5.0) Drehfeld (auch AufAb-Steuerelement
MsComctl2.ocx (6.0) genannt) mit Pfeilschaltflächen für das
Hoch- oder Herunterzählen eines Werts im
anhängenden Textfeld (Buddy)
FlatScrollBar MSCOMCTL2.OCX (6.0) Flache Bildlaufleiste, die nur bei Aktivie-
rung eine 3D-Darstellung aufweist, ansons-
ten »flach« aussieht
ProgressBar COMCTL32.OCX (5.0) Fortschrittsleiste für die animierte Fort-
MSCOMCTL.OCX (6.0) schrittsanzeige bei längeren Operationen
ImageCombo MSCOMCTL.OCX (6.0) Kombinationsfeld mit bebilderten Textein-
trägen
MonthView MSCOMCTL2.OCX (6.0) Kalender-Steuerelement für die interaktive
Datums- und Zeitraumauswahl
ListView COMCTL32.OCX (5.0) Listenansicht für die Anzeige von Textein-
MSCOMCTL.OCX (6.0) trägen mit zugeordneten Bildern (Symbo-
len) in vier unterschiedlichen Ansichten
und sortierbaren Spalten
TabStrip COMCTL32.OCX (5.0) Element für die Darstellung von Register-
MSCOMCTL.OCX (6.0) karten in Eigenschaftsdialogen

43 5
ActiveX- Steuerelemente ( OCX) – Windows- Standardsteuerelemente

Steuerelement Komponentendatei (Version) Bestimmung des Steuerelements


Slider COMCTL32.OCX (5.0) Schieberegler mit Skala für die Visualisie-
MSCOMCTL.OCX (6.0) rung analoger Einstellungen
StatusBar COMCTL32.OCX (5.0) Statusleiste für die Anzeige von Statusinfor-
MSCOMCTL.OCX (6.0) mationen am unteren Rand eines Formu-
lars
TreeView COMCTL32.OCX (5.0) Strukturansicht für die Darstellung hierar-
MSCOMCTL.OCX (6.0) chischer Abhängigkeiten und Strukturen
ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente

ToolBar COMCTL32.OCX (5.0) Symbolleiste für die Gruppierung von


MSCOMCTL.OCX (6.0) Befehlsschaltflächen am (meist oberen) For-
mularrand

Die vorliegende Ausgabe dieser Referenz stellt hier gewissermaßen exemplarisch nur das Win-
dows-Standardsteuerelement ImageList ausführlicher vor, da es als Bildlieferant für verschie-
dene Szenarien fungieren kann.

Abbildungsliste- Steuerelement (ImageList)


ImageList1 As ImageList
Beschreibung

Bes c hreibung
...................................................
Das Abbildungsliste-Steuerelement hat wie das Zeitgeber-Steuerelement zur Laufzeit keine
sichtbare Darstellung, sondern dient in erster Linie anderen Steuerelementen, die über eine
ImageList-Eigenschaft verfügen, als Lieferant von Bildressourcen.
Als Struktur für die Speicherung der Bilder verwendet das Steuerelement eine ListImages-Auf-
listung mit dem Elementtyp ListImage. Zur Erweiterung der Auflistung gibt es eine Add-
Methode und zum Löschen die Methoden Remove bzw. Clear. Der Zugriff bzw. Verweis auf ein
einzelnes Bild erfolgt wahlweise unter Angabe des in der Index-Eigenschaft des entsprechenden
ListImage-Objekts festgelegten Index (Basis ist 1) oder des in der Key-Eigenschaft vom Typ
String festgelegten Namens.
Die Overlay-Methode des Steuerelements generiert zusammengesetzte Symbole durch Überein-
anderblendung zweier Bilder der Bildliste unter Berücksichtigung einer Transparenzfarbe.
Eigenschaften

Eigens c ha ften
...................................................
BackColor, hImageList, ImageHeigth, ImageWidth, Index, ListImages, MaskColor, Name,
Object, Parent, Tag, UseMaskColor

Eigenschaft Beschreibung
BackColor Wird von der Methode Overlay sowie von ListImage.Draw als Hinter-
grundfarbe für resultierende transparente Bereiche verwendet, wenn Use-
MaskColor und MaskColor passend gesetzt sind
hImageList Zur Laufzeit schreibgeschützter Long-Wert mit dem Handle des Steuerele-
ments (wird nur für Win32-API-Aufrufe benötigt)
ImageHeight Integer-Werte, die die Breite und Höhe (in Bildpunkten) der Symbole
ImageWidth festlegt, die mit ListImage.DrawIcon, ListImage.Draw und Overlay gene-
riert werden. Die Werte sind schreibgeschützt, wenn die Bildliste Einträge
enthält.

43 6
Abbildungsliste- Steuerelement ( ImageList)

Eigenschaft Beschreibung
ListImages Auflistung mit Elementtyp ListImage und Basis 1
MaskColor Long-Wert, der die Transparenzfarbe für die Maskierung transparenter
Bereiche ausdrückt. Wird von Overlay, ListImage.Draw und List-
Image.DrawIcon verwendet, wenn UseMaskColor auf True gesetzt ist.
Object Verweis auf das nackte (Steuerelement-)Objekt, das dem Visual-Basic-
Objekt zugrunde gelegt ist. Wird in speziellen Fällen für die Auflösung
von Namensbereichkonflikten benötigt, wenn das Visual-Basic-Objekt
eine Eigenschaft oder Methode des untergelegten Objekts durch eine

ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente


gleichnamige Eigenschaft oder Methode »verdeckt«.
UseMaskColor Boolean-Wert, der bestimmt, ob die in MaskColor festgelegte Farbe als
Transparenzfarbe für Berechnung von Symbolen durch Overlay, List-
Image.Draw und ListImage.DrawIcon verwendet wird

Methoden
Methoden

...................................................
Function Objekt.Overlay(Index1 | Key1, Index2 | Key2) As Picture
Sub Objekt.ListImages.Add (Index As Integer, Key As String, _
Picture As Picture)
Sub Objekt.ListImages.Remove(Index | Key)
Sub Objekt.ListImages.Clear()
Sub Objekt.ListImage(Index | Key).ExtractIcon()

Methode Beschreibung
Overlay Liefert eine Komposition aus zwei Bildern der Bildliste als Symbol. Zur
Auswahl der Bilder kann wahlweise die Index- oder Key-Eigenschaft der
Bilder übergeben werden, wobei das im zweiten Parameter genannte Bild
über das andere gelegt wird. Die Methode beachtet die Eigenschaften
ImageHeight, ImageWidth sowie insbesondere, falls UseMaskColor auf True
gesetzt ist, MaskColor und BackColor.
Remove Entfernt das über die Index- oder Key-Eigenschaft spezifizierte Bild aus
der Abbildungsliste
Add Fügt das Bild Picture in die Abbildungsliste ein und ordnet ihm den
Namen Key zu. Ist für Index kein Wert spezifiziert, wird das Bild als letz-
tes Bild in die Liste eingefügt, ansonsten an der durch Index spezifizierten
Position (Zählung beginnt bei 1).
Clear Entfernt alle Bilder aus der Abbildungsliste
ExtractIcon Liefert das Listenelement als Symbol unter Beachtung der Eigenschaften
ImageHeight, ImageWidth sowie UseMaskColor. Als Transparenzfarbe fun-
giert die Farbe MaskColor. Falls UseMaskColor auf False gesetzt ist, gene-
riert die Methode das Symbol im markierten Zustand (Hintergrundfarbe
invertiert). Die maximale Symbolgröße, mit der die Methode zurecht-
kommt, ist 144 Bildpunkte.

43 7
ActiveX- Steuerelemente ( OCX) – Windows- Standardsteuerelemente

Anwendung

Anwendung
...................................................
Es gibt fünf Windows-Standardsteuerelemente, die speziell auf die Zusammenarbeit mit einem
ImageList-Objekt ausgelegt sind und von diesem ihre Bilder beziehen: CoolBar, ImageCombo, Tab-
Strip, TreeView und Toolbar. Sie können das Steuerelement aber auch für eigene Zwecke einset-
zen, wenn sie mehrere Bilder verwalten müssen.
Am einfachsten ist der Umgang mit einer Abbildungsliste, wenn Sie die Eigenschaften bereits
zur Entwurfszeit interaktiv gestalten. Öffnen Sie dazu den Eigenschaftsdialog des im Entwurfs-
bereich platzierten Steuerelements über das Kontextmenü und aktivieren Sie die Registerkarte
ABBILDUNGEN. Bilder, die Sie zur Entwurfszeit einfügen, speichert Visual Basic in der unkompi-
lierten Fassung automatisch in einer binären Anhangsdatei (FRX, CTX etc.) und in der kompi-
ActiveX- Steuerelemente (OCX) – Windows- Standardsteuerelemente

lierten Fassung als Ressource in der Exe-Datei.


Wenn Sie die Eigenschaften ImageHeight und ImageWidth nicht explizit vorher (auf der Register-
karte ALLGEMEIN) setzen, richten sie sich nach den Abmessungen (in Bildpunkten) des zuerst
eingefügten Bildes – und lassen sich später auch nicht mehr ändern. Um ein Bild zur Laufzeit
mit einem Namen ansprechen zu können (was im Zusammenspiel mit anderen Steuerelementen
recht vorteilhaft ist), setzen Sie die Key-Eigenschaft des jeweiligen Listenelements.

Eigensc haftsdialog eines Abbildungsliste- Steuerelements

Das Abbildungsliste-Steuerelement akzeptiert diverse Grafikformate (DIB, BMP, ICO, CUR,


GIF, JPG) und hat vom Prinzip her auch keine Probleme damit, wenn die Bilder unterschiedli-
che Größen aufweisen. Im Zusammenspiel mit den genannten Windows-Standardsteuerelemen-
ten sorgt nämlich die Methode ExtractIcon für die Umwandlung in das Symbolformat, passt
die Größe automatisch auf ImageHeight und ImageWidth an und nimmt gegebenenfalls eine Mas-
kierung vor, wenn UseMaskColor den Wert True hat und MaskColor auf eine geeignete Transpa-
renzfarbe gesetzt wurde. Beachten Sie, dass die Symbolgröße auf 144×144 Bildpunkte limitiert
ist.
Das Steuerelement lässt sich natürlich auch erst zur Laufzeit initialisieren. Sie können die Bilder
für die Listeneinträge dann einzelnen aus bereitgestellten Grafikdateien laden, sollten es aber
nicht versäumen, die Eigenschaften ImageHeight und ImageWidth vorher passend zu setzen.
With ImageList1
.ImageHeight = 50
.ImageWidth = 150
.ListImages.Add , "Bild01", LoadPicture(App.Path & "Bild01.jpg")
.ListImages.Add , "Bild02", LoadPicture(App.Path & "Bild02.jpg")
' ... usw.

43 8
Weitere ActiveX- Steuerelemente

.ListImages.Add , "Bild21", LoadPicture(App.Path & "Bild21.jpg")


.MaskColor = vbWhite
.UseMaskColor = True
.BackColor = vbRed
End With

Eine bewährte Technik ist es, das Bildausschnitt-Steuerelement (PictureClip) als Bildquelle für
das Abbildungsliste-Steuerelement einzusetzen. Gerade, wenn eine größere Anzahl von Symbo-
len oder Bitmaps gleicher Größe benötigt wird, lassen sich die Bildressourcen dann sehr vorteil-
haft in einer einzigen externen Datei zusammenfassen, die auch im Nachhinein noch geändert
werden kann:

Weitere ActiveX- Steuerelemente


PictureClip1.Rows = 3
PictureClip1.Cols = 7
PictureClip1.Picture = LoadPicture(App.Path & "Bilder.jpg")
ImageList1.ImageHeight = 50
ImageList1.ImageWidth = 150
Dim Key As String, i As Integer
For i = 0 To 20
Key = "Bild" & Right("0" & CStr(i + 1), 2)
ImageList1.ListImages.Add , Key, PictureClip1.GraphicCell(i)
Next i

Für den Zugriff auf ein einzelnes Bild gibt es mehrere Möglichkeiten. Um das Bild in der
ursprünglichen Form wiederzugewinnen, schreiben Sie:
Picture1 = ImageList1.ListImages(Index).Picture

Um das Bild als Symbol mit den Abmessungen ImageHeight und ImageWidth zu erhalten, schrei-
ben Sie:
Picture1 = ImageList1.ListImages(Index).ExtractIcon

Um das Bild als Symbol mit den Abmessungen ImageHeight und ImageWidth zu erhalten, das mit
einem zweiten Bild überlagert ist, schreiben Sie:
Picture1 = ImageList1.Overlay (Index, IndexZweitesBild)

Um das Bild in Symbolgröße in ein Formular Form1 an die Position 1000, 1000 zu zeichnen,
schreiben Sie:
Picture1 = ImageList1.ListImages(Index).Draw Form1.hDC, 1000, 1000
Verwandte Steuerelemente

...................................................
Verwandte S teuerelemente
PictureClip

Weitere ActiveX- Steuerelemente


Neben den Windows-Standardsteuerelementen gehört zum Lieferumfang der Professional Edi-
tion von Visual Basic noch eine beachtliche Sammlung weiterer Steuerelemente, von denen jedes
für sich eine eigene mehr oder weniger komplexe Programmierwelt mit sich bringt. So steckt
beispielsweise hinter dem ADO-Steuerelement die gesamte Welt der ActiveX Data Objects, der
neuen Datenbankschnittstelle von Microsoft, die dem Modell des verallgemeinerten unterneh-
mensweiten Datenzugriffs (Universal Data Access) entsprungen ist und eine Erweiterung des

43 9
Weitere ActiveX- Steuerelemente

ODBC-Standards für relationale und nichtrelationale Datenbanksysteme. Das Steuerelement


unterstützt neben OLE DB auch den Datenzugriff über die älteren Datenbankschnittstellen
ODBC und DAO.
Hinzu kommt natürlich noch die schier unüberschaubare Fülle an ActiveX-Steuerelementen,
die von Drittherstellern vertrieben werden und deren Programmierschnittstellen von beachtli-
cher Komplexität sein können. Früher als OLE-Steuerelemente bezeichnet, laufen diese Steuer-
elemente heute unter der Bezeichnung ActiveX-Steuerelemente und genügen dem COM-Stan-
dard, so dass sie sich nicht nur als Benutzeroberflächenobjekte für das gewöhnliche Design von
Visual-Basic-Formularen und -Benutzersteuerelementen mit den üblichen Möglichkeiten der
Datenbankanbindung eignen, sondern darüber hinaus für die Belebung und Ausgestaltung von
HTML-Seiten (die im Internet-Explorer angezeigt werden) zur Verfügung stehen.
Weitere ActiveX- Steuerelemente

Um ein ActiveX-Steuerelement in die Werkzeugsammlung zu laden, rufen Sie das Dialogfeld


KOMPONENTEN über den Menübefehl PROJEKT/KOMPONENTEN AUF und setzen auf der Regis-
terkarte STEUERELEMENTE vor den Namen der Komponentendatei ein Häkchen. Die folgende
Tabelle gibt einen Überblick über die wichtigsten ActiveX-Steuerelemente:

Steuerelement Komponentendatei Bestimmung des Steuerelements


Adodc Microsoft ADO Data Datensteuerelement für Datenbankanbindungen an
Control 6.0 (SP3) OLE-Datenbankdateien auf Basis der ActiveX Data
(OLE DB) Objects (ADO-Schnittstelle). Die verschiedenen
MSADODC.OCX OLE-DB-Provider machen das Steuerelement zum
vollständigen Ersatz für die älteren Datensteuerele-
mente Data und RemoteData.
CommonDialog Microsoft Common Steuerelement ohne sichtbare Darstellung, das die
Dialog Control 6.0 Windows-Standarddialoge Öffnen, Speichern unter,
(SP3) Drucken, Schriftart, Farbe als eigenständige Dialog-
COMDLG.OCX felder anzeigen kann.
DataCombo Microsoft DataList Für ADO optimierte, codekompatible Variante von
Controls 6.0 (SP3) DBCombo
(OLE DB)
MSDATLST.OCX
DataGrid Microsoft DataGrid Für ADO optimierte, codekompatible Variante von
Control 6.0 (SP3) DBGrid
(OLE DB)
MSDATGRD.OCX
DataList Microsoft DataList Für ADO optimierte, codekompatible Variante von
Controls 6.0 (SP3) DBList
(OLE DB)
MSDATLST.OCX
DataRepeater Microsoft Data- Für ADO konzipiertes Steuerelement, das die res-
Repeater Control 6.0 sourcensparende Wiederholung eines Steuerele-
(OLE DB) ments (meist Benutzersteuerelement) mit
MSDATREP.OCX Datenbankbindung zur Anzeige fortlaufender
Datensätze eines Recordset-Objekts einer Daten-
quelle (Adodc, Data, RemoteData) ermöglicht

440
Weitere ActiveX- Steuerelemente

Steuerelement Komponentendatei Bestimmung des Steuerelements


DBCombo Microsoft Data Bound Speziell auf die Arbeit mit Datenbankinformationen
List Controls 6.0 optimierte Variante des Kombinationsfelds (vgl.
DBLIST32.OCX ComboBox), dessen Listeneinträge automatisch von
einem Recordset-Objekt einer Datenquelle (Data,
RemoteData) mit den Werten eines einzelnen Daten-
felds aufgefüllt und gepflegt werden
DBGrid Microsoft Data Bound Speziell auf die Arbeit mit Datenbankinformationen
Grid Control 5.0 (SP3) ausgelegtes Datenblatt-Steuerelement, das die

Weitere ActiveX- Steuerelemente


DBGRID32.OCX Datensätze eines Recordset-Objekts einer Daten-
quelle (Adodc, Data, RemoteData) als Tabellenblatt
darstellt und die interaktive Bearbeitung ermöglicht
DBList Microsoft Data Bound Speziell auf die Arbeit mit Datenbankinformationen
List Controls 6.0 optimierte Variante des Listenfelds (vgl. ListBox),
DBLIST32.OCX dessen Listeneinträge automatisch von einem
Recordset-Objekt einer Datenquelle (Adodc, Data,
RemoteData) mit den Werten eines einzelnen Daten-
felds aufgefüllt und gepflegt werden
Inet Microsoft Internet Steuerelement ohne sichtbare Darstellung, das eine
Transfer Control 6.0 Implementation der beiden wichtigsten Internetpro-
MSINET.OCX tokolle HTTP und FTP für das Abrufen von
HTML-Dokumenten aus dem Internet sowie die
Ausführung von FTP-Befehlen bereitstellt
MaskEdBox Microsoft Masked Edit Textfeld (vgl. TextBox), das auf die Eingabe von
Control 6.0 (SP3) Werten mit spezifischen Formaten spezialisiert ist.
MSMASK32.OCX Die Formatbeschreibung erfolgt als Zeichenfolge
mit Formatsymbolen
MMControl Microsoft Multimedia Ermöglicht die Steuerung von Aufnahme- und Wie-
Control 6.0 (SP3) dergabegeräten über die MCI-Schnittstelle des Sys-
MCI32.OCX tems
MSChart Microsoft Chart Cont- Ermöglicht die grafische Darstellung von Diagram-
rol 6.0 (SP3) men auf Basis eines DataGrid-Steuerelements
(OLEDB)
MSCHRT20.OCX
MSComm Microsoft Comm Con- Ermöglicht die direkte Kommunikation über die
trol 6.0 seriellen Schnittstellen des Systems
MSCOMM32.OCX
MSFlexGrid Microsoft FlexGrid Tabellenblatt für die tabellarische Anzeige von
Control 6.0 (SP3) Daten (Text und Bilder) in verschiedenen Sortierun-
MSFLXGRD.OCX gen und Formaten

441
Weitere ActiveX- Steuerelemente

Steuerelement Komponentendatei Bestimmung des Steuerelements


MSHFlexGrid Microsoft Hierachical Tabellenblatt für die tabellarische Anzeige hierar-
FlexGrid Control 6.0 chisch gruppierter Daten (Text und Bilder) in ver-
(SP3) schiedenen Sortierungen und Formaten. Das
MSHFLXGD.OCX Steuerelement ist speziell für die Zusammenarbeit
mit dem ADO-Steuerelement konzipiert und ermög-
licht die Anzeige relational abhängiger Datensatz-
gruppen.
PictureClip Microsoft PictureClip Bildausschnitt-Steuerelement, das die Extraktion
Weitere ActiveX- Steuerelemente

Control von Teilbildern einer gegebenen Bitmap unter


Angabe eines Reihen-/Spaltenindex oder eines
Begrenzungsrechtecks unterstützt
RichTextBox Microsoft Internet Erweiterte Variante des Textfelds (TextBox) für die
Control Darstellung und Bearbeitung von formatierten Tex-
SHDOCVW.DLL ten im RTF-Format.
WebBrowser Microsoft Internet Browser-Fenster mit einem großen Teil der Funktio-
Control nalität des Internet Explorer, das die Navigation im
SHDOCVW.DLL Internet, Intranet sowie auf dem lokalen System
ermöglicht
WinSock Microsoft Winsock Steuerelement ohne sichtbare Darstellung, das den
Control 6.0 Port-basierten Verbindungsaufbau mit im TCP/IP-
MSWINSCK.OCX Netzwerk gelegenen Servern und den Datenaus-
tausch über Datagramme (UDP) sowie verbindungs-
orientiert (TCP) ermöglicht.

Die vorliegende Ausgabe dieser Referenz stellt in der Folge nur die zwei sehr grundlegenden
ActiveX-Steuerelemente PictureClip und CommonDialog ausführlicher vor.

Bildausschnitt- Steuerelement (PictureClip)


ImageList1 As ImageList
Beschreibung

Bes c hreibung
...................................................
Das zur Laufzeit unsichtbare Bildausschnitt-Steuerelement bietet zwei verschiedene Techniken
an, Teilbilder als eigenständige Bitmaps aus einer größeren Bitmap zu gewinnen. Zum einen
lässt sich die Bitmap über die Eigenschaften Rows und Cols gleich einem Gitter in gleich große
Grafikzellen unterteilen, die das Steuerelement dann über die Array-Eigenschaft GraphicCell
verfügbar macht. Zum anderen liefert die Clip-Eigenschaft frei definierbare Teilbilder der
Bitmap. Schließlich ermöglicht das Steuerelement auch noch die Skalierung der Grafikzellen
bzw. Teilbilder auf frei definierbare Abmessungen.
Eigenschaften

Eigens c ha ften
...................................................
CellHeight, CellWidth, Clip, ClipHeight, ClipWidth, ClipX, ClipY, Cols, GraphicCell,
Height, hWnd, Index, Name, Object, Parent, Picture, Rows, StretchX, StretchY, Tag,
Width,

442
Bildausschnitt- Steuerelement ( PictureClip)

Eigenschaft Beschreibung
CellHeight Integer-Werte, die Höhe und die Breite des Bildausschnitts (Clip-Eigen-
CellWidth schaft) in Bildpunkten ausdrücken. Diese Werte werden bei Änderung der
Eigenschaften Cols bzw. Rows automatisch aktualisiert und sind zur Lauf-
zeit schreibgeschützt.
Clip Picture-Wert, der den durch ClipX, ClipY, ClipHeight, ClipWidth
beschriebenen Bildausschnitt liefert
ClipHeight Höhe und Breite des von Clip gelieferten Bildausschnitts
ClipWidth

Weitere ActiveX- Steuerelemente


ClipX Koordinaten der linken oberen Ecke des von Clip gelieferten Bildaus-
ClipY schnitts in Bildpunkten
Cols Integer-Wert für die Anzahl der Spalten, in die das Steuerelement das
Gesamtbild (Picture) für die Bildung von Zellen aufteilt
GraphicCell eindimensionales Array (0-basiert) mit Elementtyp Picture, das die impli-
zit über Rows und Cols definierten Grafikzellen liefert
Picture Gesamtbild, aus dem das Steuerelement seine Ausschnitte liefert
Rows Integer-Wert für die Anzahl der Zeilen, in die das Steuerelement das
Gesamtbild (Picture) für die Bildung von Zellen aufteilt
StretchX Breite und Höhe in Bildpunkten, auf die das Steuerelement alle Graphic-
StretchY Cell-Elemente skaliert. Die Voreinstellungen für diese Werte sind die
Werte von CellHeight und CellWidth.

Anwendung

Anwendung
...................................................
Wer in seinen Programmen viel mit Bildern zu tun hat, wird ein Lied davon singen können, wie
aufwändig und lästig die Bereitstellung von Bildressourcen sein kann, gleich ob dies zur Ent-
wurfszeit oder zur Laufzeit geschieht. Wenn zig Einzeldateien nicht nur einzeln geladen, son-
dern auch gepflegt sein wollen, ist es meist günstiger, mehrere Bilder in einer einzelnen Bilddatei
zusammenzufassen und erst zur Laufzeit wieder zu extrahieren – zumal wenn die Bilder wie im
Falle von Symbolleisten, Puzzle-Elementen oder Spielfiguren, um nur einige Anwendungsbei-
spiele zu nennen, noch die gleichen Abmessungen besitzen.
Wird die Picture-Eigenschaft des Steuerelements bereits zur Entwurfszeit über das Eigen-
schaftsfenster gesetzt, speichert Visual Basic die entsprechende Bitmap zunächst als binären
Anhang in einer separaten Datei (FRX-Datei für Formulare). In der kompilierten Fassung ent-
hält die EXE-Datei alle binären Anhänge als Ressourcen, so dass die Quelldatei nicht weiter
bereitgestellt werden muss.
Anders jedoch, wenn die Bitmap erst zur Laufzeit mittels LoadPicture eingelesen wird. In die-
sem Fall muss die entsprechende Grafikdatei weiterhin verfügbar sein.
PictureClip1.Picture = LoadPicture(App.Path + "\figuren.bmp")
Die Aufteilung in einzelne Zellen können Sie zur Entwurfszeit oder zur Laufzeit vornehmen,
indem Sie die Eigenschaften Rows und Cols geeignet setzen. Wenn die Bitmap nebeneinander 13
Einzelbilder für die Abbildungsliste einer Symbolleiste enthält, schreiben Sie:
PictureClip1.Rows = 1
PictureClip1.Cols = 13

443
Weitere ActiveX- Steuerelemente

Falls die zu extrahierenden Teilbilder noch einer Skalierung bedürfen, können Sie StretchX und
StretchY auf die gewünschte Zielgröße in Bildpunkten setzen, bevor der Zugriff über die Gra-
phicCell-Eigenschaft erfolgt (bei Skalierung ist es generell besser, wenn verkleinert wird).
PictureClip1.StretchX = 16
PictureClip1.StretchY = 16
For i = 0 To 12
ImageList1.ListImages.Add , , PictureClip1.GraphicCell(i)
Toolbar1.Buttons(i).Image = i ' gleich zu ordnen
Next i

Um einen beliebigen Bildausschnitt zu erhalten, arbeiten Sie mit der Clip-Eigenschaft, nachdem
Weitere ActiveX- Steuerelemente

Sie die Koordinaten des linken oberen Punkts sowie die Abmessungen des gewünschten Teilbil-
des gesetzt haben.
With PictureClip1
.ClipHeight = ch: .ClipWidth = cw: .ClipLeft = cl: .ClipTop = ct
Object.Picture = PictureClip1.Clip
End With
Beispiel

Beis piel
...................................................
Der folgende Codeauszug aus dem Beispielprojekt Schach des Praxisteils zeigt die Initialisierung
von Steuerelementen mit den Bildern der Schachfiguren.
With PictureClip1
.Picture = LoadPicture(App.Path + "\Schachfiguren.bmp")
.Rows = 2
.Cols = 6
End With
For i = 0 To 31 ' Element mit Index 0 ist "Same"
If i > 0 Then Load figur(i)
Set figur(i).MaskPicture = PictureClip1.GraphicCell(FigIdx(i))
Set figur(i).Picture = PictureClip1.GraphicCell(FigIdx(i))
Next i
Verwandte Steuerelemente

Verwandte Steuerelemente
...................................................
ImageList

Standarddialoge- Steuerelement (CommonDialog)


CommonDialog1 As CommonDialog
Beschreibung

Bes c hreibung
...................................................
Das Standarddialoge-Steuerelement enthält die Implementation der wichtigsten Dialoge für die
Windows-Programmierung: Öffnen, Speichern unter, Schriftart, Farbauswahl Drucken und
Drucker einrichten. Entsprechend verfügt das Steuerelement für den Aufruf eines jeden Dialogs
eine eigene Show-Methode (einzig Drucken und Drucker einrichten werden über die gleiche
Methode aufgerufen) sowie eine Fülle von Eigenschaften, die zum einen die Konfiguration der
Dialoge vor dem Aufruf und zum anderen die Entgegennahme der Benutzereingaben nach dem
Aufruf ermöglichen. Die Voreinstellungen sind so gewählt, dass die Vorbereitungen für den
Aufruf der Dialoge minimal sind. Darüber hinaus gestattet es die Flags-Eigenschaft, jeden ein-

444
Standarddialoge- Steuerelement ( CommonDialog)

zelnen Dialog vor dem Aufruf speziell zu konfigurieren sowie die spezifische Einstellungen des
Benutzers in Erfahrung zu bringen, um den vollen Funktionsumfang des Steuerelements auszu-
nutzen.
Eigenschaften

...................................................
Eigens c ha ften
Action, CancelError, Color, Copies, DefaultExt, DialogTitle, FileName, FileTitle, Fil-
ter, FilterIndex, Flags, Font, FontBold, FontItalic, FontName, FontSize, FontStrikeThru,
FontUnderline, FromPage, hDC, HelpCommand, HelpContext, HelpFile, HelpKey, Index, Init-
Dir, Left, Max, Min, MaxFileSize, Name, Object, Orientation, Parent, PrinterDefault,
Top, ToPage

Weitere ActiveX- Steuerelemente


Eigenschaft Beschreibung
Action Aus Gründen der Abwärtskompatibilität nach wie vor unterstützte
Eigenschaft, deren Setzen die Anzeige eines Standarddialogs bewirkt;
die möglichen Werte sind: 0 – keine Aktion; 1 – Öffnen; 2 – Speichern
unter; 3 – Farbe; 4 – Schriftart; 5 – Drucker; 6 – Aufruf des Hilfesys-
tems
CancelError Boolean-Wert, der bestimmt, ob das Steuerelement einen Fehler signa-
lisiert, wenn der Benutzer die Schaltfläche ABBRECHEN anklickt
(True) oder nicht (False; Voreinstellung)
Color Long-Wert, der die aktuelle Farbauswahl des Standarddialogs Farbe
vorgibt bzw. liefert
Copies Integer-Wert, der die Kopienanzahl des Standarddialogs Drucker
vorgibt bzw. liefert
DefaultExt String-Wert für die standardmäßige Dateierweiterung des von den
Standarddialogen Öffnen, Schriftart und Speichern unter gelieferten
Dateinamens; das Steuerelement ergänzt die Erweiterung, falls sie
fehlt
DialogTitle String-Wert für den Titel des aufgerufenen Standarddialogs
FileName String-Wert, der den ausgewählten Dateinamen samt Pfad für die
Dialoge Öffnen, Schriftart und Speichern unter vorgibt bzw. liefert
FileTitle Schreibgeschützter String-Wert, der den über die Dialoge Öffnen,
Schriftart und Speichern unter ausgewählten Dateinamen ohne Pfad
liefert
Filter String-Wert, der einen Dateiauswahlfilter für die Dialogfelder Öff-
nen, Schriftart und Speichern unter vorgibt. Ein Filter setzt sich aus
einem Filtereintrag für die Liste DATEITYP und einer Suchspezifika-
tion (Platzhalter * und ? erlaubt) getrennt durch das Zeichen »|«
zusammen. Um mehrere Filter für einen Eintrag zur Auswahl zu stel-
len, sind die Suchspezifikationen durch ein Semikolon zu trennen. Bei-
spiel: "Bilder (JPG, GIF, BMP)|*.jpg;*.gif;*.bmp". Mehrere Filter
werden gleichfalls durch das Zeichen »|« getrennt. Beispiel:
"JPG|*.jpg|GIF|*.gif|BMP|*.bmp".

445
Weitere ActiveX- Steuerelemente

Eigenschaft Beschreibung
FilterIndex Integer-Wert, der einen in der Eigenschaft Filter definierten Filter
über seine Position auswählt bzw. den Index des vom Benutzer ver-
wendeten Filters liefert; Voreinstellung ist 1; ungültige Indizes inter-
pretiert das Steuerelement gleichfalls als 1
Flags Long-Wert, der als Bitvektor Optionen für die einzelnen Dialoge fest-
legt bzw. liefert. Die einzelnen Flags ermöglichen eine zusätzliche
Konfiguration der Dialoge, insbesondere der Zustände der Kontroll-
kästchen und Optionsfelder. (Die Bedeutung der einzelnen Flags ent-
Weitere ActiveX- Steuerelemente

nehmen Sie der Online-Hilfe zu Visual Basic.)


FontBold, Schrifteigenschaften für den Dialog Schriftart
FontItalic,
FontName, FontSize,
FontStrikeThru,
FontUnderline
FromPage Integer-Werte, die den Seitenbereich für den Dialog Drucken vorge-
ToPage ben bzw. liefern (Achtung: Die Vorgaben für den Dialog müssen mit
den Eigenschaften Min und Max vereinbar sein, sonst meldet der Dialog
einen Initialisierungsfehler.)
HelpCommand Integer-Wert, der als Bitvektor Kommandos für einen eventuellen
Aufruf des Hilfesystems vorgibt bzw. liefert (die Bedeutung der einzel-
nen Flags entnehmen Sie der Online-Hilfe zu Visual Basic)
HelpContext Long-Wert, der eine Kontext-Kennung für den Aufruf des Hilfesystems
ausgibt (Voraussetzung: HelpCommand wird auf cdlHelpContext gesetzt)
HelpFile String-Wert mit dem Zugriffspfad für die Hilfedatei. Wenn leer, wird
die Visual-Basic-Hilfedatei benutzt.
HelpKey String-Wert, der ein Stichwort für den Aufruf des Hilfesystems spezi-
fiziert (Voraussetzung: HelpCommand wird auf cdlHelpKey gesetzt)
InitDir String-Wert, der das Anfangsverzeichnis für die Auswahl eines Datei-
namens bestimmt. Wenn leer, wird das standardmäßige Arbeitsver-
zeichnis (CurDir) verwendet. Um eine Änderung des
Standardverzeichnisses durch den Dialog zu verhindern, setzen Sie das
Flag cdlOFNNoChangeDir (&H8).
Max Integer-Werte, die die maximale/minimale Seitenzahl für den Dialog
Min Drucken bzw. die maximale Zeichengröße für den Dialog Schriftart
spezifizieren. Wenn 0, kann keine Seitenauswahl im Dialog Drucken
stattfinden
MaxFileSize Integer-Wert, der die maximale Länge des Dateinamens für die
Eigenschaft FileName festlegt. Vorgabe ist 256. Der Wert lässt sich
zwischen 1 und 32.768 wählen.
Orientation Integer-Wert, der die Papierausrichtung im Dialog DRUCKER EIN-
RICHTEN vorgibt bzw. liefert: cdlPortrait (1) steht für Hochformat,
cdlLandscape (2) für Querformat

446
Standarddialoge- Steuerelement ( CommonDialog)

Eigenschaft Beschreibung
PrinterDefault Boolean-Wert, der bestimmt, ob der Dialog Drucken den ausgewähl-
ten Drucker zum Standarddrucker des Systems erklärt (True) oder
nicht (False)

Methoden

Metho den
...................................................
AboutBox, ShowColor, ShowFont, ShopHelp, ShowOpen, ShowPrinter, ShowSave

Weitere ActiveX- Steuerelemente


Methode Beschreibung
AboutBox Zeigt den Infodialog des Standarddialogs an
ShowColor Zeigt den Standarddialog Farbe an. Nach dem Aufruf enthält die
Eigenschaft Color die Farbauswahl des Benutzers.
ShowFont Zeigt den Standarddialog Schriftart an. Der erfolgreiche Aufruf setzt
voraus, dass eines der Flags cdlCFScreenFonts (&H1), cdlCFBoth
(&H3) oder cdlCFPrinterFonts (&H29) gesetzt wurde. Nach dem
Aufruf enthält die Eigenschaft Font die Schriftauswahl des Benutzers.
ShowHelp Ruft das Windows-Hilfesystem mit der über die Eigenschaft HelpFile
gesetzten Hilfedatei auf
ShowOpen Zeigt den Standarddialog Öffnen an. Nach dem Aufruf enthalten die
Eigenschaften FileName sowie FileTitle den vom Benutzer gewählten
Dateinamen. Der Wert des Kontrollkästchens SCHREIBSCHUTZ lässt
sich über das Flag cdlOFNNoReadOnlyReturn ermitteln
ShowPrinter Zeigt den Standarddialog Drucken an. Nach dem Aufruf enthält hDC
den Gerätekontext des gewählten Druckers, FromPage und ToPage ent-
halten den zu druckenden Seitenbereich, Orientation enthält die
Papierausrichtung, und Copies enthält die Anzahl der zu druckenden
Kopien. Die Werte der Optionsfelder sowie Kontrollkästchen lassen
sich über die Flags-Eigenschaft setzen und in Erfahrung bringen. Wird
die Flags-Eigenschaft vor dem Aufruf auf cdlPDPrintSetup (&H40)
gesetzt, erscheint nicht der Dialog Drucken, sondern Drucker einrich-
ten.
ShowSave Zeigt den Standarddialog Speichern unter an. Nach dem Aufruf ent-
halten die Eigenschaften FileName sowie FileTitle den vom Benutzer
gewählten Dateinamen.

Anwendung

Anwendung
...................................................
Die Standarddialoge dürften zweifelsohne zu den segensreichsten Werkzeugen gehören, die
Visual Basic einem Programmierer an die Hand gibt. Man erkennt das allein schon daran, dass
es kaum Programme gibt, die nicht in der einen oder anderen Form davon Gebrauch machen.
Wer von dem Steuerelement nichts Ungewöhnliches erwartet, es also nicht bis auf das Letzte
ausreizen will, wird überrascht sein, wie pflegeleicht die Programmierung damit ist. Der Perfek-
tionist hingegen, der die völlige Kontrolle anstrebt, wird nicht umhinkommen, sich mit der
Flags-Eigenschaft, der Fülle der für jeden einzelnen Dialog definierten Bitwerte und der mit Bit-
vektoren üblicherweise verbundenen Bitkrämerei herumschlagen zu müssen.

447
Weitere ActiveX- Steuerelemente

Öffnen
Um die Standarddialoge Öffnen bzw. Speichern unter anzuzeigen, rufen Sie die Methode ShowO-
pen bzw. ShowSave auf oder setzen die Eigenschaft Action auf 1 bzw. 2. Beide Dialoge geben das
von CurDir gelieferte aktuelle Arbeitsverzeichnis vor, falls über die Eigenschaft InitDir kein
anderes Verzeichnis spezifiziert ist. Den ausgewählten Dateinamen samt Pfad finden Sie nach
dem Aufruf in der Eigenschaft FileName, während FileTitle nur den nackten Dateinamen wie-
dergibt. Wenn Sie nicht wollen, dass die Dialoge das aktuelle Arbeitsverzeichnis ändern, setzen
Sie in der Flags-Eigenschaft das Flag cdlOFNNoChangeDir (&H8). Das Kontrollkästchen für die
Schreibschutzeinstellung wird man über das Flag cdlOFNHideReadOnly (&H4) los, was für den
Dialog Speichern unter geschehen sollte, um Verwirrungen des Benutzers vorzubeugen. Um
Weitere ActiveX- Steuerelemente

sicherzustellen, dass der Benutzer eine bestehende Datei auswählt, setzen Sie das Flag cdlOFNFi-
leMustExist (&H1000), was gleichzeitig die Erstellung eines neuen Verzeichnisses
(cdlOFNPathMustExist = &H800) über den Dateinamen unterbindet (nichtsdestotrotz kann der
Benutzer weiterhin über das Symbol NEUER ORDNER Verzeichnisse erstellen).
CommonDialog1.Flags = cdlOFNNoChangeDir + _
cdlOFNHideReadOnly + cdlOFNFileMustExist
CommonDialog1.ShowOpen
Dateiname = CommonDialog1.FileName

Soll der Benutzer mehrere Dateien auswählen können, setzen Sie das Flag cdlOFNAllowMultisel-
ect (&H200). Hierbei ergibt sich aber aus historischen Gründen ein kleines Problem: Da das
Steuerelement das Ergebnis einer Mehrfachauswahl gleichfalls in der Eigenschaft FileName
zurückliefert und dabei zur Aufrechterhaltung der Kompatibilität den Pfad und die ausgewähl-
ten Dateinamen jeweils durch ein Leerzeichen getrennt hintereinander setzt, erhalten Sie eine
veraltete Version des Dialogfelds, die nur kurze Dateinamen anzeigt und liefert (ansonsten wür-
den sich Fehler einschleichen, wenn ein Dateiname Leerzeichen enthält). Auch müssen Sie expli-
zit einen Filter vorgeben, damit der Benutzer überhaupt eine Auswahl sieht. In der gewohnten
Gestalt des Dialogfelds (also mit langen Dateinamen) lässt sich die Mehrfachauswahl vorneh-
men, wenn zusätzlich das Flag cdlOFNExplorer (&H80000) gesetzt wird. Im Textfeld DATEI-
NAME des Dialogs erscheinen die Dateinamen bei Mehrfachauswahl dann in Anführungszei-
chen, und im Wert der Eigenschaft FileName sind Pfad und Dateinamen jeweils durch
Nullzeichen voneinander getrennt. Für die Analyse splitten Sie den Wert am besten mit der
Funktion Split in ein Array auf. Das Array-Element mit dem Index 0 enthält dann den Pfadna-
men und die restlichen Array-Elemente die pfadlosen langen Dateinamen der Mehrfachaus-
wahl:
Dim Dateinamen() As String
CommonDialog1.Flags = cdlOFNAllowMultiselect + cdlOFNExplorer
CommonDialog1.ShowOpen
Dateinamen = Split(CommonDialog1.FileName, Chr(0))

Leider ist der Dialog für die Mehrfachauswahl nicht sauber genug implementiert: der Puffer für
die Eigenschaft FileName kann auch bei Mehrfachauswahl nicht viel mehr als 200 Zeichen auf-
nehmen, was bei größeren Auswahlen schnell zu Pufferfehlern führt, die das Dialogfeld dum-
merweise nicht immer meldet! Bleibt zu hoffen, dass sich dies im nächsten Updates ändert.

Drucken
Der Aufruf des Standarddialogs Drucken erfolgt über die Methode ShowPrinter oder durch Set-
zen der Action-Eigenschaft auf 5. In dem Dialogfeld kann der Benutzer wählen, ob er alle Seiten
des fraglichen Dokuments, die aktuelle Auswahl oder einen bestimmten Seitenbereich drucken
will. Voreinstellung der Flags-Eigenschaft ist cdlPDAllPages (alle Seiten). Da diese Konstante

448
Standarddialoge- Steuerelement ( CommonDialog)

den Wert 0 hat, kann sie nicht für die Maskierung der Flags-Eigenschaft verwendet werden,
sondern ergibt sich daraus, dass weder das Bit cdlPDPageNums (2) für den Seitenbereich noch
cdlPDSelection (1) für die Auswahl gesetzt ist. Um dem Benutzer die Seitenauswahl zu ermögli-
chen, müssen allerdings die Eigenschaften Min und Max vor dem Aufruf auf einen Wert größer 0
gesetzt werden. Das Dialogfeld stellt dann sicher, dass der vom Benutzer angegebene Seitenbe-
reich gültig ist, und liefert die Eingaben in den Eigenschaften FromPage und ToPage zurück. Den
Wert des Drehfelds KOPIEN gibt die Copies-Eigenschaft wieder, während der Zustand des Kon-
trollkästchens SORTIEREN nur durch Maskierung der Flags-Eigenschaft mit cdlPDCollate
(&H10) in Erfahrung zu bringen ist und der des Kontrollkästchens AUSDRUCK IN DATEI durch
Maskierung mit cdlPDPrintToFile (&H20).
Da das Dialogfeld auch die Auswahl des Druckers ermöglicht, stellt sich die Frage, wie damit zu

Weitere ActiveX- Steuerelemente


verfahren ist. Die Antwort fällt für den Visual-Basic-Programmierer eher ernüchternd aus:
Unerfreulicherweise gibt es keine Eigenschaft, die den Namen des gewählten Druckers preisge-
ben würde. Lediglich ein Gerätekontext bzw. Informationskontext lässt sich ihm über die
Eigenschaft hDC entlocken, vorausgesetzt die Flags-Eigenschaft wurde vor dem Aufruf auf cdlP-
CReturnDC (&H100) bzw. cdlPCReturnIC (&H100) gesetzt. Beide Informationen führen in die
Tiefen der GDI und erfordern gute Kenntnisse im Bereich der Win32-API-Programmierung.
Dennoch, es bleibt ein Ausweg, ein unschöner, aber durchaus praktikabler: Setzt man die
Eigenschaft DefaultPrinter des Steuerelements auf True, erklärt der Druckerdialog den ausge-
wählten Drucker automatisch zum Standarddrucker. Vorausgesetzt die TrackDefault-Eigen-
schaft des Printer-Objekts wurde nicht auf False gesetzt, macht das Printer-Objekt diese
Änderung mit und gestattet fortan den Ausdruck auf dem gewählten Gerät. Um den ursprüngli-
chen Standarddrucker wieder zurückzusetzen, ist allerdings ein weiterer Aufruf des Druckerdia-
logs nötig, sonst bleibt der gewählte Drucker dem System erhalten – unschön, wie gesagt.
Anstelle von Drucken kann ShowPrinter auch den Dialog Drucker einrichten aufrufen, der es
dem Benutzer ermöglicht, die Druckereinstellungen der auf dem System installierten Drucker
interaktiv zu ändern. Dazu muss das Flag cdlPDPrintSetup (&H40) gesetzt werden. Die Wir-
kung ist gleichfalls systemweit, sofern die DefaultPrinter-Eigenschaft auf True gesetzt ist.

Schriftart
Für den Aufruf des Standarddialogs Schriftart sorgt die Methode ShowFont bzw. das Setzen der
Action-Eigenschaft auf 4. Zur Vorbereitung des Aufrufs ist es erforderlich, dem Dialog über die
Flags-Eigenschaft kundzutun, welche Schriftarten im Angebot stehen sollen. Für die primäre
Auswahl ist eines der folgenden Flags obligatorisch: cdlCFScreenFonts (1) für die Auswahl der
Bildschriftarten; cdlCFPrinterFonts (2) für die Auswahl der Druckerschriftarten, die mit dem
Gerätekontext des aktuellen Standarddruckers kompatibel sind; cdlCFBoth (3) für alle auf dem
System installierten Schriften. Für die weitere Verfeinerung der Auswahl setzen Sie zusätzliche
Flags wie: cdlCFFixedPitchOnly (&H4000) für nichtproportionale Schriften; cdlCFTTOnly
(&H40000) für TrueType-Schriften; cdlCFScaleableOnly (&H20000) für frei skalierbare
Schriften; cdlCFANSIOnly (&H400) für Schriften, die mit dem Windows-Zeichensatz konform
sind; cdlCFNoVectorFonts (&H800) für Bitmap-Schriften; cdlCFWYSIWYG (&H8000) für Schrif-
ten, die für die Bildschirm- und die Druckerausgabe geeignet sind; cdlCFNoSimulation für origi-
nale, nicht von der GDI generierte Schriften. Beachten Sie, dass die Attribute sich teilweise
gegenseitig ausschließen, so dass es zum Laufzeitfehler 24574 »Keine Schriftarten vorhanden«
kommen kann, wenn die Auswahl leer ist. Zudem können Sie das Flag cdlCFForceFontExist
(&H10000) setzen, damit das Dialogfeld die Existenz der vom Benutzer eingegebenen Schrift
überprüft. Für eine Gültigkeitsprüfung der Schriftgröße setzen Sie die Eigenschaften Min und Max
auf geeignete Werte sowie das Flag cdlCFLimitSize (&H2000). Zu guter Letzt können Sie über
die Flags cdlCFNoFaceSel (&H80000), cdlCFNoSizeSel (&H200000) und cdlCFNoStyleSel

449
Weitere ActiveX- Steuerelemente

(&H100000) vorgeben, ob das Dialogfeld die aktuellen Werte der Eigenschaften FontName,
FontSize, FontItalic und FontBold als Vorgabe markiert oder nicht.
Die Eingaben des Benutzers finden sich nach dem Aufruf in den FontXX-Eigenschaften.
With CommonDialog1
.FontName = FontName
.FontSize = FontSize
.Flags = cdlCFScreenFonts
.ShowFont
FontName = .FontName
FontSize = .FontSize
Weitere ActiveX- Steuerelemente

Print FontName
End With

Da das Steuerelement unverständlicherweise nicht über eine Font-Eigenschaft verfügt, lassen


sich verschiedene Schriftstile, die das Dialogfeld für die eine oder andere Schrift anbietet, in
Visual Basic leider gar nicht auswerten.

Farbauswahl
Der Standarddialog Farbe wird über die Methode ShowColor bzw. durch Setzen der Action-
Eigenschaft auf 3 angezeigt. Das Dialogfeld hat zwei Ansichten: eine Standardansicht sowie
eine erweiterte Ansicht. Sind die Flags cdlCCFullOpen (&H2) und cdlCCPreventFullOpen (&H4)
nicht gesetzt, erscheint das Dialogfeld zunächst in Standardansicht, gestattet dem Benutzer aber
das Umschalten in die erweiterte Ansicht (was sich durch cdlCCPreventFullOpen verhindern
lässt). In der Standardansicht kann der Benutzer seine Farbauswahl aus 48 vordefinierten
Grundfarben sowie 16 benutzerdefinierten Farben treffen. In der erweiterten Ansicht hat er die
Möglichkeit, selbst Farben aus dem vollen TrueColor-Spektrum zu definieren. Damit das Dia-
logfeld den Wert der Color-Eigenschaft als Vorgabe für die Farbauswahl kenntlich macht, set-
zen Sie das Flag cdlCCRGBInit (&H1). Nach dem Aufruf enthält die Color-Eigenschaft die Farb-
auswahl des Benutzers.
With CommonDialog1
.Color = RGB(0, 128, 0)
.Flags = cdlCCFullOpen + cdlCCRGBInit
.ShowColor
BackColor = .Color
End With

450
Teil 2:
Praxisteil

451
Ältere Basic- Programme nach Visual Basic
portieren
Wer ein älteres in Basic geschriebenes Programm unter Visual Basic zur Ausführung bringen
will, wird nicht umhinkommen, einige Anpassungen vorzunehmen, um das Programm über-
haupt erst einmal ans Laufen zu bringen. Und bis es dann wirklich in jeder Hinsicht das
Gewünschte macht, ist zuweilen noch einiges an Schweiß erforderlich.
Vom Kern her ist Visual Basic der Sprache BASIC treu geblieben – wie sollte es auch anders
sein. Natürlich, Visual Basic ist von der Ausdruckskraft her um einiges reicher geworden als
etwa die mit QuickBasic oder QBasic vorliegenden Implementationen der Sprache. Verloren
gegangen ist aber nichts, sieht man davon ab, dass verschiedene Konzepte im Fahrwasser der
Windows-Programmierung generell einen anderen Zugang benötigen, wie beispielsweise die
Ein- und Ausgabe, der Umgang mit Farben, mit langen Dateinamen oder die Unicode-Darstel-
lung von Zeichenfolgen. Insbesondere aber an den Kontrollstrukturen sowie den Datentypen
und ihren Operationen hat sich außer allfälligen Komplettierungen und der Bequemlichkeit die-
nenden Erweiterungen nichts geändert. Mit anderen Worten, von der algorithmischen Seite her
ist für die Portierung sicher am allerwenigsten zu befürchten. Auch die traditionellen Funktio-
nen der Sprache Basic für die Manipulation von Zeichenketten sowie für mathematische
Berechnungen machen verhältnismäßig wenig Schwierigkeiten, wenngleich die Umwandlung
von Zeichenketten in Zahlen und zurück aufgrund der von Visual Basic beachteten länderspezi-
fischen Zahlendarstellung sicher Ärger machen wird. Der schwierigste Teil ist aber unbestritten
die Bildschirmausgabe gleich gefolgt von der Eingabe. Die folgende Tabelle bietet einen Über-
blick über das Problempotenzial spezifischer Bereiche.

Bereich Macht Probleme?


Kontrollstrukturen und Algo- Keine Probleme zu befürchten
rithmen
Konstanten, Variablen, Weitgehend problemlos; globale Variablen bedürfen der Über-
Bezeichner arbeitung und implizit deklarierte lokale Variablen der Kon-
trolle auf Namenskonflikte
Datentypen und Operationen Kaum Probleme zu befürchten
Mathematische Funktionen Problemlos, neue Funktionen machen vieles einfacher, zum
Beispiel die Rundung, finanzmathematische Funktionen
Selbst definierte Funktionen Weitgehend problemfrei; Shared-Vereinbarungen (globale
und Prozeduren Variablen) müssen überarbeitet werden; Namenskonflikte bei
impliziter Variablendeklaration möglich
Zeichenfolgenfunktionen Problembehaftet, da Visual Basic länderspezifische Darstellung
bei Zahlenwandlung beachtet, Unicode vs. ASCII-Code, auch
die Codetabellen für die Zeichenkodierung sind leicht unter-
schiedlich
Dateioperationen Weitgehend problemlos, zuweilen bereitet jedoch die Verarbei-
tung langer Dateinamen Schwierigkeiten
Eingabe Problematisch – bei der Portierung ist einiges an konzeptuellen
Änderungen einzuarbeiten

453
Wie importiert man den Quelltext?

Bereich Macht Probleme?


Zeichenausgabe Sehr problematisch – Print-Anweisung verändert; Print Using
fehlt, Zeilenorientierung, Cursorplatzierung anders, Schriftde-
finitionen, Farbmodell anders
Grafik Problematisch, da Veränderungen bei Koordinatensystem und
Farbmodell einzuarbeiten sind und die Grafikausgabe die Posi-
tion der Textausgabe beeinflusst
Fehlerbehandlung Problemlos, weil unverändert.
Wie importiert man den Quelltext?

Wie importiert man den Quelltext?


Legen Sie ein neues Projekt des Typs »Standard-EXE« an und laden Sie den Quelltext des zu
portierenden Programms als Standardmodul. Das geht entweder über den Menübefehl PRO-
JEKT/MODUL HINZUFÜGEN oder schlicht durch Ziehen der BAS-Datei von einem Explorer-Fens-
ter in das Projektfenster. Um keine Verfälschungen der Zeichencodes bei der Konversion vom
DOS-Textformat nach Windows zu erhalten, können Sie den Programmtext über ein Textver-
arbeitungsprogramm dezidiert als MSDOS-Text importieren und über die Zwischenablage
nach Visual Basic transferieren.

Einfache Programme
In keiner anderen Programmiersprache werden mehr Programmskizzen geschrieben, die irgend-
welche kleinen Berechnungen anstellen und das Ergebnis ausgegeben, als in Basic. Meist fehlt
einfach ein passender Interpreter, um diese Programme wieder zum Leben zu erwecken. Auch
wenn man diese Programme vom Prinzip her wie komplexe Programme nach Visual Basic por-
tieren könnte, lohnt sich der Aufwand in den meisten Fällen eher nicht – und mit kleineren
Abweichungen im Bereich der Ein- und Ausgabe lässt sich sicher leben. Wenn es Ihnen reicht,
dass Print-Ausgaben im Direktfenster (aufzurufen über (Strg)+(G)) erscheinen und Eingaben
über kleine Fenster via InputBox getätigt werden, ist die Portierung in wenigen Augenblicken
erledigt. Betrachten wir folgendes einfache QBasic-Programm, das eine Zahl abfragt und darü-
ber Auskunft gibt, ob es sich bei der Zahl um eine Primzahl handelt oder nicht.
Nach dem Import des Quelltextes zeigt das Codefenster folgenden Inhalt:
DECLARE FUNCTION Prim% (a&)
Rem Primzahltester
INPUT "Bitte Zahl eingeben: ", a&
If Prim(a&) Then k$ = "keine "
Print a&; "ist "; k$; "Primzahl"

Function Prim%(a&)
For i% = 2 To Sqr(a&)
If a& Mod i% = 0 Then
Prim% = i%
Exit Function
End If
Next
End Function

454
Einfache Programme

Visual Basic kann weder mit der DECLARE- noch mit der INPUT-Anweisung etwas anfangen, was
der Editor durch Ausgabe der entsprechenden Zeilen in roter Farbe kundtut. Aber auch die
Print-Anweisung macht Probleme. Um Code wie diesen ans Laufen zu kriegen, gehen Sie wie
folgt vor:
1. Löschen Sie DECLARE-Anweisungen. Sie sind unter Visual Basic für modulinterne Funktionen/
Prozeduren nicht nötig. (Visual Basic benutzt Declare in anderer Syntax für den Import von
Bibliotheksroutinen, die in DLLs beheimatet sind.)
2. Fassen Sie »losen Code«, das heißt den Code, der keiner Prozedur/Funktion zugeordnet ist,
in einer Prozedur namens Main zusammen und deklarieren Sie alle Shared-Variablen aus den
Funktionen/Prozeduren als globale Variablen. Lokale Variablen gleichen Namens müssen

Einfache Programme
explizit deklariert werden, um Fehlern durch Namenskonflikte vorzubeugen. (Eine Option
Explicit-Anweisung zu Beginn des Moduls deckt implizite Deklarationen auf.)
3. Ersetzen Sie Input-Anweisungen durch InputBox-Anweisungen, wobei Sie jeden via Input ge-
lesenen Wert mit einer eigenen InputBox-Anweisung bedenken müssen.
4. Ersetzen Sie jede Print-Anweisung durch eine Debug.Print-Anweisung.
5. Definieren Sie die Methode Main im Fenster PROJEKTEIGENSCHAFTEN als Startobjekt.
6. Öffnen Sie das Direktfenster ((Str)+(G)) und starten Sie das Programm.
Nach der Portierung sieht der Quelltext so aus:
Rem Primzahltester
Dim a&, k$

Sub Main()
a& = InputBox("Bitte Zahl eingeben: ")
If Prim(a&) Then k$ = "keine "
Debug.Print a&; "ist "; k$; "Primzahl"
End Sub

Function Prim%(a&)
For i% = 2 To Sqr(a&)
If a& Mod i% = 0 Then
Prim% = i%
Exit Function
End If
Next
End Function

Wer damit nicht zufrieden ist und die Implementation lieber in ein Formularmodul packen will,
muss schon einiges mehr an Aufwand betreiben – und sollte sich bei dem einfachen Programm
vielleicht sogar überlegen, ob er es nicht lieber gleich neu aufbaut. Ein generelles Problem bei
der Umsetzung älterer Basic-Programme nach Visual Basic ist nämlich die Umsetzung des (syn-
chronen) Programmablaufs, wenn Eingaben ins Spiel kommen. Da sich Visual Basic das ereig-
nisorientierte Programmiermodell von Windows zu eigen macht, ist für Visual-Basic-Pro-
gramme zunächst einmal kein fester Programmablauf vorgeschrieben: Das Programm reagiert
vielmehr auf die einzelnen Benutzereingaben. Mit anderen Worten: Das, was die Flexibilität
und Bedienfreundlichkeit von Windows-Programmen eigentlich ausmacht, wird einem bei der
Portierung leider zum Hemmschuh.
Sehen wir uns die Sache einmal genauer am Beispiel der INPUT-Anweisung an. Solange man auf
InputBox ausweicht, bleibt zwar der synchrone Programmablauf gewahrt, die Eingabe in einem
eigenen Dialogfeld stellt aber schon eine erhebliche Einschränkung dar. Der Versuch, solche
Eingaben über ein Steuerelement, beispielsweise über ein einfaches Textfeld, zu realisieren,

455
Einfache Programme

wirft sofort die Frage nach dem Programmablauf auf: Ein traditionelles Basic-Programm, wie
unser Beispiel, erwartet an einer bestimmten Stelle im Programm eine Eingabe, um im weiteren
Programmverlauf darauf rekurrieren zu können – ein Visual-Basic-Programm kann zwar auf
Eingaben, die ein Benutzer in einem Textfeld vornimmt, reagieren, etwa wenn es das Validate-
Ereignis behandelt, den Benutzer aber zu zwingen, dies an einer bestimmten Stelle im Program-
mablauf zu tun, erfordert schon einige Kunstgriffe – zumal wenn mehrere (gegebenenfalls auf-
einander aufbauende) Eingaben zu koordinieren sind. Im Sinne einer einfachen Portierung ist
das sicher nicht.

Implementation einer eigenen Input- Routine


Einfache Programme

Einen Ausweg stellt die folgende Implementation InputQB der Input-Anweisung dar: Wie Input-
Box arbeitet InputQB mit einem zweiten Formular, das jedoch nichts weiter als ein Textfeld ent-
hält und an passender Position ohne Rahmen als modales Dialogfeld zum Aufruf kommt.
InputQB gibt wie Input den Text EingabeAufforderung an der aktuellen Ausgabeposition aus und
bereitet dann das zweite Formular für den Aufruf entsprechend vor: Schrift und Farben des
Textfelds werden an das aktuelle Formular angeglichen, die Position des Formulars wird so
berechnet, dass dieses an der richtigen Stelle zu liegen kommt, und die Abmessungen werden
genau so getrimmt, dass es für eine einzeilige Eingabe bis zum Ende des aktuellen Formulars
reicht.
Sub InputQB(EingabeAufforderung As String, Param)
Dim f As New InputForm ' Eingabeformular
Dim RandOffsOben As Integer
Dim RandOffsLinks As Integer
Dim Params() As String
Print EingabeAufforderung;
' Eingabeformular für die Eingabe an (CurrentX, CurrentY) vorbereiten
f.Text1.BorderStyle = vbBSNone
f.Text1.BackColor = BackColor
f.Text1.ForeColor = ForeColor
RandOffsOben = Height – ScaleHeight – (Width – ScaleWidth) / 2
RandOffsLinks = (Width – ScaleWidth) / 2
f.Left = CurrentX + Left + RandOffsLinks
f.Top = CurrentY + Top + RandOffsOben
f.Width = ScaleWidth – CurrentX
f.Font = Font
f.Height = f.TextHeight("Test")
f.Text1.Height = f.Height
f.Text1.Width = ScaleWidth – CurrentX
f.Show vbModal, Me ' Formular aufrufen, gibt bei
' Hide die Kontrolle zurück
Param = f.Text1 ' Wert übernehmen
Print Param
End Sub

Ein wenig verzwickt ist die Berechnung der Formularposition, da Visual Basic seine Position
relativ zum Ursprung des Screen-Objekts (linker oberer Bildschirmpunkt) ausgedrückt haben
will – und nicht relativ zum Formular des rufenden Codes (das ist nur bei MDI-Formularen so).
Die Berechnung lebt übrigens von der Annahme, dass der untere Formularrand (Abstand zwi-
schen der Unterkante des Client-Bereichs und der Unterkante des Formulars) genauso breit ist
wie der rechte und linke Formularrand (genauer: die Hälfte der Summe).

456
Anspruchsvollere Programme

Die Implementation des zweiten Formulars InputForm sieht recht einfach aus. Sie setzt jedoch
ein Textfeld Text1 an der Position (0, 0) voraus und baut darauf, dass die Eigenschaft Border-
Style zur Entwurfszeit auf »0 – Kein« gesetzt wurde – anders ist ein rahmenloser Aufruf des
Formulars nicht zu bewerkstelligen.
' Modul: InputForm
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then Hide
End Sub

Wie man sieht, tut das Formular nichts weiter, als sich nach erfolgter Eingabe in das Textfeld
Text1 unsichtbar zu machen. Damit hat es folgende Bewandtnis: Da der Show-Aufruf des For-

Anspruchsvollere Programme
mulars modal erfolgt, wird der rufende Code erst fortgesetzt, wenn das gerufene Formular die
Kontrolle abgibt. Das passiert beim Ableben des Formulars, aber auch, wenn es auf »unsicht-
bar« gesetzt wird – zum Glück, denn anders könnte der rufende Code die Eingaben des Benut-
zers in das Textfeld nicht in Erfahrung bringen. Die »Parameterübergabe« lebt also davon, dass
das InputForm-Objekt noch existiert, wenn die Kontrolle zurückkommt – es stirbt erst mit Been-
digung der Routine.
Natürlich ist die hier vorgestellte Implementation kein äquivalenter Ersatz für Input, zumal die
traditionelle Syntax für diese Anweisung immer schon recht ausladend war. Die weitere Ausge-
staltung dürfte aber keine Schwierigkeiten mehr bereiten.

PrimzahlTester – im neuen Gewand


Das Projekt PrimzahlTester ist eine etwas anspruchsvollere Portierung des zuvor vorgestellten
QBasic-Programms in ein Formularmodul. Es demonstriert zum einen den Einsatz der Funktion
InputQB und zum anderen, wie man den losen Programmcode im Formularmodul platziert.
Private Sub Form_Load()
AutoRedraw = True
Show
DoProgram
' Unload Me ' Bei Bedarf
End Sub

Sub DoProgram()
InputQB "Bitte Zahl eingeben: ", Eingabe
If Eingabe = "" Then Eingabe = "0"
a& = Eingabe
If Prim(a&) Then k$ = "keine "
Print a&; "ist "; k$; "Primzahl"
End Sub

Anspruchsvollere Programme
Anspruchsvollere Programme – und diese dürften gut 90 Prozent des zu portierenden Codes
ausmachen – verlangen nach einem Formular, das den Ausgabebildschirm im Textmodus oder
im Grafikmodus simuliert. Seien Sie aber darauf gefasst, dass Ihnen hier ein gutes Stück Arbeit
bevorsteht: Gerade was die Ausgabe betrifft, sind die Unterschiede und Ungereimtheiten zwi-
schen Visual Basic und älteren Basic-Varianten nämlich am größten. Die erfolgreiche Portie-
rung mit vertretbarem Aufwand setzt da mitunter eine erhebliche Kompromissbereitschaft
voraus.

457
Anspruchsvollere Programme

Nachdem Visual Basic einige beispielsweise unter QBasic noch unverzichtbare Funktionen und
Anweisungen schlicht nicht hat, steht man häufig vor der Wahl, passende »Prothesen« zu imp-
lementieren, die den alten Code »herüberretten«, oder den inkompatiblen Code mit Mitteln
von Visual Basic neu zu schreiben. Ersteres kann sich lohnen, aber auch recht schnell in ein
Dickicht führen, das sich durch einen beherzteren Eingriff in den Code vielleicht vermeiden
ließe. Mit beiden Herangehensweisen lassen sich bis zu einem gewissen Grad befriedigende
Ersatzlösungen finden, eine Äquivalenz jedoch in den wenigsten Fällen. Bedenkt man jedoch,
dass ein älteres, noch aus DOS-Zeiten stammendes Programm heutzutage kaum wegen seiner
überzeugenden Bildschirmdarstellung und grafischen Gimmicks portiert wird, sondern wegen
seines algorithmischen Kerns, dürfte eine gewisse »Entstellung« der Benutzeroberfläche auf-
grund vereinfachender Ersatzlösungen nicht so stark ins Gewicht fallen.
Anspruchsvollere Programme

Bevor es um die konkrete Implementation einiger Standardlösungen für die wichtigsten fehlen-
den Funktionen und Prozeduren geht, noch ein paar Regeln dafür, wie Sie dem Code generell zu
Leibe rücken sollten:
1. Laden Sie den Code, wie gehabt, am besten in ein (neues) Standardmodul und kopieren Sie
ihn von da aus häppchenweise in das Formularmodul des Projekts.
2. Entfernen Sie alle DECLARE-Anweisungen ersatzlos und verschaffen Sie sich einen Überblick
über den Code. Zeilen, die der Editor in roter Farbe ausgibt, enthalten eine oder mehrere An-
weisungen, mit denen Visual Basic nichts anfangen kann. Unternehmen Sie erst einmal noch
nichts dagegen. Sie können diese Anweisungen später gegebenenfalls als selbst definierte
Funktionen/Prozeduren nachliefern und müssen dann nur die Aufrufsyntax anpassen (hierzu
gleich mehr).
3. Kopieren Sie den Code aus dem Hauptmodul in die Load-Routine des Formulars oder in eine
von dieser aufgerufene Hilfsprozedur.
4. Kopieren Sie alle Funktionen und Prozeduren in das Formularmodul und gehen Sie jede einzel-
ne Funktion/Prozedur daraufhin durch, ob sie Shared-Vereinbarungen enthält. (Shared-Vari-
ablen haben in QBasic so etwas ähnliches wie einen globalen Geltungsbereich, müssen aber von
jeder Funktion/Prozedur, die damit arbeitet, eigens über Shared-Anweisungen importiert bzw.
exportiert werden.) Deklarieren Sie die entsprechenden Variablen im Bereich Allgemein des
Formulars als globale Variablen. Bevor Sie die Shared-Anweisungen für eine Variable entfer-
nen, sollten Sie noch die Funktionen/Prozeduren ohne Shared-Vereinbarungen danach durch-
gehen, ob sie nicht zufällig die gleichen Variablenbezeichner mit impliziter Deklaration (und
somit als lokale Variable) verwenden. Wenn ja, ergänzen Sie lokale Deklarationen. Ansonsten
fangen Sie sich aufgrund von Namenskonflikten schwer aufzufindende Fehler ein.
5. Lokalisieren Sie die für die Eingabe sowie die für die Ausgabe zuständigen Routinen und ana-
lysieren Sie die Benutzerschnittstelle des Programms. Von diesen Routinen haben Sie am
meisten Ärger zu erwarten. Treffen Sie eine Entscheidung, ob Sie Eingabeschleifen und Me-
nüs des Programms im Stile von Windows neu implementieren oder ob Sie versuchen, den
vorhandenen Code durch Bereitstellung einer geeigneten Infrastruktur zu emulieren.
6. Bereinigen Sie Ungereimtheiten bei der Zeichenfolgendarstellung: beim Import nach Win-
dows entstellte Umlaute, Punkt-/Kommaproblematik bei der Wandlung von Zeichenfolgen
in Zahlenwerte (und umgekehrt) sowie veränderte Tastaturcodes.
7. Implementieren Sie Funktionen/Prozeduren und Voraussetzungen, die Visual Basic nicht un-
terstützt, und passen Sie die betroffenen Aufrufe an die neue Syntax bzw. Semantik an.
8. Spannen Sie den Compiler für die Überprüfung der syntaktischen Kompatibilität ein und
schreiben Sie nicht emulierbare, inkompatible Codesequenzen um. Geizen Sie nicht mit Kom-
mentaren.
9. Testen Sie die semantische Äquivalenz des portierten Codes schrittweise durch geeigneten
Testcode und schreiben Sie Codesequenzen, die nicht das gewünschte Ergebnis (meist Aus-
gabe) liefern, um.

458
Implementation von Inkey$

Natürlich wird jedes komplexere Programm seine eigenen Fallstricke enthalten, wenn es nicht
absolut sauber implementiert und kommentiert wurde oder gar den einen oder anderen »Trick«
benutzt. Generelle Regeln lassen sich für die Umsetzung der verschiedenen Programmiertechni-
ken kaum aufstellen. Die folgenden Abschnitte stellen verschiedene Routinen vor, die sich bei
der Portierung schon so mancher QBasic-Programme bewährt haben. Sie sind im Projekt
QBEmulation als Standardmodul zusammengefasst. Das Projekt lässt sich gut als Ausgangs-
punkt für eigene Portierungen sowie Emulationen verwenden.

Implementation von Inkey$


Neben Input fehlt Visual Basic auch die Funktion INKEY$. Hierfür lässt sich jedoch relativ ein-

Anspruchsvollere Programme
fach Ersatz finden, wenn man die Ereignisse KeyDown und KeyPress des Formulars behandelt und
eine globale Variable einsetzt, um den jeweils letzten Tastendruck zu speichern. (Falls das For-
mular ein Steuerelement besitzt, das den Fokus erhalten kann, müssen Sie die Eigenschaft
KeyPreview auf True setzen, sonst bekommt das Formular die Eingaben nicht zu sehen.)
Bekanntlich liefert INKEY$ ASCII-Zeichen als Zeichenfolge der Länge 1 und alle anderen Zei-
chen als Tastaturcodes mit vorangestelltem Nullbyte. Da das KeyPress-Ereignis nur auftritt,
wenn ein ASCII-Zeichen eingegeben wurde, arbeiten die beiden Routinen mit derselben globa-
len Variable.
Private InkeyChar As String

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)


If Shift = 0 Then ' Funktionstasten ignorieren
InkeyChar = Chr(0) + Chr(KeyCode) ' Tastaturcode merken
End If
End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)


InkeyChar = Chr(KeyAscii) ' Zeichen merken
End Sub

Function InKey$()
DoEvents
InKey$ = InkeyChar
InkeyChar = ""
End Function

Die Implementation ist zwar geradlinig, hat aber einen Haken: Die Tastaturcodes von Win-
dows sind anders als die von DOS. So hat beispielsweise die Taste (Rechts) unter DOS den
Code 77 und unter Windows den Code 39 (oder vbKeyRight). Es wird Ihnen also nicht erspart
bleiben, Tastatursteuerungen komplett zu überarbeiten. Die Tastencodes entnehmen Sie dem
Aufzählungstyp KeyCodeConstants. Aufgrund des DoEvents-Aufrufs ist die Implementation auch
gegen Endlosschleifen gefeit (wäre da nicht das »Stehaufmännchen«-Problem, wie noch aus-
führlich im Abschnitt »Ereignisbehandlung mit DoEvents, ein komplexes Problemfeld«, S. 485
erläutert). Somit stellt die klassische INKEY$-Schleife – wie hier in der Implementation einer
Schreibmaschine – keine Hürde mehr dar:

a$ = InKey$
While a$ <> Chr$(27)
Print a$;
a$ = InKey$
Wend

459
Anspruchsvollere Programme

Implementation von LOCATE, POS, CSRLIN und COLOR


Nicht wenige Basic-Programme sind auf einen Textbildschirm mit 80 Spalten und 25 Zeilen
zugeschnitten und machen massiv von der Anweisung Locate Gebrauch, die es erlaubt, die Aus-
gabeposition für die Print-Anweisung frei zu setzen. Zur Abfrage der aktuellen Position findet
man weiterhin die Funktionen POS und CSRLIN. Alle drei Routinen arbeiten mit dem jeweils
aktuellen Koordinatensystem und lassen sich recht einfach nachrüsten. Zeilen- und Spaltenzäh-
lung sind Eins-basiert.

Sub Locate(Optional Zeile = 0, Optional Spalte = 0)


If Zeile Then CurrentX = ScaleLeft + (Zeile – 1) * TextWidth("A")
Anspruchsvollere Programme

If Spalte Then CurrentY = ScaleTop + (Spalte – 1) * TextHeight("A")


End Sub

Function Pos(dummy) As Integer


Pos = CInt((CurrentX – ScaleLeft) / TextWidth("A") + 1)
End Function

Function CsrLin() As Integer


CsrLin = (CurrentY – ScaleTop) / TextHeight("A") + 1
End Function

Damit das funktioniert, ist allerdings eine gewisse Vorbereitung notwendig: das Setzen einer
nichtproportionalen Schrift sowie geeigneter Formularabmessungen.

Private Sub Form_Load()


AutoRedraw = True
FontName = "Courier New"
FontSize = 8
Width = Width – ScaleWidth + 80 * TextWidth("T")
Height = Height – ScaleHeight + 25 * TextHeight("T")
' Testen der Methoden
Locate 10, 10
Print CsrLin;
Locate, 20
Print Csrlin;
End Sub

Ein gravierendes Problem dürfte allerdings der fehlende automatische Umbruch am Zeilenende
bei der Print-Ausgabe darstellen. Hiergegen scheint aufseiten von Visual Basic kein Kraut
gewachsen zu sein, es sei denn, man implementiert die Print-Anweisung neu. Angesichts des
zusätzlichen Aufwands, den das für die Portierung bedeutet, wird es meist besser sein, die ent-
sprechenden Stellen »von Hand« zu bereinigen, als alle Print-Ausgaben umzuschreiben.
Auch die Color-Anweisung lässt sich nicht völlig äquivalent implementieren, da sich eine Ände-
rung der Hintergrundfarbe immer gleich auf das gesamte Fenster bezieht und nicht nur auf die
Texthöhe und Textbreite der kommenden Print-Ausgaben. Für die korrekte Semantik müsste
man gleichermaßen eine andere Implementation der Print-Anweisung bereitstellen.

Sub Color(Vordergrund%, Optional Hintergrund% = 0)


BackColor = QBColor(Hintergrund%)
ForeColor = QBColor(Vordergrund%)
End Sub

460
Koordinatensystem und Grafikmodus

Koordinatensystem und Grafikmodus


Wie Sie gesehen haben, war es für den Textmodus nicht erforderlich, ein Koordinatensystem zu
setzen. Sobald aber eine Grafikausgabe ins Spiel kommt, führt kein Weg mehr daran vorbei, da
ältere Basic-Versionen im Grafikmodus standardmäßig ein Koordinatensystem mit der Einheit
»Bildpunkte« verwenden, dessen Ursprung in der linken oberen Ecke des Bildschirms gelegen
und dessen vertikale Achse nach unten orientiert ist. Zum Umschalten in den Grafikmodus fin-
det man in älteren Programmen die SCREEN-Anweisung. Diese Anweisung vollständig zu imple-
mentieren, ist weder möglich noch in den wenigsten Fällen wirklich erforderlich (unter Win-
dows gibt es eben keine unterschiedlichen Grafikmodi und man kann nicht auf einer
Bildschirmseite zeichnen, während man eine andere anzeigt – vom Ansatz her könnte man

Anspruchsvollere Programme
jedoch versuchen, mit mehreren Fenstern oder mit PictureBox-Steuerelementen zu arbeiten,
zwischen denen SCREEN hin- und herschaltet). Eine einfache Implementation der Screen-Anwei-
sung könnte etwa so aussehen:

Sub Screen(Modus)
Select Case Modus
Case 10 ' 640x350
Width = Width – ScaleWidth + ScaleX(640, vbPixels, vbTwips)
Height = Height – ScaleHeight + ScaleX(350, vbPixels, vbTwips)
ScaleMode = vbPixels
Case 11, 12 ' 640x480
Width = Width – ScaleWidth + ScaleX(640, vbPixels, vbTwips)
Height = Height – ScaleHeight + ScaleX(480, vbPixels, vbTwips)
ScaleMode = vbPixels
Case Else
Err.Raise 1000, , "Bildschirmmodus nicht implementiert"
End Select
End Sub

Lassen Sie sich nicht von den Eigenschaften Height und Width ärgern! Diese Eigenschaften
erwarten unabhängig vom eingestellten Koordinatensystem ihre Werte immer in Twips.
Eine generelle Implementation der SCREEN-Funktion ist wahrlich »kein Zuckerschlecken« und
dürfte zu sehr umständlichen Lösungen führen. Am besten, Sie schreiben das zu portierende
Programm nach Möglichkeit um.
Einfacher haben Sie es mit der WINDOW-Anweisung. Sie lässt sich (bis auf die Geschichte mit der
Orientierung) unverändert in die Scale-Methode überführen. Damit wäre der Grafikmodus
»eingeschaltet« und das Koordinatensystem gesetzt, so dass man mit den Methoden Line, PSet
und Circle ungestraft zu Werke gehen kann. Na, sagen wir fast ungestraft: gegebenenfalls vor-
handene Farbe-Parameter bedürfen noch einer Übersetzung in den TrueColor-Farbraum, was
sich am einfachsten mittels der QBColor-Methode erledigen lässt. Der folgende Code zeichnet
ein rotes Rechteck im VGA-Modus 12:
Screen 12
Line (10, 10)-(630, 470), QBColor(12), BF

Schön und gut. Was aber, wenn das zu portierende Programm seine Grafikausgaben mit Text-
ausgaben kombiniert. Aufseiten von Visual Basic ist das keine triviale Angelegenheit. Immerhin,
als Schrift für die VGA-Auflösung 640×480 bietet sich »Courier New« in der Größe 8 an. Sie
hat eine Höhe von 16 Bildpunkten und eine Breite von 8 Bildpunkten, so dass sich genau die
gewünschte 80×30 Zeichenmatrix ergibt. Problematisch ist aber, dass Visual Basic die Eigen-
schaften CurrentX und CurrentY sowohl für Print als auch für die Grafikmethoden PSet, Line
und Circle verwendet. Um ein Programm mit gemischter Text- und Grafikausgabe portieren zu

461
Anspruchsvollere Programme

können, muss ein Weg gefunden werden, die Ausgabepositionen getrennt zu verwalten. Das
geht beispielsweise über zwei zusätzliche Methoden TextQB und GrafikQB sowie vier globale
Variablen für die jeweiligen Positionen und eine Zustandsvariable:
Private CurrentTextX As Single ' Positionen in Grafik-
Private CurrentTextY As Single ' und Textmodus getrennt
Private CurrentGrafikX As Single ' verwalten
Private CurrentGrafikY As Single

Enum CurrentStates
vbCurrentText = 0
Anspruchsvollere Programme

vbCurrentGrafik = 1
End Enum
Private CurrentState As CurrentStates

Sub TextQB()
If CurrentState = vbCurrentGrafik Then
CurrentState = vbCurrentText
CurrentGrafikX = CurrentX
CurrentGrafikY = CurrentY
CurrentX = CurrentTextX
CurrentY = CurrentTextY
End If
End Sub

Sub GrafikQB()
If CurrentState = vbCurrentText Then
CurrentState = vbCurrentGrafik
CurrentTextX = CurrentX
CurrentTextY = CurrentY
CurrentX = CurrentGrafikX
CurrentY = CurrentGrafikY
End If
End Sub

Die Implementation mag noch angehen, für die Portierung bedeutet das aber, dass Sie Print-
und Locate-Anweisungen mit TextQB und PSet-, Circle- und Line- mit GrafikQB flankieren müs-
sen. (Sofern Letztere keine Step-Zusätze haben und alle Parameter angegeben sind, werden sie
von Print- und Locate-Anweisungen zwar nicht durcheinander gebracht – umgekehrt aber
schon.)
Falls das Programm ein eigenes Koordinatensystem verwendet, ist noch dazu eine Implementa-
tion von WINDOW erforderlich, die neben dem Scale-Aufruf auch die aktuellen Positionen für den
Text- und Grafikmodus umrechnet. Die Implementation ist ein wenig trickreich, da sie eines
der beiden Koordinatenpaare vor Einführung des neuen Koordinatensystems in ein Referenz-
koordinatensystem transformiert und danach wieder zurücktransformiert. Das andere Koordi-
natenpaar stimmt mit CurrentX und CurrentY überein und wird implizit von Scale umgerechnet.
Außerdem definiert WINDOW ein kartesisches Koordinatensystem, bei dem die vertikale Achse
nach oben orientiert ist.
Sub Window(x1, y1, x2, y2)
ScaleMode = vbUser
If CurrentState = vbCurrentGrafik Then

462
Zusammenfassung der Emulation als Standardmodul

' Auf Referenzkoordinatensystem ausweichen


CurrentTextX = ScaleX(CurrentTextX – ScaleLeft, vbUser, vbTwips)
CurrentTextY = ScaleY(CurrentTextY – ScaleTop, vbUser, vbTwips)
f.Scale (x1, IIf(y1 > y2, y1, y2))-(x2, IIf(y1 > y2, y2, y1))
' Ins neue Koordinatensystem
CurrentTextX = ScaleX(CurrentTextX, vbTwips, vbUser) + ScaleLeft
CurrentTextY = ScaleY(CurrentTextY, vbTwips, vbUser) + ScaleTop
' akt. Position übernehmen
CurrentGrafikX = CurrentX
CurrentGrafikY = CurrentY

Anspruchsvollere Programme
Else
' Auf Referenzkoordinatensystem ausweichen
CurrentGrafikX = ScaleX(CurrentGrafikX – ScaleLeft, vbUser, vbTwips)
CurrentGrafikY = ScaleY(CurrentGrafikY – ScaleTop, vbUser, vbTwips)
f.Scale (x1, IIf(y1 > y2, y1, y2))-(x2, IIf(y1 > y2, y2, y1))
' Ins neue Koordinatensystem
CurrentGrafikX = ScaleX(CurrentGrafikX, vbTwips, vbUser) + ScaleLeft
CurrentGrafikY = ScaleY(CurrentGrafikY, vbTwips, vbUser) + ScaleTop
' akt. Position übernehmen
CurrentTextX = CurrentX
CurrentTextY = CurrentY
End If
End Sub

Zusammenfassung der Emulation als Standardmodul


Im Projekt QBEmulation ist der gesamte Emulationscode in einem weitgehend eigenständigen
Standardmodul zusammengefasst und ausgiebig kommentiert; einzig die Behandlungsroutinen
für die beiden Tastaturereignisse sowie die Initialisierung der Emulation treten im Formular in
Erscheinung. Die Aktivierung der Emulation geschieht durch einen InitQB-Aufruf unter Angabe
einer Referenz auf das Formular (Me). In Abänderung zum vorgestellten Code, müssen die Rou-
tinen im Standardmodul den Zugriff auf die Eigenschaften und Methoden des Formulars über
eine globale Objektvariable des Typs Form abwickeln. Etwas komplizierter als diskutiert ist die
Implementation der Anweisung InputQB ausgefallen, ein Tribut an die Unabhängigkeit vom
Koordinatensystem.
Der Code des Formularmoduls mit ein wenig Testcode sieht so aus:
'***********************************************************************
' Formularmodul : QBEmulationTest
' Autor : 2000 Rudolf Huttary
' : testet Emulationsmodul
'***********************************************************************
Option Explicit

Private Sub Form_Load()


InitQB Me ' Emulation initialisieren
' Testen der Methoden
Show
Screen 12
Window -1, -1, 1, 1
TextQB
Locate 10, 10

463
Anspruchsvollere Programme

Print "Hinge"; ' Erstes Textstück


GrafikQB ' Grafikmodus
Line (-1, -1)-(0, 0) ' erste Linie
TextQB ' Textmodus
Window -10, -1, 40, 20 ' Koordinatensystem ändern
Print "bungs"; ' zweites Textstück
GrafikQB ' Grafikmodus
Line -(-8, 26) ' zweite Linie direkt dransetzen
TextQB ' Textmodus
Print "voll"; ' drittes Textstück
Anspruchsvollere Programme

Locate , 20
Print Pos(0); CsrLin; ' aktuelle Position: (24, 20)
Dim s
InputQB "Bitte Text eingeben: ", s ' Texteingabe testen
Locate 1, 1 ' Eingabe links oben ausgeben
Print s
End Sub

' Teil der Emulation


Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If Shift = 0 Then ' Funktionstasten ignorieren
InkeyChar = Chr(0) + Chr(KeyCode) ' Tastaturcode merken
End If
End Sub

' Teil der Emulation


Private Sub Form_KeyPress(KeyAscii As Integer)
InkeyChar = Chr(KeyAscii) ' Zeichen merken
End Sub

Hier der Code des Standardmoduls QBEmulation:


'***********************************************************************
' Standardmodul : QBEmulation
' Autor : 2000 Rudolf Huttary
' Beschreibung : stellt einige Funktionen und Anweisungen
' für das Portieren von Code aus QBasic bereit.
' Initialisierung mit InitQB erforderlich
'***********************************************************************
Option Explicit

Public InkeyChar As String ' für Inkey$


Private f As Form
Private CurrentTextX As Single ' akt. Position für Textausgabe
Private CurrentTextY As Single
Private CurrentGrafikX As Single ' akt. Position für Grafikausgabe
Private CurrentGrafikY As Single
Enum CurrentStates
vbCurrentText = 0
vbCurrentGrafik = 1
End Enum

464
Zusammenfassung der Emulation als Standardmodul

Private CurrentState As CurrentStates ' Zustandsvariable

Sub InitQB(Formular As Form)


' Initialisiert Formular für Ausgaben im Textmodus
Set f = Formular ' Referenz auf Formular speichern
f.AutoRedraw = True ' Ausgabe nicht über Paint
f.FontName = "Courier New" ' nichtproportionale Schrift
f.FontSize = 8 ' 16x8 Bildpunkte pro Zeichen
Color ' Standardfarben setzen
f.Width = f.Width – f.ScaleWidth + 80 * f.TextWidth("T") ' 80 Spalten

Anspruchsvollere Programme
f.Height = f.Height-f.ScaleHeight + 25 * f.TextHeight("T") ' 25 Zeilen
End Sub

Function InKey$()
' Letztes Zeichen von der Tastatur holen
DoEvents ' Wartende Ereignisse verarbeiten
InKey$ = InkeyChar ' InkeyChar wird von Formularmodul
InkeyChar = "" ' gesetzt!
End Function

Sub Locate(Optional Zeile = 0, Optional Spalte = 0)


' Setzt (Zeile, Spalte) für nächsten Print-Aufruf (Eins-basiert)
If Zeile Then f.CurrentX = f.ScaleLeft + (Zeile – 1) * f.TextWidth("A")
If Spalte Then f.CurrentY = f.ScaleTop + (Spalte – 1) * f.TextHeight("A")
End Sub

Function Pos(dummy) As Integer


' Liefert aktuelle Spalte für Textausgabe
Pos = CInt((f.CurrentX – f.ScaleLeft) / f.TextWidth("A") + 1)
End Function

Function CsrLin() As Integer


' Liefert aktuelle Zeile für Textausgabe
CsrLin = (f.CurrentY – f.ScaleTop) / f.TextHeight("A") + 1
End Function

Sub Screen(Modus)
' Schaltet auf Grafikmodus um
Select Case Modus
Case 10 ' 640x350
f.FontName = "Courier New"
f.FontSize = 8
f.Width = f.Width – f.ScaleWidth + f.ScaleX(640, vbPixels, vbTwips)
f.Height = f.Height – f.ScaleHeight + f.ScaleX(350, vbPixels, _
vbTwips)
f.ScaleMode = vbPixels
Case 11, 12 ' 640 * 480
f.FontName = "Courier New"
f.FontSize = 8
f.Width = f.Width – f.ScaleWidth + f.ScaleX(640, vbPixels, vbTwips)
f.Height = f.Height – f.ScaleHeight + f.ScaleX(480, vbPixels, _

465
Anspruchsvollere Programme

vbTwips)
f.ScaleMode = vbPixels
Case Else
Err.Raise 1000, , "Grafikmodus nicht emuliert"
End Select
End Sub

Sub Color(Optional Vordergrund% = 0, Optional Hintergrund% = 15)


' Setzt Farben
f.BackColor = QBColor(Hintergrund%)
Anspruchsvollere Programme

f.ForeColor = QBColor(Vordergrund%)
End Sub

Sub TextQB()
' Speichert aktuelle Position für Grafikausgabe und
' stellt aktuelle Position für Textausgabe wieder her
' (muss vor Locate, Print und Input aufgerufen werden)
If CurrentState = vbCurrentGrafik Then
CurrentState = vbCurrentText
CurrentGrafikX = f.CurrentX
CurrentGrafikY = f.CurrentY
f.CurrentX = CurrentTextX
f.CurrentY = CurrentTextY
End If
End Sub

Sub GrafikQB()
' Speichert aktuelle Position für Textausgabe und
' stellt aktuelle Position für Grafikausgabe wieder her
If CurrentState = vbCurrentText Then
CurrentState = vbCurrentGrafik ' Zustand merken
CurrentTextX = f.CurrentX ' Textausgabepos merken
CurrentTextY = f.CurrentY
f.CurrentX = CurrentGrafikX ' Grafikposition restaurieren
f.CurrentY = CurrentGrafikY
End If
End Sub

Sub Window(x1, y1, x2, y2)


' Stellt Koordinatensystem ein, bei dem der Punkt (x1, y1) links oben
' und der Punkt (x2, y2) links unten liegt
f.ScaleMode = vbUser ' für ersten Aufruf erforderlich
If CurrentState = vbCurrentGrafik Then 'Ist Grafikpos. akt. Position?
' Für Textausgabepos auf Referenzkoordinatensystem ausweichen
CurrentTextX = f.ScaleX(CurrentTextX – f.ScaleLeft, vbUser, vbTwips)
CurrentTextY = f.ScaleY(CurrentTextY – f.ScaleTop, vbUser, vbTwips)
f.Scale (x1, y1)-(x2, y2)
' Textausgabeposition ins neue Koordinatensystem umrechnen
CurrentTextX = f.ScaleX(CurrentTextX, vbTwips, vbUser) + f.ScaleLeft
CurrentTextY = f.ScaleY(CurrentTextY, vbTwips, vbUser) + f.ScaleTop

466
Zusammenfassung der Emulation als Standardmodul

' akt. Position übernehmen


CurrentGrafikX = f.CurrentX
CurrentGrafikY = f.CurrentY
Else
' Für Grafikposition auf Referenzkoordinatensystem ausweichen
CurrentGrafikX = f.ScaleX(CurrentGrafikX – f.ScaleLeft, vbUser, _
vbTwips)
CurrentGrafikY = f.ScaleY(CurrentGrafikY – f.ScaleTop, vbUser, _
vbTwips)
f.Scale (x1, y1)-(x2, y2)

Anspruchsvollere Programme
' Grafikposition ins neue Koordinatensystem umrechnen
CurrentGrafikX = f.ScaleX(CurrentGrafikX, vbTwips, vbUser) + _
f.ScaleLeft
CurrentGrafikY = f.ScaleY(CurrentGrafikY, vbTwips, vbUser) + _
f.ScaleTop
' akt. Position übernehmen
CurrentTextX = f.CurrentX
CurrentTextY = f.CurrentY
End If
End Sub

Sub InputQB(EingabeAufforderung As String, Param)


' emuliert die QBasic-Anweisung INPUT für einen Parameter
Dim iForm As New InputForm ' Eingabeformular
Dim RandOffsOben As Integer
Dim RandOffsLinks As Integer
Dim fscalewTwips As Integer
Dim fscalehTwips As Integer
Dim fCurrentXTwips As Integer
Dim fCurrentYTwips As Integer

f.Print EingabeAufforderung;
' Höhe und Breite des Clientbereichs, Randoffsets
' sowie aktuelle Position in Twips umrechnen
f.ScaleMode = vbUser ' Falls noch nicht geschehen
fscalewTwips = f.ScaleX(f.ScaleWidth, vbUser, vbTwips)
fscalehTwips = f.ScaleY(f.ScaleHeight, vbUser, vbTwips)
RandOffsOben = f.Height – fscalehTwips – (f.Width – fscalewTwips) / 2
RandOffsLinks = (f.Width – fscalewTwips) / 2
fCurrentXTwips = f.ScaleX(f.CurrentX – f.ScaleLeft, vbUser, vbTwips)
fCurrentYTwips = f.ScaleY(f.CurrentY – f.ScaleTop, vbUser, vbTwips)

' Eingabeformular für die Eingabe an (CurrentX, CurrentY) vorbereiten


iForm.Text1.BorderStyle = vbBSNone
iForm.Text1.BackColor = f.BackColor
iForm.Text1.ForeColor = f.ForeColor
iForm.Left = fCurrentXTwips + f.Left + RandOffsLinks
iForm.Top = fCurrentYTwips + f.Top + RandOffsOben
iForm.Width = fscalewTwips – fCurrentXTwips
iForm.Text1.Font = f.Font
iForm.FontSize = f.FontSize

467
Von WANKEL. BAS zur WankelAnimation

iForm.Height = iForm.TextHeight("Test")
iForm.Text1.Height = iForm.Height
iForm.Text1.Width = fscalewTwips – f.CurrentX
iForm.Show vbModal, f ' Formular aufrufen, gibt bei
' Hide die Kontrolle an f zurück
Param = iForm.Text1 ' Wert übernehmen
f.Print Param ' ausgeben
End Sub
'***********************************************************************
' Formularmodul : InputForm
Von WANKEL.BAS zur WankelAnimation

' Autor : 2000 Rudolf Huttary


'***********************************************************************

Private Sub Text1_KeyPress(KeyAscii As Integer)


If KeyAscii = vbKeyReturn Then Hide
End Sub

Ausgabe des Testcodes für das Emulationsmodul

Von WANKEL.BAS zur WankelAnimation


Der Fundus eines jeden Programmierers, der schon einige Jahre »im Geschäft« ist, enthält so
manches verwaiste Programm, das einst viel Mühe gemacht hat, inzwischen aber einem Platt-
formwechsel zum Opfer gefallen ist. Mir geht es da nicht anders: Die Halde enthält Hunderte
kleiner Programmskizzen, aber auch eine ganze Menge liebevoll ausgestaltete Programme, die
ihren Sinn schlicht deshalb verwirkt haben, weil sie mit QuickBasic oder QBasic geschrieben
wurden und somit nur in einem DOS-Fenster unter Windows ausführbar sind. Eine dieser Skiz-
zen, das Programm WANKEL.BAS, das ich vor vielen Jahren in QBasic geschrieben habe, um
mir den mechanischen Ablauf des Kolbens im Wankelmotor als Animation vor Augen zu brin-
gen, wird Ihnen dieser Abschnitt in originaler und in portierter Fassung vorstellen.

468
Von WANKEL. BAS zur WankelAnimation

Von WANKEL.BAS zur WankelAnimation


Animationsphase im Formular von WankelAnimation

Hier zunächst der Code des altehrwürdigen Originals:


DECLARE SUB zylinder (mx!, my!)
DECLARE SUB kolben (mx!, my!, w!, sicht!)
DECLARE SUB zahn (mx!, my!, r!, h!, w!, anz!, sicht!)

Rem Konstanten
Const pi = 3.141593
Const pi3 = pi / 3
Const pi6 = pi / 6
Const pi2 = 2 * pi
Const r = 10 ' Radius Kolbenzahnrad
Const r2 = r * 2 / 3 ' Radius innerer Zahnrad
Const b = r – r2
Const mx = 0 ' Mittelpunktsverschiebung
Const my = 0 ' Mittelpunktsverschiebung
Const w = 3 ' Drehkolben-Faktor
Const z2 = 24 ' Anzahl der Zahnräder äußeres Rad
Const z1 = z2 * r2 / r ' Anzahl der Zahnräder inneres Rad
Const wi = 0 ' Winkelgeschw. inn. Rad (0 bei Radius = 2/3)
Const w2off = 0 '+ pi / z1 ' Phasenverschiebung inneres Rad

'Variablen initialisieren
st = -pi / 60 ' Schleifeninkrement, Animationsgeschwindigkeit
x1 = 0 ' Animationswinkel
x2 = 0 ' Animationswinkel

Screen 12
Print "Zähne:"; z1; "/"; z2; "schneller/langsamer: Cursor, Ende: Esc"
WINDOW (-32, -24)-(32, 24)
PSet (mx, my) ' Mittelpunkt
zylinder mx, my ' Zylinder zeichnen

469
Von WANKEL. BAS zur WankelAnimation

Do ' Animationsschleife
kolben mx + b * Cos(x2 * w), my + b * Sin(x2 * w), x2, 0
kolben mx + b * Cos(x1 * w), my + b * Sin(x1 * w), (x1), 15

zahn mx + b * Cos(x2 * w), my + b * Sin(x2 * w), r, r / 10, x2, z2, 0


zahn mx + b * Cos(x1 * w), my + b * Sin(x1 * w), r, r / 10, x1, z2, 15
zahn mx, my, r – b, r / 10, wi * x1, z1, 15

a$ = InKey$ ' Tastaturinteraktion


If a$ <> "" Then
Von WANKEL.BAS zur WankelAnimation

taste = Asc(Right$(a$, 1))


Select Case taste
Case 77: st = st + 0.2 * Abs(st) + 0.001 ' Cursor links
Case 75: st = st – 0.2 * Abs(st) – 0.001 ' Cursor rechts
Case 27, 79: Exit Do ' Abbruch
End Select
End If
x2 = x1 ' alter Winkel
x1 = x1 + st ' Schleifeninkrement
Loop

Sub kolben(mx, my, winkel, sicht)


Dim r0, r1, w1, w2, w3, ef, c1, c2, c3, a, x, y, x1, x2, x3

r0 = 2 * r
r1 = Sqr(3) * r * 1 * 0.97 ' Ellipsenradius
w1 = winkel + pi3 ' +60° , 1. Teilellipse
w2 = w1 + pi3 * 2 ' +120°, 2. Teilellipse
w3 = w2 + pi3 * 2 ' +120°, 3. Teilellipse
ef = 0.26 * r2 / r ' Ellipsenfaktor
c1 = Cos(w1): s1 = Sin(w1) ' Winkelwerte für Drehung
c2 = Cos(w2): s2 = Sin(w2) ' Winkelwerte für Drehung
c3 = Cos(w3): s3 = Sin(w3) ' Winkelwerte für Drehung

a = 0
x = r1 * Sin(a) * ef + r1 / 1.75 ' Ellipse y-Anteil mit Verschiebung
y = r1 * Cos(a) ' Ellipse y-Anteil
xx1 = x * c1 – y * s1: yy1 = x * s1 + y * c1 ' Start Teilellipse 1
xx2 = x * c2 – y * s2: yy2 = x * s2 + y * c2 ' Start Teilellipse 2
xx3 = x * c3 – y * s3: yy3 = x * s3 + y * c3 ' Start Teilellipse 3

For a = 0 To pi * 1.01 Step pi / 10 ' Schleife für halbe Ellipse


x = r1 * Sin(a) * ef + r1 / 1.75 ' Ellipse y-Anteil mit Verschiebung
y = r1 * Cos(a) ' Ellipse y-Anteil
x1 = x * c1 – y * s1: y1 = x * s1 + y * c1 ' Drehung Teilellipse 1
x2 = x * c2 – y * s2: y2 = x * s2 + y * c2 ' Drehung Teilellipse 2
x3 = x * c3 – y * s3: y3 = x * s3 + y * c3 ' Drehung Teilellipse 3
Line (xx1 + mx, yy1 + my)-(x1 + mx, y1 + my), sicht ' Teilellipse 1
Line (xx2 + mx, yy2 + my)-(x2 + mx, y2 + my), sicht ' Teilellipse 2
Line (xx3 + mx, yy3 + my)-(x3 + mx, y3 + my), sicht ' Teilellipse 3
xx1 = x1: xx2 = x2: xx3 = x3

47 0
Von WANKEL. BAS zur WankelAnimation

yy1 = y1: yy2 = y2: yy3 = y3


Next a
End Sub

Sub zahn(mx, my, r, h, w, anz, sicht)


dw = pi / anz
rz1 = r – h / 2
rz2 = r + h / 2
Min = 1000
PSet (mx + Cos(w – dw) * rz1, my + Sin(w – dw) * rz1), sicht

Von WANKEL.BAS zur WankelAnimation


For y = 0 To anz
x = w + 2 * dw * y
zx1 = mx + Cos(x + dw) * rz1
zy1 = my + Sin(x + dw) * rz1
di = zx1 * zx1 + zy1 * zy1
If Min > di Then
Min = Sqr(di): dx = zx1: dy = zy1
End If
Line -(mx + Cos(x) * rz2, my + Sin(x) * rz2), sicht
Line -(zx1, zy1), sicht
Next
End Sub

Sub zylinder(mx, my)


r0 = 2 * r
PSet (r0 * Cos(x) + mx + b * Cos(x * w), _
r0 * Sin(x) + my + b * Sin(x * w))
For x = 0 To pi2 + pi / 40 Step pi / 40
Line -(r0 * Cos(x) + mx + b * Cos(x * w), _
r0 * Sin(x) + my + b * Sin(x * w))
Next x
End Sub

Sieht man von den mathematischen Einzelheiten und den vielen Parametern ab, ist das Pro-
gramm recht einfach aufgebaut. Es enthält ein Hauptmodul, das die Variableninitialisierung
vornimmt, den Zylinder zeichnet und ansonsten die Animationsschleife durchläuft, bis der
Benutzer die Taste (Esc) drückt. In jeder Animationsphase überzeichnet der Schleifenkörper
die vorherige Phase des Kolbens und des äußeren Zahnrads mit Hintergrundfarbe und zeichnet
dann den Kolben sowie beide (!) Zahnräder unter Beachtung eines Winkelinkrements neu. Der
Benutzer kann die Rotationsgeschwindigkeit des Kolbens verändern, indem er die Cursortasten
(Rechts) oder (Links) drückt. In der DOS-Version wird die Grundgeschwindigkeit der Anima-
tion schlicht durch die Ausführungsgeschwindigkeit des Programms bestimmt, und die
Geschwindigkeitsregelung erfolgt durch Manipulation des Winkelinkrements. Die drei Funktio-
nen des Programms kolben, zylinder und zahn zeichnen die drei unterschiedlichen Figuren, aus
denen sich die Animation zusammensetzt. Da der Zylinder feststehend ist (das ist nicht bei allen
Wankelmotoren so), braucht er nur ein einziges Mal vor Eintritt in die Animationsschleife
gezeichnet zu werden. Das innere Zahnrad steht zwar still, würde aber von dem äußeren Zahn-
rad mit der Zeit ausradiert werden, so dass es kurzerhand gleichfalls in jeder Phase nachge-
zeichnet wird.

47 1
Von WANKEL. BAS zur WankelAnimation

Die einzelnen Funktionen geben eigentlich außer der Berechnung der Drehung nicht allzu viel
Interessantes her. Eine Drehung um den Winkel w bildet einen Punkt (x, y) auf den Punkt (x',
y') ab. Dabei gilt folgende Beziehung:
x' = x · cos(w) – y · sin(w)
y' = x · sin(w) + y · cos(w)
Die Funktion zylinder zeichnet den Wankel-Zylinder um den Punkt (mx, my) als vieleckiges
Polygon, wobei sich die Eckpunkte des Polygons als Summe zweier Kreisfunktionen ergeben,
deren Frequenzen im ganzzahligen Verhältnis 1:3 zueinander stehen. Die zuständige Konstante
hat den Bezeichner w und ist als »Drehkolbenfaktor« kommentiert. (Ändern Sie doch den Wert
Von WANKEL.BAS zur WankelAnimation

einmal!) Wer das Prinzip nicht kennt: Die Eckpunkte für die polygonale Annäherung an einen
Kreis erhält man, indem man eine Variable zwischen 0 und 2 als Winkel laufen lässt, dann in
horizontaler Richtung den Sinus sowie in vertikaler Richtung den Cosinus (oder umgekehrt)
des Winkels anträgt und schließlich die Werte mit dem gewünschten Radius skaliert. Nimmt
man für die beiden Richtungen unterschiedliche Radien, ergibt sich eine (horizontal/vertikal
ausgerichtete) Ellipse.
Die Funktion zahn zeichnet ein vereinfachtes Zahnrad in Form einer Zickzacklinie. Die Auf-
rufparameter definieren der Reihe nach: x- und y-Koordinaten des Mittelpunkts, Radius, Zahn-
höhe, Phasenwinkel, Zähneanzahl und Linienfarbe. Die Methode kolben zeichnet schließlich
den Kolben in angenäherter Form, indem sie drei Ellipsenabschnitte aus vieleckigen Polygonen
passend aneinander klebt. (Im Gegensatz zum Zylinder des Wankelmotors ist die geschlossene
Darstellung des Kolbens von der Mathematik her recht anspruchsvoll und die Berechnung zu
aufwändig für eine Animation – die Ellipsenabschnitte ergeben eine brauchbare Annäherung.
Leider lässt sich die Circle-Funktion für das Zeichnen der Ellipsen nicht einsetzen, da Basic
Ellipsen nur mit horizontal/vertikal ausgerichteten Achsen zeichnet) Die Parameter der Funk-
tion sind der Reihe nach: x- und y-Koordinaten des Mittelpunkts, Phasenwinkel, Linienfarbe.

Die portierte Fassung


Die portierte Fassung WankelAnimation des Codes unterscheidet sich nicht sonderlich von der
originalen Fassung, wenn man das zuvor vorgestellte Modul QBEmulation zur Verfügung hat.
Änderungen und Ergänzungen erscheinen im Listing fettgedruckt.
'***********************************************************************
' Formularmodul : WankelAnimation
' Autor : 2000 Rudolf Huttary
' Beschreibung : Demonstriert Ablauf im Inneren des Wankelmotors
'***********************************************************************
Rem Konstanten
Const pi = 3.141593
Const pi3 = pi / 3
Const pi6 = pi / 6
Const pi2 = 2 * pi
Const r = 10 ' Radius Kolbenzahnrad
Const r2 = r * 2 / 3 ' Radius inneres Zahnrad
Const b = r – r2
Const mx = 0 ' Mittelpunktsverschiebung
Const my = 0 ' Mittelpunktsverschiebung
Const w = 3 ' Drehkolben-Faktor
Const z2 = 48 ' Anzahl der Zahnräder äußeres Rad
Const z1 = z2 * r2 / r ' Anzahl der Zahnräder inneres Rad

47 2
Die portierte Fassung

Const wi = 0 ' Winkelgeschwindigkeit inneres Rad (0 bei Radius = 2/3)


Const w2off = 0 '+ pi / z1 ' Phasenverschiebung inneres Rad

Dim st, x1, x2

' Teil der Emulation


Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If Shift = 0 Then ' Funktionstasten ignorieren
InkeyChar = Chr(0) + Chr(KeyCode) ' Tastaturcode merken
End If
End Sub

Von WANKEL.BAS zur WankelAnimation


' Teil der Emulation
Private Sub Form_KeyPress(KeyAscii As Integer)
InkeyChar = Chr(KeyAscii) ' Zeichen merken
End Sub

Private Sub Form_Load()


InitQB Me
Timer1.Interval = 100
st = -pi / 60 ' Schleifeninkrement, Animationsgeschwindigkeit
x1 = 0 ' Animationswinkel
x2 = 0 ' Animationswinkel
Screen 12
Print "Zähne:"; z1; "/"; z2; "schneller/langsamer: Cursor, Ende: Esc"
Window -32, -24, 32, 24
PSet (mx, my) ' Mittelpunkt
zylinder mx, my ' Zylinder zeichnen
End Sub

Sub kolben(mx, my, winkel, sicht)


Dim r1, w1, w2, w3, ef, c1, c2, c3, a, x, y, x1, x2, x3
r1 = Sqr(3) * r * 1 * 0.97 ' Ellipsenradius
w1 = winkel + pi3 ' +60° , 1. Teilellipse
w2 = w1 + pi3 * 2 ' +120°, 2. Teilellipse
w3 = w2 + pi3 * 2 ' +120°, 3. Teilellipse
ef = 0.26 * r2 / r ' Ellipsenfaktor
c1 = Cos(w1): s1 = Sin(w1) ' Winkelwerte für Drehung
c2 = Cos(w2): s2 = Sin(w2) ' Winkelwerte für Drehung
c3 = Cos(w3): s3 = Sin(w3) ' Winkelwerte für Drehung

a = 0
x = r1 * Sin(a) * ef + r1 / 1.75 ' Ellipse y-Anteil mit Verschiebung
y = r1 * Cos(a) ' Ellipse y-Anteil
xx1 = x * c1 – y * s1: yy1 = x * s1 + y * c1 ' Start Teilellipse 1
xx2 = x * c2 – y * s2: yy2 = x * s2 + y * c2 ' Start Teilellipse 2
xx3 = x * c3 – y * s3: yy3 = x * s3 + y * c3 ' Start Teilellipse 3

For a = 0 To pi * 1.01 Step pi / 10 ' Schleife für halbe Ellipse


x = r1 * Sin(a) * ef + r1 / 1.75 ' Ellipse y-Anteil mit Verschiebung
y = r1 * Cos(a) ' Ellipse y-Anteil

47 3
Von WANKEL. BAS zur WankelAnimation

x1 = x * c1 – y * s1: y1 = x * s1 + y * c1 ' Drehung Teilellipse 1


x2 = x * c2 – y * s2: y2 = x * s2 + y * c2 ' Drehung Teilellipse 2
x3 = x * c3 – y * s3: y3 = x * s3 + y * c3 ' Drehung Teilellipse 3
Line (xx1 + mx, yy1 + my)-(x1 + mx, y1 + my), _
QBColor(sicht) ' Teilellipse 1
Line (xx2 + mx, yy2 + my)-(x2 + mx, y2 + my), _
QBColor(sicht) ' Teilellipse 2
Line (xx3 + mx, yy3 + my)-(x3 + mx, y3 + my), _
QBColor(sicht) ' Teilellipse 3
xx1 = x1: xx2 = x2: xx3 = x3
Von WANKEL.BAS zur WankelAnimation

yy1 = y1: yy2 = y2: yy3 = y3


Next a
End Sub

Sub zahn(mx, my, r, h, w, anz, sicht)


dw = pi / anz
rz1 = r – h / 2
rz2 = r + h / 2
Min = 1000
PSet (mx + Cos(w – dw) * rz1, my + Sin(w – dw) * rz1), QBColor(sicht)
For y = 0 To anz
x = w + 2 * dw * y
zx1 = mx + Cos(x + dw) * rz1
zy1 = my + Sin(x + dw) * rz1
di = zx1 * zx1 + zy1 * zy1
If Min > di Then
Min = Sqr(di): dx = zx1: dy = zy1
End If
Line -(mx + Cos(x) * rz2, my + Sin(x) * rz2), QBColor(sicht)
Line -(zx1, zy1), QBColor(sicht)
Next
End Sub

Sub zylinder(mx, my)


r0 = 2 * r
PSet (r0 * Cos(x) + mx + b * Cos(x * w),
r0 * Sin(x) + my + b * Sin(x * w))
For x = 0 To pi2 + pi / 40 Step pi / 40
Line -(r0 * Cos(x) + mx + b * Cos(x * w),
r0 * Sin(x) + my + b * Sin(x * w))
Next x
End Sub

Private Sub Timer1_Timer()


' Do ' Animationsschleife
kolben mx + b * Cos(x2 * w), my + b * Sin(x2 * w), x2, 15
kolben mx + b * Cos(x1 * w), my + b * Sin(x1 * w), (x1), 0

zahn mx + b * Cos(x2 * w), my + b * Sin(x2 * w), r, r / 10, x2, z2, 15


zahn mx + b * Cos(x1 * w), my + b * Sin(x1 * w), r, r / 10, x1, z2, 0
zahn mx, my, r – b, r / 10, wi * x1, z1, 0

47 4
Die portierte Fassung

a$ = InKey$ ' Tastaturinteraktion


If a$ <> "" Then
taste = Asc(Right$(a$, 1))
Select Case taste
Case vbKeyLeft: st = st + 0.2 * Abs(st) + 0.001 ' Cursor rechts
Case vbKeyRight: st = st – 0.2 * Abs(st) – 0.001 ' Cursor links
Case 27, vbKeyEnd: Unload Me: Exit Sub ' Abbruch
End Select
End If
x2 = x1 ' alter Winkel

Von WANKEL.BAS zur WankelAnimation


x1 = x1 + st ' Schleifeninkrement
' Loop
End Sub

Als einzige Abweichung von der ursprünglichen Programmlogik ist die Umsetzung der INKEY$-
Schleife in eine Timer-Behandlungsroutine zu bemerken. Eine Beibehaltung der ursprünglichen
Logik wäre vom Prinzip her zwar möglich, jedoch mit Rücksicht auf das Multitasking alles
andere als sinnvoll. Das Zeitgeber-Steuerelement hat den Vorteil, dass es eine recht stabile und
systemunabhängige Zeitbasis für die Abfolge der einzelnen Animationsphasen bereitstellt.

475
Mathematik und Algorithmen
Wer programmiert, tut gut daran, mit der Mathematik auf gutem Fuße zu stehen. Der
geschickte und sichere Umgang mit den mathematischen Funktionen der Sprache bringt nicht
nur Vorteile für die saubere Implementation schneller und sicherer Algorithmen, er ist zuweilen
sogar Voraussetzung, wenn es um die Bewältigung kniffliger Angelegenheiten geht. Da wären
zum einen die einfachen linearen Transformationen (Translation und Skalierung), wie sie für
den Übergang zwischen verschiedenen Koordinatensystemen auftreten. Um die Anzahl solcher
Transformationen klein zu halten, empfiehlt es sich, im Ausgabebereich (Form, Printer, Pictu-
reBox, UserControl, UserDocument) mittels Scale das Koordinatensystem so zu wählen, dass
keine unübersichtlichen und zeitaufwändigen Umrechnungen erforderlich werden. Während die
vordefinierten Koordinatensysteme, die man durch Setzen der Eigenschaft ScaleMode auf eine
der vordefinierten Konstanten (vbPixels, vbMillimeters, ...) einstellt, ihren Ursprung links oben
in der Ecke der Ausgabefläche haben und nichts weiter als unterschiedliche Skalierungsmaße
für die Koordinatenachsen vorgeben, lassen sich mittels Scale Koordinatensysteme mit unter-
schiedlich orientierten sowie beliebig skalierten Koordinatenachsen bei freier Wahl des
Ursprungs einstellen. Man übergibt Scale einfach die Koordinaten des linken oberen Punkts
und des rechten unteren Punkts der Ausgabefläche in ihrer aktuellen Gestalt (vgl. Height, Width)
und definiert damit den Ausschnitt, die Skalierung, die Orientierung und den Ursprung in
einem Aufwasch. Was die Sprache nicht vorsieht, ist eine zusätzliche Drehung der Koordinaten-
achsen aus der Senkrechten bzw. Waagrechten heraus. Da hilft nur die im vorigen Abschnitt
vorgestellte Drehung – nachträglich auf die Punktkoordinaten angewandt.
Darüber hinaus ist das mathematische Vokabular der Sprache reichhaltig genug, um selbst
komplexeste Berechnungen anstellen zu können. Ein Anwendungsgebiet ist beispielsweise die
Visualisierung von Funktionsverläufen mittels zweidimensionaler Funktionsgraphen. Nimmt
man die Farbinformation als »dritte« Dimension, lassen sich recht aussagekräftige Darstellun-
gen errechnen. Vom Prinzip her führt man dazu den Graphen (gegebenenfalls durch Projektion)
auf eine der folgenden Darstellungen zurück.
1. eindimensionale Abbildungen (aber auch Relationen), bei denen ein Wert aus einem Defini-
tionsbereich einem Wert aus einem Wertebereich zugeordnet wird. Für die Darstellung wer-
den Definitions- und Wertebereich je einer Achse zugeordnet, so dass sich ein Kurvenverlauf
ergibt (Beispiele dazu finden Sie im Referenzteil in den Abschnitten »Resize-Methode« und
»ScaleLeft-Eigenschaft und ScaleTop-Eigenschaft«, wo es um die Ausgabe einer Sinuskurve
bzw. einer approximierten Rechteckkurve geht). Die Kurve wird entweder aus Punkten zu-
sammengesetzt oder aus Liniensegmenten (Polygon).
2. zweidimensionale Abbildungen, bei denen ein zweidimensionaler Wertebereich auf einen
eindimensionalen Wert abgebildet wird. Die Darstellung des eindimensionalen Werts erfolgt
entweder als Farbwert (vgl. das Projekt Apfelmann, in diesem Abschnitt) oder als Höhenwert
bei perspektivischer Projektion (Kurvenschar erscheint dann als »Landschaft«).
3. zweidimensionale Abbildungen, bei denen ein eindimensionaler Definitionsbereich in einen
zweidimensionalen Wertebereich abgebildet wird. Die Darstellung zeigt häufig nur den Kur-
venverlauf im Wertebereich, kann aber auch nach dem vorgenannten Prinzip erfolgen. Ein
Beispiel dafür ist die Kreisfunktion, bei der ein Winkelwert in der einen Dimension auf den
Sinus und in der anderen auf den Cosinus des Winkels abgebildet wird – speziell bei der
Kreisfunktion lässt sich der Winkel sogar direkt im Wertebereich ablesen, das ist aber nicht
die Regel (vgl. die Darstellung des Wankel-Zylinders sowie der Ellipsenabschnitte im vorhe-
rigen Abschnitt »Das Programm WANKEL.BAS«).
Unter Algorithmus wird landläufig eine »Vorschrift für die Ausführung einer komplexen Ope-
ration« verstanden. Auch wenn sich im weiteren Sinne jede Prozedur/Funktion unter diesem
Begriff subsumieren lässt, spricht man eigentlich nur dann von einem Algorithmus, wenn es um

477
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

die Implementation eines spezifischen Verfahrens geht, das entweder metasprachlich (etwa als
mathematische Formel) oder natürlichsprachlich (als Anleitung im Sinne eines Kochrezepts)
beschrieben ist. Zu den klassischen Algorithmen zählen Sortierverfahren wie Bubble-Sort (vgl.
den Abschnitt »Schleifen«, S. 40) oder Quick-Sort, Iterationsverfahren etwa für die Integralbe-
rechnung oder die numerische Approximation, aber auch Berechnungen verschiedenster Art,
wie die von Primzahlen (vgl. »Funktionen selbst definieren«), Determinanten, Folgengliedern
oder Reihensummen.
Wie viel Komplexität und auch »Anmut« hinter einer einfachen Rechenvorschrift stecken kann,
demonstriert auf besonders eindrucksvolle Weise die Mandelbrotmenge, deren Graph aufgrund
seiner Form als »Apfelmännchen« bezeichnet wird. (Ein wenig mehr Mathematisches findet
sich im Abschnitt »Von WANKEL.BAS zur WankelAnimation », S. 468, sowie im Abschnitt
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

»3DAnimation – Drahtgittermodelle frei im Raum gedreht«, S. 577).

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


Die von dem Mathematiker Benoit B. Mandelbrot im Zuge seiner Beschäftigung mit so genann-
ten »Julia«-Mengen Anfang der Siebzigerjahre entdeckte Mandelbrotmenge zählt heute noch zu
den augenscheinlichsten Ergebnissen der Chaosforschung und dürfte der noch jungen Wissen-
schaft zusehends auf die Beine geholfen haben. Mandelbrot benutzte damals einen IBM-Com-
puter, um die Menge erstmals zu visualisieren, und war umgehend von ihrer »bizarren Schön-
heit« bezaubert.
Der mathematische Kern der Mandelbrotmenge ist wahrlich einfach. Man untersucht eine
parametrisierte Folge im komplexen Zahlenraum daraufhin, ob sie konvergiert oder divergiert.
Die Folgenvorschrift lautet:
f0 = 0
fn+1 = fn² + z
wobei der Parameter z aus der komplexen Ebene gewählt wird. Für die Visualisierung der
Menge untersucht man das Verhalten der Folge fn, indem man z systematisch in einem
bestimmten (um die Null herum gelegenen) Bereich variiert und für jedes z bis zu cMaxIterat
(also endlich viele) Folgenglieder berechnet. Übersteigt der Betrag eines Folgenglieds einen hin-
reichend groß gewählten Grenzwert cGrenze, bricht man die Iteration ab und wertet die zu c
gehörige Folge als divergent – z gehört dann nicht zur Mandelbrotmenge. Die Anzahl der Itera-
tionen, die bis zum Abbruch nötig waren, trägt man als Farbwert für den Punkt z in der kom-
plexen Ebene an. Sind dagegen für ein z alle Folgenglieder vom Betrag her kleiner gleich dem
Grenzwert, wertet man die zu z gehörige Folge als konvergent und z als Element der Man-
delbrotmenge. Das Ergebnis dieser Vorschrift gehört zu den »Bildern, die um die Welt gingen«.
Das Projekt ApfelmannZoom, mit dem die abgebildeten Bildschirme erzeugt wurden, hat – wie
der Titel bereits verrät – neben dem reinen Algorithmus für die Berechnung der Mandelbrot-
menge noch eine recht komfortable Zoomfunktion zu bieten. Um sich in das Bild hineinzuzoo-
men, markiert man den gewünschten Ausschnitt mit der Maus unter Verwendung der linken
Maustaste. Das geht auch wiederholt, bis die Rechengenauigkeit des Datentyps Double
erschöpft ist und das Bild streifig wird. Ein Klick mit der linken Maustaste bringt dagegen das
jeweils zuvor berechnete Bild wieder zum Vorschein. Einer Fahrt durch die Mandelbrotmenge
steht also nichts mehr im Wege – nun ja, allzu rasant dürfte sie nicht werden, denn unter Basic
ist das Laufzeitverhalten des Programms nicht gerade als überzeugend zu bezeichnen. Je nach
Größe des Formulars müssen Sie auf einem halbwegs vernünftigen System schon zwischen 10
und mehreren hundert Sekunden je Bild veranschlagen.

478
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

479
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

Ausgabe des Programms Apfelmann

Ein Kompilieren des Programms mit allen Beschleunigungsoptionen halbiert zwar die Ausfüh-
rungszeit in etwa, so richtig Beine macht es dem Programm aber auch nicht.
Vor einer eingehenderen Diskussion der Implementation zunächst das Listing im Überblick:
'***********************************************************************
' Formularmodul : ApfelmannZoom
' Autor : 2000 Rudolf Huttary
' Beschreibung : Zeichnet Mandelbrotmenge
' : Zoomfähig, Bereichsauswahl mit der Maus
'***********************************************************************
' Konstanten für Startbereich
Const cx1 As Single = -2.1
Const cy1 As Single = -1.4
Const cx2 As Single = 0.7
Const cy2 As Single = 1.4

' Konstanten für Algorithmus


Const cMaxIterat As Double = 200
Const cGrenze As Double = 10000

Const cZoom = "Apfelmann – Zoomstufe "

' Gobale Variablen für Bildschirmpunkte


Private PixelsX, PixelsY

' Globale Variablen für Gummiband


Private MouseStartX As Single, MouseEndX As Single
Private MouseStartY As Single, MouseEndY As Single
Private Tracking As Boolean
Private Break As Boolean

480
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

' Undo-Info für Zoomfunktion


Dim Stack()

Private Sub Form_Load()


' Verhältnis Höhe/Breite richtig stellen
Height = ScaleWidth * (cy2 – cy1) / (cx2 – cx1) + _
(Height – ScaleHeight)
ReDim Preserve Stack(4, 0) ' Stack anlegen
Caption = cZoom & 0 ' Zoomstufe ausgeben
ScaleMode = vbPixels ' Anzahl der Bildpunkte merken

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


PixelsX = ScaleWidth
PixelsY = ScaleHeight
AutoRedraw = True
Scale (cx1, cy1)-(cx2, cy2) ' Startbereich einstellen
Show ' Damit man das Zeichnen sieht
Apfel
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Dim Index As Integer
If Button = vbLeftButton Then ' Hineinzoomen?
Tracking = True ' Gummiband einschalten
MouseStartX = X ' Start- und Endkoordinaten
' vorgeben
MouseStartY = Y
MouseEndX = X
MouseEndY = Y
Else ' Herauszoomen!
PopFromStack
End If
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Dim dm
If Tracking Then
' Verhältnis Höhe/Breite für Aussschnitt erzwingen
Y = (MouseStartY + Sgn(Y – MouseStartY) * Abs(X – MouseStartX) * _
(ScaleHeight / ScaleWidth))

' altes Gummiband löschen und dann neu zeichnen


dm = DrawMode ' alten Zeichenmodus merken
DrawMode = vbInvert ' XOR-Zeichenmodus einschalten
Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
Line (MouseStartX, MouseStartY)-(X, Y), , B
DrawMode = dm ' alten Zeichenmodus restaurieren
MouseEndX = X: MouseEndY = Y ' vorläufige Endkoordinaten merken
End If
End Sub

481
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
If Tracking Then
Tracking = False ' Gummiband ausschalten
dm = DrawMode ' alten Zeichenmodus merken
DrawMode = vbInvert ' XOR-Zeichenmodus einschalten

' Gummiband löschen


Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
DrawMode = dm ' alten Zeichenmodus restaurieren
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

' x-Koordinaten ggf. vertauschen


If MouseStartX = X Or MouseStartY = Y Then Exit Sub
If MouseStartX > MouseEndX Then
MouseEndX = MouseStartX
MouseStartX = X
Else
MouseEndX = X
End If

' y-Koordinaten ggf. vertauschen


If MouseStartY > MouseEndY Then
MouseEndY = MouseStartY
MouseStartY = Y
Else
MouseEndY = Y
End If

' Zeichnen des gezoomten Bereichs vorbereiten


PushOnStack
Cls
Scale (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY)
Apfel
End If
End Sub

' Prozedur zeichnet Mandelbrotmenge für geltendes Koordinatensystem


Private Sub Apfel()
Dim m_x1 As Double, m_x2 As Double, m_y1 As Double, m_y2 As Double
Dim step_x As Double, step_y As Double
Dim r1 As Double, re As Double, im As Double
Dim zr As Double, zi As Double
Dim it As Long
Static Zoomstufe As Integer
Zoomstufe = Zoomstufe + 1

' Bereichsgrenzen und Schrittweiten ermitteln


m_x1 = ScaleLeft
m_x2 = ScaleLeft + ScaleWidth
m_y1 = ScaleTop
m_y2 = ScaleTop + ScaleHeight

482
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

step_x = (m_x2 – m_x1) / PixelsX


step_y = (m_y2 – m_y1) / PixelsY

For zr = m_x1 To m_x2 Step step_x ' alle Spalten in x-Richtung


For zi = m_y1 To m_y2 Step step_y ' alle Punkte in Spalte zr
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
For it = 0 To cMaxIterat ' Iteration für Punkt
r1 = re * re – im * im + zr
im = 2 * re * im + zi

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


re = r1
If re * re + im * im > cGrenze Then ' divergent?
PSet (zr, zi), it * 16 ' Ja: Punkt ausgeben
Exit For
End If
Next it ' Iteration beendet
Next zi ' Spalte beendet?

' Ereignisse verarbeiten. Abbruch, falls Formular geschlossen wurde


' oder Zoomstufe inzwischen zu klein ist
If DoEvents = 0 Or Zoomstufe > UBound(Stack, 2) + 1 Then
Zoomstufe = Zoomstufe – 1
Exit Sub
Else ' Warten bis Zoomstufe erreicht
While Zoomstufe < UBound(Stack, 2) + 1
If DoEvents = 0 Then Exit Sub ' Formular geschlossen?
Wend
End If
Next zr ' Bild fertig?
Zoomstufe = Zoomstufe – 1
End Sub

Private Sub PushOnStack()


Dim Index As Integer
Index = UBound(Stack, 2) + 1
ReDim Preserve Stack(4, Index) ' Push-Operation

' Koordinatensystem merken


Stack(0, Index) = ScaleLeft
Stack(1, Index) = ScaleTop
Stack(2, Index) = ScaleWidth
Stack(3, Index) = ScaleHeight
Set Stack(4, Index) = Image ' Bild merken
Caption = cZoom & Index
End Sub

Private Sub PopFromStack()


Dim Index As Integer
Index = UBound(Stack, 2)
If Index > 0 Then ' Stack leer?
' Nein: Koordinatensystem wiederherstellen

483
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

ScaleLeft = Stack(0, Index)


ScaleTop = Stack(1, Index)
ScaleWidth = Stack(2, Index)
ScaleHeight = Stack(3, Index)
' Gespeichertes Bild zeichnen
PaintPicture Stack(4, Index), ScaleLeft, ScaleTop
ReDim Preserve Stack(4, Index – 1) ' Pop-Operation
Caption = cZoom & Index – 1
End If
End Sub
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

Einstiegspunkt in das Programm ist, wie sollte es anders sein, die Load-Routine. Sie initialisiert
das Formular so, dass der Client-Bereich den über Konstanten definierten Startbereich für die
Berechnung der Mandelbrotmenge verzerrungsfrei und vollständig abbilden kann. Dies bein-
haltet eine Anpassung der Formularhöhe an die zur Entwurfszeit gewählte Formularbreite
sowie eine entsprechende Wahl des Koordinatensystems. Darüber hinaus werden noch zwei
globale Variablen mit der Anzahl der Bildpunkte in horizontaler und vertikaler Richtung initia-
lisiert, was der Routine Apfel die Berechnung der Schrittweite für die komplexe Ebene erleich-
tert, sowie ein dynamisches Array Stack, das im Zusammenhang mit dem Speichern der für die
Zoomfunktion erforderlichen Informationen seinen Namen alle Ehre macht. Die Ausgabe der
jeweils aktuellen Zoomstufe erfolgt über die Caption-Eigenschaft in der Titelzeile des Formu-
lars.

Implementation des Apfelmännchen- Algorithmus


An der Routine Apfel ist eigentlich nur die Kernroutine für die Berechnung der einzelnen Ele-
mente der Mandelbrotmenge interessant. Die beiden äußeren Schleifen samt Initialisierung sind
obligatorischer Überbau ohne Besonderheiten. Der Iterationsalgorithmus für einen einzelnen
Parameter z = zr + i zi ist eine exakte Umsetzung der Visualisierungsvorschrift in die Sprache
Basic.
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
For it = 0 To cMaxIterat ' Iteration für Punkt
r1 = re * re – im * im + zr
im = 2 * re * im + zi
re = r1
If re * re + im * im > cGrenze Then ' divergent?
PSet (zr, zi), it * 16 ' Ja: Punkt ausgeben
Exit For
End If
Next it ' Iteration beendet

Da Basic für komplexe Zahlen keinen passenden Datentyp unterstützt, findet die Berechnung
komponentenweise unter Verwendung von Double-Variablen statt. Die Addition ist komponen-
tenweise definiert und macht keine Probleme, einzig die Quadratur (bzw. Multiplikation) einer
komplexen Zahl mag ein wenig seltsam anmuten, wenn man das hinter den komplexen Zahlen
steckende Prinzip nicht kennt. Die Formel dafür lautet z² = zr² – zi² + i 2zizr. Der Betrag einer
komplexen Zahl erhält man dagegen über das gewöhnliche Maß der euklidischen Ebene:
|z| = (zr² + zi²)½. Da es sich bei dieser Iteration um die innerste Schleife einer mehrfach ver-
schachtelten Schleife handelt, sollte man natürlich alles dafür tun, das Laufzeitverhalten so
günstig wie möglich zu gestalten. Viel Zeit (ca. 50 Prozent) geht allerdings in der PSet-Anwei-
sung verloren, die jeden Punkt einzeln zum Bildschirm »befördert«. PSet erwartet als Farbe

484
Optimierung

einen Long-Wert, bei dem die unteren drei Byte die Sättigung für die Farbkomponenten Rot,
Grün und Blau enthalten. Grundlegende Information für die Farbgestaltung ist die Zählvariable
it. Sie gibt an, wie schnell die Folge divergiert. Wie die Farbabbildung dann im Einzelnen aus-
sieht, fällt in die Kategorie künstlerische Freiheit. Die Multiplikation mit 16 ist nur eine Vari-
ante, wer es bunt liebt, könnte die Anweisung auch so gestalten:
PSet (zr, zi), QBColor(it Mod 16)

Oder, wie wäre es mit einer geheimnisvollen grünen Korona?


PSet (zr, zi), RGB((it Mod 16) * 16, it * 4, it)

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


Optimierung
Der Code zeigt verschiedene Optimierungen, die für einen guten Programmierer selbstverständ-
lich sein sollten. So ist beispielsweise die einfache Multiplikation um einiges schneller als die
Quadratur mit dem Operator ^, und Zählvariablen vom Typ Long sind schneller als Zählvariab-
len aller anderen Typen. Auch macht es wenig Sinn, die Wurzel bei der Berechnung des Betrags
mittels Sqr zu ziehen, da sich der Vergleichswert ja auch auf das Quadrat des Werts trimmen
lässt. Das Zwischenspeichern des zuerst errechneten Realteils in der Variable r1 ist notwendig,
da der ursprüngliche Wert noch für die Berechnung des Imaginärteils zi benötigt wird. Analy-
siert man den Code auf weitere Möglichkeiten für die Optimierung, zeigt sich, dass sich noch
einige Multiplikationen durch einfaches Zwischenspeichern einsparen lassen. Das bringt zwar
nicht gerade viel, dafür dass es zwei weitere Variablen zzr und zzi erfordert und den Code doch
einigermaßen entstellt, aber warum sollte man das Prozent an Laufzeitgewinn verschenken?
re = 0 ' Realteil initialisieren
im = 0 ' Imaginärteil initialisieren
zzr = 0
zzi = 0
For it = 0 To cMaxIterat ' Iteration für Punkt
im = 2 * re * im + zi
re = zzr – zzi + zr
zzr = re * re
zzi = im * im
If zzr + zzi > cGrenze Then ' divergent?
PSet (zr, zi), it * 16 ' Ja: Punkt ausgeben
Exit For
End If
Next it ' Iteration beendet

Ereignisbehandlung mit DoEvents, ein komplexes Problemfeld


Ein wichtiger Punkt im Zusammenhang mit zeitaufwändigen Algorithmen ist die Aufrechter-
haltung der Reaktivität des Programms gegenüber Benutzeraktionen. Damit der Benutzer nicht
das Gefühl bekommt, das Programm sei abgestürzt oder reagiere nur schleppend auf seine Akti-
onen, empfiehlt es sich, beim Programmentwurf auf die so genannte Zehntelsekundenregel zu
achten. Sie besagt, dass ein Ereignis nicht viel länger als eine Zehntelsekunde auf seine Behand-
lung warten sollte. Da Visual Basic die Behandlungsroutine für ein Ereignis standardmäßig erst
dann aufruft, wenn die Behandlung des vorherigen Ereignisses abgeschlossen ist, sollte dem-
nach jede Behandlungsroutine dafür sorgen, dass sie mit 100 Millisekunden an Laufzeit aus-
kommt. Das ist leichter gesagt als getan: Insbesondere eine Routine wie Apfel, egal von welcher
Behandlungsroutine sie aufgerufen wird, dürfte mit ihrer mehrsekündigen bis mehrminütigen
Laufzeit einen doch recht erheblichen Verstoß gegen diese Regel darstellen. Was also tun, wenn

485
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

der Zeitbedarf einer Routine die Grenze der Zumutung übersteigt? Als Lösung bietet sich der
Einsatz der Anweisung DoEvents an. Sie kann als Prozedur oder als Funktion aufgerufen werden
und übergibt die Kontrolle temporär an den Ereignisbehandlungsmechanismus des Laufzeitsys-
tems, um die Behandlung des nächsten eventuell anstehenden Ereignisses einzuschieben. Falls
kein Ereignis ansteht, geht die Kontrolle umgehend, ansonsten nach Behandlung des nächsten
anstehenden Ereignisses an die unterbrochene Routine zurück. Beachtet man die Zehntelsekun-
denregel, ist der beste Platz für DoEvents nicht nach der innersten Schleife (das wäre Laufzeitver-
schwendung), sondern nach der zweitinnersten, also jeweils nach Beendigung einer Spalte.
So weit, so gut. Bei näherer Betrachtung stellt sich aber gleich die Frage, was passiert, wenn der
Benutzer das Formular schließt, bevor die auf diese Weise unterbrochene Routine mit ihrer
Arbeit fertig ist und (wie im vorliegenden Fall) das Formular weiterhin benötigt? Nun, Visual
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

Basic lädt das entladene Formular beim nächsten Zugriff auf eine seiner Eigenschaften oder
Methoden implizit erneut, mit dem Effekt, dass als Nächstes ein Load-Ereignis zur Behandlung
ansteht. Im vorliegenden Programm würde das Load-Ereignis dummerweise erneut die Routine
Apfel ausführen, noch ehe der alte Aufruf derselben Routine fertig ist. Da sowohl Apfel als
auch DoEvents einen rekursiven Aufruf nicht übelnehmen, wäre das vom Prinzip her kein Prob-
lem, wenn nicht die »Befehlsverweigerung« dabei herauskommen würde. Abhilfe schafft der
Aufruf in der folgenden Form:
If DoEvents = 0 Then Exit Sub

Als Funktion aufgerufen liefert DoEvents nämlich genau dann den Wert 0 zurück, wenn kein
Formular der Anwendung mehr offen oder sichtbar ist, das eine Nachrichtenbehandlung vor-
nimmt. Damit die Sache auch funktioniert, muss man jedoch beim Codedesign entweder darauf
achten, dass auch in der rufenden Routine – im vorliegenden Fall also in Form_Load bzw. in
Form_MouseUp – keine Zugriffe auf Eigenschaften oder Methoden des Formulars mehr erfolgen,
denn das hätte natürlich gleichsam den »Stehaufmänncheneffekt«, oder man führt die den
DoEvents-Aufruf enthaltende Routine als Funktion aus und lässt sie beispielsweise False zurück-
geben, wenn das Formular nicht mehr existiert. (Ein Beispiel für Letzteres findet sich im Projekt
DiaProjektor.)
Wer das beherzigt, bekommt immerhin schon einmal einen sicheren Programmabbruch hin,
gegen einen rekursiven Aufruf der unterbrochenen Routine ist er aber noch nicht gefeit –
warum auch, wenn dieser vom Prinzip her kein Problem bereitet. Natürlich kann der rekursive
Aufruf, wie im Beispielprogramm, auch zum Problem werden. Dazu folgendes Szenario: Starten
Sie das nur mit dieser einfachen DoEvents-Logik ausgestattete Beispielprogramm Apfelmann-
ZoomTest und wählen Sie, noch ehe das Bild fertig gezeichnet ist, mit der Maus einen Teilbe-
reich aus. Die Routine Apfel geht dann in die Rekursion und zeichnet den vergrößerten Aus-
schnitt. Wenn Sie nun warten, bis der Ausschnitt fertig gezeichnet ist und nach ca. einer
weiteren Sekunde mittels der rechten Maustaste auf das Ausgangsbild zurückschalten, werden
Sie sehen, dass die ursprünglich unterbrochene Routine weiterzeichnet. Leider hat die Routine
sofort nach Fertigstellung des Ausschnittsbilds die Kontrolle zurückerhalten und ihre Arbeit
noch während der Anzeige des Ausschnittsbilds wieder aufgenommen, so dass nun im Aus-
gangsbild ein gutes Stück fehlt. Im Ausschnittsbild selbst ist davon nichts (oder fast nichts) zu
bemerken, da die meisten der berechneten Punkte entweder außerhalb liegen oder aufgrund der
Koordinatensystemanpassung genau »ins Bild passen«. Wenn Sie dagegen auf das Ausgangsbild
zurückschalten, noch ehe das Ausschnittsbild fertig gezeichnet ist, erhält die für das Aus-
schnittsbild zuständige Routine die Kontrolle zurück und zeichnet dieses im Ausgangsbild fer-
tig. Das Ausgangsbild wird an dieser Stelle aufgrund von Rechenungenauigkeiten und mehrfa-
chen Zeichnens einzelner Bildpunkte gerade am Rand der Mandelbrotmenge unscharf.
Was also fehlt, ist eine gewisse Steuerung der Rekursion, die erstens einen noch nicht vollende-
ten Aufruf für einen Ausschnitt abbricht, wenn der Benutzer auf das Ausgangsbild zurückschal-
tet, und zweitens einen noch nicht vollendeten Aufruf für das Ausgangsbild lahm legt, solange

486
Benutzerschnittstelle

ein Ausschnitt davon angezeigt wird. Das klingt zwar kompliziert, lässt sich aber im Wesentli-
chen über eine zusätzliche statische (!) Variable Zoomstufe gepaart mit ein wenig Logik erschla-
gen.
Static Zoomstufe As Integer
Zoomstufe = Zoomstufe + 1
...
' Ereignisse verarbeiten. Abbruch, falls Formular geschlossen wurde
' oder Zoomstufe inzwischen zu klein ist
If DoEvents = 0 Or Zoomstufe > UBound(Stack, 2) + 1 Then
Zoomstufe = Zoomstufe – 1

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


Exit Sub
Else ' Warten bis Zoomstufe erreicht
While Zoomstufe < UBound(Stack, 2) + 1
If DoEvents = 0 Then Exit Sub ' Formular geschlossen?
Wend
End If
Next zr ' Bild fertig?
Zoomstufe = Zoomstufe – 1
End Sub

Anhand eines Vergleichs zwischen der bei Eintritt und Austritt gepflegten Variable Zoomstufe
und der Größe des Stacks für die gespeicherten Bilder erfährt die Routine, ob sie abbrechen soll,
weil der Benutzer das Zeichnen des Ausschnitts unterbrochen und auf das Ausgangsbild
zurückgeschaltet hat, oder ob sie warten soll, bis der Benutzer auf das zugehörige Bild zurück-
schaltet. Die Logik für das Warten ist als While-Schleife implementiert, die nichts weiter tut, als
so lange DoEvents-Aufrufe auszuführen, bis die Zoomstufe zum aktuellen Zustand des Stacks
passt oder (wie gehabt) der Benutzer das Formular schließt.

Benutzerschnittstelle
Die von dem Programm verwendete Benutzerschnittstelle ist denkbar einfach: Die linke Maus-
taste zieht ein Gummiband auf und gestattet somit eine Bereichsauswahl unter Bezug auf das
jeweils aktuelle Koordinatensystem. Einzelheiten zur Implementation des Gummibandes selbst
finden Sie im Abschnitt »Gummiband – Bereiche interaktiv auswählen«, S. 492. Die vorlie-
gende Implementation sorgt dafür, dass das Seitenverhältnis des ausgewählten Bereichs immer
dem Seitenverhältnis des Client-Bereichs des Formulars entspricht. Damit errechnet sich die y-
Endkoordinate des Gummibands letztlich mehr oder weniger direkt aus der x-Endkoordinate:
Y = (MouseStartY + Sgn(Y – MouseStartY) * Abs(X – MouseStartX) * _
(ScaleHeight / ScaleWidth))

Weiterhin sorgt eine geeignete Vertauschung der Start- und Endkoordinaten im Rahmen von
Form_MouseUp dafür, dass die Orientierung gewahrt bleibt.
Die mit dem Abschluss der Bereichsauswahl verbundene Aktion ist schließlich ein PushOnStack-
Aufruf, der in Simulation einer Stack-Operation das Abspeichern des aktuellen Koordinatensys-
tems sowie des Bildes übernimmt, gefolgt von einem Koordinatensystemwechsel und einem
erneuten, gegebenenfalls auch rekursiven Aufruf der Routine Apfel. Beachten Sie, dass Apfel in
dieser Implementation ohne Parameter auskommt, weil sich die Routine auf das aktuelle Koor-
dinatensystem bezieht und somit einfach den aktuellen Client-Bereich als Bereichsgrenzen ver-
wenden kann.

487
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

PushOnStack
Cls
Scale (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY)
Apfel

Die rechte Maustaste hingegen stellt das Ausgangsbild für den aktuellen Ausschnitt wieder her.
Die Aktion ist im Zuge von Form_MouseDown implementiert und besteht letztlich nur aus einem
PopFormStack-Aufruf, der das Koordinatensystem wiederherstellt und das gespeicherte Aus-
gangsbild erneut in den Client-Bereich zeichnet. Dazu gleich mehr.

Der Stack
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge

Bleibt also noch das letzte etwas anspruchsvollere Konzept: der Stack. Als Speicher, der nach
dem Prinzip des last-in-first-out funktioniert, ist er natürlich prädestiniert für die von dem Pro-
gramm unterstützte Zoomfunktionalität. Seine Aufgabe besteht darin, die Folge der Ausgangs-
bilder und deren Bereichsinformationen abzuspeichern und bei Bedarf wieder zu restaurieren.
Das Fertigzeichnen unvollständig gezeichneter Bilder ergibt sich aus der DoEvents-Logik der
Apfel-Routine und benötigt keine zusätzliche Information, die im Stack abgelegt werden
müsste. Die Implementation des Stacks liegt in Form eines auf Modulebene vereinbarten zwei-
dimensionalen dynamischen Arrays vor. Von der Load-Routine angelegt, wird das Array bei
jedem PushOnStack-Aufruf in der zweiten Dimension um ein Element vergrößert, so dass Platz
für fünf weitere Feldwerte entsteht. Es mag Ihnen vielleicht ungewohnt vorkommen, die »wich-
tigere« Information an zweiter Position zu finden, da Visual Basic bei mehrdimensionalen
dynamischen Arrays jedoch nur die letzte Dimension einer dynamischen Bereichsänderung
zugänglich macht, muss man wohl oder übel damit leben. Auf einen Stackzeiger verzichtet die
Implementation, da sich die gewünschte Information, wo das oberste Element zu finden ist,
recht einfach über die UBound-Funktion ergibt. Für mehrdimensionale Arrays unterstützt diese
Funktion einen optionalen zweiten Parameter, über den sich (von 1 beginnend) die Dimension,
deren Grenze man ermitteln will, spezifizieren lässt – für LBound gilt natürlich Analoges. Nach-
dem als Elementtyp des Arrays Variant vereinbart ist, spielt es keine Rolle, dass die zu spei-
chernde Information nicht durchwegs denselben Typ trägt. Das Bild erhält man über die Image-
Eigenschaft des Formulars, was allerdings voraussetzt, dass die AutoRedraw-Eigenschaft auf True
gesetzt wurde. Und die Bereichsinformation ergibt sich aus den ScaleXXX-Eigenschaften. Hier
der recht geradlinige Code der Routine:
Private Sub PushOnStack()
Dim Index As Integer
Index = UBound(Stack, 2) + 1
ReDim Preserve Stack(4, Index) ' Push-Operation

' Koordinatensystem merken


Stack(0, Index) = ScaleLeft
Stack(1, Index) = ScaleTop
Stack(2, Index) = ScaleWidth
Stack(3, Index) = ScaleHeight
Set Stack(4, Index) = Image ' Bild merken
Caption = cZoom & Index
End Sub

Das Gegenstück PopFromStack zu PushOnStack sieht nicht viel anders aus. Es kommt zum Auf-
ruf, wenn der Benutzer die rechte Maustaste klickt, um auf das Ausgangsbild des aktuellen Aus-
schnitts zurückzuwechseln. Die Routine liest die zuoberst auf dem Stack gelegene Information
unter Verwendung des »Stackzeigers« aus, stellt damit das Koordinatensystem wieder her und

488
Einzelbilder speichern

zeichnet schließlich das Bild mittels PaintPicture. Dabei ist es insbesondere von Vorteil, dass
PaintPicture mit dem aktuellen Koordinatensystem arbeitet, was aufwändige Umrechnungen
und Transformationen erspart. Vom Prinzip her könnte man das Bild auch als Hintergrundbild
der Picture-Eigenschaft des Formulars zuordnen, doch das wäre nicht sauber, weil es dann
gegen Cls resistent wäre und auch in neuen Ausschnitten erst einmal durchscheinen würde.
Private Sub PopFromStack()
Dim Index As Integer
Index = UBound(Stack, 2)
If Index > 0 Then ' Stack leer?
' Nein: Koordinatensystem wiederherstellen

ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge


ScaleLeft = Stack(0, Index)
ScaleTop = Stack(1, Index)
ScaleWidth = Stack(2, Index)
ScaleHeight = Stack(3, Index)
' Gespeichertes Bild zeichnen
PaintPicture Stack(4, Index), ScaleLeft, ScaleTop
ReDim Preserve Stack(4, Index – 1) ' Pop-Operation
Caption = cZoom & Index – 1
End If
End Sub

Einzelbilder speichern
Falls Ihnen daran gelegen ist, das eine oder andere »Werk« des Programms dauerhaft auf Fest-
platte zu bannen, etwa um es weiterzuverwenden, können Sie dem Formular ein kleines Menü
DATEI mit einem Befehl SPEICHERN spendieren und eine Behandlungsroutine implementieren,
die ein Standarddialoge-Steuerelement zur Eingabe des Dateinamens aufruft und das Bild dar-
aufhin mittels SavePicture abspeichert. Der Code dazu könnte etwa so aussehen.
Private Sub mnuDateiSpeichern_Click()
CommonDialog1.Filter = "Bitmap|*.bmp"
CommonDialog1.DefaultExt = "*.bmp"
CommonDialog1.ShowSave
If CommonDialog1.FileName <> "" Then
SavePicture Image, CommonDialog1.FileName
End If
End Sub

489
Formulare und Ansichten
Für die Arbeit mit mehreren Formularen gibt es unter Visual Basic einen hierarchischen Ansatz,
der den Einsatz eines MDI-Formularmoduls mit untergeordneten Formularen vorsieht sowie
einen nichthierarchischen Ansatz, bei dem sich die einzelne SDI-Formulare wechselseitig steuern
und synchronisieren.
MDI-Formulare setzt man im Allgemeinen für Anwendungen ein, in denen der Benutzer meh-
rere Dokumente gleichen Typs bearbeiten können soll. Sie kennen das von Ihrer Textverarbei-
tung her. Ein einfaches, aber durchaus leistungsfähiges Beispielprojekt für ein MDI-Formular
diskutiert der Referenzteil im Abschnitt »MDIForm-Objekt« (S. 313 ). Es trägt den Namen MDI-
Projekt. Mit Windows 9x ist die MDI-Anwendung jedoch wieder zunehmend ins Hintertreffen
geraten, weil das 32-Bit-Multitasking die Ausführung mehrerer Instanzen ein und desselben
Programms sehr einfach macht (und wohl auch, weil man herausgefunden hat, dass die meisten
Anwender MDI-Anwendungen ohnehin nur wie SDI-Anwendungen nutzen).
Die gewöhnlichen SDI-Formulare sind dagegen das Arbeitspferd des Visual-Basic-Programmie-
rers, wenn es darum geht, Anwendungen zu implementieren, die nicht so recht in das hierarchi-
sche Modell passen wollen, weil sie entweder zu einfach gestrickt sind und abgesehen von
»modalen Dialogen« (gebundene Anzeige) nur mit einem einzigen Formular auskommen oder
eben das eher lose Zusammenspiel mehrerer Formulare erfordern. Es mag daher nicht verwun-
dern, dass mehr als 90 Prozent der in Visual Basic implementierten Anwendungen von SDI-For-
mularen ausgehen, von den ActiveX-Komponenten einmal abgesehen, die gleichfalls der SDI-
Programmierung zuzurechnen sind.

Ereignisbehandlung
»Programmieren unter Windows heißt Ereignisse behandeln«. Wer von der prozeduralen Pro-
grammierung unter DOS oder UNIX her kommt, wird sich angesichts eines Visual-Basic-Pro-
gramms erst einmal fragen, wo denn hier »hinten und vorne ist«. In der Tat ist das Umsatteln
auf das Programmiermodell von Windows mitunter ein schwieriger Prozess, weil man eben
nicht sieht, was hinter den Kulissen vor sich geht. Man muss sich darauf verlassen, dass ein
Visual-Basic-Programm in bestimmten Situationen bestimmte Ereignisse signalisiert bekommt,
und kann dann den Code sozusagen als Antwort auf diese Ereignisse gestalten. »Programmie-
ren mit Ereignissen« heißt auch »Programmieren mit Objekten«. Nur Objekte können Ereig-
nisse generieren sowie die Ereignisse anderer Objekte behandeln. Das erste Ereignis im Leben
eines Objekts ist das Initialize-Ereignis. Das Eintreffen von Initialize sowie seines Gegen-
stücks Terminate, das letzte Ereignis im Leben eines Objekts, ist so sicher wie das Amen in der
Kirche. Was die weiteren Ereignisse betrifft, so hängt es von der Ausstattung und Art des jewei-
ligen Objekts ab, welche Ereignisse es signalisiert bekommt. Ein Formularobjekt sieht nach dem
Laden des ihm zugeordneten Fensters beispielsweise immer ein Load-Ereignis und beim Entla-
den des Fensters ein QueryUnload-Ereignis, gefolgt von einem Unload-Ereignis. Und da ein For-
mularobjekt sein Fenster auf das Initialize-Ereignis hin lädt (der Code dafür steckt hinter den
Kulissen) folgt beim Starten eines Formulars unmittelbar auf das Initialize-Ereignis ein Load-
Ereignis. Formularobjekt und Fenster sind also als verschiedene Objekte zu betrachten, die
wechselweise miteinander kommunizieren – bzw. sich gegenseitig »Ereignisse« mitteilen. Aus
diesem Grund kann das Fenster eines Formularobjekts zur Laufzeit jederzeit mittels der Unload-
Methode entladen und später wieder durch einfaches Ansprechen einer Eigenschaft oder
Methoden des Formulars erneut geladen werden. Beide Vorgänge werden von den Ereignissen
Load bzw. QueryUnload und Unload flankiert. Auf das Load-Ereignis folgen dann das Resize-
Ereignis und schließlich das Activate-Ereignis, wenn das Fenster des Formulars innerhalb der
Anwendung zum aktiven Fenster wird.

491
Ereignisbehandlung

Jedes Ereignis berichtet somit von einem bestimmten Vorkommnis, und Vorkommnisse gibt es
üblicherweise eine ganze Menge im Leben eines Objekts. So wird das Formular, dessen Fenster
das aktive Fenster ist, über jede Benutzeraktion mittels eines Ereignisses benachrichtigt. Die
Mausereignisse sind Click, DblClick, MouseDown, MouseMove, MouseUp und die Tastaturereignisse
KeyDown, KeyPress und KeyUp. Wieder andere Ereignisse berichten von Aktionen im Zusammen-
hang mit den Steuerelementen, die auf dem Formular platziert sind. Die meisten Steuerelement-
objekte führen ein ähnliches Doppelleben wie Formularobjekte. Das heißt, sie arbeiten gleich-
falls innig mit einem Fenster zusammen: dem Fenster, das ihre Darstellung enthält. Ereignisse,
die vom Fensterobjekt eines Steuerelements signalisiert werden, gelten daher nicht dem Formu-
larobjekt, sondern dem Steuerelementobjekt. Und so unterschiedlich wie die Natur eines Steue-
relements sein kann, so unterschiedlich können auch die Ereignisse sein, die sein Fensterobjekt
Ereignisbehandlung

signalisiert.
Ein Ereignis berichtet also, dass sich etwas ereignet hat. Das Programm kann auf dieses Ereignis
reagieren, muss aber nicht. Das ist im Vergleich zur prozeduralen Programmierung ein großer
Unterschied. Als Visual-Basic-Programmierer kümmert man sich nur um die Ereignisse, die für
die Problemstellung relevant sind. Alles andere lässt man »ungehört verhallen«. »Sich um ein
Ereignis kümmern« bedeutet: eine Behandlungsroutine dafür implementieren. Eine Behand-
lungsroutine wird in den meisten Fällen die von dem Ereignis überbrachten »Nachrichten«
(Funktionsparameter) auswerten und dann so reagieren, wie es die Inhalte der Nachrichten
erforderlich machen. (Dabei ist es durchaus erlaubt, ja sogar gute Programmiertechnik, wenn
sich Ereignisbehandlungsroutinen gegenseitig aufrufen.) Die Behandlung des zu einem Menü-
befehl namens »Datei laden« gehörigen Click-Ereignisses wird also beispielsweise den Ladevor-
gang einer Datei auslösen, oder das Change-Ereignis einer Bildlaufleiste ein Verschieben der
Ansicht im Fenster des Formulars.
Nach diesem Prinzip baut sich das gesamte Programm auf. Es gibt keine zentrale Logik mehr
(die gibt es natürlich schon, sie steckt aber gleichfalls hinter den Kulissen), die Programmlogik
zerfällt vielmehr in ein Mosaik kleiner Teile, die jeweils als spezifische Lösung auf ein ganz spe-
zifisches Problem ausgelegt sind und ihren bescheidenen Teil zum »Großen Ganzen« beitragen.

Gummiband – Bereiche interaktiv auswählen


Als recht vielseitiges Werkzeug ermöglicht die im Beispielprojekt Gummiband vorgestellte Imp-
lementation die grafisch orientierte Bereichsauswahl in Fenstern, etwa zum Zeichnen, zum
Zoomen des Fensterinhalts oder zur Auswahl von Objekten. Zur Überraschung vieler Program-
mierer gehört das Gummiband aber weder zur Ausstattung von Visual Basic noch zu den
Diensten des Betriebssystems. Es gilt also, selbst in die Tasten zu greifen. Die Implementierung
ist nicht sehr schwer, und man kann dabei eine Menge über die Ereignisprogrammierung mit
Windows lernen.
Am häufigsten wird das Gummiband als »Verschieben des Mauszeigers bei gedrückter linker
Maustaste« implementiert. Der gesamte Vorgang lässt sich (wie die meisten durch Benutzerin-
teraktion ausgelösten Vorgänge) in drei Phasen aufteilen: Start, Verlauf (mit Feedback für den
Benutzer), Ende (mit Bestätigung oder Abbruch). Für das Gummiband sind diese Phasen
1. Drücken der linken Maustaste – markiert Startpunkt
2. Bewegung der Maus bei gedrückter linker Maustaste – zeichnet und löscht Rechteck
3. Loslassen der linken Maustaste – markiert Endpunkt, löscht Rechteck und leitet die mit dem
Gummiband verbundene Funktion ein
Jede dieser Phasen meldet Windows Ihrem Programm in Form entsprechender Ereignisse. Das
Laufzeitsystem von Visual Basic verarbeitet diese Ereignisse automatisch, indem es für jedes die
betreffende Ereignisprozedur aufruft – vorausgesetzt, das betroffene Formularobjekt enthält
eine Implementation für diese Prozedur. Mit anderen Worten, drückt der Benutzer die Maus-

492
Gummiband – Bereiche interaktiv auswählen

taste, kommt die Ereignisprozedur Form_MouseDown zum Aufruf. Lässt er sie wieder los, kommt
Form_MouseDown zum Zuge. Ein Bewegen der Maus wird dagegen von Form_MouseMove-Aufrufen
begleitet. (Windows zeigt Mausbewegungen durch ein richtig gehendes Stakkato von Ereignis-
sen an, so dass die Animation des Gummibandes in sehr einfacher Weise in die Prozedur
Form_MouseMove gepackt werden kann.)

Ereignisbehandlung
Bereichsauswahl mit dem Gummiband

Für das Zusammenwirken der drei Prozeduren ist die Vereinbarung einiger globaler Variablen
erforderlich. So für die Koordinaten des Start- und Endpunkts und für den Zustand »Maustaste
gedrückt« – das Gummiband soll ja nur bei gedrückter Maustaste erscheinen. Hier die Imple-
mentierung:
'***********************************************************************
' Formularmodul: Gummiband
' Autor : 2000 Rudolf Huttary
' Beschreibung : demonstriert die Bereichsauswahl mit der Maus
'***********************************************************************

' Globale Variablen


Private MouseStartX As Single, MouseEndX As Single
Private MouseStartY As Single, MouseEndY As Single
Private Tracking As Boolean

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Tracking = True ' Gummiband einschalten
MouseStartX = X ' Start- und Endkoordinaten vorgeben
MouseStartY = Y
MouseEndX = X
MouseEndY = Y
End Sub

493
Ereignisbehandlung

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Dim dm
If Tracking Then
dm = DrawMode ' alten Zeichenmodus merken
DrawMode = vbInvert
' altes Band löschen und dann neu zeichnen
Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
Line (MouseStartX, MouseStartY)-(X, Y), , B
MouseEndX = X: MouseEndY = Y ' vorläufige Endkoordinaten merken
Ereignisbehandlung

DrawMode = dm ' alten Zeichenmodus einstellen


End If
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Dim dm
Tracking = False ' Gummiband ausschalten
MouseEndX = X: MouseEndY = Y ' nicht unbedingt erforderlich
dm = DrawMode ' alten Zeichenmodus merken
DrawMode = vbInvert
Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
DrawMode = dm ' alten Zeichenmodus einstellen
' Einleiten der gewünschten Aktion, Zeichnen, Zoomen, Auswählen etc.
' Die Koordinaten sind (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY)
End Sub

Ein Beispiel für den konkreten Einsatz des Gummibandes entlang dieser Implementierung findet
sich im Rahmen des Projekts ApfelmannZoom, wo es für die Auswahl des Zoombereichs
zuständig ist. In Abweichung vom vorgestellten Code ist hier das Seitenverhältnis des Gummi-
bandes jedoch fest vorgegeben, damit die relativen Verhältnisse der Fensterabmessungen beim
Zoomen erhalten bleiben.
Der Zustand »Maustaste gedrückt« lässt sich natürlich auch im Rahmen der Prozedur
Form_MouseMove ermitteln, da der Parameter Button bei jedem Aufruf den aktuellen Zustand der
Maustasten als Bitvektor übermittelt. In dem Vektor gibt Bit 0 den Zustand der linken, Bit 1
der rechten und Bit 2 der mittleren Maustaste an. Somit lässt sich das Gummiband vollständig
auch in Form_MouseMove implementieren. Das Formular Gummiband1 zeigt eine mögliche Lösung:
'***********************************************************************
' Formularmodul: Gummiband1
' Autor : 2000 Rudolf Huttary
' Beschreibung : demonstriert die Bereichsauswahl mit der Maus
'***********************************************************************
' Globale Variablen
Private MouseStartX As Single, MouseEndX As Single
Private MouseStartY As Single, MouseEndY As Single
Private Tracking As Boolean

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
Dim dm
If Button And vbLeftButton Then ' Linke Maustaste gedrückt?

494
DDE- Verbindungen

If Tracking Then ' Gummiband oder Startkoordinaten?


dm = DrawMode
DrawMode = vbInvert
' altes Band löschen und dann neu zeichnen
Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
Line (MouseStartX, MouseStartY)-(X, Y), , B
MouseEndX = X: MouseEndY = Y ' vorläufige Endkoordinaten merken
DrawMode = dm
Else ' Koordinaten initialisieren
Tracking = True ' und Gummiband einschalten

Ereignisbehandlung
MouseStartX = X
MouseStartY = Y
MouseEndX = X
MouseEndY = Y
End If
Else ' Maustaste nicht gedrückt
If Tracking Then
dm = DrawMode
DrawMode = vbInvert
Line (MouseStartX, MouseStartY)-(MouseEndX, MouseEndY), , B
DrawMode = dm
Tracking = False ' Gummiband ausschalten
End If
End If
End Sub

Dieser Code leistet zwar das Gleiche, er ist aber nicht gerade »schön« und aufgrund der auf-
wändigen Fallunterscheidungen schlecht lesbar.

DDE- Verbindungen
Der dynamische Datenaustausch (DDE) war die erste Möglichkeit für Anwendungen, substan-
ziell miteinander zu kommunizieren. Er umfasst den Austausch von Befehlen und Daten zwi-
schen Formularen und/oder Steuerelementen. Seit Einführung des dokumentenzentrierten
OLE2.0 und der 32-Bit-Technologie wird das eher anwendungszentrierte DDE zwar nicht mehr
oft eingesetzt, Visual Basic bietet dafür aber noch eine vollwertige Unterstützung.
Hier ein Überblick über den Mechanismus: Eine DDE-Verbindung wird zwischen zwei Objek-
ten hergestellt, von denen das eine als Quelle und das andere als Ziel bezeichnet wird. Beide
Objekte müssen unterschiedlichen Prozessen angehören. Als Quelle kommen Objekte der
Typen Form und MDIForm in Betracht und als Ziel Objekte der Typen Label, PictureBox und
TextBox. Ein Formularobjekt kann bis zu 128 unterschiedliche DDE-Verbindungen gleichzeitig
als Quelle bedienen. Eine Anwendung kann je nach Erfordernis in die Rolle eines DDE-Client
und in die Rolle eines DDE-Servers schlüpfen – auch gleichzeitig.

Datenaustausch durch DDE- Verknüpfung


Aus Sicht eines auf einem Formular DDEForm platzierten Steuerelements DEEQuelle sieht die auto-
matische DDE-Verknüpfung wie folgt aus: Damit es als Datenlieferant fungieren kann, muss
die Eigenschaft LinkMode seines Formularobjekts den Wert vbSource bzw. 1 aufweisen. Der
Wert dieser Eigenschaft lässt sich zur Laufzeit jederzeit zwischen vbLinkNone und vbLinkSource
hin und her schalten, sofern er nicht zur Entwurfszeit auf vbLinkNone bzw. 0 gesetzt wurde –
dann ist er nämlich zur Laufzeit schreibgeschützt. Für das Steuerelement selbst gibt es keine
Auflagen, das Formular erledigt alles.

495
Ereignisbehandlung

Wenn nun ein in einer anderen Anwendung gelegenes Zielobjekt DDEZiel seinen Wert mit dem
Datenelement DDEQuelle des Quellobjekts automatisch bei jeder Wertänderung synchronisieren
will, muss es eine automatische DDE-Verknüpfung einrichten. Der Code dafür ist:
DDEZiel.LinkMode = 0 ' ggf.bestehende Verbindung zurücksetzen
DDEZiel.LinkTopic = "VBAnwendung|DDEForm" ' Anwendung und Formular
DDEZiel.LinkItem = "DDEQuelle" ' Quelle festlegen!
DDEZiel.LinkMode = vbAutomatic ' Verbindung aufbauen

Zu beachten gilt es dabei eigentlich nur, dass die Datentypen der beiden beteiligten Steuerele-
mente kompatibel sein müssen. Zudem sollten beide Anwendungen laufen, wenn die DDE-Ver-
bindung durch Setzen der Eigenschaft LinkMode auf vbLinkAutomatic bzw. eröffnet wird. Der
Ereignisbehandlung

Wert von LinkTopic setzt sich aus dem Namen App.Title der Quellanwendung und dem Link-
Topic-Wert des Quellobjekts (auch Thema genannt) zusammen – getrennt durch das Zeichen
»|«. (App.Title wird unter PROJEKTEIGENSCHAFTEN auf der Seite ERSTELLEN gesetzt.) Als Wert
von LinkItem muss schließlich der Bezeichner des Steuerelements (als Zeichenfolge) angegeben
werden, das die Daten für die Verknüpfung liefern soll.
Wie eine Analyse der LinkOpen-Ereignisse beim Verbindungsaufbau zeigt (vgl. die folgende
Abbildung), ist das Formularobjekt Ansprechpartner des Zielobjekts, nicht das Steuerelement,
das die Daten bereitstellt. Ist eine automatische DDE-Verbindung einmal eröffnet, bleibt die
Synchronisation zwischen Quelle und Ziel so lange bestehen, bis entweder das Zielobjekt oder
das Quellobjekt seine LinkMode-Eigenschaft auf vbLinkNone (0) setzt – ein Vorgang, der auf bei-
den Seiten das Ereignis LinkClose auslöst. Das Formularobjekt beendet mit diesem Schritt übri-
gens alle aktuell gehaltenen DDE-Verbindungen und nimmt neue Verbindungsanfragen erst
wieder an, wenn LinkMode erneut den Wert vbLinkSource hat. DDE-Verbindungen, bei denen
dem Formularobjekt untergeordnete Objekte als Zielobjekte auftreten, bleiben davon allerdings
unberührt.
Nicht immer ist die automatische Synchronisation einer Verknüpfung erwünscht. Aus diesem
Grund lassen sich DDE-Verbindungen auch in den Modi »Manuell« und »Manuell mit Benach-
richtigung« eröffnen. Der erste Modus ergibt sich, wenn LinkMode auf vbLinkManual gesetzt
wird, und der zweite Modus, wenn LinkMode auf vbLinkNotify gesetzt wird. In beiden Fällen
muss das Zielobjekt von sich aus die Methode LinkRequest ausführen, um den aktuellen Wert
des Quellobjekts zu erhalten. Der Unterschied besteht darin, dass im zweiten Modus, wenn sich
der Wert des Quellobjekts geändert hat, eine Benachrichtigung in Form eines LinkNotify-Ereig-
nisses stattfindet, die im ersten Modus unterbleibt.
Das Quellobjekt kann das Zielobjekt im Modus »Manuell mit Benachrichtigung« durch Aufruf
der Methode LinkSend des die Daten liefernden Steuerelements auch außer der Reihe zur Aktu-
alisierung auffordern. Das ist beispielsweise notwendig, wenn das Picture-Objekt eines Bild-
felds verändert wurde.
DDE-Verbindungen sind bilateral. Ein Zielobjekt kann daher auch den Spieß umdrehen und
den Wert des Quellobjekts verändern, indem es die Methode LinkPoke ausführt. (Dies wird
allerdings nicht von allen Anwendungen unterstützt.) Kommt es während einer DDE-Kommu-
nikation zu einem DDE-spezifischen Fehler, etwa wenn das Datenformat nicht stimmt, tritt das
Ereignis LinkError auf.

DDE- Kommandos
Neben der einfachen Verknüpfung zwischen Quelle und Ziel bietet DDE einem Zielobjekt auch
die Möglichkeit, Kommandos über eine geöffnete DDE-Verbindung an das Quellobjekt zu schi-
cken. Ein solches DDE-Kommando ist nichts weiter als eine Zeichenkette, deren Interpretation
keineswegs in irgendeiner Form standardisiert, sondern völlig im Ermessen der Quelle gelegen
ist. Den Versand bewerkstelligt ein Aufruf der LinkExecute-Methode des Zielobjekts. Aufseiten

496
DDE- Verbindungen

des Quellobjekts macht sich das Kommando als LinkExecute-Ereignis bemerkbar, das die Kom-
mandozeichenfolge als Parameter anbietet.
Angenommen, Sie wollen ein Kommando »Beenden« implementieren, das eine andere DDE-
Anwendung aus der Ferne beendet. Der Name der DDE-Anwendung sei Quelle und der ihres
Hauptformulars QuelleForm. Um das Kommando von einem Zielobjekt Ziel aus zu verschi-
cken, öffnen Sie (falls noch nicht geschehen) eine DDE-Verbindung und rufen die Methode
LinkExecute des Zielobjekts auf:
Ziel.LinkMode = 0 ' Verbindung zu anderer Quelle ggf. schließen
Ziel.LinkTopic = "Quelle|QuelleForm" ' Anwendung und Thema festlegen
Ziel.LinkMode = vbLinkManual ' Verbindung eröffnen

Ereignisbehandlung
Ziel.LinkExecute "Beenden" ' DDE-Kommando verschicken0

Auf der Gegenseite müssen Sie darauf achten, dass die LinkMode-Eigenschaft des Formulars
QuelleForm (bereits beim Entwurf) auf vbLinkSource gesetzt ist. Der Rest ist nichts weiter als
Ereignisbehandlung:
Private Sub QuelleForm_LinkExecute(CmdStr As String, Cancel As Integer)
If CmdStr = "Beenden" Then
Unload Me ' Befehl interpretieren
Cancel = False
End If
End Sub

Wenn die Quelle das Kommando erfolgreich ausgeführt hat, muss es den Cancel-Parameter
explizit auf False oder 0 setzen, sonst bekommt es die Zielanwendung mit dem Laufzeitfehler
285, »Andere Anwendung führt die DDE-Methode oder -Operation nicht aus«, zu tun.

DDE- Demo – wenn Programme kommunizieren


Das Thema DDE kommt mittlerweile in der einschlägigen Literatur zu Visual Basic immer kür-
zer. Aus diesem Grund konzentriert sich das Beispielprojekt DDE-Demo nicht so sehr auf eine
konkrete Problemstellung, sondern eher auf Grundsätzliches: Es führt die im vorangestellten
Abschnitt erläuterten Techniken schlicht von der Implementationsseite her vor. Die Anwen-
dung besteht aus einem einzelnen Formular namens Form1, auf dem vier Textfelder namens
Quelle1, Quelle2, DDEZiel und DDEKommando enthalten sind. Zudem findet sich auf dem Formular
eine Standardschaltfläche namens Command1.
Startet man das Programm und klickt auf die Schaltfläche Command1 oder das Textfeld DDEZiel,
versucht dieses, eine DDE-Verbindung zu der Anwendung »DDEDemo« mit dem Thema
»Form1« herzustellen, was nicht glückt, aber doch zeigt, dass DDE-Verbindungen nicht refle-
xiv (d.h.: innerhalb ein und desselben Programms) hergestellt werden können. Folgt man dem
Rat der Fehlermeldung und startet eine weitere Instanz des Programms (dazu muss es gegebe-
nenfalls erst kompiliert werden), klappt der Verbindungsaufbau. Die folgende Abbildung zeigt
eine laufende Sitzung mit zwei Instanzen des Programms.
Um die Ausgaben im linken Teil des Formulars interpretieren zu können, ist es wichtig, den
Aktionsablauf zu rekonstruieren.
1. Start von Instanz1 und Klick auf die Schaltfläche – ergibt eine Fehlermeldung und die Aus-
gabe »DDEKommando_LinkOpen«.
2. Start von Instanz2 und erneuter Klick auf die Schaltfläche von Instanz1 – ergibt im Formular
von Instanz1 die Ausgabe »DDEKommando_LinkOpen« und im Formular von Instanz2 die
Ausgabe »Form_LinkOpen«. Das Formularobjekt von Instanz2 fungiert jetzt als Quellob-
jekt. Es nimmt Befehle entgegen, die in das Textfeld DDEKommando von Instanz1 eingegeben
und durch einen Klick auf die Schaltfläche (im Namen von DDEKommando) abgeschickt werden.

497
Ereignisbehandlung
Ereignisbehandlung

Die beiden Instanzen des Programms DDE- Demo unterhalten DDE- Verbindungen zueinander

3. Erneuter Klick auf die Schaltfläche von Instanz1 – das Formularobjekt von Instanz2 erhält
nun ein LinkExecute-Ereignis mit dem Befehlstext »(Befehl eingeben)« und generiert – ohne
weitere Interpretation – die Ausgabe »Form_LinkExecute: (Befehl eingeben)«.
4. Klick auf das Textfeld DDEText von Instanz1 – das eröffnet eine automatische DDE-Kommu-
nikation mit dem Textfeld Quelle1 von Instanz2 und überträgt dessen Inhalt in das Textfeld
DDEText. Im Formular von Instanz2 weist die Ausgabe »Form_LinkOpen« darauf hin, dass
eine zweite DDE-Verbindung eröffnet wurde. Die Ausgabe »DDEText_LinkOpen« im For-
mular von Instanz1 zeigt, dass DDEText Zielobjekt dieser Verbindung ist. Jeder weitere Klick
auf das Textfeld DDEText schaltet die LinkItem-Eigenschaft zwischen »Quelle1« und
»Quelle2« hin und her, so dass einmal das eine Textfeld und einmal das andere die Verknüp-
fung bedient und seinen Wert an DDEText liefert. Ein Auf- und Abbau der Verbindung ist da-
für nicht erforderlich. Eingaben in das Textfeld Quelle1 (bzw. Quelle2) von Instanz2 werden
aufgrund der gewählten Verbindungsart (LinkMode hat den Wert vbLinkAutomatic) unmittel-
bar an das in Instanz1 gelegene Zielobjekt DDEText weitergeleitet.
5. Aktivierung von Instanz2 und Klicks auf das Steuerelement DDEText sowie auf die Schaltflä-
che Command1 – Instanz2 initiiert daraufhin weitere DDE-Verbindungen analog der Aktionen
2 und 4, nur mit vertauschten Rollen – wie sich an den Ausgaben gut ablesen lässt. Insgesamt
bestehen dann also vier Verbindungen, wobei jede Instanz zweimal als Quelle und zweimal
als Ziel auftritt.
6. Aktivierung von Instanz1 und Eingabe des Kommandos »Beenden« in das Textfeld DDEKom-
mando – die Eingabetaste oder ein Klick auf die Schaltfläche sendet das Kommando, worauf-
hin Instanz2 seine Ausführung beendet. Wie die Ausgabe im Formular von Instanz1 zeigt,
treten dabei vier Ereignisse auf, da Visual Basic implizit alle Verbindungen abbricht. Die fol-
gende Abbildung zeigt das Fenster von Instanz1 nach Beendigung von Instanz2.

Fenster von Instanz1 nac h Beendigung von Instanz2 über einen DDE- Befehl

498
DDE- Verbindungen

Hier der Code:


'***********************************************************************
' Formularmodul : DDE-Demo
' Autor : 2000 Rudolf Huttary
' Beschreibung : demonstriert DDE-Verbindungen
'***********************************************************************
Private DDECmdZähler As Integer
Private DDETextZähler As Integer
Private PictureZähler As Integer

Ereignisbehandlung
Private Sub Form_Load()
If App.PrevInstance Then
Caption = "DDE – Demo: Instanz2"
Quelle1 = "Instanz2-" & "Quelle1"
Quelle2 = "Instanz2-" & "Quelle2"
Else
Caption = "DDE – Demo: Instanz1"
Quelle1 = "Instanz1-" & "Quelle1"
Quelle2 = "Instanz1-" & "Quelle2"
End If
DDEText = "(Klick öffnet DDE-Verbindung)"
Command1.Caption = "DDE-Verbindung öffnen"
End Sub

Private Sub Form_LinkClose()


Print "Form_LinkClose"
End Sub

Private Sub Form_LinkOpen(Cancel As Integer)


Print "Form_LinkOpen"
End Sub

Private Sub Form_LinkExecute(CmdStr As String, Cancel As Integer)


Print "Form_LinkExecute: " & CmdStr ' Befehl ausgeben
Cancel = False
If CmdStr = "Beenden" Then Unload Me ' Befehl interpretieren
End Sub

Private Sub DDEText_LinkClose()


Print "DDEText_LinkClose"
DDEText = "(Klick öffnet DDE-Verbindung)"
DDETextZähler = 0
End Sub

Private Sub DDEText_LinkOpen(Cancel As Integer)


Print "DDEText_LinkOpen"
End Sub

Private Sub DDEText_Click()


If DDETextZähler = 0 Then ' Beim ersten Klick: Verbindung herstellen

499
Ereignisbehandlung

DDEText.LinkMode = 0
DDEText.LinkTopic = "DDE-Demo|Form1" ' Anwendung und Formular
DDEText.LinkItem = "Quelle1" ' Quelle festlegen!
On Error GoTo StarteAnwendung
DDEText.LinkMode = vbLinkAutomatic
Else ' Bei weiteren Klicks: Quelle wechseln
DDEText.LinkItem = "Quelle" & 1 + DDETextZähler Mod 2
End If
DDETextZähler = DDETextZähler + 1
Exit Sub
Ereignisbehandlung

StarteAnwendung:
MsgBox (Err.Description & vbCrLf & _
" Abhilfe: Weitere Instanz des Programms starten")
Exit Sub
End Sub

Private Sub Command1_Click()


If DDECmdZähler = 0 Then ' Beim ersten Klick: Verbindung herstellen
DDEKommando.LinkMode = 0
DDEKommando.LinkTopic = "DDE-Demo|Form1"
On Error GoTo StarteAnwendung
DDEKommando.LinkMode = vbLinkManual
Command1.Caption = "DDE-Kommando senden"
Else ' Bei weiteren Klicks: Befehl senden
DDEKommando.LinkExecute DDEKommando
End If
DDECmdZähler = 1

Exit Sub
StarteAnwendung:
MsgBox ("Fehler " & Err.Number & " " & Err.Description & vbCrLf & _
" Abhilfe: Weitere Instanz des Programms starten")
Exit Sub
End Sub

Private Sub DDEKommando_LinkClose()


Print "DDEKommando_LinkClose"
DDECmdZähler = 0
Command1.Caption = "DDE-Verbindung öffnen"
End Sub

Private Sub DDEKommando_LinkOpen(Cancel As Integer)


Print "DDEKommando_LinkOpen"
End Sub

Wie man sieht, weist der Code an sich trotz der komplexen Funktionalität keine Besonderheiten
auf. Damit die DDE-bezogenen Ereignisse besser beobachtet werden können, enthalten die ent-
sprechenden Behandlungsroutinen geeignete Print-Anweisungen. Der Code pflegt für jede Ver-
bindung eine globale Variable, deren Wert eine Aussage darüber macht, ob die Verbindung
besteht oder (neu) aufgebaut werden muss. An den beiden Stellen, wo ein Verbindungsaufbau
passiert, ist eine Fehlerbehandlung notwendig – für den Fall, dass der Aufbau fehlschlägt.

500
OLE- Drag&Drop

OLE- Drag&Drop
Die OLE-Drag&Drop-Operation ist ein Vorgang, bei dem der Benutzer den Inhalt oder einen
zuvor ausgewählten Teil des Inhalts einer Quellkomponente mit gedrückter Maustaste über
eine Zielkomponente zieht und dort ablegt. Vom Effekt her passiert dabei nichts anderes als bei
der Benutzung der Zwischenablage.
Im Gegensatz zur gewöhnlichen Drag&Drop-Operation, die nicht über die Grenzen einer
Anwendung (lies: EXE-Datei oder DLL) hinausführt, da der Mechanismus mit konkreten Refe-
renzen auf Steuerelemente hantiert, gibt es für die Reichweite der OLE-Drag&Drop-Operation
keinerlei Beschränkungen. Sie funktioniert innerhalb eines Formulars, von Formular zu Formu-
lar, aber auch von Anwendung zu Anwendung. Der wesentliche Unterschied zwischen den bei-

Ereignisbehandlung
den Mechanismen besteht darin, dass die OLE-Drag&Drop-Operation eine dokumentenzent-
rierte Systemschnittstelle (lies: Systemkomponente) benutzt, die speziell auf die Übermittlung
von DataObject-Objekten eingerichtet ist. Während das Ziel einer Drag&Drop-Operation
Zugriff auf alle Eigenschaften und Methoden des Quellobjekts erhält, sieht die Zielkomponente
einer OLE-Drag&Drop-Operation nur ein Containerobjekt, welches ein in einem oder mehre-
ren standardisierten Formaten vorliegendes Dokument bereitstellt.
Die meisten in Visual Basic verfügbaren Steuerelemente unterstützen OLE-Drag&Drop zu
einem gewissen Grad. Viele Standardsteuerelemente sowie ActiveX-Steuerelemente (insbeson-
dere die mit den Editionen Professional und Enterprise ausgelieferten Steuerelemente) bieten
außer dem manuellen Modus auch eine automatische Unterstützung für OLE-Drag&Drop.
Was von der Theorie her ein mächtiges Gebäude ist, erweist sich in der Praxis meist handlicher,
als man es erwarten würde. Ein auf den Automatikbetrieb eingerichtetes Steuerelement unter-
stützt entsprechende Einstellungen für die Eigenschaften OLEDragMode und OLEDropMode. Aus
Sicht der Programmierung bleibt dann nichts weiter zu tun, als das Steuerelement für die Rolle
als Quellkomponente und/oder als Zielkomponente in den Automatikmodus zu versetzen. Alles
Weitere erledigt sich gewissermaßen von selbst. Der manuelle Modus birgt dagegen weitaus
mehr Möglichkeiten, auf den Vorgang einzuwirken bzw. diesen zu gestalten.

Automatikmodus
Die einfachste Situation für eine OLE-Drag&Drop-Operation liegt vor, wenn die betroffene
Komponente im Automatikmodus betrieben wird. Es reicht dann, die Eigenschaft OLEDropMode
für die Funktion als Zielkomponente bzw. die Eigenschaft OLEDragMode für die Funktion als
Quellkomponente geeignet zu initialisieren. Dies kann im Entwurfsmodus geschehen, aber auch
zur Laufzeit – beispielsweise in der Initialisierungsroutine Form_Load:
Private Sub Form_Load()
...
Text1.OLEDragMode = vbOLEDragAutomatic ' = 1
Text1.OLEDropMode = vbOLEDropAutomatic ' = 2
End Sub

Das war es bereits. Der Benutzer kann nun zum einen den Inhalt des Steuerelements nach Her-
zenslust mit der Maus in eine Zielkomponente (beispielsweise in ein Word-Dokument) ver-
schieben bzw. auch kopieren, wenn er beim Ablegen die Taste (Strg) gedrückt hält. Zum ande-
ren lassen sich auf die gleiche Weise auch die Inhalte anderer textorientierter Komponenten in
das Steuerelement verschieben bzw. kopieren.
Was die Funktion als Zielkomponente betrifft, gibt es nichts weiter zu sagen: Der Automatik-
modus bietet keinerlei Handhabe für Änderungen oder Zusätzliches. In der Funktion als Quell-
komponente erhält das Steuerelement dagegen im Verlauf der OLE-Drag&Drop-Operation
eine Reihe von Ereignissen, die eine gewisse Kontrolle über den Vorgang ermöglichen.
Als erstes Ereignis tritt OLEStartDrag auf, das den Start der Operation anzeigt und die beiden
Parameter Data und AllowedEffects bereitstellt. Data ist eine Objektreferenz auf ein DataObject-

501
Ereignisbehandlung

Objekt, das den übermittelten Inhalt umhüllt. Der Typ des Inhalts lässt sich durch Aufruf der
Methode GetFormat bestimmen, während GetData den Inhalt selbst liefert. Um den Inhalt (samt
Typ) neu zu setzen, genügt ein SetData-Aufruf. AllowedEffects ist dagegen ein Bitvektor, der
bestimmt, welche Operationen die Quellkomponente für den Inhalt des DataObject-Objekts
unterstützt: Ein gesetztes Bit 0 (vbDropEffectCopy) erlaubt das Kopieren und ein gesetztes Bit 1
(vbDropEffectMove) das Verschieben. Die meisten Steuerelemente erlauben beide Operationen
und geben den Standardwert 3 vor. Um die Operation zu unterbinden, können Sie den Wert
auch auf 0 setzen.
Obwohl der SetData-Aufruf den Inhalt für gewöhnlich bereits in Reaktion auf OLEStartDrag in
einem oder mehreren Formaten bereitstellt, kann eine Komponente mit der Bereitstellung auf-
wändiger Formate auch auf das OLESetData-Ereignis warten. Voraussetzung für das Auftreten
Ereignisbehandlung

dieses Ereignisses ist, dass ein SetData-Aufruf der Form


Data.SetData , vbCFSpezialFormat
also unter Auslassung des ersten Parameters vorausgegangen ist. In diesem Fall tritt das Ereignis
auf, wenn die Zielkomponente auf das OLEDragDrop-Ereignis hin ihren GetData-Aufruf durch-
führt. Somit ist eine Bereitstellung des Inhalts nur erforderlich, wenn die Operation auch tat-
sächlich ausgeführt wird – der Vorteil bei umfangreichen Inhalten liegt auf der Hand.
Im Automatikmodus überträgt ein Textfeld standardmäßig nur den markierten Teil seines
Inhalts. Um auf jeden Fall den ganzen Inhalt zu übertragen und nur die Kopieroperation zuzu-
lassen, sieht die Behandlungsroutine für das OLEStartDrag-Ereignis so aus:
Private Sub Text1_OLEStartDrag(Data As DataObject, _
AllowedEffects As Long)
AllowedEffects = vbDropEffectCopy ' 1 (nur Kopieren möglich)
Data.SetData Text1, vbCFText ' gesamten Wert übermitteln
End Sub
Im weiteren Verlauf der Operation treten OLEGiveFeedback-Ereignisse auf, die eine Reaktion auf
OLEDragOver-Ereignisse aufseiten der Zielkomponente darstellen. (Im Automatikmodus »beant-
wortet« eine Zielkomponente OLEDragOver-Ereignisse allerdings intern, ohne dass es zum Auf-
ruf einer gegebenenfalls bereitgestellten Behandlungsroutine für dieses Ereignis kommt.) Der
erste Parameter Effect im OLEGiveFeedback-Ereignis ist eine Mitteilung der Zielkomponente
über die Art der resultierenden Operation, falls der Benutzer das Objekt ablegt. Eine Quellkom-
ponente kann dieses Ereignis behandeln, um dem Benutzer ein geeignetes optisches Feedback
etwa in Form eines benutzerdefinierten Mauszeigers zu geben und ihn so über die Art der
zustande kommenden Operation zu unterrichten. Dazu wird die Cursorform über die MouseI-
con-Eigenschaft des Screen-Objekts bereitgestellt und durch Setzen des DefaultCursors-Parame-
ters auf den Wert False sowie der Eigenschaft Screen.MousePointer auf vbCustom aktiviert. Hier
ein Beispiel
Private EffectIcon As Picture
Private AltesScreenIcon As Picture
Private AlterScreenPointer As Integer

Private Sub Quelle_OLEStartDrag(Data As DataObject, _


AllowedEffects As Long)
Set AltesScreenIcon = Screen.MouseIcon ' Alte Form merken
AlterScreenPointer = Screen.MousePointer ' Alten Zeiger merken
If EffectIcon Is Nothing Then ' Form schon geladen?
Set EffectIcon = LoadPicture("OLECopy.ico") ' Form laden
End If
End Sub

502
OLE- Drag&Drop

Private Sub Quelle_OLEGiveFeedback(Effect As Long, _


DefaultCursors As Boolean)
If Effect And vbDropEffectCopy Then ' Nur fürs Kopieren
Set Screen.MouseIcon = EffectIcon ' Andere Form setzen
Screen.MousePointer = vbCustom ' Benutzerdefinierte Form
DefaultCursors = False ' Eigene Form verwenden
End If
End Sub
Das letzte Ereignis, das die Quellkomponente zu Gesicht bekommt, ist OLECompleteDrag. Es
informiert die Komponente, welche Operation nun im Endeffekt passiert ist. Eine Behandlung

Ereignisbehandlung
dieses Ereignisses kann beispielsweise erforderlich sein, wenn die Quellkomponente die ver-
schobenen Daten nicht von selbst löscht (oder nicht alle damit im Zusammenhang stehenden
Ressourcen freigibt), aber auch, um einen gegebenenfalls bei der Behandlung von OLEGiveFeed-
back gesetzten Mauszeiger wieder loszuwerden:
Private Sub Quelle_OLECompleteDrag(Effect As Long)
Screen.MouseIcon = AltesScreenIcon ' Alte Form setzen
Screen.MousePointer = AlterScreenPointer ' Alten Zeiger setzen
End Sub

Manueller Modus
Eine Quellkomponente kann auch »manuell« durch Aufruf der Methode OLEDrag dazu bewegt
werden, eine OLE-Drag&Drop-Operation zu beginnen. Im manuellen Modus, wenn die Eigen-
schaft OLEDragMode den Wert vbOLEDragManual hat, ist dies sogar die einzige Möglichkeit. Der
Ablauf ist dann genauso wie im Automatikmodus, außer dass eine Bereitstellung des zu über-
mittelnden Inhalts bei der Behandlung des OLEStartDrag- oder OLEGetData-Ereignisses erfolgen
kann. Ein Inhalt kann übrigens auch in mehreren verschiedenen (auch benutzerdefinierten) For-
maten bereitgestellt werden. Ein Gegenstück von OLEDrag, etwa eine Methode namens
»OLEDrop« zum Ablegen, gibt es nicht – und würde auch keinen Sinn machen.
Wird die Zielkomponente im manuellen Modus vbOLEDropManual (1) betrieben, ergibt sich an
zwei Stellen die Möglichkeit, von der Implementation her gestalterisch auf den Vorgang einzu-
wirken. Da ist zunächst einmal das OLEDragOver-Ereignis. Vergleichbar mit dem MouseMove-
Ereignis tritt es auf, wenn der Mauszeiger im Verlauf einer OLE-Drag&Drop-Operation in den
Bereich der Zielkomponente eintritt, darin bewegt wird oder diesen wieder verlässt. Durch
seine stattliche Anzahl an Parametern vermittelt dieses Ereignis der Komponente eine vollstän-
dige Vorausschau auf den möglichen Ausgang der Operation. Der Parameter Data macht den
eigentlichen Inhalt der Operation sowie dessen Datentyp einer genaueren Analyse zugänglich –
eine Manipulation des Inhalts mittels SetData ist jedoch nicht zulässig. Der zuvor schon disku-
tierte Parameter Effect zeigt an, welche Operationen (Verschieben und/oder Kopieren) die
Quellkomponente unterstützt, und erlaubt es der Zielkomponente, die von ihr unterstützten
Operationen in umgekehrter Richtung kundzutun. Die Parameter Button und Shift enthalten
Bitvektoren, die den aktuellen Zustand der Maus- und Funktionstasten beschreiben. Die Para-
meter X und Y geben die aktuelle Mausposition wieder, und State zeigt schließlich an, ob der
Bereich der Zielkomponente soeben betreten (vbEnter) oder verlassen (vbLeave) wurde oder ob
sich einfach nur die Mausposition innerhalb des Bereichs (vbOver) verändert hat.
Bei der Auswertung des Effect-Parameters sollten Sie eine geeignete Maskierung verwenden,
damit die Kompatibilität des Codes gegenüber künftigen Erweiterungen (Belegung zusätzlicher
Bits des Vektors mit Bedeutung) gewahrt bleibt. Nehmen wir an, die Kopieroperation soll stattfin-
den, wenn keine Funktionstaste gedrückt ist, und die Verschiebeoperation, wenn (Strg) gedrückt
ist. Das sieht dann leider ein wenig umständlich aus, lässt sich aber wiederverwenden und sollte
als eigenständige Prozedur verpackt von der Behandlungsroutine aus aufgerufen werden:

503
Ereignisbehandlung

Private Sub BestimmeEffect(Effect As Long, Button As Integer, _


Shift As Integer)
If Shift = 0 And (Effect And vbDropEffectCopy) > 0 Then
Effect = vbDropEffectCopy ' Kopieroperation setzen
ElseIf (Shift And vbShiftMask) > 0 _
And (Effect And vbDropEffectMove) > 0 _
Then
Effect = vbDropEffectMove ' Verschiebeoperation setzen
Else
Effect = vbDropEffectNone ' Operation nicht unterstützt!
Ereignisbehandlung

End If
End Sub

Private Sub Ziel_OLEDragOver(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single, _
State As Integer)
BestimmeEffect Effect, Button, Shift
if Not Data.GetFormat(vbCFText) Then ' Nur Textformat ist zulässig
Effect = vbDropEffectNone
End if
End Sub

Der Windows Explorer setzt übrigens auch das dritte Bit des Bitvektors, wenn es darum geht,
Dateien zu transportieren. Die entsprechende Operation hat die Bedeutung »Verknüpfung mit
Datei erstellen« und lässt sich in Visual Basic 6.0 implementieren, auch wenn aktuell noch
keine Maskenkonstante dafür definiert ist.
Im manuellen Modus sollte die Zielkomponente das OLEDragOver-Ereignis auf jeden Fall dazu
nutzen, mittels der GetFormat-Methode des Parameters Data festzustellen, ob sie mit den Daten
überhaupt etwas anfangen kann, und wenn ja, Effect auf die Operation zu setzen, die ange-
sichts des aktuellen Zustands der Maustasten und Funktionstasten resultieren würde.
Die zweite Möglichkeit für den Eingriff ergibt sich durch das Ereignis OLEDragDrop. Es verkün-
det der Komponente, dass sie Ziel einer OLE-Drag&Drop-Operation ist und tritt somit auf,
sobald der Benutzer die Maustaste loslässt. An Parametern stellt das Ereignis dieselben Werte
bereit wie OLEDragOver, so dass für die Ermittlung der durchzuführenden Operation vom Prin-
zip her die gleiche Logik bzw. eine Prozedur verwendet werden kann. Im Unterschied zu OLE-
DragOver wird die Behandlungsroutine von OLEDragDrop aber konkret mit dem Parameter Data
arbeiten und den eigentlichen »Inhalt« der OLE-Drag&Drop via GetData entgegennehmen.
Hier der Code für die Entgegennahme eines Inhalts im Format vbCFText:
Private Sub Ziel_OLEDragDrop(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, Y As Single)
BestimmeEffect Effect, Button, Shift
If Effect <> vbDropEffectNone then
Ziel = Data.GetData(vbCDText)
End If
End Sub

Nun fehlt eigentlich nur noch der letzte Schritt, der die Quellkomponente darüber informiert,
welche Operation nun tatsächlich im Rahmen von OLEDragDrop ausgeführt wurde. Diese muss
ja wissen, ob sie den übermittelten Inhalt bei sich löschen soll oder nicht. Die Quellkomponente
erhält daher noch ein letztes Ereignis, nämlich OLEDragComplete. Da die meisten Steuerelemente

504
OLE- Drag&Drop

von sich aus aufräumen, ist die Behandlung eigentlich nur dann erforderlich, wenn dies nicht,
oder nicht vollständig geschieht oder vielleicht sogar nur unter Vorbehalt geschehen soll.

Ausblick
Die für Visual Basic definierten Formatkonstanten decken nur einen kleinen Teil der tatsächlich
beim System registrierten Formate ab. Registriert man mittels der Win32-API-Funktion Regi-
sterClipBoardFormat ein eigenes Format, steht dieses fortan auf dem System für die OLE-Kom-
munikation zur Verfügung. Die Funktion erwartet einen Bezeichnerstring für das Format und
liefert nach erfolgreicher Registrierung den Wert für die neue Formatkonstante. War das For-
mat bereits registriert, etwa von einer anderen Instanz der gleichen Anwendung, liefert die
Funktion schlicht den Handle dieses Formats. Eine Registrierung ist zwar ratsam, aber nicht

Ereignisbehandlung
unbedingt erforderlich, wenn das Format nur »intern« benutzt werden soll. Selbst wenn die
Wahrscheinlichkeit einer Kollision mit einem registrierten Format bei Wahl einer arbiträren
Zahl als Handle für das Format recht klein ist, empfiehlt sich doch ein Test mit der Win32-API-
Funktion GetClipFormatName, ob der Handle im System bereits mit einer anderen Bedeutung
belegt ist.
Wenn Sie ein Format verwenden, das der Aufzählungstyp ClipBoardConstants nicht mit einer
Konstanten bedenkt, erwartet die Methode SetData die zu übermittelnden Daten als Byte-
Array. Andere Datentypen müssen Sie also vorher geeignet umwandeln. Vergessen Sie dabei
nicht, eine Längeninformation voranzustellen, da Windows die benötigte Pufferlänge großzügig
aufrundet – mit der Folge, dass GetData zumeist mehr Bytes abholt, als SetData hineinsteckt. Ein
kleines Beispiel für die Arbeit mit einem eigenen Format finden Sie im Referenzteil unter
»OLEStartDrag-Ereignis« (S. 250 ).

OLEDragDrop – die »eierlegende Wollmilchsau«


Das Beispielprojekt OLEDragDrop zu diesem Thema ist so etwas wie eine »eierlegende Woll-
milchsau« im Bereich des OLE-Drag&Drop. Es beinhaltet zwei Formulare, von denen das eine,
Form1, als Zielkomponente auftritt und mit einer recht ansehnlichen Fülle unterschiedlicher
OLE-Drag&Drop-Operationen etwas anfangen kann, während das andere, Form2, einige Steu-
erelemente enthält, die sich zum Testen der Zielkomponente eignen.
Die Zielkomponente unterstützt folgende Operationen:
1. Ablegen einer Zeichenfolge, die aus einer textorientierten Komponente stammt. (Auch RTF-
orientierte Komponenten kommen als Quelle in Frage, die Darstellung berücksichtigt aller-
dings keine Formatierungen.)
2. Ablegen einer Bitmap, die aus einem PictureBox- oder Image-Steuerelement stammt. (Als
Quelle kommt auch eine sonstige bildorientierte Komponente mit OLE-Drag-Fähigkeiten in
Frage.)
3. Ablegen einer Grafik im Zwischenformat WMF, die aus einem PictureBox- oder Image-Steu-
erelement stammt. (Als Quelle kommt auch eine sonstige WMF-orientierte Komponente mit
OLE-Drag-Fähigkeiten in Frage.)
4. Ablegen einer oder mehrerer Dateien, die aus einem FileListBox-Steuerelement, einem Fens-
ter des Windows Explorers oder einer sonstigen Komponente stammen, welche die Dateiaus-
wahl gestattet und OLE-Drag-Fähigkeiten besitzt. Dabei akzeptiert die Zielkomponente
diverse Textformate (TXT, INI, BAT, LOG, REG, HTM, HTML, INF, ASC) sowie alle gän-
gigen Bildformate und zeigt den Inhalt der Dateien nach Möglichkeit an. Durch einen einfa-
chen Mausklick in den Formularbereich lässt sich die Anzeige auf die jeweils nächste Datei
weiterschalten.
5. Für 1. bis 4. unterstützt die Zielkomponente das Kopieren der Inhalte und für 1. bis 3. (bei
gedrückter Taste (Umschalt)) zusätzlich das Verschieben der Inhalte.

505
Ereignisbehandlung

Da ein Formular in Visual Basic selbst nicht als Quellkomponente auftreten kann, werden Ver-
schiebeoperationen zur »Einbahnstraße« – der Inhalt geht also verloren! Der Aufwand, in das
Formular ein PictureBox-Steuerelement einzufügen, das anstelle des Formulars als Zielkompo-
nente auftritt, ist zwar vergleichsweise klein, hätte das Beispielprogramm aber doch unnötig
verkompliziert.
Ereignisbehandlung

Form2 dient als Testplattform für Form1 als Zielkomponente

Form1 nach Ablage der im vorigen Bild gezeigten FileListBox-Auswahl

Hier zunächst einmal der Code für Form1, der, bis auf eine gewisse Ausgestaltung des Funk-
tionsumfangs, den für den manuellen Modus skizzierten Aufbau besitzt.
'***********************************************************************
' Formularmodul : OLEDragDrop
' Autor : 2000 Rudolf Huttary
' Beschreibung : Zielformular für OLE-Drag&Drop-Operationen
'***********************************************************************
Private Dateien As DataObjectFiles ' für Dateienliste
Private DateiIdx As Integer ' Index für aktuell angezeigte Datei

506
OLE- Drag&Drop

Private Form2 As New Form2 ' Zweites Formular mit Auswahl

Private Sub Form_Load()


' Formulare untereinander aber in die Mitte des Bildschirms
Left = (Screen.Width – Width) / 2
Form2.Left = (Screen.Width – Form2.Width) / 2 ' Form2 wird generiert
Top = (Screen.Height – Form2.Height – Height) / 2
Form2.Top = Top + Height
Form2.Show ' zweites Formular anzeigen
End Sub

Ereignisbehandlung
Private Sub Form_Click()
If Not Dateien Is Nothing Then ' schon initialisiert?
DateiIdx = (1 + DateiIdx) Mod Dateien.Count ' nächste Datei
LadeDatei ' Dateiinhalt anzeigen
End If

End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim fs As Object
' Kopieren oder Verschieben?
BestimmeEffect Effect, Button, Shift
If Effect = vbDropEffectNone Then ' Operation nicht zulässig
Exit Sub ' und Tschüß
End If

' Bitmap?
If Data.GetFormat(vbCFDIB) Or Data.GetFormat(vbCFBitmap) Then
Picture = Data.GetData(vbCFDIB)
Caption = "Bitmap"
End If
' Metafile?
If Data.GetFormat(vbCFMetafile) Or Data.GetFormat(vbCFEMetafile) Then
Picture = Data.GetData(vbCFMetafile)
Caption = "Zwischendatei"
End If
' Ordinäre Zeichenfolge?
If Data.GetFormat(vbCFText) Or Data.GetFormat(vbCFRTF) Then
Picture = Nothing
Cls
Caption = "Zeichenfolge"
Print Data.GetData(vbCFText)
End If
' Datei(n)?
If Data.GetFormat(vbCFFiles) Then
DateiIdx = 0 ' Index initialisieren
Set Dateien = Data.Files ' Dateiliste übernehmen
LadeDatei ' Erste Datei anzeigen
End If

507
Ereignisbehandlung

End Sub

Private Sub Form_OLEDragOver(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single, _
State As Integer)
BestimmeEffect Effect, Button, Shift
If Not (Data.GetFormat(vbCFFiles) Or Data.GetFormat(vbCFDIB) Or _
Data.GetFormat(vbCFBitmap) Or Data.GetFormat(vbCFText) Or _
Data.GetFormat(vbCFMetafile) Or Data.GetFormat(vbCFEMetafile) _
Or Data.GetFormat(vbCFRTF)) _
Ereignisbehandlung

Then
Effect = vbDropEffectNone ' ablehnen,da OLE-Format unbekannt
End If

End Sub

Private Sub BestimmeEffect(Effect As Long, Button As Integer, Shift As Integer)


If Shift = 0 And (Effect And vbDropEffectCopy) > 0 Then
Effect = vbDropEffectCopy ' Kopieroperation setzen
ElseIf (Shift And vbShiftMask) = Shift _
And (Effect And vbDropEffectMove) > 0 _
Then ' nur die Umschalttaste?
Effect = vbDropEffectMove ' Verschiebeoperation setzen
Else
Effect = vbDropEffectNone ' Operation nicht unterstützt!
End If
End Sub

Private Sub LadeDatei()


Dim fs As Object
Dim Datei As String
Dim DateiTyp As String
Datei = UCase(Dateien(DateiIdx + 1))
' Kleiner Bug-Fix, da FileListbox bei Wurzelverzeichnissen
' einen Fehler macht ...
If Mid(Datei, 3, 2) = "\\" Then
Datei = Left(Datei, 3) + Mid(Datei, 5)
End If
Caption = Dateien(DateiIdx + 1) ' Dateinamen in Titelleiste anzeigen

Cls ' Text löschen


Picture = Nothing ' Bild Löschen
' TextDatei?
If InStrRev(Datei, ".TXT") Or InStrRev(Datei, ".INI") Or _
InStrRev(Datei, ".INI") Or InStrRev(Datei, ".BAT") Or _
InStrRev(Datei, ".LOG") Or InStrRev(Datei, ".REG") Or _
InStrRev(Datei, ".HTM") Or InStrRev(Datei, ".HTML") Or _
InStrRev(Datei, ".INF") Or InStrRev(Datei, ".ASC") _
Then ' Dateisystem-Objekt anlegen
Set fs = CreateObject("Scripting.FileSystemobject")
On Error Resume Next ' Falls Datei inzwischen unbekannt ...

508
OLE- Drag&Drop

Print fs.OpenTextfile(Datei).ReadAll ' Datei en bloc ausgeben


Else
On Error Resume Next ' Falls Format unbekannt, passiert nichts
Cls ' Text löschen
Picture = LoadPicture(Datei)
End If
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)


Unload Form2 ' zweites Formular ggf. entladen

Ereignisbehandlung
End Sub

Über die Load-Routine gibt es nicht viel zu sagen: Sie lädt das Testformular Form2 und ordnet
beide Formulare mittig untereinander auf dem Bildschirm an. Danach verharrt Form1 sozusagen
in Warteposition, bis es Ziel einer OLE-Drag&Drop-Operation wird. Die Behandlung der
zuerst eintreffenden OLEDragOver-Ereignisse besteht aus einer zweistufigen Analyse. Im ersten
Schritt kommt die Prozedur BestimmeEffect zum Aufruf, die anhand der Parameter Effect und
Shift bestimmt, ob der Benutzer den OLE-Inhalt kopieren oder verschieben ((Umschalt)
gedrückt) will, und Effect gleich geeignet setzt. Der zweite Schritt beinhaltet die Auswertung
des angebotenen Datenformats. Obwohl das Formular eigentlich nur mit dem Format vbCFPa-
lette nichts Rechtes anfangen kann (das Formular nimmt Paletten zwar problemlos entgegen,
man »sieht« nur nichts), ist die Auswertung im Hinblick auf künftige Erweiterungen »positiv«
formuliert – und nicht als Ausschluss, was natürlich eleganter wäre.
Die Logik für die Behandlung des OLEDragDrop-Ereignisses sieht nicht viel anderes aus: Der
Ermittlung der gewünschten Operation durch BestimmeEffect folgt eine Fallunterscheidung für
die verschiedenen akzeptierten Datenformate. Bei textuellen Inhalten beschränkt sich das For-
mular (notgedrungen) auf das Format vbCFText und nimmt die Darstellung mit Print vor.
Bitmaps sowie WMF- und EMF-Grafiken lassen sich ohne weitere Umstände in die Picture-
Eigenschaft übernehmen, was zugleich für eine automatische Darstellung sorgt. Ein wenig mehr
Arbeit macht dagegen das Format vbCFFiles, das beispielsweise vom Windows Explorer oder
von FileListBox-Komponenten geliefert wird. Der von GetData gelieferte Inhalt trägt in diesem
Fall den Typ DataObjectFiles und ist eine Files-Auflistung mit den für die OLE-Drag&Drop-
Operation markierten Dateinamen. Die Routine übernimmt die Liste in eine globale Variable
und ruft dann die Prozedur LadeDatei auf. Aufgabe von LadeDatei ist die Anzeige der durch
DateiIdx spezifizierten »aktuellen« Datei in der Liste. Die Prozedur versucht als Erstes, anhand
der Dateierweiterung herauszufinden, ob es sich bei der Datei um eine Textdatei handelt. Falls
ja, organisiert sie sich vom Windows Scripting Host eine Instanz des FileSystemObject-Objekts
und lässt sich von dieser die Textdatei en bloc als Zeichenfolge für die Ausgabe mit Print lie-
fern – die unkomplizierteste Methode, an den kompletten Inhalt einer Textdatei zu gelangen.
Liefert die Dateierweiterung keinen Hinweis auf eine Textdatei, nimmt die Prozedur an, dass es
sich um eine Grafikdatei handelt, und versucht, diese mittels LoadPicture zu laden. Falls das
schiefgeht, fängt die Routine den Fehler ab und leert nur das Formular.
Nun, die Rede war von einer Dateiliste und nicht nur von einer einzelnen Datei: Ein Klick auf
das Formular ruft LadeDatei für die jeweils nächste Datei in der Liste auf und erlaubt es dem
Benutzer, sich der Reihe nach alle Dateiinhalte anzusehen.
Von der »offiziellen« Seite her wäre das alles gewesen, was es über die Implementation von
Form1 zu sagen gibt. Bleibt noch der inoffizielle Teil, ein Work-around, der einen Implementati-
onsfehler in der FileListBox-Komponente umschifft. Als Quellkomponente in einer OLE-
Drag&Drop-Operation setzt die Komponente in der Files-Auflistung nämlich einen fehlerhaf-
ten Pfad, wenn die Auswahl dem Wurzelverzeichnis eines Laufwerks angehört: Aus irgendei-
nem Grund enthält er einen Schrägstrich zu viel. Der Fehler ist in den Titelleisten der beiden
Formulare zu sehen (vgl. Abbildungen) und wird gar vom Windows Explorer mit der lapidaren

509
Ereignisbehandlung

Fehlermeldung »Dateisystemfehler 1026« bedacht, wenn dieser als Zielkomponente getestet


wird. Der Work-around tut nichts weiter, als den überflüssigen Schrägstrich zu eliminieren. Ein
Versuch, den Fehler aufseiten der Quellkomponente in der Behandlungsroutine für das Ereignis
OLEStartDrag zu korrigieren (was eigentlich der vernünftigere Ansatz wäre), scheitert leider, da
die Files-Eigenschaft des DataObject-Objekts zur Laufzeit schreibgeschützt ist. Bleibt also zu
hoffen, dass Microsoft den Fehler mit der nächsten Version von Visual Basic korrigiert.
Die Implementation von Form2 gibt nicht viel mehr her, als das, was bereits im Abschnitt
»Anwendung« besprochen wurde. Die Steuerelemente Text1, Image1 und Picture1 arbeiten als
Quell- und Zielkomponenten im Automatikmodus. Einzig das FileListBox-Steuerelement File1
ist für den manuellen Modus eingerichtet und zeigt dem Benutzer Smiley-Symbole als Feedback
während einer OLE-Drag&Drop-Operation an:
Ereignisbehandlung

'***********************************************************************
' Formularmodul : Form2
' Autor : 2000 Rudolf Huttary
' Beschreibung : Quellformular für OLE-Drag&Drop-Operationen
'***********************************************************************
Private EffectCopyIcon As Picture
Private EffectNoneIcon As Picture
Private AltesScreenIcon As Picture
Private AlterScreenPointer As Integer

Private Sub Form_Load()


Caption = File1.Path ' Pfad in Titelleiste anzeigen
End Sub

Private Sub Drive1_Change()


Dir1 = Drive1 ' DirListBox aktualisieren
End Sub

Private Sub Dir1_Change()


File1 = Dir1 ' FileListBox aktualisieren
End Sub

Private Sub File1_PathChange()


Caption = File1.Path ' Pfad in Titelleiste anzeigen
End Sub

Private Sub File1_OLEStartDrag(Data As DataObject, _


AllowedEffects As Long)
Set AltesScreenIcon = Screen.MouseIcon ' Alte Form merken
AlterScreenPointer = Screen.MousePointer
Screen.MousePointer = vbCustom ' Benutzerdefinierte Form
If EffectCopyIcon Is Nothing Then ' Form schon geladen?
Set EffectCopyIcon = LoadPicture(App.Path + "\EffectCopy.ico")
Set EffectNoneIcon = LoadPicture(App.Path + "\EffectNone.ico")
End If
Caption = Data.Files(1) ' Erste Datei in Titelleiste anzeigen
' das deckt Implementationsfehler bei
' Wurzelverzeichnis auf
End Sub

51 0
DiaProjektor – SDI- Formulare synchronisieren

Private Sub File1_OLEGiveFeedback(Effect As Long, _


DefaultCursors As Boolean)
Select Case Effect
Case vbDropEffectCopy ' fürs Kopieren
Set Screen.MouseIcon = EffectCopyIcon ' Andere Form setzen
Case vbDropEffectNone ' Operation nicht möglich
Set Screen.MouseIcon = EffectNoneIcon ' Andere Form setzen
Case Else
DefaultCursors = True
End Select

DiaProjektor – SDI- Formulare synchronisieren


DefaultCursors = False ' Eigene Form verwenden
End Sub

Private Sub File1_OLECompleteDrag(Effect As Long)


Screen.MouseIcon = AltesScreenIcon ' Alte Form setzen
Screen.MousePointer = AlterScreenPointer ' Alten Zeiger setzen
End Sub

DiaProjektor – SDI- Formulare synchronisieren


Das in diesem Abschnitt vorgestellte Programm DiaProjektor dürfte das umfangreichste Bei-
spiel in diesem Buch sein. Das Projekt wurde bewusst als Kontrast zu den sonst eher schlicht
gehaltenen Beispielprogrammen ausgewählt, da es nicht nur den logischen Aufbau einer durch-
schnittlichen Anwendung mit mehreren Ansichten und einer ganzen Reihe von Menübefehlen
demonstriert, sondern auch, dass »der Teufel letztlich doch wieder im Detail steckt«. Als recht
ordentliches Präsentationsprogramm für JPEGs und GIFs verdient das Programm schon fast
das Attribut »fertige Anwendung«, wären da nicht noch einige Punkte auf der Wunschliste wie
OLE-Drag&Drop, Abspeichern von Indexansichten, Optionen-Dialog usw. Dennoch, die Fea-
ture-Liste ist beachtlich und lässt bereits auf einen ganzen Sack voller Konzepte schließen, deren
Implementation es am vorliegenden Quellcode zu diskutieren gilt.
● Dateiauswahl: einzeln, mehrfach, ganzes Verzeichnis
● Bildwechsel: wahlweise Menüsteuerung, Tastatursteuerung, Maussteuerung, Zeitgeber-
steuerung
● Anzeigen: Vollbildanzeige und Fensteranzeige
● Voller Funktionsumfang auch in Vollbildansicht durch Tastatursteuerung und Kontext-
menü
● Skalierung: automatisch auf verfügbaren Anzeigebereich
● Ansichten: »Einzeldia« und »Indexprint«
● Diaauswahl in Indexansicht per Maus
● Caching der jeweils letzten Indexansicht in beiden Anzeigearten
● Infodialog
Damit Sie eine gewisse Vorstellung davon erhalten, was Sie auf der Codeseite erwartet,
zunächst eine Funktionsbeschreibung des Programms sowie der Benutzerschnittstelle: Beim
Start konfrontiert Sie das Programm umgehend mit dem Standarddialog DATEI ÖFFNEN, über
den sich die Bilder für die Diashow auswählen lassen. Nach Wahl des Verzeichnisses können
Sie entweder den Vorschlag »(alle)« akzeptieren, um daraus alle im Verzeichnis befindlichen
Bilddateien in den Formaten BMP, JPG und GIF (in eben dieser Reihenfolge) zu laden, oder per
Mehrfachauswahl nur die Dateien auswählen, die Sie interessieren. Der Vollständigkeit halber
kann eine Mehrfachauswahl auch aus einer einzigen Datei bestehen, in diesem Fall dürfte die

51 1
DiaProjektor – SDI- Formulare synchronisieren

Diashow aber recht eintönig werden. Falls Sie den Dialog abbrechen, erhalten Sie ein leeres For-
mular und können über das Menü DATEI den Befehl wiederholen oder das Programm regulär
beenden. Ansonsten präsentiert Ihnen das Programm in der Indexansicht die (maximal) zwan-
zig ersten Bilder (vgl. Abbildung) beschriftet mit dem jeweiligen Dateinamen. Sie können jeder-
zeit zwischen der Fensteranzeige und der Vollbildanzeige wechseln, indem Sie die Taste (Esc)
drücken oder den entsprechenden Befehl aus dem DATEI-Menü bzw. Kontextmenü auswählen.
Um den Index-Print für die nächsten zwanzig Bilder zu erhalten, drücken Sie eine der Tasten
(Rechts), (Oben) oder (Bild-Oben) oder Sie navigieren über das Menü (Bild). Die Navigation
in umgekehrter Richtung erfolgt analog.
DiaProjektor – SDI- Formulare synchronisieren

Indexansicht der Programms Diaprojektor

Falls Sie in die Ansicht »Einzeldia« umschalten wollen, klicken Sie einfach auf das gewünschte
Bild oder Sie wechseln die Ansicht über den entsprechenden Menübefehl. Wie nicht anderes zu
erwarten, ist die Navigation auch in dieser Ansicht gleichfalls wieder über die Cursortasten mög-
lich, mit dem Unterschied, dass die Tasten (Oben), (Bild-Oben) bzw. (Unten), (Bild-Unten) in
das nächste Indexblatt und somit zwanzig Einzelbilder weiter- bzw. zurückführen. Außerdem
übernimmt die linke Maustaste nun die Funktion »Nächstes Bild«. Wie in der Abbildung zu
sehen, bietet das Menü (Bild) zudem noch zwei TIMER-Funktionen an, die eine automatische
Fortschaltung auf das jeweils nächste Einzeldia (nach dem letzen Dia kommt wieder das erste)
vornehmen. Die Wirksamkeit dieser Funktionen bleibt allerdings auf diese Ansicht beschränkt.
Um den Funktionsumfang auch in der Vollbildanzeige aufrechterhalten zu können, pflegt das
Programm ein Kontextmenü, das alle über die Menüleiste angebotenen Menübefehle auflistet.

51 2
DiaProjektor – SDI- Formulare synchronisieren

DiaProjektor – SDI- Formulare synchronisieren


Die Einzeldiaansicht von DiaProjektor

Kontextmenü und Dateimenü von DiaProjektor

Das Projekt enthält drei Formulare, MainForm, FullScreenForm und About, wobei 95 Prozent des
Codes im Modul MainForm konzentriert sind. Diese Verteilung hat sich aufgrund der Tatsache
ergeben, dass MainForm und FullScreenForm im Wesentlichen dieselbe Logik verwenden können.
Gäbe es in Visual Basic eine Möglichkeit, ein Rahmenfenster im Nachhinein in ein Fenster ohne
Rahmen zu wandeln und umgekehrt, wäre das Formular FullScreenForm (und die gesamte für
die Synchronisation der beiden Formulare notwendige Logik) nicht notwendig gewesen. So
aber gibt das Programm gute Einsichten in die Prinzipien der wechselseitigen Steuerung von

51 3
DiaProjektor – SDI- Formulare synchronisieren

SDI-Formularen. Das dritte Formular, ein reiner Infodialog, wird als gebundener – oder wie es
immer so schön heißt: »modaler« – Dialog über das Hilfemenü ? aufgerufen. Die Logik dafür
ist äußerst primitiv.
DiaProjektor – SDI- Formulare synchronisieren

Der Infodialog von DiaProjektor

Das Programmdesign
Wer genau hinsieht, wird es am Programmdesign erkennen, dass der Code von der Einzeldiaan-
sicht in der Fensteranzeige ausgehend über die Vollbildanzeige zur Indexansicht hin »gewach-
sen« ist. Im letzten Schritt erfolgte schließlich die Implementation des Caching der jeweils aktu-
ellen Indexansicht als Optimierungsmaßnahme für einen schnelleren Bildaufbau. Bei einem
monolithischen Entwurf wäre die Logik vermutlich ein wenig einfacher ausgefallen. Doch in
der Praxis wird man nicht wegen jedem neuen Feature gleich »das ganze Kartenspiel neu
mischen«. Für die Analyse des Programms bietet sich der gleiche Weg an: vom Einfachen zum
Komplexen und Feature für Feature. Zuerst aber das Listing im Zusammenhang.
'***********************************************************************
' Projekt : DiaProjektor
' Autor : 2000 Rudolf Huttary
' Formularmodul : MainForm
'***********************************************************************

' Allgemeine Definitionen


Option Explicit
Const cIdxZeilen = 4
Const cIdxSpalten = 5
Const cLargeStep = cIdxZeilen * cIdxSpalten ' Seitenwert für Bildwechsel
Enum vbCaching
cCaching = True
cNoCaching = False
End Enum

Private ActualForm As Form ' aktuelles Formular


Private VollbildForm As Form ' Formular für Vollbildmodus

Private FileNames() As String ' Array für Dateinamen


Private FileIndex As Long ' Index für aktuelle Datei
Private bIndexView As Boolean ' Schalter für Indexansicht
Private Beendet As Boolean

51 4
Das Programmdesign

'***********************************************************************
' Code für Formularereignisse
'***********************************************************************
Private Sub Form_Load()
Set ActualForm = Me ' Fensteranzeige als Starteinstellung
ReDim FileNames(0 To 1)
Show
mnuÖffnen_Click ' Ordner abfragen
End Sub

DiaProjektor – SDI- Formulare synchronisieren


Public Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
' Tastaturschnittstelle
Select Case KeyCode
Case vbKeyHome ' zum ersten Bild
mnuBildErstes_Click
Case vbKeyLeft ' ein Bild zurück mit Überlauf
mnuBildVoriges_Click
Case vbKeyRight ' ein Bild vor mit Überlauf
mnuBildNächstes_Click
Case vbKeyEscape ' Vollbildanzeige/Fensteranzeige
mnuVollbild_Click
Case vbKeyUp, vbKeyPageUp ' mehrere Bilder weiter mit Überlauf
FileIndex = (FileIndex + cLargeStep – 1) Mod UBound(FileNames)
mnuBildNächstes_Click
Case vbKeyDown, vbKeyPageDown ' mehrere Bilder zurück mit Überlauf
FileIndex = FileIndex – cLargeStep – 1
If FileIndex < 1 Then FileIndex = FileIndex + UBound(FileNames)
mnuBildNächstes_Click
Case vbKeyF3 ' Timer ein/aus: 3 Sekunden
If Not mnuTimer3.Enabled Then Exit Sub
mnuTimer3_Click
Case vbKeyF5 ' Timer ein/aus: 5 Sekunden
If Not mnuTimer5.Enabled Then Exit Sub
mnuTimer5_Click
End Select
End Sub

Private Sub Form_Resize()


If Height < 1000 Then Height = 1000 ' minimale Größe erzwingen
If FileIndex Then
Anzeigen cNoCaching
End If
End Sub

Public Sub Form_MouseDown(Button As Integer, Shift As Integer, _


x As Single, y As Single)
If Button = vbLeftButton Then
' In Indexansicht wählt Klick Einzeldia aus
If bIndexView Then
' Treffertest, um Index des Einzeldias zu berechnen
FileIndex = FileIndex + _

51 5
DiaProjektor – SDI- Formulare synchronisieren

Int(y / ActualForm.ScaleHeight * cIdxZeilen) * cIdxSpalten + _


Int(x / ActualForm.ScaleWidth * cIdxSpalten)
If FileIndex > UBound(FileNames) Then
FileIndex = UBound(FileNames)
End If
mnuIndex_Click
ElseIf mnuBildNächstes.Enabled Then
mnuBildNächstes_Click ' Blättern
End If
Else
DiaProjektor – SDI- Formulare synchronisieren

Kontextmenü ' Kontextmenü anzeigen


End If
End Sub

Private Sub Form_Unload(Cancel As Integer)


Beendet = True ' wegen PopupMenu!
' Vollbildformular entladen
If Not (VollbildForm Is Nothing) Then Unload VollbildForm
End Sub

'***********************************************************************
' Code für Menübefehle
'***********************************************************************
Private Sub mnuDateiErstes_Click()
mnuBildErstes_Click
End Sub

Private Sub mnuDateiNächstes_Click()


mnuBildNächstes_Click
End Sub

Private Sub mnuDateiVoriges_Click()


mnuBildVoriges_Click
End Sub

Private Sub mnuDateiTimer3_Click()


mnuTimer3_Click
End Sub

Private Sub mnuDateiTimer5_Click()


mnuTimer5_Click
End Sub

Private Sub mnuIndex_Click()


DiaIndex cCaching
End Sub

Private Sub mnuVollbild_Click() ' Umschalten: Einzeldia/Vollb.


' Aktivierung durch Menübefehl Vollbildanzeige/Fensteranzeige oder Esc
Static Viewstate As Integer
ResetTimer

51 6
Das Programmdesign

If Viewstate = 0 Then ' erster Aufruf?


Set VollbildForm = New FullScreenForm ' Vollbildformular anlegen
Set VollbildForm.FirstForm = Me ' Referenz auf MainForm
Viewstate = 1
End If
If Viewstate = 1 Then ' zur Vollbildanzeige?
Visible = False
Set ActualForm = VollbildForm
mnuVollbild.Caption = "&Fensteranzeige"
VollbildForm.Show

DiaProjektor – SDI- Formulare synchronisieren


Viewstate = 2
Else ' zur Fensteranzeige
VollbildForm.Visible = False
Set ActualForm = Me
mnuVollbild.Caption = "&Vollbildanzeige"
Show
Viewstate = 1
End If
Anzeigen cCaching
End Sub

Private Sub mnuÖffnen_Click()


Dim bArrayNichtLeer As Boolean

StopTimer

' Standdarddialog initialisieren und aufrufen


dlgDateiOpen.Filter = "*.jpg;*.gif;*.bmp|*.jpg;*.gif;*.bmp"
dlgDateiOpen.CancelError = True
dlgDateiOpen.FileName = "(alle)"
dlgDateiOpen.Flags = cdlOFNAllowMultiselect + cdlOFNExplorer _
+ cdlOFNLongNames
On Error GoTo Abbruch ' Falls Benutzer abbricht
dlgDateiOpen.ShowOpen ' Standarddialog "Öffnen"

' Der folgende Code wird nicht ausgeführt,


' wenn der Öffnen-Dialog abgebrochen wurde!
FileNames(0) = Left(dlgDateiOpen.FileName, _
InStrRev(dlgDateiOpen.FileName, "\")) ' Pfad
FileIndex = 1 ' ab erstem Bild anzeigen
If dlgDateiOpen.FileTitle = "(alle).jpg" Then
ReDim Preserve FileNames(0 To 0)
' FS_FindFiles FileNames ' mit FileSystemObject-Objekt
FindFiles FileNames ' mit Dir-Funktion
bIndexView = False ' Indexansicht vorbereiten
ElseIf InStr(dlgDateiOpen.FileName, Chr(0)) Then
FileNames = Split(dlgDateiOpen.FileName, Chr(0))
FileNames(0) = FileNames(0) + "\"
bIndexView = False ' Indexansicht vorbereiten
Else
ReDim FileNames(0 To 1)

51 7
DiaProjektor – SDI- Formulare synchronisieren

FileNames(1) = dlgDateiOpen.FileTitle
bIndexView = True ' Einzeldiaansicht vorbereiten
End If

' Menübefehle zum Bildwechsel aktivieren


bArrayNichtLeer = FileNames(1) <> "" ' Wurden Dateien gefunden?
mnuBildErstes.Enabled = bArrayNichtLeer
mnuBildNächstes.Enabled = bArrayNichtLeer
mnuBildVoriges.Enabled = bArrayNichtLeer
mnuTimer3.Enabled = bArrayNichtLeer
DiaProjektor – SDI- Formulare synchronisieren

mnuTimer5.Enabled = bArrayNichtLeer
DiaIndex cNoCaching ' Bild(er) Anzeigen

Abbruch:
End Sub

Private Sub mnuBeenden_Click()


On Error Resume Next
Unload Me
End Sub

Private Sub mnuBildErstes_Click() ' Erstes Bild anzeigen


ResetTimer
FileIndex = 1
Anzeigen cCaching
End Sub

Private Sub mnuBildNächstes_Click() ' Nächstes Bild anzeigen


ResetTimer
If bIndexView Then ' Indexansicht?
If FileIndex + cLargeStep > UBound(FileNames) Then ' Überlauf?
FileIndex = 1
Else
FileIndex = FileIndex + cLargeStep
End If
Else
FileIndex = FileIndex Mod UBound(FileNames) + 1
End If
Anzeigen cCaching
End Sub

Private Sub mnuBildVoriges_Click() ' Voriges Bild anzeigen


ResetTimer
If bIndexView Then ' Indexansicht?
If FileIndex – cLargeStep < 1 Then ' Unterlauf?
FileIndex = ((UBound(FileNames) – 2) \ cLargeStep) * cLargeStep + 1
Else
FileIndex = FileIndex – cLargeStep
End If
Else
FileIndex = (FileIndex – 2 + UBound(FileNames)) _

51 8
Das Programmdesign

Mod UBound(FileNames) + 1
End If
Anzeigen cCaching
End Sub

Private Sub mnuTimer3_Click()


ResetTimer
mnuTimer5.Checked = False ' Häkchen aktualisieren
mnuDateiTimer5.Checked = False
If mnuTimer3.Checked = False Then ' Timer schon gesetzt?

DiaProjektor – SDI- Formulare synchronisieren


Timer1.Interval = 3000 ' Nein: Timer auf 3 Sekunden
Timer1.Enabled = True
mnuTimer3.Checked = True
mnuDateiTimer3.Checked = True
Else ' Ja: ausschalten
Timer1.Enabled = False
mnuTimer3.Checked = False
mnuDateiTimer3.Checked = False
End If
End Sub

Private Sub mnuTimer5_Click()


ResetTimer
mnuTimer3.Checked = False ' Häkchen aktualisieren
mnuDateiTimer3.Checked = False
If mnuTimer5.Checked = False Then ' Timer schon gesetzt?
Timer1.Interval = 5000 ' Nein: Timer auf 5 Sekunden
Timer1.Enabled = True
mnuTimer5.Checked = True
mnuDateiTimer5.Checked = True
Else ' Ja: ausschalten
Timer1.Enabled = False
mnuTimer5.Checked = False
mnuDateiTimer5.Checked = False
End If
End Sub

Private Sub mnuAbout_Click() ' Info-Dialog anzeigen


About.Show vbModal
End Sub

Private Sub Timer1_Timer()


mnuBildNächstes_Click
End Sub

'***********************************************************************
' Code für Hilfsroutinen
'***********************************************************************

Private Sub ResetTimer()


If Timer1.Enabled Then

51 9
DiaProjektor – SDI- Formulare synchronisieren

Timer1.Enabled = False
Timer1.Enabled = True
End If
End Sub

Private Sub StopTimer()


Timer1.Enabled = False ' Timer ausschalten
Timer1.Interval = 0
mnuTimer3.Checked = False
mnuTimer5.Checked = False
DiaProjektor – SDI- Formulare synchronisieren

mnuDateiTimer3.Checked = False
mnuDateiTimer5.Checked = False
mnuTimer3.Enabled = False
mnuTimer5.Enabled = False
mnuDateiTimer3.Enabled = False
mnuDateiTimer5.Enabled = False
End Sub

' Lädt Bild von Datei und zeichnet es in maximaler Größe


' im übergebenen Bereich
Private Sub ShowDia(Index As Long, Ansicht As Form, _
Optional x As Single, Optional y As Single, _
Optional b As Single, Optional h As Single)

Dim Pic As Picture


Dim BildBreite, BildHöhe

If b * h = 0 Then ' Parameter weggelassen?


b = Ansicht.ScaleWidth ' Abmessungen von Client-Bereich
h = Ansicht.ScaleHeight ' verwenden
End If

' Bild einlesen


On Error GoTo Fehlerbehandlung ' Falls was schief geht
Set Pic = LoadPicture(FileNames(Index))
Caption = "Bild" + Str(Index) + " von" + Str(UBound(FileNames)) + _
" – " + FileNames(0) + FileNames(Index)

' maximale Bildgröße berechnen


BildHöhe = Pic.Height
BildBreite = b
BildHöhe = BildHöhe * BildBreite / Pic.Width
If BildHöhe > h Then
BildHöhe = h
BildBreite = Pic.Width * BildHöhe / Pic.Height
End If
On Error GoTo 0

' Bild im aktuellen Formular zentriert zeichnen


Ansicht.Line (x, y)-(x + b, y + h), vbBlack, BF
Ansicht.PaintPicture Pic, x + (b – BildBreite) / 2, _

520
Das Programmdesign

y + (h – BildHöhe) / 2, BildBreite, BildHöhe


Exit Sub

Fehlerbehandlung:
Dim Text As String
With Ansicht
If Not bIndexView Then
Text = "Bildformat nicht erkannt"
' Fehlertext mittig ausgeben
.Cls

DiaProjektor – SDI- Formulare synchronisieren


.CurrentX = (.ScaleWidth – .TextWidth(Text)) / 2
.CurrentY = (.ScaleHeight – .TextHeight(Text)) / 2
' With funktioniert bei Print und Line nicht!!!
Caption = "Bildformat nicht erkannt"
Ansicht.Print Caption
Else
Ansicht.Line (x, y)-(x + b, y + h), RGB(50, 50, 50), BF
End If
End With
End Sub

' Fügt alle auf *.jpg, *.gif oder *.bmp endenden Dateinamen
' in das Array FileNames ein. Erweitert Array!
Private Sub FindFiles(FileNames() As String)
Dim Name As String
Dim UName As String

Name = Dir(FileNames(0) + "*.*") ' Erster Dateiname


UName = UCase(Name)
While Name <> ""
If InStr(UName, ".JPG") Or InStr(UName, ".GIF") Or _
InStr(UName, ".BMP") Then
ReDim Preserve FileNames(0 To UBound(FileNames) + 1) ' Vergrößern
FileNames(UBound(FileNames)) = Name ' Dateiname einfügen
End If
Name = Dir ' nächster Dateiname
UName = UCase(Name)
Wend
End Sub

' Fügt alle auf *.jpg, *.gif oder *.bmp endenden Dateinamen
' in das Array FileNames ein. Erweitert Array!
Private Sub FS_FindFiles(FileNames() As String)
Dim fs As New FileSystemObject
Dim Datei As File
Dim Path As Folder
Dim UName As String
Dim Idx As Long ' Zähler

Set Path = fs.GetFolder(FileNames(0))


Idx = UBound(FileNames)

521
DiaProjektor – SDI- Formulare synchronisieren

ReDim FileNames(Idx To Path.Files.Count) ' mehr können es nicht werden

For Each Datei In Path.Files


UName = UCase(Datei.Name) ' Schreibweise einheitlich
If InStr(UName, ".JPG") Or InStr(UName, ".GIF") Or _
InStr(UName, ".BMP") Then
Idx = Idx + 1
FileNames(Idx) = Datei.Name
End If
Next
DiaProjektor – SDI- Formulare synchronisieren

ReDim Preserve FileNames(0 To Idx) ' Reduktion auf tatsächl. Anzahl


End Sub

' Schaltet zwischen Einzeldia und Indexansicht


Private Sub DiaIndex(Optional Caching As vbCaching)
If bIndexView Then ' Schalter setzen
mnuTimer3.Enabled = True ' Timer-Befehle zulassen
mnuTimer5.Enabled = True
mnuDateiTimer3.Enabled = True
mnuDateiTimer5.Enabled = True
mnuIndex.Caption = "&Indexansicht" ' Menübefehl aktualisieren
bIndexView = False
Else
StopTimer
mnuIndex.Caption = "&Einzeldia"
bIndexView = True
End If
Anzeigen Caching
End Sub

' Stellt Indexansicht zusammen


Private Function ShowIndex(ByVal Ansicht As Form) As Boolean
Dim x As Single, y As Single, b As Single, h As Single
Dim Idx As Long, EndIndex As Long
Static statCount As Long
Dim dynCount As Long

With Ansicht
' Vorbereitungen
statCount = (statCount + 1) Mod 10000 ' stat. Rekursionsz. pflegen
dynCount = statCount ' dyn. Rekursionszähler init.

b = .ScaleWidth / cIdxSpalten ' Spaltenbreite errechnen


h = .ScaleHeight / cIdxZeilen ' Zeilenhöhe errechnen
EndIndex = (FileIndex + cLargeStep)
.FontSize = 7 ' Schriftgröße vorgeben
.Cls

' Bilder ab Startindex ausgeben


For Idx = FileIndex To EndIndex
x = ((Idx – FileIndex) Mod cIdxSpalten) * b + b * 0.025

522
Das Programmdesign

y = ((Idx – FileIndex) \ cIdxSpalten) * h


ShowDia Idx, Ansicht, x, y, b * 0.95, h * 0.9

' Ereignisse zulassen. Formular geschlossen?


' Indexansicht beendet? Rekusiver Aufruf?
If DoEvents = 0 Or bIndexView = False _
Or statCount <> dynCount Then
' statCount = statCount – 1 ' Rekursionszähler pflegen
Exit Function
End If

DiaProjektor – SDI- Formulare synchronisieren


' Dateiname unter Bild setzen
If Idx <= UBound(FileNames) Then
.CurrentX = x
.CurrentY = y + h – .TextHeight("a")
Ansicht.Print FileNames(Idx)
End If
Next Idx
End With
ShowIndex = True
End Function

' Zeigt einzelnes Bild oder Index an. Verwendet bei Indexansicht
' das Anzeige-Steuerelement des jeweilgen Formulars als Cache
Private Sub Anzeigen(Optional Caching As vbCaching)
Static LetzterVollbIdx As Long
Static LetzterFensterIdx As Long
Dim Idx As Long

If bIndexView Then ' Indexansicht?


' Index für erstes Bild der Indexansicht ausrechnen
FileIndex = FileIndex – FileIndex Mod (cIdxZeilen * cIdxSpalten) + 1
If FileIndex > UBound(FileNames) Then FileIndex = 1
If Visible Then ' Fensteranzeige'
' Cache aktuell?
If FileIndex = LetzterFensterIdx And Caching Then
PaintPicture Cache, 0, 0 ' Ja: Cache zeichnen
Else
Idx = FileIndex ' Nein: Startindex merken
If ShowIndex(ActualForm) Then ' Regulär beendet?
Cache = Image ' Cache aktualisieren
LetzterFensterIdx = Idx ' Index für Cache merken
Else
Exit Sub
End If
End If
Else ' Vollbildanzeige
' Cache aktuell?
If FileIndex = LetzterVollbIdx And Caching Then
VollbildForm.PaintPicture VollbildForm.Cache, 0, 0 ' aus Cache
Else

523
DiaProjektor – SDI- Formulare synchronisieren

Idx = FileIndex ' Nein: Startindex merken


If ShowIndex(ActualForm) Then ' Regulär beendet?
Set VollbildForm.Cache = VollbildForm.Image ' in Cache
LetzterVollbIdx = Idx ' Index für Cache merken
Else
Exit Sub
End If
End If
End If
Caption = "Index ab Bild " & FileIndex & " – " _
DiaProjektor – SDI- Formulare synchronisieren

& FileNames(FileIndex)
Else
ShowDia FileIndex, ActualForm ' Einzeldiaansicht
End If
End Sub

Private Sub Kontextmenü()


mnuDateiErstes.Visible = True ' unsichtbare Befehle in Dateimenü
mnuDateiNächstes.Visible = True
mnuDateiVoriges.Visible = True
mnuDateiTimer3.Visible = True ' sichtbar machen
mnuDateiTimer5.Visible = True
PopupMenu mnuDatei
If Not Beendet Then ' Formular noch geöffnet?
mnuDateiErstes.Visible = False ' Befehle wieder verbergen
mnuDateiNächstes.Visible = False
mnuDateiVoriges.Visible = False
mnuDateiTimer3.Visible = False
mnuDateiTimer5.Visible = False
End If
End Sub
'***********************************************************************
' Projekt : DiaProjektor
' Autor : 2000 Rudolf Huttary
' Formularmodul : FullScreenForm
'***********************************************************************

Public FirstForm As Form

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)


' Tastaturbehandlung übernimmt das Formular MainForm
FirstForm.Form_KeyDown KeyCode, Shift
End Sub

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


FirstForm.Form_MouseDown Button, Shift, X, Y
End Sub
'***********************************************************************
' Projekt : DiaProjektor
' Autor : 2000 Rudolf Huttary

524
Info- Dialog als gebundenes Formular aufrufen

' Formularmodul : About.frm


'***********************************************************************

Private Sub OK_Click()


Unload Me
End Sub

Ein nur oberflächlicher Blick auf die drei Codemodule verrät bereits, dass die gesamte Steue-
rung des Programmablaufs im Modul MainForm zu finden ist. Grund genug, die Module Full-
ScreenForm und About schnell und nachhaltig abzuhaken.

DiaProjektor – SDI- Formulare synchronisieren


Info- Dialog als gebundenes Formular aufrufen
Das eigentlich nur zur Demonstration des gebundenen Aufrufs sowie der Vollständigkeit halber
eingeführte Formular About tut nichts weiter, als sich nach einem Klick auf die Schaltfläche OK
gleich mittels Unload Me wieder zu verabschieden – die meiste Arbeit steckt somit in der visuellen
Gestaltung. Der Show-Aufruf für das Formular findet sich im Modul MainForm, in der für den
Menübefehl ? zuständigen Behandlungsroutine mnuAbout_Click:
Private Sub mnuAbout_Click() ' Info-Dialog anzeigen
About.Show vbModal
End Sub
Immerhin hat der so einfach wirkende Aufruf zwei Besonderheiten: Erstens bewirkt der Wert
vbModal für den optionalen Parameter, dass die Programmausführung von MainForm darauf war-
tet, bis das aufgerufene Formular die Kontrolle wieder zurückgibt – daher die Bezeichnung
gebundenes Formular. Zweitens ist noch nicht einmal die Vereinbarung einer Objektvariable
für den Aufruf des Formulars erforderlich, weil Visual Basic für jedes Formular eines Projekts
implizit eine globale Objektvariable mit dem Bezeichner des Formulardatentyps vereinbart. Auf
diese Weise ergibt sich die Möglichkeit der anonymen Instanziierung, die letztlich gar nicht
anonym ist.

Ereignisse delegieren und Instanziierung durch One- Shot- Logik


Das Formular FullScreenForm steht About an Einfachheit um nicht viel nach. Da es für die Voll-
bildanzeige bestimmt ist, muss seine BorderStyle-Eigenschaft bereits zur Entwurfszeit auf »0 –
Kein« gesetzt werden, weil dies zur Laufzeit nicht mehr möglich ist. Die einzige Aktivität des
Formulars besteht darin, eintreffende KeyDown- und MouseDown-Ereignisse unbesehen an seinen
Aufrufer weiterzuleiten (Delegation). So also kann MainForm »am Drücker« bleiben, auch wenn
FullScreenForm den Fokus hat. Die Umsetzung erfordert eine mit globalem Geltungsbereich ver-
einbarte Variable FirstForm, die der Aufrufer mit einer Referenz auf sich selbst initialisieren
muss, und natürlich eine Public-Deklaration der jeweiligen Behandlungsroutinen aufseiten des
Aufrufers:
' Im Modul FullScreenForm ...
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
' Tastaturbehandlung übernimmt das Formular MainForm
FirstForm.Form_KeyDown KeyCode, Shift
End Sub

' Im Modul MainForm ...


Public Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
' Tastaturschnittstelle
Select Case KeyCode
...

525
DiaProjektor – SDI- Formulare synchronisieren

Die Instanziierung des Formulars hätte man freilich in die Load- oder gar Initialize-Behand-
lung von MainForm verlegen können, nachdem die entsprechenden Routinen ja nur einmal zum
Aufruf kommen. Um keine Ressourcen zu vergeuden (vielleicht wird der Benutzer gar nicht in
die Vollbildanzeige schalten?), geschieht sie im vorliegenden Fall jedoch erst bei Bedarf. Näm-
lich beim ersten Aufruf der Routine mnuVollbild_Click von MainForm. Deren Aufgabe besteht
darin, zwischen der Fensteranzeige und der Vollbildanzeige hin- und herzuschalten. Zur Ver-
meidung einer wiederholten Instanziierung setzt die Routine eine One-Shot-Logik ein, welche
die einmalige Ausführung des New-Aufrufs garantiert. Nachdem die Routine ohnehin darüber
Buch führen muss, welche Art der Anzeige gerade aktiv ist, bietet sich eine statische Integer-
Variable Viewstate als Zustandsvariable an, die Visual Basic bekanntlich nur für den ersten
DiaProjektor – SDI- Formulare synchronisieren

Eintritt in die Routine mit 0 initialisiert. Natürlich könnte man VollbildForm auch auf Nothing
abfragen und ansonsten mit der Visible-Eigenschaft beispielsweise von MainForm arbeiten. Der
Show-Aufruf, der hier nichts anders tut, als die Visible-Eigenschaft auf True zu setzen, erfolgt –
wie angedeutet – gleichfalls in Abhängigkeit von Viewstate in derselben Routine.
Private Sub mnuVollbild_Click() ' Umschalten: Einzeldia/Vollbild
' Aktivierung durch Menübefehl Vollbildanzeige/Fensteranzeige oder Esc
Static Viewstate As Integer
ResetTimer
If Viewstate = 0 Then ' erster Aufruf?
Set VollbildForm = New FullScreenForm ' Vollbildformular anlegen
Set VollbildForm.FirstForm = Me ' Referenz auf MainForm
Viewstate = 1
End If
If Viewstate = 1 Then ' zur Vollbildanzeige?
Visible = False
Set ActualForm = VollbildForm
mnuVollbild.Caption = "&Fensteranzeige"
VollbildForm.Show
Viewstate = 2
Else ' zur Fensteranzeige
VollbildForm.Visible = False
Set ActualForm = Me
mnuVollbild.Caption = "&Vollbildanzeige"
Show
Viewstate = 1
End If
Anzeigen cCaching
End Sub

Bei VollbildForm handelt es sich um eine auf Modulebene vereinbarte Objektvariable des Typs
Form, die somit in allen Routinen von MainForm sichtbar und beispielsweise zum expliziten Ent-
laden des Formulars im Zuge der Unload-Behandlung vonnöten ist.
Private Sub Form_Unload(Cancel As Integer)
Beendet = True ' wegen DoEvents!
' Vollbildformular entladen
If Not (VollbildForm Is Nothing) Then Unload VollbildForm
End Sub

Die Prüfung, ob VollbildForm überhaupt eine gültige Referenz ist, ist hier unvermeidlich, da
Unload (aus welchem Grund auch immer) mit dem Wert Nothing nichts anfangen kann.

526
Programmstart und Auswahl der Bilddateien im Standarddialog Öffnen

Programmstart und Auswahl der Bilddateien im Standarddialog Öffnen


Bei Programmen mit mehreren Formularen stellt sich die Frage, welches Formular Visual Basic
beim Programmstart wie instanziiert. Dies ist leicht zu beantworten: Das Startformular wird im
Eigenschaftsdialog im Listenfeld STARTOBJEKT ausgewählt – im vorliegenden Fall lautet der
Eintrag also: MainForm. Die Instanziierung der anderen Formulare obliegt dann dem Startfor-
mular.
MainForm dient als Formular für die Fensteransicht, das heißt, es hat einen Rahmen und lässt
auch Größenänderungen zu. Die Entwurfsansicht fördert drei Steuerelemente zu Tage, ein Stan-
darddialoge-Steuerelement, das die Dateiauswahl ermöglicht, ein Zeitgeber-Steuerelement für
die Funktion des automatischen Bildwechsels sowie ein Anzeige-Steuerelement (wegen des

DiaProjektor – SDI- Formulare synchronisieren


schwarzen Hintergrunds schlecht zu sehen), das zur Laufzeit unsichtbar bleibt und als Cache
für die Indexansicht fungiert.
Da MainForm keine Initialize-Behandlung vornimmt, sieht das Formular als Erstes das Load-
Ereignis. Die Behandlungsroutine initialisiert die auf Modulebene vereinbarte Objektvariable
ActualForm mit einer Referenz auf sich selbst. ActualForm wird später immer auf das Formular
verweisen, das dem aktuellen Anzeigemodus entspricht – bei Programmstart ist das die Fenster-
anzeige – und so insbesondere alle Ausgabeoperationen dirigieren. Der Show-Aufruf noch vor
der Dateiauswahl durch mnuÖffnen_Click ist eine kosmetische Maßnahme und ermöglicht es
dem Benutzer, den meist zeitintensiven Aufbau der Indexansicht zu beobachten.
Private Sub Form_Load()
Set ActualForm = Me ' Fensteranzeige als Starteinstellung
ReDim FileNames(0 To 1)
Show
mnuÖffnen_Click ' Ordner abfragen
End Sub

Mit mnuÖffnen_Click geht das Programm bereits in den »Alltag« über, denn diesen Befehl kann
auch der Benutzer jederzeit über die Menüs oder per Tastenbefehl auslösen. Seine Implementa-
tion unterteilt sich in drei Blöcke: Aufruf des Standarddialogs Öffnen für die Mehrfachauswahl;
Auswertung des Pfads und Zusammenstellen einer Dateiliste im globalen Array FileNames; Vor-
bereitung und Veranlassung der Anzeige.
Private Sub mnuÖffnen_Click()
Dim bArrayNichtLeer As Boolean

StopTimer

' Standdarddialog initialisieren und aufrufen


dlgDateiOpen.Filter = "*.jpg;*.gif;*.bmp|*.jpg;*.gif;*.bmp"
dlgDateiOpen.CancelError = True
dlgDateiOpen.FileName = "(alle)"
dlgDateiOpen.Flags = cdlOFNAllowMultiselect + cdlOFNExplorer _
+ cdlOFNLongNames
On Error GoTo Abbruch ' Falls Benutzer Dialog abbricht
dlgDateiOpen.ShowOpen ' Standarddialog "Öffnen"

' Der folgende Code wird nicht ausgeführt,


' wenn der Öffnen-Dialog abgebrochen wurde!
FileNames(0) = Left(dlgDateiOpen.FileName, _
InStrRev(dlgDateiOpen.FileName, "\")) ' Pfad
FileIndex = 1 ' ab erstem Bild anzeigen

527
DiaProjektor – SDI- Formulare synchronisieren

If dlgDateiOpen.FileTitle = "(alle).jpg" Then


ReDim Preserve FileNames(0 To 0)
' FS_FindFiles FileNames ' mit FileSystemObject-Objekt
FindFiles FileNames ' mit Dir-Funktion
bIndexView = False ' Indexansicht vorbereiten
ElseIf InStr(dlgDateiOpen.FileName, Chr(0)) Then
FileNames = Split(dlgDateiOpen.FileName, Chr(0))
FileNames(0) = FileNames(0) + "\"
bIndexView = False ' Indexansicht vorbereiten
Else
DiaProjektor – SDI- Formulare synchronisieren

ReDim FileNames(0 To 1)
FileNames(1) = dlgDateiOpen.FileTitle
bIndexView = True ' Einzeldiaansicht vorbereiten
End If

' Menübefehle zum Bildwechsel aktivieren


bArrayNichtLeer = FileNames(1) <> "" ' Wurden Dateien gefunden?
mnuBildErstes.Enabled = bArrayNichtLeer
mnuBildNächstes.Enabled = bArrayNichtLeer
mnuBildVoriges.Enabled = bArrayNichtLeer
mnuTimer3.Enabled = bArrayNichtLeer
mnuTimer5.Enabled = bArrayNichtLeer
DiaIndex cNoCaching ' Bild(er) Anzeigen

Abbruch:
End Sub

Der Umgang mit dem Standarddialog Öffnen ist im Wesentlichen business as usual, einzig die
Mehrfachauswahl im Stile von Windows 9x erfordert das Setzen einiger zusätzlicher Flags.
Ärgerlicherweise ist der Puffer für die Rückgabe des Dateinamens auch bei eingeschalteter
Mehrfachauswahl auf etwas über 200 Zeichen begrenzt, so dass die Anzahl der auswählbaren
Dateinamen recht klein ist. Einem ernsthaften Einsatz dieser Funktionalität steht weiterhin die
recht erratisch implementierte Fehlererkennung des Steuerelements im Wege. Falls der Benutzer
den Dialog abbricht, ist der Wert der Eigenschaft FileName nicht gültig. Damit das Steuerele-
ment in diesem Fall einen Laufzeitfehler signalisiert, muss die CancelError-Eigenschaft auf True
gesetzt werden. Die Behandlung des Laufzeitfehlers an der Sprungmarke Abbruch sieht nichts
weiter als den Abbruch des gesamten Befehls vor – wobei eine gegebenenfalls bereits geladene
Dateiliste erhalten bleibt. Nachdem kein On Error Goto 0 folgt, gilt das natürlich auch für alle
anderen Laufzeitfehler, falls noch welche in der Routine auftreten sollten – eine nicht gerade
penible, aber in verschiedenen Fällen durchaus vertretbare Programmierpraxis.
Das Steuerelement tut die Auswahl des Benutzers über die Eigenschaften FileName und File-
Title kund. Dabei gibt es drei Fälle zu unterscheiden:
1. Der Benutzer hat nur eine einzelne Datei ausgewählt. Da FileName dann den qualifizierten
Namen enthält, lassen sich Pfad und Dateiname trennen und in das Array FileNames über-
nehmen. Als Ansicht ist natürlich die Einzeldiaansicht sinnvoll.
2. Der Benutzer hat eine Mehrfachauswahl getroffen. Falls diese einen Pufferüberlauf produ-
ziert hat, ist der Dateiname ungültig, was das Programm im weiteren Verlauf mit der Fehler-
meldung »Bildformat nicht erkannt« moniert. Eine korrekte Mehrfachauswahl ist daran zu
erkennen, dass das Nullzeichen in der Eigenschaft FileName zu finden ist, welches die Namen-

528
Programmstart und Auswahl der Bilddateien im Standarddialog Öffnen

seinträge trennt. Für die Aufspaltung in das Array FileNames ist Split das Mittel schlechthin,
und auch der Pfadname landet da, wo er hin soll, da der erste Eintrag bei einer Mehrfach-
auswahl immer den Pfad benennt. Als Ansicht fungiert die Indexansicht.
3. Der Benutzer hat es im ÖFFNEN-Dialog bei der Voreinstellung »(alle)« belassen. In diesem
Fall muss eine Liste aller im Verzeichnis befindlichen Grafikdateien des Typs JPG, BMP oder
GIF zusammengestellt werden, bevor die Bilder in der Indexansicht angezeigt werden kön-
nen. Sie finden dafür im Code die beiden Prozeduren FindFiles und FS_FindFiles, die sich
alternativ für diese Aufgabe einsetzen lassen. FindFiles arbeitet mit der Dir-Funktion von Vi-
sual Basic, während FS_FindFiles ein FileSystemObject-Objekt anfordert, das letztlich die
gleiche Information liefert, nur um etliches langsamer – was bereits bei über hundert Dateien
unangenehm wird. Im Zusammenhang mit dem FileSystemObject-Objekt könnte man auch

DiaProjektor – SDI- Formulare synchronisieren


auf den Gedanken kommen, das Auswahlkriterium über die Eigenschaft Type des File-Ob-
jekts zu formulieren, das ist jedoch nicht empfehlenswert, da gerade für die betroffenen Da-
teitypen viele unterschiedliche Registrierungen im Umlauf sind.
' Fügt alle auf *.jpg, *.gif oder *.bmp endenden Dateinamen
' in das Array FileNames ein. Erweitert Array!
Private Sub FindFiles(FileNames() As String)
Dim Name As String
Dim UName As String

Name = Dir(FileNames(0) + "*.*") ' Erster Dateiname


UName = UCase(Name)
While Name <> ""
If InStr(UName, ".JPG") Or InStr(UName, ".GIF") Or _
InStr(UName, ".BMP") Then
ReDim Preserve FileNames(0 To UBound(FileNames) + 1) ' Vergrößern
FileNames(UBound(FileNames)) = Name ' Dateiname einfügen
End If
Name = Dir ' nächster Dateiname
UName = UCase(Name)
Wend
End Sub

' Fügt alle auf *.jpg, *.gif oder *.bmp endenden Dateinamen
' in das Array FileNames ein. Erweitert Array!
Private Sub FS_FindFiles(FileNames() As String)
Dim fs As New FileSystemObject
Dim Datei As File
Dim Path As Folder
Dim UName As String
Dim Idx As Long ' Zähler

Set Path = fs.GetFolder(FileNames(0))


Idx = UBound(FileNames)
ReDim FileNames(Idx To Path.Files.Count) ' mehr können es nicht werden

For Each Datei In Path.Files


UName = UCase(Datei.Name) ' Schreibweise einheitlich
If InStr(UName, ".JPG") Or InStr(UName, ".GIF") Or _
InStr(UName, ".BMP") Then

529
DiaProjektor – SDI- Formulare synchronisieren

Idx = Idx + 1
FileNames(Idx) = Datei.Name
End If
Next
ReDim Preserve FileNames(0 To Idx) ' Reduktion auf tatsächl. Anzahl
End Sub

Beide Funktionen erwarten den Pfadnamen als Element mit dem Index 0 im Array FileNames
und durchsuchen dann – jede auf ihre Weise – das gesamte Verzeichnis nach Dateien des Typs
JPG, BMP, GIF. Die gefundenen Dateinamen landen schließlich der Reihe nach im Array (diese
Reihenfolge bestimmt später auch die Bildabfolge), das in FindFiles mit jedem gefundenen
DiaProjektor – SDI- Formulare synchronisieren

Dateinamen um ein Element erweitert wird, in FS_FindFiles dagegen nur einmal recht großzü-
gig, und zum Schluss wieder zurechtgestutzt wird. Beachten Sie, dass die Funktionen mit Blick
auf eine zukünftige Verwendung keine Vorannahmen über den aktuellen Füllzustand des
Arrays treffen.
In Kombination mit dem Indexzeiger FileIndex stellt das Array FileNames die Datenbasis für
das Anzeigesystem dar. In der vorliegenden Implementation wird die Datenbasis bei jedem ÖFF-
NEN-Befehl neu angelegt.

Das Anzeigesystem
Trotz seiner Vielschichtigkeit ist das Anzeigesystem weitgehend hierarchisch aufgebaut, wie Sie
am besten dem in der Grafik dargestellten Aufrufdiagramm entnehmen.

Aufrufzusammenhang zwischen Benutzerschnittstelle und Anzeigesystem

Umsc haltung zwisc hen Indexansic ht und Vollbildansic ht

An oberster Stelle der Hierarchie steht die Prozedur DiaIndex, die zwischen der Einzeldiaansicht
und der Indexansicht hin- und herschaltet. Sie ist für die Pflege der auf Modulebene bekannten
Zustandsvariable bViewState und den Aufruf der Routine Anzeigen verantwortlich. Außerdem
berichtigt die Routine den Zeiger FileIndex dahingehend, dass er immer auf das nächst kleinere
Vielfache von cLargeStep (hier: 20) plus 1 verweist. Das hat nicht nur Vorteile für das Caching,

53 0
Das Anzeigesystem

es verleiht der Indexansicht auch den Charakter eines eigenständigen Bildes. Darüber hinaus
fällt der Routine die Aufgabe zu, die Menübefehle für den automatischen Bildwechsel für die
Indexansicht zu deaktivieren (StopTimer) sowie für die Einzeldiaansicht zu aktivieren. Sie kön-
nen den StopTimer-Aufruf aber auch auskommentieren, denn vom Prinzip her ist die vom
Anzeigesystem verwendete DoEvents-Logik gegenüber einem Bildwechsel während des Bildauf-
baus unempfindlich. Bei hochauflösenden Bildern oder leistungsschwachen Systemen kann es
allerdings passieren, dass der Bildaufbau der Weiterschaltung nicht hinterherkommt.
Von der Programmiertechnik her gesehen, ist die Einflussnahme auf die Enable-Eigenschaft von
Menübefehlen ein sehr wirksames und gleichzeitig elegantes Mittel, um in einem spezifischen
Kontext bestimmte Befehle lahm zu legen bzw. zuzulassen. Gleichzeitig stellen die Werte der
Eigenschaften Visible, Enabled und Checked der Menüeinträge eine Art Zustandsbeschreibung

DiaProjektor – SDI- Formulare synchronisieren


der Benutzerschnittstelle dar. Scheuen Sie sich also nicht, sie zur Steuerung der Programmlogik
einzusetzen.
Enum vbCaching
cCaching = True
cNoCaching = False
End Enum
...
' Schaltet zwischen Einzeldia und Indexansicht
Private Sub DiaIndex(Optional Caching As vbCaching)
If bIndexView Then ' Schalter setzen
mnuTimer3.Enabled = True ' Timer-Befehle zulassen
mnuTimer5.Enabled = True
mnuDateiTimer3.Enabled = True
mnuDateiTimer5.Enabled = True
mnuIndex.Caption = "&Indexansicht" ' Menübefehl aktualisieren
bIndexView = False
Else
StopTimer
mnuIndex.Caption = "&Einzeldia"
bIndexView = True
FileIndex = FileIndex – FileIndex Mod (cIdxZeilen * cIdxSpalten) + 1
End If
Anzeigen Caching
End Sub
...
Private Sub StopTimer()
Timer1.Enabled = False ' Timer ausschalten
Timer1.Interval = 0
mnuTimer3.Checked = False
mnuTimer5.Checked = False
mnuDateiTimer3.Checked = False
mnuDateiTimer5.Checked = False
mnuTimer3.Enabled = False
mnuTimer5.Enabled = False
mnuDateiTimer3.Enabled = False
mnuDateiTimer5.Enabled = False
End Sub

Der Code der Routine DiaIndex weist wenig Besonderheiten auf, außer dass der Parameter
Caching als optionaler Parameter mit dem Enum-Typ vbCaching definiert ist und unbesehen der

53 1
DiaProjektor – SDI- Formulare synchronisieren

Routine Anzeigen übergeben wird. Enum-Aufzählungen sind unter Visual Basic zwar keine eigen-
ständigen Typen und schränken insbesondere auch den zugrunde liegenden Wertebereich Long
nicht ein, sie bieten aber den Vorteil, dass sie Konstanten mit »sprechenden Namen« bereitstel-
len und dass der Code-Editor die gesamte Aufzählung einblendet, wo ein Wert dieses »Typs«
erwartet wird.

Caching
Die Logik der Prozedur Anzeigen ist da schon etwas komplizierter. Hauptaufgabe dieser Rou-
tine ist das nach Vollbildanzeige und Fensteranzeige getrennte Caching der jeweils aktuellen
Indexansicht. Zu diesem Zweck pflegt die Routine getrennt nach Anzeige zwei statische Variab-
len mit dem Bildindex der jeweils als letztes fertig (!) gezeichneten Indexansicht und überträgt
DiaProjektor – SDI- Formulare synchronisieren

außerdem den über die Image-Eigenschaft zugänglichen Formularinhalt in das unsichtbare (!)
Anzeige-Steuerelement Cache des jeweiligen Formulars. Falls der Bildindex der aktuellen
Anzeige bei Eintritt in die Routine dem für den Cache gespeicherten Wert entspricht, wird nur
der Cache-Inhalt, also die Picture-Eigenschaft des Anzeige-Steuerelements, in das Formular
gezeichnet, anderenfalls kommt es zum Aufruf der Funktion ShowIndex, die für das Zeichnen
der Indexansicht zuständig ist. Die Funktion liefert True, wenn die Indexansicht fertig gezeich-
net werden konnte und steuert die Auffrischung des Cache.
Erfolgt der Aufruf der Routine bei aktiver Einzeldiaansicht, passiert nichts weiter als ein Show-
Dia-Aufruf. Ein Caching der Einzeldiaansicht ist unnötig, weil ein Einzeldia wohl selten mehr-
mals hintereinander angezeigt wird. Das Caching der Indexansicht hat aber den enormen Vor-
teil, dass der Benutzer schnell zwischen den beiden Ansichten umschalten kann, wenn er Bilder
über die Indexansicht für die Einzeldiaansicht auswählt.
' Zeigt einzelnes Bild oder Index an. Verwendet bei Indexansicht
' das Anzeige-Steuerelement des jeweilgen Formulars als Cache
Private Sub Anzeigen(Optional Caching As vbCaching)
Static LetzterVollbIdx As Long
Static LetzterFensterIdx As Long
Dim Idx As Long

If bIndexView Then ' Indexansicht?


' Index für erstes Bild der Indexansicht ausrechnen
FileIndex = FileIndex – FileIndex Mod (cIdxZeilen * cIdxSpalten) + 1
If FileIndex > UBound(FileNames) Then FileIndex = 1
If Visible Then ' Fensteranzeige'
' Cache aktuell?
If FileIndex = LetzterFensterIdx And Caching Then
PaintPicture Cache, 0, 0 ' Ja: Cache zeichnen
Else
Idx = FileIndex ' Nein: Startindex merken
If ShowIndex(ActualForm) Then ' Regulär beendet?
Cache = Image ' Cache aktualisieren
LetzterFensterIdx = Idx ' Index für Cache merken
Else
Exit Sub
End If
End If
Else ' Vollbildanzeige
' Cache aktuell?
If FileIndex = LetzterVollbIdx And Caching Then
VollbildForm.PaintPicture VollbildForm.Cache, 0, 0 ' aus Cache

53 2
Das Anzeigesystem

Else
Idx = FileIndex ' Nein: Startindex merken
If ShowIndex(ActualForm) Then ' Regulär beendet?
Set VollbildForm.Cache = VollbildForm.Image ' in Cache
LetzterVollbIdx = Idx ' Index für Cache merken
Else
Exit Sub
End If
End If
End If

DiaProjektor – SDI- Formulare synchronisieren


Caption = "Index ab Bild " & FileIndex & " – " _
& FileNames(FileIndex)
Else
ShowDia FileIndex, ActualForm ' Einzeldiaansicht
End If
End Sub

Der Code der Routine enthält eine ganze Reihe von Fallunterscheidungen, die aber alle recht
durchsichtig sind. Interessant ist die Situation beim ersten Aufruf der Routine in der Indexan-
sicht. Da Visual Basic die statischen Variablen mit 0 initialisiert und der Index des ersten Bildes
1 ist, kommt es in jedem Fall zum Neuzeichnen der Ansicht. Um das Neuzeichnen der Indexan-
sicht aber auch am Cache vorbei erzwingen zu können, gibt es den Aufrufparameter Caching.
Diese Möglichkeit ist speziell für Form_Resize und mnuÖffnen_Click wichtig. Zur Unterschei-
dung der Vollbildanzeige von der Fensteranzeige wird die Visible-Eigenschaft von MainForm
herangezogen.

Zeic hnen der Indexansic ht

Die Aufgabe der Funktion ShowIndex besteht darin, die Indexansicht in das aktuelle Formular
zu zeichnen. Da sie sich dazu der Prozedur ShowDia bedienen kann, die ein Einzelbild einliest
und geeignet skaliert in den angegebenen Bereich zeichnet, muss sie sich nur um die Aufteilung
des Anzeigebereichs in Zeilen und Spalten sowie um die Beschriftung der Einzeldias kümmern.
In der Praxis eröffnet allerdings die Tatsache, dass der Bildaufbau einige Sekunden in Anspruch
nehmen kann, ein weiteres Problemfeld: Es ist eine DoEvents-Ablaufsteuerung erforderlich,
damit der Benutzer den Bildaufbau überhaupt verfolgen kann und die Reaktivität der Benutzer-
schnittstelle während des Bildaufbaus erhalten bleibt. Für gewöhnlich handelt man sich mit
DoEvents gleich einen ganzen Sack voller Probleme ein. Hier ist das nicht anders. Probleme gibt
es im Zusammenhang mit:
1. dem Caching bei rekursiven Aufrufen
2. dem Wechsel des Anzeigemodus während des Bildaufbaus
3. dem Umschalten in die Einzeldiaansicht
4. dem vorzeitigen Schließen des Formulars.
Jedem der Probleme wirkt die Implementation gesondert entgegen:
1. Nachdem immer nur die letzte Indexansicht in einem Anzeigemodus fertig gezeichnet werden
muss, führt die Routine über einen statischen und einen dynamischen Aufrufzähler darüber
Buch, wie tief sie in der Rekursion steckt. Ein ungleicher Zählerstand weist darauf hin, dass
der von der Rekursionsstufe gezeichnete Inhalt nicht mehr aktuell ist, und führt zum Ab-
bruch der Rekursionsstufe.
2. Eine optionale Pflege des Aufrufzählers bei Abbruch der Routine kann das Fertigzeichnen ei-
ner begonnenen Indexansicht auch bei einem Wechsel des Anzeigemodus sicherstellen. Ge-
zeichnet wird dann im unsichtbaren Formular!

533
DiaProjektor – SDI- Formulare synchronisieren

3. Jeder Wechsel in die Einzeldiaansicht bricht den Bildaufbau der Indexansicht umgehend in
allen Rekursionsstufen ab.
4. Eine Auswertung des von DoEvents gelieferten Werts bricht den Bildaufbau der Indexansicht
umgehend in allen Rekursionsstadien ab, wenn der Benutzer das Programm beenden will.
5. ShowIndex liefert nur dann den Funktionswert True, wenn die Indexansicht erfolgreich zu
Ende gezeichnet werden konnte. Das ist wichtig für das Caching auf der Ebene von DiaIndex.
' Stellt Indexansicht zusammen
Private Function ShowIndex(ByVal Ansicht As Form) As Boolean
Dim x As Single, y As Single, b As Single, h As Single
Dim Idx As Long, EndIndex As Long
DiaProjektor – SDI- Formulare synchronisieren

Static statCount As Long


Dim dynCount As Long

With Ansicht
' Vorbereitungen
statCount = (statCount + 1) Mod 10000 ' stat. Rekursionsz. pflegen
dynCount = statCount ' dyn. Rekursionszähler init.

b = .ScaleWidth / cIdxSpalten ' Spaltenbreite errechnen


h = .ScaleHeight / cIdxZeilen ' Zeilenhöhe errechnen
EndIndex = (FileIndex + cLargeStep)
.FontSize = 7 ' Schriftgröße vorgeben
.Cls

' Bilder ab Startindex ausgeben


For Idx = FileIndex To EndIndex
x = ((Idx – FileIndex) Mod cIdxSpalten) * b + b * 0.025
y = ((Idx – FileIndex) \ cIdxSpalten) * h
ShowDia Idx, Ansicht, x, y, b * 0.95, h * 0.9

' Ereignisse zulassen. Formular geschlossen?


' Indexansicht beendet? Rekusiver Aufruf?
If DoEvents = 0 Or bIndexView = False _
Or statCount <> dynCount Then
' statCount = statCount – 1 ' Rekursionszähler pflegen
Exit Function
End If

' Dateiname unter Bild setzen


If Idx <= UBound(FileNames) Then
.CurrentX = x
.CurrentY = y + h – .TextHeight("a")
Ansicht.Print FileNames(Idx)
End If
Next Idx
End With
ShowIndex = True
End Function

Die Funktion beginnt mit der Pflege der Rekursionszähler: Sie erhöht den für alle Rekursions-
stufen nur einmal existierenden statischen Zähler statCount und überträgt den Zählerstand in

53 4
Bilder einlesen und in maximaler Größe zeichnen

den bei jedem Aufruf neu angelegten dynamischen Zähler dynCount. Tritt im Zuge von DoEvents
Rekursion auf, kann der Fall eintreten, dass sich die Zählerstände unterscheiden, sobald die
gezeichnete Ansicht nicht mehr aktuell ist. Das ergibt ein gutes Kriterium für den Abbruch
unterbrochener Rekursionsstufen. Vielleicht ist es Ihnen aufgefallen: Die Funktion zeichnet die
Ansicht nicht mittels ActualForm, sondern lässt sich das Zielformular über einen ByVal-Parame-
ter bereitstellen. Obwohl man bei Rekursion generell nicht auf globale Werte zugreifen sollte,
wäre es hier kein Problem, mit ActualForm zu arbeiten, schließlich bricht die Rekursion ja
immer am tiefsten Punkt ab. Dass der Parameter dennoch da ist, hat folgenden subtilen Hinter-
grund: Belässt man die im Then-Teil der DoEvents-Analyse auskommentierte Zeile zur Pflege des
statischen Zählers im Code, kann die Routine eine angefangene Ansicht in der Rekursion auch
im unsichtbaren Formular fertig zeichnen und dafür braucht sie dann eine Referenz auf das

DiaProjektor – SDI- Formulare synchronisieren


Formular, für das der Aufruf ursprünglich stattfand. Ohne die Zeile könnte der Aufrufparame-
ter in der vorliegenden Situation tatsächlich entfallen.
Kern der Funktion ist die Schleife, die die Ausgabepositionen für die einzelnen Miniaturen
berechnet und ShowDia für die Bildausgabe aufruft. Die Einteilung der Anzeige in Zeilen und
Spalten richtet sich nach eigens dafür definierten Konstanten. cLargeStep gibt die Anzahl der
Miniaturen pro Ansicht wieder und geht somit auch in die Berechnung des Bildindex beim Blät-
tern in der Indexansicht ein.
Const cIdxZeilen = 4
Const cIdxSpalten = 5
Const cLargeStep = cIdxZeilen * cIdxSpalten ' Seitenwert für Bildwechsel

Bei der Berechnung der Begrenzungsrechtecke für die Miniaturen wird ein Rand von fünf Pro-
zent zwischen den Bildern sowie ein Rand für den direkt unter das Begrenzungsrechteck
gezeichneten Dateinamen berücksichtigt. Die Schriftgröße für die Ausgabe ist fest mit 7 Punkt
vorgegeben. Es steht Ihnen frei, all diese Werte anders zu definieren oder gar dem Benutzer die
Möglichkeit der Einflussnahme im Rahmen eines zusätzlichen Optionen-Dialogs zu überlassen.

Bilder einlesen und in maximaler Größe zeichnen


Frei nach dem Motto »den Letzten beißen die Hunde« fällt ShowDia schließlich der Part zu, das
über den Parameter Index spezifizierte Bild mit LoadPicture einzulesen und bestmöglich in den
verfügbaren Bereich eingepasst zu zeichnen. Eine passende Fehlerbehandlung sorgt dafür, dass
Fehler während des Einlesens oder aufgrund von Visual Basic nicht akzeptierter Bildformate in
der Einzeldiaansicht mit dem Text »Bildformat nicht erkannt« und in der Indexansicht schlicht
mit einem dunkelgrauen Rechteck bedacht werden. Falls alles gut geht, setzt die Routine den
Dateinamen in die Titelleiste nebst Bildnummer und Gesamtanzahl der Bilder, berechnet die
Größe und zentrierte Lage des Bildes im Anzeigebereich und zeichnet es schließlich mittels
PaintPicture, nachdem es ein schwarzes Rechteck in den Bereich gezeichnet hat.
' Lädt Bild von Datei und zeichnet es in maximaler Größe
' im übergebenen Bereich
Private Sub ShowDia(Index As Long, Ansicht As Form, _
Optional x As Single, Optional y As Single, _
Optional b As Single, Optional h As Single)

Dim Pic As Picture


Dim BildBreite, BildHöhe

If b * h = 0 Then ' Parameter weggelassen?


b = Ansicht.ScaleWidth ' Abmessungen von Client-Bereich
h = Ansicht.ScaleHeight ' verwenden
End If

535
DiaProjektor – SDI- Formulare synchronisieren

' Bild einlesen


On Error GoTo Fehlerbehandlung ' Falls was schief geht
Set Pic = LoadPicture(FileNames(Index))
Caption = "Bild" + Str(Index) + " von" + Str(UBound(FileNames)) + _
" – " + FileNames(0) + FileNames(Index)

' maximale Bildgröße berechnen


BildHöhe = Pic.Height
BildBreite = b
BildHöhe = BildHöhe * BildBreite / Pic.Width
DiaProjektor – SDI- Formulare synchronisieren

If BildHöhe > h Then


BildHöhe = h
BildBreite = Pic.Width * BildHöhe / Pic.Height
End If
On Error GoTo 0

' Bild im aktuellen Formular zentriert zeichnen


Ansicht.Line (x, y)-(x + b, y + h), vbBlack, BF
Ansicht.PaintPicture Pic, x + (b – BildBreite) / 2, _
y + (h – BildHöhe) / 2, BildBreite, BildHöhe
Exit Sub

Fehlerbehandlung:
Dim Text As String
With Ansicht
If Not bIndexView Then
Text = "Bildformat nicht erkannt"
' Fehlertext mittig ausgeben
.Cls
.CurrentX = (.ScaleWidth – .TextWidth(Text)) / 2
.CurrentY = (.ScaleHeight – .TextHeight(Text)) / 2
' With funktioniert bei Print und Line nicht!!!
Caption = "Bildformat nicht erkannt"
Ansicht.Print Caption
Else
Ansicht.Line (x, y)-(x + b, y + h), RGB(50, 50, 50), BF
End If
End With
End Sub

Die Aufrufparameter für die Bereichsdefinition sind als optionale Parameter vereinbart und
müssen daher nicht unbedingt angegeben werden. Falls einer der Parameter für die Bereichsab-
messungen b oder h den Wert 0 hat, nimmt die Routine dafür die aktuellen Abmessungen des
Anzeigebereichs. Damit kann sie für die Einzeldiaansicht ohne Bereichsangaben aufgerufen
werden.

Vollbildanzeige
Für gewöhnlich sollte sich ein Programm im Hinblick auf andere eventuell gleichzeitig laufende
Anwendungen eher bescheiden und zurückhaltend auf Fenster beschränken, die dem Benutzer
eine Veränderung der Größe und der Position sowie einen Wechsel des Anzeigezustands ermög-
lichen. Dennoch gibt es aber Anwendungsbereiche, für die das selbstbewusste Auftreten einer

53 6
Vollbildanzeige

Anwendung im Vollbildmodus nicht nur erwünscht, sondern als möglicher Anzeigezustand


geradezu gefordert ist. Man denke etwa an Malprogramme, Fotoeditoren oder an visuelle Prä-
sentationen, wie sie in vielen Multimediaprodukten und Spielen zu finden sind. Freilich wird
man als Programmierer diesen Modus, der die Windows-Oberfläche zu verschleiern vermag,
nur als Option anbieten, da er die Benutzerschnittstelle doch weitgehend auf die Möglichkeiten
einschränkt, wie sie DOS-Programmen seinerzeit zur Verfügung standen: die Navigation mit
der Tastatur und die Reaktion auf Mausereignisse. Viele Anwendungen mit optionaler Vollbil-
dansicht – DiaProjektor macht da keine Ausnahme – erlauben die umgehende Rückkehr in den
rahmengebundenen Anzeigemodus über die (Esc)-Taste, einen Mausklick oder ein Kontext-
menü.
Voraussetzung für die programmtechnische Umsetzung der Vollbildanzeige ist ein Formular

DiaProjektor – SDI- Formulare synchronisieren


ohne Rahmenleiste und ohne Menü. Erfreulicherweise blendet Windows bei maximierter
Anzeige eines solchen Formulars auch die Taskleiste aus.
Für die Implementation gehen Sie wie folgt vor:
1. Fügen Sie in Ihr Projekt neben dem normalen Ausgabeformular ein eigenes, menüloses For-
mular ein, das die Vollbildanzeige übernimmt.
2. Setzen Sie die Eigenschaft BorderStyle des Formulars bereits im Entwurfsmodus auf 0.
3. Setzen Sie die Eigenschaft WindowState im Entwurfsmodus auf »2 Maximiert« oder zur Lauf-
zeit auf vbMaximized bzw. 2.
4. Sehen Sie im normalen Ausgabeformular eine Möglichkeit zum Umschalten in den Vollbild-
modus vor, etwa durch einen geeigneten Menübefehl.
5. Sehen Sie im Vollbildformular eine Möglichkeit zum Umschalten in den normalen Ausgabe-
modus vor – etwa durch Implementation von Form_KeyDown, Form_Click oder ein Kontextme-
nü.
Visual Basic 6.0 erlaubt es zwar, die BorderStyle-Eigenschaft (entgegen anders lautender Infor-
mationen in der Online-Hilfe) zur Laufzeit zu ändern, die Eigenschaft ControlBox ist jedoch
schreibgeschützt. Somit lässt sich ein Fenster mit Rahmen auch zur Laufzeit in den Vollbildmo-
dus versetzen, wenn die Eigenschaft ControlBox zur Entwurfszeit auf False gesetzt wurde. In
diesem Fall reicht es, zur Laufzeit Caption auf die leere Zeichenfolge, BorderStyle auf vbSNone
bzw. 0 und gegebenenfalls die Eigenschaft Visible aller Menüobjekte auf False zu setzen. Wer
nun glaubt, es sei möglich, ohne eigenes Vollbildformular auszukommen, der hat Recht: Im
Prinzip geht das; mit einem Hauptformular ohne Systemmenü lässt sich allerdings nicht allzu
viel anfangen, da es in der Titelleiste weder Schaltflächen für Maximieren/Wiederherstellen und
Minimieren besitzt noch dem Benutzer sonstwie eine Größenveränderung ermöglicht.
Das Anlegen des zweiten Formulars, der Umgang mit Benutzereingaben sowie die Zustands-
pflege der Formulare für die Vollbildanzeige wurden bereits im Abschnitt »Ereignisse delegieren
und Instanziierung durch One-Shot-Logik« (S. 525) vorgestellt. Bleibt also noch zu klären,
nach welcher Technik die Aktualisierung der Anzeige erfolgt. Falls beide Anzeigen die gleiche
Ansicht darstellen, wie es im diskutierten Beispiel der Fall ist, macht es natürlich Sinn, für beide
Anzeigen die gleichen Ausgaberoutinen zu verwenden und den Zugriff auf die Eigenschaften
und Methoden der Formulare über eine Objektvariable ActualForm des Typs Form zu bewerk-
stelligen. Die Umschaltung zwischen der Fensteranzeige und der Vollbildanzeige sieht vom Prin-
zip her so aus:
Private ActualForm As Form ' aktuelles Formular
...
If Visible Then ' zur Vollbildanzeige?
Hide
Set ActualForm = VollbildForm
VollbildForm.Show

537
DiaProjektor – SDI- Formulare synchronisieren

Else ' zur Fensteranzeige


VollbildForm.Hide
Set ActualForm = Me
Show
End If

und die Ausgabe so:


ActualForm.PaintPicture Pic, x, y

Trick – die erschlichene Vollbildanzeige


Wenn Sie wollen, können Sie sich jedoch auch einen Trick zunutze machen, auf höchst einfache
DiaProjektor – SDI- Formulare synchronisieren

und recht ungewöhnliche Weise zu einer Vollbildansicht zu kommen, bei der sogar die gesamte
Menüfunktionalität für die Bedienung durch Zugriffstasten vollständig gewährleistet bleibt.
Der einzige Nachteil: Die Taskleiste von Windows verschwindet nicht.
Der Trick ist verblüffend einfach – wenn man ihn kennt: Sie definieren die Abmessungen und
die Position des Fensters einfach so, dass der Rahmen des Fensters vollständig jenseits des sicht-
baren Bildbereichs zu liegen kommt und der Client-Bereich exakt den Bereich des Screen-
Objekts einnimmt.
Top = (ScaleHeight – Height) – (ScaleWidth – Width) / 2
Left = (ScaleWidth – Width) / 2
Height = Height – ScaleHeight + Screen.Height
Width = Width – ScaleWidth + Screen.Width
Left = ScaleWidth – Width

Menü und Kontextmenü


In grafischen Benutzeroberflächen wie Windows sind es Benutzer gewohnt, Anwendungen intu-
itiv über Menüs bedienen zu können, ohne irgendwelche Tastenkombinationen auswendig ler-
nen zu müssen. Beim Entwurf eines Programms sollten Sie daher darauf achten, alle wichtigen
Operationen als Menübefehle zu implementieren. Die Technik dafür ist sehr einfach:
1. Rufen Sie in der Entwurfsansicht das Kontextmenü des Formulars auf und wählen Sie darin
den Befehl MENÜ-EDITOR. In dem erscheinenden gleichnamigen Dialog können Sie nun der
Reihe nach alle Menüs sowie die dazugehörigen Menübefehle definieren.
2. Legen Sie ein neues Menü (beispielsweise DATEI) an, indem Sie einen neuen Eintrag im Lis-
tenfeld markieren und in den Textfeldern CAPTION und NAME den im Menü erscheinenden
Menünamen sowie den für das Menüobjekt im Code verwendeten Bezeichner eintragen. Da-
mit das Menü über eine (Alt)-Kombination zugänglich wird, stellen Sie dem zu unterstrei-
chenden Buchstaben das Zeichen »&« voran.
3. Legen Sie die Menübefehle an, indem Sie zuerst auf die Schaltfläche NÄCHSTER und dann auf
die Pfeilschaltfläche RECHTS klicken. Sie erhalten einen neuen Eintrag, der etwas eingerückt
erscheint. Die Definition des Menübefehlnamens sowie des im Code verwendeten Bezeich-
ners erfolgt wie in 2. Falls Sie für den Befehl zusätzlich noch ein Tastenkürzel vereinbaren
wollen, können Sie dieses aus dem Angebot im Listenfeld SHORTCUT auswählen. Das Lauf-
zeitsystem filtert Tastenkürzel heraus und generiert automatisch die dazugehörigen Menüer-
eignisse. Trennlinien fügen Sie ein, indem Sie anstelle eines Menübefehlnamens ein
Minuszeichen »-« eintragen. Um mehrere Befehle unter gleichem Bezeichner in einem Be-
zeichnerarray zusammenzufassen, definieren Sie wie bei Steuerelemente-Arrays die Index-Ei-
genschaft im Textfeld INDEX. Abgesehen davon müssen alle Bezeichner von Menübefehlen,
Menüs und Trennlinien eindeutige Bezeichner tragen.

53 8
Menü und Kontextmenü

4. Falls Sie einen Befehl als Untermenü auslegen wollen, rücken Sie die ihm untergeordneten Be-
fehle mittels der Pfeilschaltfläche RECHTS einfach um eine Stelle weiter ein. Die Einrückung
drückt die hierarchische Beziehung aus.
5. Legen Sie die Anzeigeeigenschaften Visible, Enabled und Checked der Menübefehle entweder
gleich zur Entwurfszeit oder später zur Laufzeit fest.

Der Menüeditor DiaProjektor – SDI- Formulare synchronisieren


Menübefehle, deren Visible-Eigenschaft auf False gesetzt ist, sind zur Laufzeit nicht nur nicht
sichtbar, auch ihre Zugriffstasten funktionieren nicht. Menübefehle, deren Enabled-Eigenschaft
auf False gesetzt ist, bleiben zwar sichtbar, erscheinen aber aufgehellt und reagieren weder auf
die Maus noch auf Zugriffstasten oder Tastenkürzel. Die vom Menü-Editor standardmäßig auf
False gesetzte Checked-Eigenschaft bestimmt, ob der Menübefehl mit oder ohne Häkchen dar-
gestellt wird.
Die Visible-Eigenschaft bringt eine gewisse Flexibilität in die ansonsten unter Visual Basic
recht dürftig ausgefallenen Möglichkeiten für die codeseitige Gestaltung von Menüs. Visual
Basic erlaubt es nicht, bestehende Menüs zur Laufzeit zu erweitern oder Menübefehle einfach
nur »umzuhängen«. Auch das dynamische Erweitern von Befehlearrays funktioniert nicht. Der
einzige verbleibende Spielraum ergibt sich durch Ein- und Ausblenden von Befehlen über deren
Visible-Eigenschaft sowie die Änderung der Caption-Eigenschaft – Tastenkürzel, deren Defini-
tion eindeutig sein muss, bleiben immer an die Menüschaltfläche gebunden, unabhängig von
deren Beschriftung, Zugriffstasten richten sich nur nach der Beschriftung.

539
DiaProjektor – SDI- Formulare synchronisieren

Die Definition, die in der Abbildung des Menü-Editorfensters zu sehen ist, erzeugt sowohl das
Dateimenü als auch das Kontextmenü des Beispielprogramms DiaProjektor – die Visible-
Eigenschaft macht es möglich (!).

Kontextmenüs
Gerade in einem Programm wie DiaProjektor, das mit einer Vollbildanzeige ausgestattet ist,
aber auch in vielen anderen Fällen bietet es Vorteile, wenn der Benutzer die aktuell möglichen
Operationen in Form eines Kontextmenüs per rechtem Mausklick im schnellen Zugriff hat. Die
Definition eines Kontextmenüs erfolgt genauso wie die eines gewöhnlichen Menüs, außer dass
Sie die Visible-Eigenschaft des Menüs auf False setzen sollten, damit es nicht in der Menüleiste
erscheint. Sie haben aber auch die Möglichkeit, gewöhnliche Menüs oder Untermenüs als Kon-
DiaProjektor – SDI- Formulare synchronisieren

textmenüs aufzurufen, was den Vorteil hat, dass Sie für die Befehle keine eigenen Behandlungs-
routinen implementieren müssen, sondern auf die bestehenden Routinen aufbauen können. Das
in DiaProjektor verwendete Kontextmenü ist eine Erweiterung des Dateimenüs bzw. anders-
herum: Das Dateimenü ist ein in Teilen ausgeblendetes Kontextmenü. Der Code für den Aufruf
lautet:
Private Sub Kontextmenü()
mnuDateiErstes.Visible = True ' unsichtbare Befehle in Dateimenü
mnuDateiNächstes.Visible = True
mnuDateiVoriges.Visible = True
mnuDateiTimer3.Visible = True ' sichtbar machen
mnuDateiTimer5.Visible = True
PopupMenu mnuDatei
If Not Beendet Then ' Formular noch geöffnet?
mnuDateiErstes.Visible = False ' Befehle wieder verbergen
mnuDateiNächstes.Visible = False
mnuDateiVoriges.Visible = False
mnuDateiTimer3.Visible = False
mnuDateiTimer5.Visible = False
End If
End Sub

Wie die If-Struktur in dieser Implementation erkennen lässt, kann auch für die PopupMenu-
Methode das im Zusammenhang mit DoEvents bereits andernorts vorgestellte »Stehaufmänn-
chenproblem« auftreten, nämlich, dass ein über das Kontextmenü geschlossenes Formular
sofort wieder geladen wird, wenn nach dem PopupMenu-Aufruf noch ein Zugriff auf eine Eigen-
schaft oder Methode des Formulars erfolgt. Abhilfe schafft eine auf Modulebene vereinbarte
Boolean-Variable Beendet, die während der Unload-Behandlung gesetzt wird.
Private Sub Form_Unload(Cancel As Integer)
Beendet = True ' wegen PopupMenu
' Vollbildformular entladen
If Not (VollbildForm Is Nothing) Then Unload VollbildForm
End Sub

Menüpflege und Timer


Ein gut gepflegtes Menü ist für den Benutzer eine wertvolle Informationsquelle über den
Zustand des Programms und seine aktuellen Möglichkeiten. Das betrifft besonders Zustände,
die nicht oder nur schlecht anderweitig ersichtlich sind. Eine eingeschaltete Vollbildanzeige
erkennt der Benutzer auch ohne Häkchen vor dem entsprechenden Menüeintrag. Mehrere
Ansichten auseinander zu halten, ist dagegen schon schwieriger, erfordert aber immer noch

540
Menü und Kontextmenü

keine detektivischen Fähigkeiten, wie das Programm DiaProjektor augenfällig demonstriert.


Den Zustand der Timer-Funktion oder anderer unsichtbarer Helferlein muss man dagegen
irgendwo ablesen können – am besten dort, wo die Aktivierung/Deaktivierung geschieht: am
Menübefehl selbst.

DiaProjektor – SDI- Formulare synchronisieren


Die Timer- Funktion »Bildweitersc haltung alle 5 Sekunden« ist aktiviert

Die Implementation der Behandlungsroutine für diesen Menübefehl pflegt die Zustände dreier
weiterer Menübefehle.
Private Sub mnuTimer5_Click()
ResetTimer
mnuTimer3.Checked = False ' Häkchen aktualisieren
mnuDateiTimer3.Checked = False
If mnuTimer5.Checked = False Then ' Timer schon gesetzt?
Timer1.Interval = 5000 ' Nein: Timer auf 5 Sekunden
Timer1.Enabled = True
mnuTimer5.Checked = True
mnuDateiTimer5.Checked = True
Else ' Ja: ausschalten
Timer1.Enabled = False
mnuTimer5.Checked = False
mnuDateiTimer5.Checked = False
End If
End Sub

Für die Indexansicht von DiaProjektor werden die Timer-Befehle mittels StopTimer deaktiviert.
Private Sub StopTimer()
Timer1.Enabled = False ' Timer ausschalten
Timer1.Interval = 0
mnuTimer3.Checked = False
mnuTimer5.Checked = False
mnuDateiTimer3.Checked = False
mnuDateiTimer5.Checked = False
mnuTimer3.Enabled = False
mnuTimer5.Enabled = False
mnuDateiTimer3.Enabled = False
mnuDateiTimer5.Enabled = False
End Sub

541
DiaProjektor – SDI- Formulare synchronisieren

Beide Timer- Funktionen sind deaktiviert

Benutzerschnittstelle
Die Benutzerschnittstelle eines Programms unterteilt sich in Menübefehle, Mausbefehle und
Zugriffstasten (die vom System abgefangenen Tastenkürzel zählen zu den Menübefehlen, da sie
DiaProjektor – SDI- Formulare synchronisieren

bei der Anwendung als solche ankommen). Im Beispielprogramm DiaProjektor sind alle drei
vertreten. Das Laufzeitsystem von Visual Basic generiert für jeden Menübefehl ein separates
Click-Ereignis, so dass die Implementation eines Menübefehls durch Bereitstellung einer
Behandlungsroutine für das jeweilige Ereignis erledigt werden kann. Unterschiedliche Menü-
befehle für denselben Befehl, die in verschiedenen Menüs beheimatet sind, sollten von der glei-
chen Routine bedient werden, was am besten durch Delegation zu lösen ist:
Private Sub mnuDateiNächstes_Click()
mnuBildNächstes_Click
End Sub

Das gilt auch für Befehle und Funktionen, die sich auf einen Menübefehl zurückführen lassen,
so beispielsweise für die Befehle der Tastaturschnittstelle in DiaProjektor:
Public Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
' Tastaturschnittstelle
Select Case KeyCode
Case vbKeyHome ' zum ersten Bild
mnuBildErstes_Click
Case vbKeyLeft ' ein Bild zurück mit Überlauf
mnuBildVoriges_Click
Case vbKeyRight ' ein Bild vor mit Überlauf
mnuBildNächstes_Click
Case vbKeyEscape ' Vollbildanzeige/Fensteranzeige
mnuVollbild_Click
Case vbKeyUp, vbKeyPageUp ' mehrere Bilder weiter mit Überlauf
FileIndex = (FileIndex + cLargeStep – 1) Mod UBound(FileNames)
mnuBildNächstes_Click
Case vbKeyDown, vbKeyPageDown ' mehrere Bilder zurück mit Überlauf
FileIndex = FileIndex – cLargeStep – 1
If FileIndex < 1 Then FileIndex = FileIndex + UBound(FileNames)
mnuBildNächstes_Click
Case vbKeyF3 ' Timer ein/aus: 3 Sekunden
If Not mnuTimer3.Enabled Then Exit Sub
mnuTimer3_Click
Case vbKeyF5 ' Timer ein/aus: 5 Sekunden
If Not mnuTimer5.Enabled Then Exit Sub
mnuTimer5_Click
End Select
End Sub

542
Benutzerschnittstelle

Aber auch für den Timer:


Private Sub Timer1_Timer()
mnuBildNächstes_Click
End Sub

Beachten Sie, dass die Tastenbefehle (F3) und (F5) bewusst nicht nur als Zugriffstasten, son-
dern auch über die Tastaturschnittstelle implementiert sind. Das hat den Vorteil, dass sie auch
in der Vollbildanzeige, wo es kein Menü gibt, als Tastenbefehle verfügbar bleiben. In der Fens-
teranzeige nimmt der Tastenbefehl den Weg über die Menübehandlung des Laufzeitsystems und
in der Vollbildanzeige über die Tastaturschnittstelle, was sich leicht über einen Unterbrechungs-
punkt in der entsprechenden Zeile nachweisen lässt.

DiaProjektor – SDI- Formulare synchronisieren


Die Funktion der linken Maustaste ist von der Ansicht abhängig. In der Einzeldiaansicht schal-
tet sie auf das jeweils nächste Bild weiter, in der Indexansicht wählt sie das Bild unter der Maus
aus und zeigt dieses in der Einzeldiaansicht an. Die rechte Maustaste ruft dagegen das Kontext-
menü auf.
Public Sub Form_MouseDown(Button As Integer, Shift As Integer, _
x As Single, y As Single)
If Button = vbLeftButton Then
' In Indexansicht wählt Klick Einzeldia aus
If bIndexView Then
' Treffertest, um Index des Einzeldias zu berechnen
FileIndex = FileIndex + _
Int(y / ActualForm.ScaleHeight * cIdxZeilen) * cIdxSpalten + _
Int(x / ActualForm.ScaleWidth * cIdxSpalten)
If FileIndex > UBound(FileNames) Then
FileIndex = UBound(FileNames)
End If
mnuIndex_Click
ElseIf mnuBildNächstes.Enabled Then
mnuBildNächstes_Click ' Blättern
End If
Else
Kontextmenü ' Kontextmenü anzeigen
End If
End Sub

Das einzig »Anspruchsvolle« an diesem Code ist die Trefferprüfung, die den Index des Bildes an
der aktuellen Mausposition zunächst theoretisch errechnet und dann gegebenenfalls auf den
Index des letzten Bildes zurechtstutzt. Der Rest ist schiere Fallunterscheidung.
Die Bildweiterschaltung in DiaProjektor reduziert sich somit im Wesentlichen auf drei Behand-
lungsroutinen, die nichts weiter tun, als den Index des nächsten anzuzeigenden Bildes zu
berechnen und dann die Routine Anzeigen aufzurufen.
Private Sub mnuBildErstes_Click() ' Erstes Bild anzeigen
ResetTimer
FileIndex = 1
Anzeigen cCaching
End Sub

Private Sub mnuBildNächstes_Click() ' Nächstes Bild anzeigen


ResetTimer

543
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

If bIndexView Then ' Indexansicht?


If FileIndex + cLargeStep > UBound(FileNames) Then ' Überlauf?
FileIndex = 1
Else
FileIndex = FileIndex + cLargeStep
End If
Else
FileIndex = FileIndex Mod UBound(FileNames) + 1
End If
Anzeigen cCaching
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

End Sub

Private Sub mnuBildVoriges_Click() ' Voriges Bild anzeigen


ResetTimer
If bIndexView Then ' Indexansicht?
If FileIndex – cLargeStep < 1 Then ' Unterlauf?
FileIndex = ((UBound(FileNames) – 2) \ cLargeStep) * cLargeStep + 1
Else
FileIndex = FileIndex – cLargeStep
End If
Else
FileIndex = (FileIndex – 2 + UBound(FileNames)) _
Mod UBound(FileNames) + 1
End If
Anzeigen cCaching
End Sub

Bildlaufleisten für Ansichten einsetzen und auf


Größenänderungen reagieren
Wahrscheinlich ist es Ihnen bereits aufgefallen: Formulare und auch Bildfelder besitzen im
Gegensatz zu Textfeldern und Listenfeldern keine automatischen Bildlaufleisten, wie man sie
von der Dokumentenansicht kommerzieller Programme her gewohnt ist. Das einzige, was da
übrig bleibt, ist die Arbeit mit einem Steuerelement, das Bildlaufleisten unterstützt (etwa Text-
Box, wenn nur Text darzustellen ist, ansonsten gegebenenfalls auch RichTextBox), oder eben der
Einsatz der Bildlaufleisten-Steuerelemente VScrollBar und HScrollBar (respektive FlatScroll-
Bar) und der beherzte Griff in Tasten für die Implementierung der dafür erforderlichen Logik.
Um es gleich vorwegzunehmen, wahre Freude kommt bei der Programmierung mit Bildlaufleis-
ten in Visual Basic nicht auf. Warum die Entwickler den Eigenschaften Value, Min und Max nicht
den Datentyp Single sowie das Koordinatensystem des Containerobjekts zugrunde gelegt
haben, werden sie wohl selbst nicht beantworten können. Die minimalistische Implementation
bietet zudem keine vernünftige Handhabe, um auf die Abmessung der Bildlaufmarke im Sinne
einer proportionalen Repräsentation einzuwirken, und außerdem fehlt die wünschenswerte
Möglichkeit – etwa durch ein Stilattribut –, zwischen der Operation im Intervall [Min, Max] und
der im Intervall [Min, Max – LargeChange] wählen zu können. Ganz zu schweigen von dem Prob-
lem, dass die Bildlaufleiste wie ein Cursor zu blinken anfängt, wenn kein Steuerelement auf dem
Formular ist, das bereit ist, den Fokus anzunehmen. Wer hofft, die Bildlaufleiste von Visual
Basic vernünftig für das einsetzen zu können, wofür sie konzipiert wurde, nämlich für den Bild-
lauf im Sinne des Verschiebens eines Ausschnitts über einen Bereich, der muss sich durch eine

544
Bildlauf – ein kleiner Betrachter für große Bilder

Reihe von Widrigkeiten quälen und schließlich häufig doch mit einer halbgaren Lösung zufrie-
dengeben. Der Grund dafür ist mal wieder in der Abwärtskompatibilität zu suchen. Obwohl
Windows 9x inzwischen auch eine 32-Bit-Implementation der Bildlaufleiste zur Verfügung
stellt, setzen die Standardsteuerelemente sowie auch das »neue« Steuerelement FlatScrollBar
von Visual Basic 6.0 (leider) noch auf die 16-Bit-Version auf, was natürlich gewisse Einschrän-
kungen mit sich bringt. Was zunächst einfach aussieht, artet schnell in wüste Umrechnereien
aus, so dass schnell der Ruf nach einer Scale-Methode und Eigenschaften vom Typ Single laut
wird. Die folgenden beiden Programme BildLauf und HexView verwenden die »alten« Bildlauf-
leisten HScrollBar und VScrollBar. Sie durch das Steuerelement FlatScrollBar zu ersetzen,
erfordert keine Änderung in der Implementation, wenn Sie die Ausrichtung bereits zur Ent-
wurfszeit festlegen.

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


Bildlauf – ein kleiner Betrachter für große Bilder
Genug der Trauer, sehen wir uns das Beispielprogramm Bildlauf an, das es erlaubt, ein Bild
über den Standarddialog Öffnen oder per OLE-Drag&Drop zu laden und den sichtbaren Aus-
schnitt per Bildlaufleisten zu verschieben. Das Formular ist in seiner Größe veränderlich und
passt die Bildlaufleisten sowie deren Zustände an seine jeweiligen Abmessungen an. Die
Anzeige der Bildlaufleisten erfolgt nur, wenn das Bild in der jeweiligen Dimension nicht in den
Client-Bereich des Formulars passt. Um zu vermeiden, dass eine der Bildlaufleisten blinkt, weil
kein anderes Steuerelement den Fokus entgegennimmt, verwendet die Implementation ein
Dummy-Textfeld als Fokusfänger, das unsichtbar bleibt, weil es außerhalb des sichtbaren
Bereichs positioniert wird.

Das Programm Bildlauf in Aktion

Hier der Code:


'***********************************************************************
' Formularmodul: Bildlauf
' Autor : 2000 Rudolf Huttary
' Beschreibung : demonstriert Implementation von Bildlaufleisten
'***********************************************************************
Option Explicit
Dim PicWidth As Integer, PicHeight As Integer
Dim pic As Picture

545
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

Private Sub Form_Load()


HScroll1.Left = 0
VScroll1.Top = 0
Text1.Locked = True ' Fokusfänger für Eingaben sperren
mnuDateiÖffnen_Click
End Sub

Private Sub Form_Paint()


If Not pic Is Nothing Then ' Bild geladen?
' sichtbaren Ausschnitt zeichnen
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

PaintPicture pic, ScaleLeft, ScaleTop, , , _


2 * ScaleLeft, 2 * ScaleTop, HScroll1.Width, VScroll1.Height
End If
End Sub

Private Sub Form_Resize()


If Not WindowState = vbMinimized Then
Height = IIf(Height < 1000, 1000, Height)
Width = IIf(Width < 1000, 1000, Width)
' Sichtbarkeit der Bildlaufleisten errechnen
If PicWidth > ScaleWidth – VScroll1.Width And _
PicHeight > ScaleHeight – HScroll1.Height Then ' Beide nötig?
HScroll1.Visible = True
VScroll1.Visible = True
ElseIf PicWidth > ScaleWidth Then ' horizontal?
HScroll1.Visible = True
VScroll1.Visible = False
ElseIf PicHeight > ScaleHeight Then ' vertikal?
VScroll1.Visible = True
HScroll1.Visible = False
Else ' Beide unnötig
HScroll1.Visible = False
VScroll1.Visible = False
End If
' Korrektur: Doch beide unnötig?
If PicWidth <= ScaleWidth And PicHeight <= ScaleHeight Then
HScroll1.Visible = False
VScroll1.Visible = False
End If

' Abmessungen der Bildlaufleisten


VScroll1.Left = ScaleLeft + ScaleWidth – VScroll1.Width
VScroll1.Height = ScaleHeight + HScroll1.Height * HScroll1.Visible
HScroll1.Top = ScaleTop + ScaleHeight – HScroll1.Height
HScroll1.Width = ScaleWidth – IIf(VScroll1.Visible, _
VScroll1.Width, 0)
Text1.Left = ScaleLeft + ScaleWidth ' Fokusfänger !!

' Bildlaufparameter anpassen


If Not pic Is Nothing Then
If VScroll1.Visible Then

546
Bildlauf – ein kleiner Betrachter für große Bilder

VScroll1.Max = PicHeight – VScroll1.Height


VScroll1.LargeChange = VScroll1.Height
VScroll1.SmallChange = VScroll1.Height / 10
End If
If HScroll1.Visible Then
HScroll1.Max = PicWidth – HScroll1.Width
HScroll1.LargeChange = HScroll1.Width
HScroll1.SmallChange = HScroll1.Width / 10
End If
End If

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


' Bildlaufleisten ggf. unsichtbar machen, falls Bild passt
Refresh
End If
End Sub

Private Sub mnuDateiBeenden_Click()


Unload Me
End Sub

Private Sub mnuDateiÖffnen_Click()


CommonDialog1.Filter = "Bilder (JPG, GIF, BMP)|*.jpg;*.gif;*.bmp"
CommonDialog1.ShowOpen ' Bilddatei in Erfahrung bringen
If CommonDialog1.FileName <> "" Then
ReadPic CommonDialog1.FileName
Caption = "Bildlauf – " & CommonDialog1.FileTitle
Form_Resize ' Bildlaufleisten aktualisieren
End If
End Sub

Private Sub HScroll1_Change()


' Ursprung nach links verschieben
ScaleLeft = HScroll1.Value
Refresh
End Sub

Private Sub HScroll1_Scroll()


' Anloges Verschieben während des Ziehens
ScaleLeft = HScroll1.Value
Text1.SetFocus ' Fokusfänger
Refresh ' Neu zeichnen
End Sub

Private Sub VScroll1_Change()


' Ursprung nach oben verschieben
ScaleTop = VScroll1
Text1.SetFocus ' Fokusfänger
Refresh
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, x As Single, y As Single)

547
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

' Nur Datei von Explorer-Fenster entgegennehmen


If Data.GetFormat(vbCFFiles) Then
ReadPic Data.Files(1)
Form_Resize ' Bildlaufleisten aktualisieren
End If
End Sub

' Bild einlesen


Private Sub ReadPic(FileName As String)
On Error GoTo Abbruch
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

Set pic = LoadPicture(FileName)


' Bildabmessungen in Twips umrechnen
ScaleMode = vbTwips ' Twips einstellen
ScaleMode = vbUser ' Twips einstellen
On Error GoTo NeuSkalierenW
PicWidth = ScaleX(pic.Width, vbHimetric, vbUser)
On Error GoTo NeuSkalierenH
PicHeight = ScaleY(pic.Height, vbHimetric, vbUser)
Exit Sub

NeuSkalierenW:
ScaleWidth = ScaleWidth / 10
Resume
NeuSkalierenH:
ScaleHeight = ScaleHeight / 10
Resume
Abbruch:

End Sub

Beim Programmstart klebt die Load-Routine die Bildlaufleisten an das linke bzw. obere Ende
des Client-Bereichs, sperrt das Textfeld für Eingaben und führt dann die Behandlungsroutine
mnuDateiÖffnen_Click für den Menübefehl ÖFFNEN aus. Diese ruft den Standarddialog ÖFFNEN
und lässt dann die vom Benutzer spezifizierte Datei von ReadPic einlesen. Das Besondere an
ReadPic ist, dass die Routine nach dem erfolgreichen Laden des Bildes dessen Abmessungen in
die für das Formular geltende Skalierungseinheit Twips umrechnet und versucht, die Werte im
Datentyp Integer der dafür vorgesehenen Variablen PicWidth und PicHeight unterzukriegen.
Dahinter steckt der Gedanke, das Koordinatensystem Eins-zu-Eins für den von 16-Bit-Bildlauf-
leisten unterstützten Wertebereich 0 bis 32767 benutzen zu können. Falls das nicht klappt, tritt
ein Laufzeitfehler auf, dessen Behandlung die Spreizung der jeweiligen Koordinatenachse um
den Faktor 10 gefolgt von einem erneuten Umrechnungsversuch vorsieht. Dies passiert so oft,
bis das Koordinatensystem passt. Als Vorbereitung bewirkt der Code
ScaleMode = vbTwips ' Twips einstellen
ScaleMode = vbUser ' benutzerdef. Koordinatensystem aktivieren

dass sich das benutzerdefinierte Koordinatensystem mit dem Koordinatensystem vbTwips deckt.
Mit diesem Verfahren darf das Bild in einer Dimension theoretisch bis zu 232 Twips messen
(was etwa 80 km entspricht). Falls Sie die tatsächlichen Spreizungsfaktoren benötigen, schrei-
ben Sie:
ScaleFaktX = ScaleX(1, vbUser, vbTwips)
ScaleFaktX = ScaleY(1, vbUser, vbTwips)

548
Bildlauf – ein kleiner Betrachter für große Bilder

Auf das Einlesen des Bildes folgt der Aufruf Resize_Form. Diese speziell auf die Behandlung des
Resize-Ereignisses zugeschnittene Routine aktualisiert die Zustände beider Bildlaufleisten unter
Bezugnahme auf die aktuellen Abmessungen des Client-Bereichs und veranlasst dann die Aus-
gabe des Bildes. Die Zustandsaktualisierung der Bildlaufleisten erfordert im ersten Schritt einen
Test, inwieweit ihre Anzeige überhaupt erforderlich ist. Das ist logisch ein wenig verzwickt, da
sich die Fälle, dass das Bild gerade noch in den Client-Bereich passt, sowie dass beide Leisten
angezeigt werden und das Bild eben gerade deshalb nicht mehr in den Client-Bereich passt,
überschneiden. Die vorgestellte Lösung mit der Nachkorrektur des schwierigen Falls ist sicher
nicht die eleganteste, aber sie ist gut lesbar und funktioniert:
If PicWidth > ScaleWidth – VScroll1.Width And _

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


PicHeight > ScaleHeight – HScroll1.Height Then ' Beide nötig?
HScroll1.Visible = True
VScroll1.Visible = True
ElseIf PicWidth > ScaleWidth Then ' horizontal?
HScroll1.Visible = True
VScroll1.Visible = False
ElseIf PicHeight > ScaleHeight Then ' vertikal?
VScroll1.Visible = True
HScroll1.Visible = False
Else ' Beide unnötig
HScroll1.Visible = False
VScroll1.Visible = False
End If
' Korrektur: Doch beide unnötig?
If PicWidth <= ScaleWidth And PicHeight <= ScaleHeight Then
HScroll1.Visible = False
VScroll1.Visible = False
End If

Sobald die Sichtbarkeit geklärt ist, lässt sich die Länge der Bildlaufleisten errechnen. Der Code
stellt zwei äquivalente Lösungen vor, wie man eine Fallunterscheidung geschickt implizit for-
mulieren kann: einmal als Multiplikation mit dem Wahrheitswert des Kriteriums, wobei das
Vorzeichen des Werts True (-1) zu beachten ist, und einmal als IIf-Ausdruck. Darüber hinaus
sorgt der Code dafür, dass das Dummy-Textfeld Text1 außerhalb des Client-Bereichs bleibt.
VScroll1.Left = ScaleLeft + ScaleWidth – VScroll1.Width
VScroll1.Height = ScaleHeight + HScroll1.Height * HScroll1.Visible
HScroll1.Top = ScaleTop + ScaleHeight – HScroll1.Height
HScroll1.Width = ScaleWidth – IIf(VScroll1.Visible, VScroll1.Width, 0)
Text1.Left = ScaleLeft + ScaleWidth ' Fokusfänger !!

Es fehlt noch die Anpassung der Eigenschaften Max, LargeChange und SmallChange an die aktuel-
len Gegebenheiten. Der Bildlaufbereich Max errechnet sich aus der Breite bzw. Höhe des Bildes
(im aktuellen Koordinatensystem) abzüglich der aktuellen Ausschnittsbreite bzw. -höhe. Diese
Differenz ist nur dann positiv, wenn die Leiste angezeigt wird und erfordert somit eine Fallun-
terscheidung. LargeChange sollte auf die Breite bzw. Höhe des sichtbaren Ausschnitts gesetzt
werden, um einen exakten Vorschub um genau eine Ausschnittsbreite bzw. -höhe zu erhalten.
In diesem Fall drückt die Ausdehnung der Bildlaufmarke relativ zum Bildlaufschaft exakt die
Ausdehnung des Ausschnitts relativ zur Ausdehnung des Bildes aus. In der Praxis wird Lar-
geChange zuweilen auch etwas kleiner gesetzt, um eine Überlappung beim seitenbasierten Bild-
lauf (Mausklick in den Bildlaufschaft) zu erreichen. Für LargeChange ist nichts Spezielles vorge-
schrieben. Ein guter Wert dafür ist etwa ein Zehntel des Werts von LargeChange für Bilder,

549
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

während man für zeilenorientierte Darstellungen das Verhältnis über die aktuelle Zeilenanzahl
pro Seite berechnen wird.
If Not pic Is Nothing Then
If VScroll1.Visible Then
VScroll1.Max = PicHeight – VScroll1.Height
VScroll1.LargeChange = VScroll1.Height
VScroll1.SmallChange = VScroll1.Height / 10
End If
If HScroll1.Visible Then
HScroll1.Max = PicWidth – HScroll1.Width
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

HScroll1.LargeChange = HScroll1.Width
HScroll1.SmallChange = HScroll1.Width / 10
End If
End If

Jetzt gilt es noch eine Hürde zu überwinden, nämlich die Ausgabe des Bildes mit PaintPicture.
Sie sollte so erfolgen, dass nur der jeweils relevante Bildausschnitt gezeichnet werden muss.
Wenn Sie mit einer Paint-Routine arbeiten, reicht ein Refresh-Aufruf innerhalb von
Form_Resize, ansonsten müssen Sie die Paint-Routine (oder deren Äquivalent) explizit aufrufen.
Der Code lautet:
Private Sub Form_Paint()
If Not pic Is Nothing Then ' Bild geladen?
' sichtbaren Ausschnitt zeichnen
PaintPicture pic, ScaleLeft, ScaleTop, , , _
2 * ScaleLeft, 2 * ScaleTop, HScroll1.Width, VScroll1.Height
End If
End Sub

Auch wenn die Paint-Routine harmlos aussieht, der PaintPicture-Aufruf hat es in sich, was die
Findung der Parameterwerte betrifft, weil die Implementation von PaintPicture nicht gerade
intuitiv bzw. fehlerhaft ist. Da Bildlaufleisten, Koordinatensystem und Bild aufgrund der beson-
deren Wahl von Max exakt aufeinander abgestimmt sind, sollte klar sein, was zu tun ist: Der
linke obere Punkt für die Ausgabe ist der linke obere Punkt des Client-Bereichs im aktuellen
Koordinatensystem, also (ScaleLeft, ScaleHeight). Der linke obere Punkt des Bildausschnitts
hat in diesem Koordinatensystem relativ zum Bildursprung gleichfalls die Koordinaten
(ScaleLeft, ScaleHeight) und sollte links oben im Client-Bereich erscheinen. Man möchte nun
meinen, der Aufruf sollte so aussehen:
PaintPicture pic, ScaleLeft, ScaleTop, , , ScaleLeft, ScaleTop, _
HScroll1.Width, VScroll1.Height

denn schließlich zeichnet


PaintPicture pic, ScaleLeft, ScaleTop

unabhängig vom Ursprung des Koordinatensystems das Bild artig in die linke obere Ecke. Wie
ein Blick auf die »Lösung« verrät, denkt Microsoft darüber jedoch anders: PaintPicture erwar-
tet auch die Koordinaten für einen Bildausschnitt relativ zum Ursprung des Koordinatensystems
– somit sind der linke obere Punkt für die Ausgabe und der linke obere Punkt für den Aus-
schnitt (bezogen auf den Bildursprung) zu addieren. Jetzt sind Sie dran!
Die Abmessungen des Ausschnitts ergeben sich über die Werte für die Breite bzw. Höhe der
Bildlaufleisten, die Form_Resize ja in jedem Fall richtig berechnet.

550
HexView – eine schnelle Textansicht für große Dateien

Bleibt als Letztes ein Blick auf die Change- und Scroll-Behandlung der Bildlaufleisten. Eine
Scroll-Behandlung für die vertikale Bildlaufleiste wurde in Bildlauf bewusst weggelassen,
damit sich der Unterschied ausprobieren lässt. Das Change-Ereignis tritt in einer einzelnen Bild-
laufleistenaktion nur ein einziges Mal auf, nachdem der Benutzer eine Positionsänderung der
Bildlaufmarke vollzogen hat, das Scroll-Ereignis tritt dagegen mehrfach auf, wenn der Benut-
zer die Bildlaufmarke mit der Maus zieht. Damit die Bildlaufleiste nicht zu blinken anfängt,
wird der Fokus an das Textfeld weitergeschoben.
Private Sub HScroll1_Change()
' Ursprung nach links verschieben
ScaleLeft = HScroll1.Value

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


Text1.SetFocus ' Fokusfänger
Refresh
End Sub

Private Sub HScroll1_Scroll()


' Anloges Verschieben während des Ziehens
ScaleLeft = HScroll1.Value
Refresh ' Neu zeichnen
End Sub

Private Sub VScroll1_Change()


' Ursprung nach oben verschieben
ScaleTop = VScroll1
Text1.SetFocus ' Fokusfänger
Refresh
End Sub

HexView – eine schnelle Textansicht für große Dateien


Im Gegensatz zu Bildansichten nach dem Muster der Beispiele DiaProjektor und Bildlauf ist die
Ausgabe von Textansichten zuweilen mit einem erheblichen Rechenaufwand verbunden. Und
der Umgang mit Bildlaufleisten sieht vom Prinzip her genauso aus – bis auf einige Details, da
man sich mit einem vorgegebenen Koordinatensystem herumschlagen muss.
Das Beispielprojekt HexView demonstriert die Implementation einer Textansicht und stellt
dabei nicht nur eine Reihe von Zeichenfolgenfunktionen vor, sondern auch den Zugriff auf
Binärdateien. Das für das Programm verwendete Formular enthält zwei (!) Bildlaufleisten für
den horizontalen und eine für den vertikalen Bildlauf, ein Textfeld, dem die leidliche Aufgabe
als Fokusfänger zufällt, sowie ein Standarddialoge-Steuerelement, das für die Ermittlung des
Dateinamens herangezogen wird. Alternativ öffnet das Programm aber auch Dateien, die per
OLE-Drag&Drop in das Fenster der Anwendung abgelegt werden.
Wie die Abbildung zeigt, generiert das Programm seine Ansicht so, wie man sie von einem
»HexViewer« erwarten würde. Der Zeilenaufbau hat Tradition: Byteposition in hexadezimaler
Repräsentation zu Beginn der Zeile, danach die Bytes in hexadezimaler Repräsentation gefolgt
von der ASCII-Repräsentation. Im Gegensatz zu vielen anderen als Freeware erhältlichen Hex-
Viewern, zeigt das Programm auch bei großen Dateien (in der abgebildeten Sitzung umfasst die
Datei 12 MB) keine nennenswerten Verzögerungen, da es jeweils nur die für die aktuelle
Ansicht benötigten Daten aus der Binärdatei liest. Der Grund, warum viele vergleichbare Pro-
gramme bei Dateien ab ca. 512 KB dichtmachen, liegt tatsächlich am eingeschränkten Wertebe-
reich der 16-Bit-Bildlaufleiste. HexView verwendet den Trick, einfach zwei Bildlaufleisten zu
kaskadieren, um diese Beschränkung zu überwinden.

551
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

Das Programm HexView in Aktion

Freilich lässt der Funktionsumfang des Programms noch einiges zu wünschen übrig, beispiels-
weise eine Suchfunktion oder gar einen Bearbeitungsmodus. Nehmen Sie den Quelltext doch
einfach als Ausgangsposition für eigene Implementationsversuche in dieser Richtung.
'***********************************************************************
' Formularmodul: HexViewer
' Autor : 2000 Rudolf Huttary
' Beschreibung : Demonstriert den Einsatz von Bildlaufleisten für
' Textansichten
'***********************************************************************

Option Explicit
Const cLines = 40
Const cCols = 16
Const cChars = 80
Const cMaxScroll As Long = 32768

Dim BinLines As Long ' Zeilenanzahl gesamt


Private Lines As Long ' Zeilenanzahl in Ansicht

Private Sub Form_Load()


HScroll1.Left = 0 ' links ankleben
VScroll1.Top = 0 ' oben ankleben
VScroll2.Top = 0 ' oben ankleben
VScroll1.Height = HScroll1.Width ' gleiche "Breite"
VScroll2.Height = HScroll1.Width ' gleiche "Breite"
Text1.Locked = True ' Fokusfänger für Eingaben sperren
FontName = "FixedSys" ' nichtproportionale Schrift
Show
Height = Height – ScaleHeight + cLines * TextHeight("a")
Width = Width – ScaleWidth + cChars * TextWidth("a") + VScroll1.Width
Scale (0, 0)-(cChars, cLines)

552
HexView – eine schnelle Textansicht für große Dateien

Lines = cLines
mnuDateiÖffnen_Click
End Sub

Private Sub Form_Paint()


Dim i As Long
Dim LastLine As Long
If BinLines Then
CurrentX = 0 ' ganz links
LastLine = ScaleTop + Lines

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


If LastLine > BinLines – 1 Then
LastLine = BinLines
ScaleTop = BinLines – Lines
End If
CurrentY = ScaleTop ' zur obersten Zeile
For i = ScaleTop + 1 To LastLine
Print MakeLine(i)
Next i
End If
End Sub

Private Sub Form_Resize()


If Not WindowState = vbMinimized Then
Height = IIf(Height < 1200, 1200, Height)
Width = IIf(Width < 1000, 1000, Width)
Text1.Top = ScaleHeight ' Fokusfänger!
HScroll1.Visible = ScaleWidth < cChars ' Sichtbarkeit
VScroll1.Visible = BinLines > Lines ' Sichtbarkeit
VScroll2.Visible = BinLines > cMaxScroll ' Sichtbarkeit
Lines = Int(ScaleHeight + HScroll1.Height * HScroll1.Visible)

' Abmessungen der Bildlaufleisten


HScroll1.Top = ScaleTop + ScaleHeight – HScroll1.Height
HScroll1.Width = ScaleWidth + VScroll1.Width * VScroll1.Visible
VScroll1.Left = ScaleLeft + ScaleWidth – VScroll1.Width
VScroll1.Height = ScaleHeight + HScroll1.Height * HScroll1.Visible

' horizontale Bildlaufparameter anpassen


If HScroll1.Visible Then
HScroll1.Max = cChars – ScaleWidth
HScroll1.LargeChange = ScaleWidth
HScroll1.SmallChange = 1
End If
' vertikale Bildlaufparameter anpassen
If BinLines >= cMaxScroll Then
VScroll2.Left = VScroll1.Left
VScroll2.Height = VScroll1.Height
VScroll1.Left = VScroll2.Left – VScroll1.Width
VScroll1.Height = VScroll2.Height
VScroll2.Max = BinLines / cMaxScroll
VScroll2.LargeChange = VScroll2.Max / 10

553
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

VScroll2.SmallChange = 1
End If
If VScroll1.Visible Then
VScroll1.Max = BinLines Mod cMaxScroll – Lines
VScroll1.LargeChange = Lines – 1
VScroll1.SmallChange = 1
End If
Refresh
End If
End Sub
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

Private Sub mnuDateiÖffnen_Click()


CommonDialog1.Filter = "Alle Dateien|*.*"
CommonDialog1.ShowOpen ' Datei in Erfahrung bringen
If CommonDialog1.FileName <> "" Then
OpenBinary CommonDialog1.FileName
End If
Form_Resize ' Bildlaufl. aktualisieren
End Sub

Private Sub mnuDateiBeenden_Click()


Unload Me
End Sub

Private Sub OpenBinary(FileName)


VScroll1 = 0 ' Re-Initialisierung
VScroll2 = 0 ' Re-Initialisierung
HScroll1 = 0
ScaleTop = 0
ScaleLeft = 0
BinLines = 0
Caption = "HexView"
' Datei öffnen
Close 1
On Error GoTo Abbruch
Open FileName For Binary As 1
Caption = "HexView – " & Mid(FileName, InStrRev(FileName, "\") + 1) _
& " (" & Format(LOF(1), "#,#") & " Bytes)"
BinLines = LOF(1) / cCols + 1 ' Zeilenanzahl
Abbruch:
End Sub

Private Sub VScroll1_Scroll()


UpdateV
End Sub

Private Sub VScroll1_Change()


UpdateV
End Sub

554
HexView – eine schnelle Textansicht für große Dateien

Private Sub VScroll2_Scroll()


UpdateV
End Sub

Private Sub VScroll2_Change()


UpdateV
End Sub

Private Sub UpdateV()


ScaleTop = VScroll2 * cMaxScroll + VScroll1

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


Text1.SetFocus
Refresh ' neu zeichnen
End Sub

Private Sub HScroll1_Scroll()


' Anloges Verschieben während des Ziehens
ScaleLeft = HScroll1
Text1.SetFocus
Refresh ' neu zeichnen
End Sub

Private Sub HScroll1_Change()


' Verschieben am Ende der Aktion
ScaleLeft = HScroll1
Text1.SetFocus ' Fokusfänger
Refresh ' neu zeichnen
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, x As Single, y As Single)
' Nur Datei von Explorer-Fenster entgegennehmen
If Data.GetFormat(vbCFFiles) Then
OpenBinary Data.Files(1)
Form_Resize ' Bildlaufl. aktualisieren
End If
End Sub

' Liest Length Bytes ab Position FromIdx, gibt Dateilänge zurück


Private Function ReadBinary(Bin$, FromIdx As Long, Length As Long) _
As Long
If BinLines Then
Seek 1, FromIdx
Bin = Input(Length, 1) ' Block Lesen
ReadBinary = LOF(1) ' Länge
End If
End Function

' Generiert eine Zeile für die Hexansicht


Private Function MakeLine(Zeile As Long) As String
Dim i As Long, lenBin As Long
Dim h$, Bin$, HexLine$, CharLine$ ' Stringpuffer

555
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

Dim ByteH As Integer

i = (Zeile – 1) * cCols + 1
lenBin = ReadBinary(Bin, i, cCols) ' cCols Zeichen ab i lesen
For i = 1 To cCols ' Byteweise durch den String
If i + (Zeile – 1) * cCols >= lenBin Then Exit For
ByteH = Asc(Mid(Bin, i, 1)) ' byteweise!
h = Right("0" + Hex(ByteH), 2) + " " ' nach Hex
If ByteH < 32 Then ' nicht druckbares Zeichen?
ByteH = Asc(".")
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

End If
HexLine = HexLine + h
CharLine = CharLine + Chr(ByteH)
Next i

' Zeile zusammenbauen


' Hexadezimale Zeilenanfänge
' MakeLine = Right(" " & Hex((Zeile – 1) * cCols), 8) & ": " & _
' HexLine
' Dezimale Zeilenanfänge
MakeLine = Right(" " & Str((Zeile – 1) * cCols), 8) & ": " & _
HexLine
MakeLine = Left(MakeLine + Space(45), 58) + "- " + CharLine
End Function

Wie für dateiorientierte SDI-Anwendungen üblich, ruft HexView nach Erledigung der Initiali-
sierung noch im Rahmen von Load den Standarddialog ÖFFNEN auf. Durchaus interessant in
dieser Routine ist die Berechnung der Voreinstellung für die Formularabmessungen, in die die
Zeichenbreite bzw. -höhe der eingestellten nichtproportionalen Schrift eingeht. Height und
Width sind unabhängig vom Koordinatensystem immer in Twips anzugeben. Der frühe Show-
Aufruf ist leider erforderlich, damit auch die Höhe der Menüleiste in die Berechnung für die
Zeilenhöhe eingeht. Das Koordinatensystem ergibt sich dann einfach aus den Werten für die
Zeilenanzahl und die Zeichenzahl je Zeile und behält seine Skalierung (nicht jedoch seinen
Ursprung!) im gesamten Programmablauf bei.
Const cLines = 40
Const cCols = 16
Const cChars = 80

Private Sub Form_Load()


HScroll1.Left = 0 ' links ankleben
VScroll1.Top = 0 ' oben ankleben
VScroll2.Top = 0 ' oben ankleben
VScroll1.Height = HScroll1.Width ' gleiche "Breite"
VScroll2.Height = HScroll1.Width ' gleiche "Breite"
Text1.Locked = True ' Fokusfänger für Eingaben sperren
FontName = "FixedSys" ' nichtproportionale Schrift
Show
Height = Height – ScaleHeight + cLines * TextHeight("a")
Width = Width – ScaleWidth + cChars * TextWidth("a") + VScroll1.Width
Scale (0, 0)-(cChars, cLines)
Lines = cLines

556
HexView – eine schnelle Textansicht für große Dateien

mnuDateiÖffnen_Click
End Sub

Falls der Benutzer den Dialog abbricht, kann er die Routine mnuDateiÖffnen_Click später
immer noch per Menübefehl ÖFFNEN aktivieren oder aber er importiert die Daten per OLE-
Drag&Drop. (Details und Implementationstechniken für OLE-Drag&Drop-Operationen fin-
den Sie im Abschnitt »OLE-Drag&Drop«, S. 501.)
Private Sub mnuDateiÖffnen_Click()
CommonDialog1.Filter = "Alle Dateien|*.*"
CommonDialog1.ShowOpen ' Datei in Erfahrung bringen

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


If CommonDialog1.FileName <> "" Then
OpenBinary CommonDialog1.FileName
End If
Form_Resize ' Bildlaufl. aktualisieren
End Sub

Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, x As Single, y As Single)
' Nur Datei von Explorer-Fenster entgegennehmen
If Data.GetFormat(vbCFFiles) Then
OpenBinary Data.Files(1)
Form_Resize ' Bildlaufl. aktualisieren
End If
End Sub

Den Kern beider Routinen bildet der OpenBinary-Aufruf, dessen Aufgabe darin besteht, Bild-
laufleisten und Koordinatensystem zu reinitialisieren und die Datei FileName im binären Modus
zu öffnen. Außerdem berechnet die Routine die Zeilenanzahl BinLines für die komplette Dar-
stellung der Datei im gewählten Zeilenformat:
Private Sub OpenBinary(FileName)
VScroll1 = 0 ' Reinitialisierung
VScroll2 = 0
HScroll1 = 0
ScaleTop = 0
ScaleLeft = 0
BinLines = 0
Caption = "HexView"
' Datei öffnen
Close 1
On Error GoTo Abbruch
Open FileName For Binary As 1
Caption = "HexView – " & Mid(FileName, InStrRev(FileName, "\") + 1) _
& " (" & Format(LOF(1), "#,#") & " Bytes)"
BinLines = LOF(1) / cCols + 1 ' Zeilenanzahl
Abbruch:
End Sub

Die Voraussetzung für das korrekte Zeichnen der Ansicht schafft Form_Resize. Diese als
Behandlungsroutine für das Resize-Ereignis erforderliche Methode verhindert, dass der Client-
Bereich zu klein wird und dass die Bildlaufleisten nicht nur an der richtigen Position sitzen, son-
dern auch den aktuellen Ausschnitt bezogen auf die gesamte Ansicht korrekt visualisieren.

557
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

Wegen der 16-Bit-Beschränkung muss deshalb gegebenenfalls noch eine zweite vertikale Bild-
laufleiste angezeigt werden. Ansonsten ist die Logik fast die gleiche wie die für eine Bildansicht.
Die Routine klärt die Sichtbarkeit der Bildlaufleisten, ermittelt die Anzahl der in der Ansicht
darstellbaren Zeilen, korrigiert die Abmessungen der Bildlaufleisten und passt schließlich noch
die Bildlaufleistenparameter an die aktuellen Gegebenheiten an, bevor sie die Ansicht via
Refresh zum Zeichnen freigibt.
Private Sub Form_Resize()
If Not WindowState = vbMinimized Then
Height = IIf(Height < 1200, 1200, Height)
Width = IIf(Width < 1000, 1000, Width)
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

Text1.Top = ScaleHeight ' Fokusfänger!


HScroll1.Visible = ScaleWidth < cChars ' Sichtbarkeit
VScroll1.Visible = BinLines > Lines ' Sichtbarkeit
VScroll2.Visible = BinLines > cMaxScroll ' Sichtbarkeit
Lines = Int(ScaleHeight + HScroll1.Height * HScroll1.Visible)

' Abmessungen der Bildlaufleisten


HScroll1.Top = ScaleTop + ScaleHeight – HScroll1.Height
HScroll1.Width = ScaleWidth + VScroll1.Width * VScroll1.Visible
VScroll1.Left = ScaleLeft + ScaleWidth – VScroll1.Width
VScroll1.Height = ScaleHeight + HScroll1.Height * HScroll1.Visible

' horizontale Bildlaufparameter anpassen


If HScroll1.Visible Then
HScroll1.Max = cChars – ScaleWidth
HScroll1.LargeChange = ScaleWidth
HScroll1.SmallChange = 1
End If
' vertikale Bildlaufparameter anpassen
If BinLines >= cMaxScroll Then
VScroll2.Left = VScroll1.Left
VScroll2.Height = VScroll1.Height
VScroll1.Left = VScroll2.Left – VScroll1.Width
VScroll1.Height = VScroll2.Height
VScroll2.Max = BinLines / cMaxScroll
VScroll2.LargeChange = VScroll2.Max / 10
VScroll2.SmallChange = 1
End If
If VScroll1.Visible Then
VScroll1.Max = BinLines Mod cMaxScroll – Lines
VScroll1.LargeChange = Lines – 1
VScroll1.SmallChange = 1
End If
Refresh
End If
End Sub

Die zweite vertikale Bildlaufleiste kommt nur dann ins Spiel, wenn die Zeilenanzahl nicht mehr
in den Datentyp Integer passt. In diesem Fall wirkt sie wie der kleine Zeiger einer Uhr: Jeder
Einzelschritt der rechten Bildlaufleiste ist ein voller Durchlauf der linken. Die Ereignisbehand-
lung für die Bildlaufleisten ist überraschend einfach, die Routinen VScroll1_Change,

558
HexView – eine schnelle Textansicht für große Dateien

VScroll1_Scroll, VScroll2_Change und VScroll2_Scroll können dafür sogar den identischen


Code benutzen, der in UpdateV zusammengefasst ist.
Private Sub UpdateV()
ScaleTop = VScroll2 * cMaxScroll + VScroll1
Text1.SetFocus
Refresh ' neu zeichnen
End Sub

Man sieht: Jede Bildlaufleistenoperation verschiebt den Ursprung des Koordinatensystems in


vertikaler Richtung. Noch einfacher ist der Fall bei der horizontalen Bildlaufleiste:

Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen


Private Sub HScroll1_Scroll()
' Anloges Verschieben während des Ziehens
ScaleLeft = HScroll1
Text1.SetFocus
Refresh ' neu zeichnen
End Sub

Private Sub HScroll1_Change()


' Verschieben am Ende der Aktion
ScaleLeft = HScroll1
Text1.SetFocus ' Fokusfänger
Refresh ' neu zeichnen
End Sub

Die via Refresh auf den Plan gerufene Paint-Routine gibt nur den aktuellen Ausschnitt aus,
wobei ScaleTop + 1 die Zeilennummer der ersten auszugebenden Zeile beschreibt.
Private Sub Form_Paint()
Dim i As Long
Dim LastLine As Long
CurrentX = 0 ' ganz links
LastLine = ScaleTop + Lines
If LastLine > BinLines – 1 Then
LastLine = BinLines
ScaleTop = BinLines – Lines
End If
CurrentY = ScaleTop ' zur obersten Zeile
For i = ScaleTop + 1 To LastLine
Print MakeLine(i)
Next i
End Sub

MakeLine, die fleißigste Routine in diesem Aufbau, übernimmt die Zusammenstellung der ein-
zelnen Zeilen. Dazu lässt sie sich von der Routine ReadBinary die zu der jeweiligen Zeile gehöri-
gen Daten aus der noch geöffneten Datei in Form einer Zeichenfolge sowie die Gesamtlänge der
Datei liefern. Unter Hinzunahme der aktuellen Zeilennummer bastelt die Funktion daraus die
für hexadezimale Ansichten übliche Zeilendarstellung.
' Liest Length Bytes ab Position FromIdx, gibt Dateilänge zurück
Private Function ReadBinary(Bin$, FromIdx As Long, Length As Long) As Long
If BinLines Then
Seek 1, FromIdx

559
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren

Bin = Input(Length, 1) ' Block Lesen


ReadBinary = LOF(1) ' Länge
End If
End Function

' Generiert eine Zeile für die Hexansicht


Private Function MakeLine(Zeile As Long) As String
Dim i As Long, lenBin As Long
Dim h$, Bin$, HexLine$, CharLine$ ' Stringpuffer
Dim ByteH As Integer
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen

i = (Zeile – 1) * cCols + 1
lenBin = ReadBinary(Bin, i, cCols) ' cCols Zeichen ab i lesen
For i = 1 To cCols ' Byteweise durch den String
If i + (Zeile – 1) * cCols >= lenBin Then Exit For
ByteH = AscB(Mid(Bin, i, 1)) ' byteweise!
h = Right("0" + Hex(ByteH), 2) + " " ' nach Hex
If ByteH < 32 Then ' nicht druckbares Zeichen?
ByteH = Asc(".")
End If
HexLine = HexLine + h
CharLine = CharLine + Chr(ByteH)
Next i

' Zeile zusammenbauen


' Hexadezimale Zeilenanfänge
MakeLine = Right(" " & Hex((Zeile – 1) * cCols), 8) & ": " & _
HexLine
' Dezimale Zeilenanfänge
' MakeLine = Right(" " & Str((Zeile – 1) * cCols), 8) & ": " & _
' HexLine
MakeLine = Left(MakeLine + Space(45), 58) + "- " + CharLine
End Function

Nachdem ReadBinary die Funktion Input zum Lesen der Daten einsetzt, liefert sie als Ergebnis
eine Unicode-Zeichenfolge, so dass MakeLin mittels Mid die einzelnen Bytes extrahieren kann.
Würde ReadBinary mit InputB arbeiten (was von der Laufzeit her günstiger ist), müsste MakeLin
für die Zerlegung eben MidB verwenden.

Weitere Features?
In der vorgestellten Form bietet der Code einen sehr guten Ausgangspunkt für die Implementa-
tion weiterer Features. Als Erstes wird man eine Suchfunktion ergänzen, wobei sich die Eingabe
des Suchstrings sinnvollerweise über ein eigenes Formular mit zwei Textfeldern lösen lässt:
eines für die Eingabe einer ASCII-Zeichenfolge, eines für die Eingabe einer hexadezimalen Zei-
chenfolge. Durch sinngemäße Erweiterung des Schemas gelangt man ohne großen Aufwand zur
Ersetze-Funktionalität.
Etwas mehr Einsatz erfordert da schon die Implementierung eines Bearbeitungsmodus, in dem
der Benutzer die Datei wie einen Text im Überschreibmodus editieren kann. HexViewer wird
damit zum »Patch-Editor«. Da ein Formular, anders als ein Textfeld, für seinen Client-Bereich
keinen Bearbeitungsmodus kennt, kann man sich eines kleinen Tricks bedienen, um dennoch in
den Genuss der Eingabefunktionalität zu kommen: Man spendiert dem Formular zwei weitere,

560
Registrierung

randlose Textfelder und sorgt dafür, dass diese die gleiche Schriftdefinition wie das Formular
sowie eine geeignete Farbdefinition aufweisen. Im zweiten Schritt begrenzt man die Zeichenan-
zahl und die Abmessungen des einen Textfelds so, dass es die 48 Zeichen für den hexadezima-
len Teil einer Zeile aufnehmen kann, und die des anderen Textfelds so, dass die 16 Zeichen des
ASCII-Blocks hineinpassen. Positioniert man die Textfelder nun noch an der richtigen Stelle
und weist ihnen die von ihnen verdeckten Zeichenfolgen als Wert zu, simuliert das die Eingabe
»vor Ort«. Der Rest ist eine Frage der Implementation einer eigenen Tastatur- sowie Maus-
schnittstelle und der wechselseitigen Aktualisierung der Textfelder. Die Implementation kann
die Änderungen dann bei Verlassen der jeweiligen Zeile zurückschreiben. Als weitere Verbesse-
rung bietet sich die Einbeziehung der Zwischenablage an. Ausgerüstet mit der Funktionalität
der Zwischenablage kann der Benutzer beispielsweise zwei Instanzen der Anwendung starten

Registrierung
und Sequenzen hin- und herkopieren. Die Implementation von OLE-Drag&Drop ist dann nur
noch eine reine Frage der Formalität.

Registrierung
Vielleicht werden Sie sich noch daran erinnern: Zu Zeiten von Windows 3.x pflegte jedes Pro-
gramm eine eigene INI-Datei, in der es Einstellungen bis zur nächsten Sitzung persistent abspei-
chern konnte. Seit Windows 9x gibt es dafür die Systemregistrierung, eine zentrale Datenbank,
in der alle Programme gemeinschaftlich ihre persistenten Einstellungen abspeichern können –
und sollten. Wenn Sie einmal mit dem Systemprogramm Regedit einen Blick in die Registrierda-
tenbank geworfen haben, werden Sie vielleicht eine Vorstellung davon bekommen haben, welch
immense Datenmengen darin abgelegt sind und wie vielschichtig die hierarchische Struktur der
Datenbank doch ist. Schachteltiefen von acht oder neun Schlüsseln sind keine Seltenheit. Und
wenn Sie diesen Abschnitt lesen, weil Sie darin auch ein Plätzchen für Ihr Programm suchen,
sind Sie genau richtig.
Um es gleich vorwegzunehmen, der Zugriff auf die Registrierdatenbank von Visual Basic ist mit
gewissen Einschränkungen verbunden, mit denen sich aus der Sicht einer gewöhnlichen Anwen-
dung aber durchaus leben lässt. So landen alle Informationen, die ein Visual-Basic-Programm
unter Verwendung der »offiziellen« Methode SaveSetting speichert, in folgendem Zweig:
HKEY_CURRENT_USER\Software\VB and VBA Program Settings\

Weiterhin stehen einem Visual-Basic-Programm für die Strukturierung seiner Informationen


nicht mehr als zwei Schlüsselebenen zur Verfügung. Die obere Ebene ist für den »Programmna-
men« reserviert. Da sich dieser aber frei wählen lässt, kann ein Visual-Basic-Programm ohne
Weiteres die Schlüssel anderer Visual-Basic-Programme lesen und manipulieren sowie seine
eigene Informationen auch unter mehreren Programmnamen ablegen. In der Ebene darunter
finden sich dann die Unterschlüssel für die Kategorien oder Abschnitte mit den eigentlichen
Werteinträgen, also Eins-zu-Eins-Zuordnungen zwischen Namen und den eigentlichen Werten.
(Achtung: In der deutschen Benutzeroberfläche des Programms Regedit wird unglücklicher-
weise der Wertname als »Wert« und der Wert an sich als »Daten« bezeichnet!) Damit deckt
sich die Struktur der in der Systemregistrierung abgespeicherten Information genau mit der frü-
herer INI-Dateien. Ein Fortschritt ist das nicht, wenn man sich aber an die Regel hält, dass in
der Systemdatenbank nur solche Informationen abgelegt werden sollten, die zu den Starteinstel-
lungen eines Programms gehören, lässt sich damit ohne Weiteres auskommen.
Das gesamte Set der für den Zugriff auf die Registrierung relevanten Größen umfasst nur vier
Methoden, deren Zweck sich allein schon aus der Namensgebung heraus ablesen lässt: SaveSet-
ting, GetSetting, GetAllSettings und DeleteSetting.

561
Registrierung

RegTest – Sitzungen wieder aufnehmen


Gibt es für den Benutzer etwas Schöneres, als seine Anwendung in der nächsten Sitzung wieder
in dem Zustand vorzufinden, in dem er sie in der letzten Sitzung verlassen hat? Leider reizen
nur die wenigsten Windows-Anwendungen dieses Konzept bis in die letzte Konsequenz aus.
(Windows selbst ist davon nicht ausgenommen! Das entsprechende Feature kommt nun erst mit
Windows 2000 richtig in Fahrt.) Das kleine Projekt RegTest soll Ihnen eine Vorstellung davon
vermitteln, wie einfach die Umsetzung dieses Konzepts eigentlich doch ist.
Registrierung

Das Formular der Anwendung RegTest

Auf dem Formular der Anwendung finden sich vier Schaltflächen, deren Funktion sich über die
Beschriftung erschließt, sowie zwei Bildfelder, in denen Farben abgebildet sind und die auf
einen Mausklick hin den Standarddialog Farbe für die Auswahl einer anderen Farbe öffnen. Ein
Klick auf die Schaltfläche EINSTELLUNGEN SPEICHERN speichert die Farbwerte der Bildfelder in
einem Abschnitt namens »Farben« und den aktuellen Anzeigemodus sowie die aktuelle Position
und die Abmessungen des Formulars in einem Abschnitt namens »Metrik«. Da Position und
Abmessungen nur für den normalen Anzeigemodus (weder maximiert noch minimiert) gelten,
werden sie auch nur von diesem Modus aus gespeichert. Für die anderen Anzeigemodi rechnet
sich Windows die Werte bekanntlich selbstständig aus. Ein Klick auf die Schaltfläche EINSTEL-
LUNGEN ABRUFEN entnimmt die aktuell gespeicherten Werte der Systemregistrierung und ver-
setzt das Formular in den gespeicherten Zustand zurück. Zudem erscheint im Client-Bereich des
Formulars eine Liste mit den gespeicherten Werten. Ein Klick auf die Schaltfläche EINSTELLUN-
GEN LÖSCHEN entfernt den für das Programm angelegten Schlüssel (samt der beiden Unter-
schlüssel) schließlich wieder aus der Registrierung, so dass der Befehl EINSTELLUNGEN ABRUFEN
wirkungslos bleibt. Wenn das Formular schließlich mittels der Standardschaltfläche BEENDEN,
über das Systemmenü oder über eines der SCHLIEßEN-Symbole in der Titelleiste geschlossen
wird, erscheint ein Dialog, der nachfragt, ob der aktuelle Zustand gespeichert werden soll – das
ist in diesem Fall nötig, weil der Befehl EINSTELLUNGEN LÖSCHEN sonst kleine bleibende Wir-
kung entfalten würde.
Hier der Quelltext:
'***********************************************************************
' Standardmodul : QBEmulation
' Autor : 2000 Rudolf Huttary
' Beschreibung : Demonstriert das Speichern und Laden von Einstellungen
' in der Systemregisterung
'***********************************************************************

Option Explicit

562
RegTest – Sitzungen wieder aufnehmen

Private Sub Form_Load()


cmdLoadSettings_Click
End Sub

' Einstellungen aus der Registrierung laden


Private Sub cmdLoadSettings_Click()
Dim Entries
Dim i As Long
If Visible Then
Cls

Registrierung
Entries = GetAllSettings("RegTest", "Farben")
If Not IsEmpty(Entries) Then
For i = 0 To UBound(Entries, 1)
Print Entries(i, 0) & " = " & Entries(i, 1)
Next i
End If
Entries = GetAllSettings("RegTest", "Metrik")
If Not IsEmpty(Entries) Then
For i = 0 To UBound(Entries, 1)
Print Entries(i, 0) & " = " & Entries(i, 1)
Next i
End If
End If
picColor1.BackColor = GetSetting("RegTest", "Farben", "ForeColor", _
Str(picColor1.BackColor))
picColor2.BackColor = GetSetting("RegTest", "Farben", "BackColor", _
Str(picColor2.BackColor))
WindowState = GetSetting("RegTest", "Metrik", "WindowState", _
Str(WindowState))
If WindowState = vbNormal Then
Left = GetSetting("RegTest", "Metrik", "Left", Str(Left))
Top = GetSetting("RegTest", "Metrik", "Top", Str(Top))
Width = GetSetting("RegTest", "Metrik", "Width", Str(Width))
Height = GetSetting("RegTest", "Metrik", "Height", Str(Height))
End If
End Sub

' Einstellungen in der Registrierung speichern


Private Sub cmdSaveSettings_Click()
SaveSetting "RegTest", "Metrik", "WindowState", Str(WindowState)
If WindowState = vbNormal Then
SaveSetting "RegTest", "Metrik", "Left", Str(Left)
SaveSetting "RegTest", "Metrik", "Top", Str(Top)
SaveSetting "RegTest", "Metrik", "Width", Str(Width)
SaveSetting "RegTest", "Metrik", "Height", Str(Height)
End If
SaveSetting "RegTest", "Farben", "ForeColor", Str(picColor1.BackColor)
SaveSetting "RegTest", "Farben", "BackColor", Str(picColor2.BackColor)
End Sub

563
Registrierung

' Alle Einstellungen aus der Registrierung entfernen


Private Sub cmdDeleteSettings_Click()
On Error Resume Next
DeleteSetting "RegTest"
End Sub

' Programm beenden


Private Sub cmdQuitt_Click()
Unload Me
End Sub
Registrierung

' Erste Farbe ändern


Private Sub picColor1_Click()
CommonDialog1.Color = picColor1.BackColor
CommonDialog1.ShowColor
picColor1.BackColor = CommonDialog1.Color
End Sub

' Zweite Farbe ändern


Private Sub picColor2_Click()
CommonDialog1.Color = picColor2.BackColor
CommonDialog1.ShowColor
picColor2.BackColor = CommonDialog1.Color
End Sub

' Programm beenden


Private Sub Form_Unload(Cancel As Integer)
If MsgBox("Einstellungen speichern?", vbYesNo) = vbYes Then
cmdSaveSettings_Click
End If
End Sub

Der Code ist so geradlinig gehalten, dass es neben der bereits erwähnten logischen Notwendig-
keit für die Rückfrage im Rahmen der Unload-Behandlung eigentlich nur zwei Besonderheiten
gibt: die Fehlerbehandlung für den DeleteSetting-Aufruf und das bedingte Speichern bzw. Aus-
lesen der Position und der Abmessungen des Formulars.
Die Methode DeleteSetting generiert einen Laufzeitfehler, wenn sie ihrer Aufgabe, einen
Schlüssel, Unterschlüssel oder Werteintrag zu löschen, nicht erfolgreich nachkommen kann,
weil dieser nicht existiert. Diese doch recht rüde Maßnahme im Vergleich zur »Schwere« des
Fehlers, dass etwas »nicht gelöscht werden kann, weil es entweder schon gelöscht wurde oder
gar nicht da war«, wäre besser mit einem Rückgabewert des Typs Boolean gelöst worden. Wie
dem auch sei, das Problem lässt sich mittels On Error Resume Next nachhaltig aus dem Weg räu-
men. Vergessen Sie aber nicht, gleich dahinter noch ein On Error Goto 0 zu setzen, um die Wir-
kung dieser doch recht ignoranten Fehlerbehandlung wieder aufzuheben, falls in der gleichen
Routine noch weiterer Code folgt.
Was die zweite Besonderheit betrifft, so kann man sich über das richtigere Vorgehen streiten.
Wenn das Formular im Modus »Maximiert« oder »Minimiert« geschlossen wird, darf es die
aktuellen Werte für die Abmessungen und die Position eigentlich nicht speichern, denn sonst
würde es sich nach dem Wiedereinlesen der dann falschen Werte nicht mehr in den Normalzu-
stand zurückversetzen lassen. Die einfachste Lösung besteht darin, die Werte nur dann zu spei-
chern bzw. zu lesen, wenn das Formular in der normalen Fensteransicht geschlossen wird bzw.

564
RegTest – Sitzungen wieder aufnehmen

wurde. Diesen Weg geht auch das Beispielprogramm. Will man, dass sich ein im maximierten
oder minimierten Modus gestartetes (weil so beendetes) Programm auch wieder an seine letzte
normale Position erinnert, ist einiges an zusätzlicher Logik notwendig. Ob sich der Aufwand
jedoch im Verhältnis zum Effekt lohnt, dürfte wohl eher von der sonstigen Problemstellung des
Programms abhängen.

Registrierung

565
Objektorientiertes Basic
Wer heute mit Visual Basic programmiert, programmiert mit Objekten – ob er will oder nicht
und ob er es wahrhaben will oder nicht. Formulare sind Objekte, Steuerelemente sind Objekte
und letztlich alles, »was irgendwie mit einem Punkt notiert werden kann«, abgesehen von
benutzerdefinierten Type-Datentypen. Da all diese Objekte bereits mit einer vorgefertigten
Infrastruktur aufwarten, konzentriert sich die Programmierung nicht nur auf den geschickten
Einsatz des Vorhandenen, sie beugt sich auch dessen Eigenheiten und – zuweilen auch –
Beschränktheiten.
Seit Einführung der Klassenmodule in Visual Basic ist die Programmierung abstrakter Datenty-
pen möglich geworden. Ein abstrakter Datentyp ist die funktionale Definition (lies: Spezifika-
tion) eines Datentyps und seiner Operationen aus der Sicht des Benutzers – wobei der »Benut-
zer« in diesem Fall der Programmierer ist, der diesen Datentyp in seinen Programmen einsetzt.
Konkreter Vertreter eines abstrakten Datentyps ist das Objekt. Wie die Implementation des hin-
ter einem abstrakten Datentyp steckenden Objekts im Einzelnen aussieht, spielt für den Benut-
zer keine Rolle, nach dem Motto: »Hauptsache, das Ding macht, was es machen soll«. Ja, die
Implementation sollte sogar darauf bedacht sein, dass der Benutzer nur das zu sehen bekommt,
was er sehen soll und keinen Deut mehr – denn dann kann er auch keinen Unfug anstellen, der
das Objekt dazu bringt, sich nicht mehr im Sinne seiner Spezifikation zu verhalten. Man spricht
in diesem Fall von Verkapselung.
Sie können davon ausgehen, dass alle von Visual Basic angebotenen Modularten außer dem
Standardmodul eigene Klassen definieren, die auf eine bereits bestehende Klasse aufsetzen. Für
das Formularmodul heißt diese Klasse Form, für ein Benutzersteuerelementmodul UserControl
und für ein Klassenmodul ClassModul. All diese Klassen sind bereits fertig implementierte abs-
trakte Datentypen, die als – zuweilen recht reichhaltig ausgestattete – »Umgebung« für das
Modul fungieren. Aus diesem Grund »kann« ein Formular oder ein Benutzersteuerelement
bereits eine ganze Menge, noch bevor Sie die erste Codezeile in das Modul geschrieben haben.
Im abstrakten Sinne gilt dies auch für das Klassenmodul, dessen Umgebung ClassModul heißt
und immerhin zwei Ereignisse generiert: das Initialize-Ereignis, wenn die benutzerdefinierte
Klasse instanziiert wird (lies: ein neues Objekt produziert), und das Terminate-Ereignis, wenn
diese Instanz wieder zerstört wird.
Die folgenden beiden Abschnitte widmen sich dem Klassenmodul und dem Benutzersteuerele-
mentmodul. Indem sie die Implementation abstrakter Datentypen demonstrieren, beleuchten sie
die Prinzipien der objektorientierten Programmierung unter Visual Basic von ihrer gestalteri-
schen Seite her.

Klassen selbst definieren


Gehören Sie auch zu den Leuten, die sich vor Beginn einer Arbeit den Arbeitsplatz aufräumen
und dann die Werkzeuge und Bauteile zurechtlegen? Nein? Wenn Sie mit eigenen Klassen pro-
grammieren wollen, sollten Sie aber dazu übergehen. Wer die Wahl hat, hat nämlich die Qual.
Was bei der Programmierung mit vorkonfektionierten Objekten eher im Hintergrund steht,
drängt sich bei der Implementation eigener Klassen in den Vordergrund: die eigene Konzeption.
Die zentralen Überlegungen bei der Konzeption eines abstrakten Datentyps lauten daher:
1. Welche Informationen fasst man zu einer Klasse zusammen und mit welchen Mitteln reprä-
sentiert man diesen Informationen? Das bestimmt die Datenstruktur der Klasse (Innensicht).
2. Was soll der Besitzer eines Objekts dieser Klasse von diesen Information in welcher Form se-
hen und manipulieren können? Daraus ergeben sich die Eigenschaften der Klasse (Außen-
sicht).

567
Klassen selbst definieren

3. Welche Operationen soll der Besitzer über einem Objekt dieser Klasse ausführen können?
Das bestimmt die Methoden der Klasse (Außensicht).
4. Gibt es Vorfälle, die ein Objekt dieser Klasse seinem Besitzer unaufgefordert mitteilen kön-
nen sollte? Das bestimmt die Ereignisse der Klasse (Außensicht).
Erst wenn diese Fragen beantwortet sind, kommt die letzte Überlegung:
5. Wie lassen sich die Eigenschaften, Methoden und Ereignisse mit Blick auf die konkrete Da-
tenstruktur prozedural umsetzen? Das bestimmt die Implementation der Klasse.

Ring – eine einfache Klasse demonstriert Grundlegendes


Klassen selbst definieren

Bevor Sie damit beginnen, eigene Klassen mit mehrseitigem Code zu implementieren, sollten Sie
Ihr Verständnis der grundlegenden Mechanismen des von Visual Basic benutzten Objektbe-
griffs noch einmal überprüfen. Der wichtigste Unterschied zwischen Variablen mit einem einfa-
chen Datentyp und Objektvariablen besteht darin, dass Erstere einen Wert an sich repräsentie-
ren und Letztere nur einen Verweis auf einen solchen Wert. Mit den Objektvariablen hielt in
Visual Basic also durch die Hintertür ein Zeigerkonzept Einzug, das es als solches in der Spra-
che offiziell – also explizit – nicht gibt. Wer mit Visual Basic nach wie vor klassisch-prozedural
programmiert, merkt in der Tat recht wenig davon, außer dass ihn seltsame Compilermeldun-
gen wie »Ungültige Verwendung einer Eigenschaft« oder »Objekt unterstützt diese Eigenschaft
oder Methode nicht« zuweilen zur Raison rufen, eine Let-Anweisung gegen eine Set-Anweisung
auszutauschen oder umgekehrt. Wer Klassen selbst gestaltet, muss dagegen sehr genau wissen,
was hinter den Kulissen vor sich geht.
Um eine eigene Klasse schreiben zu können, benötigen Sie als Rahmen ein Projekt, in das Sie ein
Klassenmodul einfügen können. Wenn Sie wollen, können Sie das Codeskelett der Klasse (samt
Klassenmodul) auch unter Zuhilfenahme des Add-Ins KLASSENGENERATOR in einer interaktiven
Sitzung gestalten und weiterhin pflegen. (Das Add-In »VB6 Klassengenerator« muss dazu gege-
benenfalls über den Add-In-Manager zuerst geladen werden.) Nach meinem Geschmack bringt
das aber nur bei »langweiligen« Klassen etwas. Und da der Klassengenerator unter Verdacht
steht, geheimnisvolle Abstürze der Entwicklungsumgebung (aufgrund von internen Stack-über-
läufen) zu fördern, sollten Sie dazu übergehen, Ihre Arbeit dann am besten vor jedem Compiler-
lauf zu speichern (dafür gibt es im Dialogfeld OPTIONEN übrigens einen Schalter).

Einsatz des Klassengenerators


Hier das Ergebnis einer Sitzung mit dem Add-In für eine Klasse namens Ring, die einen ganz-
zahligen Ringzähler mit frei wählbarem Zählbereich implementiert und ihren eigenen Zähler-
stand wahlweise auf einem standardmäßigen Formular oder einem beliebigen Objekt mit Aus-
gabefläche ausgeben können soll.

Struktur der Klasse im Klassengenerator zusammengestellt

568
Ring – eine einfache Klasse demonstriert Grundlegendes

Das vom Klassengenerator erzeugte Codeskelett hat folgende Gestalt:


Option Explicit

'lokale Variable(n) zum Zuweisen der Eigenschaft(en)


Private mvarCounter As Long 'lokale Kopie
Private mvarRingForm As Form 'lokale Kopie
Private mvarMinVal As Long 'lokale Kopie
Private mvarMaxVal As Long 'lokale Kopie
Public Sub PrintVal(Optional Target As Object)
End Sub

Klassen selbst definieren


Public Property Let MaxVal(ByVal vData As Long)
'wird beim Zuweisen eines Werts zu der Eigenschaft auf der linken Seite
'einer Zuweisung verwendet.
'Syntax: X.MaxVal = 5
mvarMaxVal = vData
End Property

Public Property Get MaxVal() As Long


'wird beim Ermitteln eines Eigenschaftswerts auf der rechten Seite
'einer Zuweisung verwendet.
'Syntax: Debug.Print X.MaxVal
MaxVal = mvarMaxVal
End Property

Public Property Let MinVal(ByVal vData As Long)


'wird beim Zuweisen eines Werts zu der Eigenschaft auf der linken Seite
'einer Zuweisung verwendet.
'Syntax: X.MinVal = 5
mvarMinVal = vData
End Property

Public Property Get MinVal() As Long


'wird beim Ermitteln eines Eigenschaftswerts auf der rechten Seite
'einer Zuweisung verwendet.
'Syntax: Debug.Print X.MinVal
MinVal = mvarMinVal
End Property

Public Property Set PrintTarget(ByVal vData As Form)


'wird beim Zuweisen eines Objekts zu der Eigenschaft auf der linken
'Seite einer Set-Anweisung verwendet.
'Syntax: Set x.RingForm = Form1
Set mvarRingForm = vData
End Property

Public Property Get PrintTarget() As Form


'wird beim Ermitteln eines Eigenschaftswerts auf der rechten Seite
'einer Zuweisung verwendet.
'Syntax: Debug.Print X.RingForm

569
Klassen selbst definieren

Set PrintTarget = mvarRingForm


End Property

Public Property Let Counter(ByVal vData As Long)


'wird beim Zuweisen eines Werts zu der Eigenschaft auf der linken Seite
'einer Zuweisung verwendet.
'Syntax: X.Counter = 5
mvarCounter = vData
End Property
Klassen selbst definieren

Public Property Get Counter() As Long


'wird beim Ermitteln eines Eigenschaftswerts auf der rechten Seite
'einer Zuweisung verwendet.
'Syntax: Debug.Print X.Counter
Counter = mvarCounter
End Property

Der Klassenknecht hat neben einer Fülle von immer gleichen Standardkommentaren alle Ele-
mentvariablen deklariert und Codegerüste für Property-, Sub- und Function-Routinen erzeugt.
Elementvariablen tragen das Präfix mvar (von engl.: member variable). Sie wurden durchgängig
als Private vereinbart und daher mit je einer Property Get- und Property Let/Set-Routine
bedacht. Dass die Eigenschaft Counter das Attribut »Standardeigenschaft« erhalten hat, sieht
man dem Code nicht an (!), es lässt sich aber über EXTRAS/PROZEDURATTRIBUTE nachprüfen.

Den Ringzähler implementieren


Die fertige Implementation der Klasse sieht so aus:
'***********************************************************************
' Klasse : Ring
' Autor : 2000 Rudolf Huttary
' Beschreibung : Implementiert echten Ringzähler, der bei Überlauf
' und bei Unterlauf überspringt.
' Die Bereichsgrenzen sind frei wählbar.
' Wenn Bereichsgrenzen gleich sind, erfolgt keine
' Ringzählung
'***********************************************************************
Option Explicit

'lokale Variable(n) zum Zuweisen der Eigenschaft(en)


Private mvarCounter As Long 'lokale Kopie
Private mvarPrintTarget As Form 'lokale Kopie
Private mvarMinVal As Long 'lokale Kopie
Private mvarMaxVal As Long 'lokale Kopie

' Zähler in Interval einpassen und setzen


Public Property Let Counter(ByVal vData As Long)
If mvarMinVal = 0 And mvarMaxVal = 0 Then
mvarCounter = vData
Exit Property
End If
If vData < mvarMinVal Then
vData = vData + (1 + (mvarMinVal – vData) _

570
Ring – eine einfache Klasse demonstriert Grundlegendes

\ (mvarMaxVal – mvarMinVal)) * (mvarMaxVal – mvarMinVal)


End If
mvarCounter = (vData – mvarMinVal) Mod (mvarMaxVal – mvarMinVal) _
+ mvarMinVal
End Property

' Wert des Zählers liefern (Standardeigenschaft)


Public Property Get Counter() As Long
Counter = mvarCounter
End Property

Klassen selbst definieren


' Obere Bereichsgrenze des Zählers setzen
Public Property Let MaxVal(ByVal vData As Long)
If vData = MinVal Then ' wenn gleich, Ringzählung ausschalten
mvarMinVal = 0
mvarMaxVal = 0
Exit Property
ElseIf vData < mvarMinVal Then
Err.Raise 1002, "Ring", _
"Ring: MaxVal kleiner oder gleich MinVal nicht möglich"
End If
mvarMaxVal = vData
Counter = mvarCounter ' Wert ggf. anpassen"
End Property

' Obere Bereichsgrenze des Zählers liefern


Public Property Get MaxVal() As Long
MaxVal = mvarMaxVal
End Property

' Untere Bereichsgrenze des Zählers setzen


Public Property Let MinVal(ByVal vData As Long)
If vData = MaxVal Then ' wenn gleich, Ringzählung ausschalten
mvarMinVal = 0
mvarMaxVal = 0
Exit Property
ElseIf vData > MaxVal Then
Err.Raise 1003, "Ring", _
"Ring: MinVal größer gleich oder MaxVal nicht möglich"
End If
mvarMinVal = vData
Counter = Counter ' Wert ggf. anpassen"
End Property

' Untere Bereichsgrenze des Zählers liefern


Public Property Get MinVal() As Long
MinVal = mvarMinVal
End Property

' Zielfenster für Ausgabe mit PrintVal setzen


Public Property Set PrintTarget(ByVal vData As Form)

57 1
Klassen selbst definieren

Set mvarPrintTarget = vData


End Property

' Standardwert des Objekts ausgeben


Public Sub PrintVal(Optional Target As Object)
If Target Is Nothing Then ' Parameter nicht angegeben?
If Not mvarPrintTarget Is Nothing Then ' Wurde Zielfenster gesetzt?
mvarPrintTarget.Print mvarCounter ' Ja: im Zielfenster ausg.
Else
Debug.Print mvarCounter ' Nein: im Direktfenster ausg.
Klassen selbst definieren

End If
Else
Target.Print mvarCounter ' Im angebenen Zielf. ausgeben
End If
End Sub

Sie sehen, es ist doch allerhand nötig, um ein so einfaches Konzept »einigermaßen wasserdicht«
als Objekt zu implementieren. Damit das Objekt mit der Ringzählung überhaupt beginnt, muss
zumindest eine Grenze ungleich 0 gesetzt sein – das macht Sinn. Ansonsten können die
Bereichsgrenzen beliebig gewählt werden, solange darauf geachtet wird, dass die obere Grenze
nicht kleiner als die untere und die untere nicht kleiner als die obere gewählt wird – die Reihen-
folge beim Setzen spielt hier also eine Rolle! Der Rest ist Rechnerei. Da die Mod-Operation von
Visual Basic für negative Zahlen negative Werte liefert, ist sie unbrauchbar, sobald ein Wert,
der kleiner als die untere Grenze ist (Unterlauf des Ringzählers) in den Bereich abgebildet wer-
den muss. Die Lösung sieht nicht sehr freundlich aus, tut aber das, was sie soll:
' Zähler in Interval einpassen und setzen
Public Property Let Counter(ByVal vData As Long)
If mvarMinVal = 0 And mvarMaxVal = 0 Then
mvarCounter = vData
Exit Property
End If
If vData < mvarMinVal Then
vData = vData + (1 + (mvarMinVal – vData) _
\ (mvarMaxVal – mvarMinVal)) * (mvarMaxVal – mvarMinVal)
End If
mvarCounter = (vData – mvarMinVal) Mod (mvarMaxVal – mvarMinVal) _
+ mvarMinVal
End Property

Nachdem Counter als Standardeigenschaft festgelegt ist, führt bereits die Anweisung
Dim r As New Ring
r = 10 ' ausgeschrieben: r.Counter = 10

zum Aufruf dieser Routine. Sie kommt auch zum Aufruf, wenn Sie weiterschreiben:
Dim r1 As New Ring
r1 = r ' ausgeschrieben: r1.Counter = r.Counter

Hier findet also mitnichten eine Zuweisung des gesamten Objekts (inklusive Bereichsgrenzen)
statt, sondern nur der Eigenschaft Counter, was eine beliebte Fehlerquelle ist.
Das Setzen der Bereichsgrenzen geht gleichfalls nicht ohne einen gewissen Analyseaufwand vor
sich. Die entsprechende Routine muss den Ringzähler ausschalten, wenn obere und untere

572
Ring – eine einfache Klasse demonstriert Grundlegendes

Grenze gleich gesetzt werden, prüfen, ob ansonsten die untere Bereichsgrenze kleiner als die
obere ist, und schließlich dafür Sorge tragen, dass der aktuelle Zählerstand in den neuen
Bereich abgebildet wird.
' Untere Bereichsgrenze des Zählers setzen
Public Property Let MinVal(ByVal vData As Long)
If vData = MaxVal Then ' wenn gleich, Ringzählung ausschalten
mvarMinVal = 0
mvarMaxVal = 0
Exit Property
ElseIf vData > MaxVal Then

Klassen selbst definieren


Err.Raise 1003, "Ring", _
"Ring: MinVal größer gleich oder MaxVal nicht möglich"
End If
mvarMinVal = vData
Counter = Counter ' Wert ggf. anpassen"
End Property

Property Let/ Get/ Set


Als zusätzliches »Schmankerl« hat die Klasse noch zwei weitere Features erhalten. Ein Ring-
Objekt kann einen Verweis auf einen Ausgabekontext speichern und ihren Wert (gegebenenfalls
unter Verwendung eines abweichenden Ausgabekontexts) selbsttätig ausgeben. Falls kein Aus-
gabekontext definiert wurde, nimmt es standardmäßig das Direktfenster debug.
' Zielfenster für Ausgabe mit PrintVal setzen
Public Property Set PrintTarget(ByVal vData As Form)
Set mvarPrintTarget = vData
End Property

' Referenz auf Zielfenster für Ausgabe liefern


Public Property Get PrintTarget() As Form
Set PrintTarget = mvarPrintTarget
End Property

' Standardwert des Objekts ausgeben


Public Sub PrintVal(Optional Target As Object)
If Target Is Nothing Then ' Parameter nicht angegeben?
If Not mvarPrintTarget Is Nothing Then ' Wurde Zielfenster gesetzt?
mvarPrintTarget.Print mvarCounter ' Ja: im Zielfenster ausgeben
Else
Debug.Print mvarCounter ' Nein: im Direktfenster ausgeben
End If
Else
Target.Print mvarCounter ' Im angebenen Zielf. ausgeben
End If
End Sub

Grund für die Ausgestaltung dieser Funktionalität war die Demonstration einer Property Set-
Routine, wo die anderen Eigenschaften doch alle mit Property Let-Routinen ausgestattet sind.
Der Unterschied zwischen den beiden Routinentypen liegt in der Art der Zuweisung, die erfolgt.
Falls es sich um die Zuweisung eines konkreten Werts (elementarer Datentyp oder dynamisches
Array) oder um die echte Kopie eines Objekts handelt, schreiben Sie eine Let-Routine, und falls

57 3
Klassen selbst definieren

es sich nur um die Zuweisung einer Objektreferenz handelt, eine Set-Routine. Die Herausgabe
des Werts einer Eigenschaft erfolgt dagegen unterschiedslos mittels einer Property Get-Routine.
Property Get/Let/Set-Routinen kommen somit immer dann ins Spiel, wenn ein Gleichheitszei-
chen auftaucht – bei Rechtswerten die Get-Routine und bei Linkswerten je nachdem die Set-
oder die Let-Routine.

Parameterübergabe bei Funktionsaufrufen


Die Parameterübergabe bei Funktionsaufrufen kann wirklich zu lästigen Fehlern führen, wenn
man nicht genau weiß, was dabei vor sich geht.
Sub Set5(ByVal r As Ring)
Klassen selbst definieren

r = 5
End Sub

Sub Set6(ByRef r As Ring)


r = 6
End Sub

Private Sub Form_Load()


Dim RingVar As New Ring

Set5 RingVar
r.PrintVal ' Ausgabe 5
Set6 RingVar
r.PrintVal ' Ausgabe 6

End Sub

So ist als Erstes zu bemerken, dass es in diesem Beispiel wirklich keinen Unterschied macht, ob
die Objektvariable der Funktionen als ByRef oder als ByVal vereinbart ist. Den Unterschied gibt
es natürlich, nur auf anderer Ebene: Wenn Set5 den Wert der Objektvariable r ändert, dieser
also ein anderes Objekt zuweist, hat das für RingVar keine Konsequenzen, wenn Set6 dies
macht, würde sich auch der Wert von RingVal ändern.
Zweitens, wie der Debugger leicht zeigt, kommt weder bei dem einen Aufruf noch bei dem
anderen Aufruf eine Get- oder Let-Routine zur Ausführung. Welche auch, es gibt ja keine Eigen-
schaft, die den Typ Ring hat. Selbst wenn es eine solche gäbe – geben wir ihr den Namen Value
– und diese dazu noch Standardeigenschaft wäre, käme bei Übergabe eines Funktionsparame-
ters weder die Get-Routine noch die Set-Routine zum Aufruf, da der Compiler zuerst prüft, ob
der Objekttyp passt, und nur wenn dieser nicht passt, den Standardparameter auswertet.
Anders verhält es sich jedoch, wenn Sie den Wert bewusst oder aus Versehen klammern:
Function SetValue(ByRef r As Ring)
Set r = AndererWert
End Function
...
SetValue (RingVar) ' Standardparameter

Nun kommt schon mal die Get Value-Routine zum Aufruf, weil eine Auswertung des Standard-
parameters stattfindet. Man möchte nun meinen, dass auch noch die Set Value-Routine für
RingVar zum Aufruf kommen kann, weil SetValue ja einen ByRef-Parameter einsetzt. Das geht
aber nicht, weil die Typen wieder gleich sind und das Objekt selbst erneut das Rennen macht –
es sei denn, man schreibt den Standardparameter explizit hin.

574
Ring – eine einfache Klasse demonstriert Grundlegendes

Ein viel schwerwiegenderes Problem ist aber die Tatsache, dass man einer Routine Eigenschaf-
ten eines Objekts zwar als Parameter übergeben kann, Änderungen des Werts, auch wenn die
Übergabe mit ByRef erfolgt ist, außerhalb der Routine grundsätzlich nicht sichtbar werden.
Auch wenn dieses Verhalten logisch erscheint, müsste die Routine doch den Zugriff auf den
Wert weiterhin über Get und Let/Set handhaben, so ist es hochgradig inkonsistent mit den all-
gemeinen Regeln der Parameterübergabe und führt leicht zu schwer auffindbaren Fehlern – ein
echter Pferdefuß in der Objektimplementation von Visual Basic.
Dass der Aufruf Set5 die Eigenschaft MaxValue nicht ändern kann, ist korrekt:
RingVar.MaxVal = 0
Set5 RingVar.MaxVal

Klassen selbst definieren


Print RingVar.MaxVal ' Ausgabe: 0

aber dass auch Set6 damit nicht durchkommt, ist ärgerlich:


RingVar.MaxVal = 0
Set6 RingVar.MaxVal
Print RingVar.MaxVal ' Ausgabe: 0

Denn der folgende Aufruf sollte semantisch äquivalent sein:


Dim Max As Long
RingVar.MaxVal = 0
Max = RingVar.MaxVal = 0
Set6 Max
RingVar.MaxVal = Max
Print RingVar.MaxVal ' Ausgabe: 6

Kopien von Objekten anfertigen


Wie vervielfältigt man Objekte? Die Set-Anweisung hantiert bekanntlich nur mit Objektrefe-
renzen. Vom Prinzip her könnte man die Vervielfältigung eines Objekts zwar als Let-Anwei-
sung für eine Standardeigenschaft formulieren, die den gleichen Typ wie das Objekt hat, in die-
sem Fall müsste das zu kopierende Objekt dem anderen Objekt jedoch seinen gesamten
Zustand entweder über Public-Variablen oder über entsprechende Public- bzw. Friend-Eigen-
schaften zumindest zugänglich machen – dazu wären die entsprechenden Get-Routinen erfor-
derlich. Das ist natürlich nicht gerade im Sinne des Konzepts »abstrakter Datentyp« und absor-
biert außerdem die wichtige Ressource »Standardeigenschaft«, von der es je Klasse ja immer
nur eine gibt. Der einzige Weg, mit legalen Mitteln an die Kopie eines Objekts zu kommen, ist
der, dass das Objekt diese selbst anfertigt – sprich, eine Methode Clone vorsieht, die ein neues
Objekt gleichen Typs instanziiert und schrittweise in den gleichen Zustand versetzt. Aber auch
dieser Weg ist nicht immer möglich, wenn es schreibgeschützte Eigenschaften gibt, an die kein
Rankommen ist.
Im Folgenden ein Vorschlag, wie die Clone-Methode für die Klasse Ring aussehen könnte. Eine
Kopie »von außerhalb des Objekts« zu erstellen, ist nicht möglich, da die Eigenschaft PrintTar-
get lesegeschützt ist und somit keine Get-Routine besitzt.
' Kopie des Objekts erzeugen und Verweis darauf liefern
Public Function Clone() As Ring
Set Copy = New Ring ' neues Objekt anlegen
If mvarMaxVal > 0 Then ' Fehlermeldung vermeiden
Copy.MaxVal = mvarMaxVal ' restliche Eigenschaften
Copy.MinVal = mvarMinVal
Else
Copy.MinVal = mvarMinVal

575
Klassen selbst definieren

Copy.MaxVal = mvarMaxVal ' restliche Eigenschaften


End If
Copy = Me ' Standardwert!
Set Copy.PrintTarget = mvarPrintTarget
End Function

Sobald die Implementation einer Klasse fertig ist (falls möglich auch bereits zwischendurch),
sollten Sie einen speziellen Testcode zusammenstellen, der alle Funktionalitäten der Klasse auf
Herz und Nieren prüft. Bei der Fehlersuche und -analyse ist der Debugger übrigens ein ausge-
sprochen wertvolles, wenn nicht gar unverzichtbares Hilfsmittel. Hier ein Testcode für die
Klasse Ring, bei dem Anweisungen, die bewusst Fehler und spezielle Zustände erzeugen, aus-
Klassen selbst definieren

kommentiert wurden.
' Testcode für die Klasse Ring
Option Explicit

Sub Form_Load()
Dim a As New Ring, b As New Ring
Dim i

Set a.PrintTarget = Me
a.MaxVal = 10
a.MinVal = 3

'Set a.PrintTarget = Nothing ' Debug-Ausgabe testen!


'a.MaxVal = 2 ' Fehlererkennung testen
'a.MinVal = 10 ' Fehlererkennung testen
a = 9 ' Wert im Bereich testen
a.PrintVal ' Ausgabe: 9
a = 19 ' Wert oberhalb testen
a.PrintVal ' Ausgabe: 5
'a.MinVal = a.MaxVal ' Ringzählung ausschalten
a = -19 ' Wert unterhalb testen
a.PrintVal ' Ausgabe: 9

'a.PrintVal Me ' mit Argument testen


a = b ' weist nur Wert zu! : aus 0 wird 7!
a.PrintVal ' Ausgabe: 7
'Set a = b ' ändert Referenz von a auf b!

Set b = a.Clone ' setzt a auf Kopie von b!


Print a.Counter, a.MaxVal, a.MinVal ' Ausgabe: 7 10 3
Print b.Counter, b.MaxVal, b.MinVal ' Ausgabe: 7 10 3
b = -19 ' aus -19 wird 9
a.PrintVal ' Ausgabe: 7
b.PrintVal ' Ausgabe: 9

add(a, b).PrintVal Me ' Bereich ist (0,0), Wert ist 16


End Sub

Function add(ByVal a As Ring, b As Ring) As Ring


Set add = New Ring ' Neues Objekt

576
3DAnimation – Drahtgittermodelle frei im Raum gedreht

add = a + b
End Function

3DAnimation – Drahtgittermodelle frei im Raum gedreht


Ziel dieses Abschnitts wird es sein, ein Drahtgittermodell im dreidimensionalen Raum frei dre-
hen und in der Projektion von allen Seiten betrachten zu können. Darüber hinaus sollte man
das Objekt in seinem aktuellen Zustand speichern und wieder einlesen können.
Die Antworten auf die eingangs des übergeordneten Abschnitts angestellten Überlegungen
sehen für das Drahtgitter als Klasse Shape3D etwa so aus.
1. Die Repräsentation ist klar: Ein Drahtgitter der Klasse Shape3D besteht aus einer Ansamm-

Klassen selbst definieren


lung von Linien des Typs Line3D, die ihrerseits durch Punkte des Typs Point3D in einem ge-
meinsamen Koordinatensystem beschrieben werden.
2. Eigenschaften sind eigentlich keine nötig, wenn sich das Objekt selbst darstellen, speichern
und laden kann. Rotation und Linienfarbe kann man via Parameter übergeben. Sinnvoll ist
aber sicher eine Value-Eigenschaft, die eine Kopie der Datenstruktur ermöglicht, wenn es kei-
ne Clone-Methode gibt. Denkbar sind aber auch noch weitere Eigenschaften wie: standard-
mäßige Linienfarbe, Linienstärke und Perspektive der Darstellung sowie vielleicht
Bewegungsrichtung und -geschwindigkeit, Rotationsachse und -geschwindigkeit und gar
noch die dazugehörigen Beschleunigungen.
3. An Methoden benötigt das Objekt eine Möglichkeit, eine bestehende Beschreibung zu lö-
schen (Clear), eine Linie in eine bestehende Beschreibung einzufügen (Insert), sich darzustel-
len (Draw), sich in einer Datei zu speichern (Save), eine bestehende Repräsentation aus einer
Datei zu laden (Load) und sich zu drehen (Rot3D). Mit Blick auf weitere Einsatzbereiche wären
sicher auch noch eine Translation sowie eine Skalierung sinnvoll.
4. Was die vierte Überlegung betrifft: Das Objekt könnte beispielsweise Kollisionen mit ande-
ren Objekten bemerken und melden, das macht aber in dem vorgestellten einfachen Rahmen
keinen Sinn.

57 7
Klassen selbst definieren
Klassen selbst definieren

Zwei Phasen der Figur Pyramide in 3D- Animation

Antwort auf Überlegung 5 ist die Implementation selbst. Sie sollte schrittweise geschehen, wenn
– wie im vorliegenden Fall – keine exakte Spezifikation vorliegt. Dazu zäumt man das Pferd am
besten von hinten auf und kümmert sich als Erstes um die Klasse Point3D sowie um die Art und
Weise, wie sich ein Objekt dieser Klasse am geschicktesten drehen lässt. Die Abbildung zeigt
einen kleinen Vorgeschmack.

Rotation3D – eine Klasse, deren Objekte »Drehungen« sind

Vom Prinzip her könnte man die Drehung eines einzelnen Punkts – und darauf lässt sich ja das
Drehen eines Drahtgitters reduzieren – vollständig in eine Methode der Klasse Point3D packen.
Die Methode erhält dann drei Double-Parameter zur Entgegennahme der Winkel für die drei
möglichen Drehebenen und dreht dann die aktuellen Koordinaten des Punkts in einer vielleicht
etwas wüsten Rechnerei – Klappe zu, Affe tot. Das hätte jedoch nicht nur Laufzeitnachteile,
weil für die Drehung eines jeden einzelnen Punkts doch eine ganze Reihe von Sinus- und Cosi-
nus-Operationen anfallen würden, es wäre auch viel zu »prozedural« gedacht. Macht man sich
den objektorientierten Gedanken zu Eigen, erkennt man schnell, dass sich eine Drehung wun-
derbar als eigenständiges Objekt auffassen lässt. Als Operationen bieten sich an: Zurücksetzen
auf die neutrale Drehung, die einen Punkt auf sich selbst abbildet, (Init-Methode); Weiterdre-
hen um einen gegebenen Winkel auf der xy-Ebene (RotXY), der xz-Ebene (RotXZ) und der zy-
Ebene (RotYZ); Drehen eines Punkts (Rot3D) und schließlich die Komposition (lies: »aus Zwei
mach Eins«) zweier Drehungen (RotXYZ).
Bleibt noch die Frage nach der Repräsentation und der tatsächlichen Berechnung. In der Mathe-
matik ist es üblich, eine Rotation im dreidimensionalen Raum als lineare Abbildung zu betrach-
ten, deren Repräsentation über eine 3×3-Matrix erfolgt. Betrachtet man einen Punkt als 1×3-
Matrix, kann die Anwendung einer Linearen Abbildung auf den Punkt nach den Gesetzen der
Matrizenrechnung als Multiplikation der Matrix mit dem Punkt erfolgen. Und die Komposition
zweier Drehungen ergibt sich aus dem Produkt der beiden Matrizen.
Wie aber kommt man vom Winkel zur Matrix? Die Drehung auf einer von zwei Koordinaten-
achsen aufgespannten Ebene entspricht der bereits im Zusammenhang mit dem Projekt Wan-
kelAnimation vorgestellten Drehung im Zweidimensionalen mit unveränderter dritter Koordi-
nate. Für eine Drehung um die xy-Ebene also:
x' = cos(w) · x - sin(w) · y + 0·z
y' = sin(w) · x + cos(w) · y + 0·z
z' = 0·x + 0·y + 1· z

578
3DAnimation – Drahtgittermodelle frei im Raum gedreht

Die anderen Drehungen ergeben sich nach dem gleichen Schema. In die Matrizenrechnung
umgesetzt, sieht das Ganze dann so aus:

   −     
 
 
             
    

    −    
 
 
           
       

Klassen selbst definieren


 

   
 
            −   
       

  
 
         
  
 
Für die Multiplikation zweier Matrizen M und N gilt die Formel:

 =∑ 


 
⋅ 

und für die Multiplikation einer Matrize M mit einem Punkt P:

 =∑ 


 
⋅ 

Keine Angst vor den Formeln! In der Implementation sieht die Sache eher harmlos aus.
Um die neue Klasse zu implementieren, legen Sie am besten ein neues Projekt 3DAnimation des
Typs »Standard-EXE« an und fügen ein Klassenmodul mit dem Namen Rotation3D ein. Die
Entwicklungsumgebung von Visual Basic bietet Ihnen für die Gestaltung der neuen Klasse einen
Klassengenerator in Form eines Add-Ins an, er bringt allerdings nicht allzu viel, weil man im
Allgemeinen über die Hälfte des von ihm produzierten Codes wieder über den Jordan schickt
und im weiteren Verlauf an seine Benennungskonvention gebunden ist. Außerdem hat der Klas-
sengenerator so seine Macken, nicht nur wenn es um die Hierarchisierung von Klassen geht.
Die fertige Implementation der Klasse sieht so aus.
'***********************************************************************
' Klasse : Rotation3D
' Autor : 2000 Rudolf Huttary
' Beschreibung : Repräsentiert Drehung im 3-dimensionalen Raum
' : Standardeigenschaft ist Value
'***********************************************************************
Option Explicit

' Repräsentation
Private Matrix() As Double ' Rotationsmatrix
Private m() As Double ' Hilfsmatrix

Private Pi4 As Double

57 9
Klassen selbst definieren

' Echte Zuweisung (Standardeigenschaft)


Public Property Let Value(New_Value() As Double)
Matrix = New_Value ' Echte Kopie!
End Property

' Liefert Referenz auf Objekt


Public Property Get Value() As Double()
Value = Matrix
End Property
Klassen selbst definieren

' Rotiert Punkt in Koordinatendarstellung


Public Sub Rot3D(x As Double, y As Double, z As Double)
Dim x1 As Double, y1 As Double
x1 = Matrix(0, 0) * x + Matrix(0, 1) * y + Matrix(0, 2) * z
y1 = Matrix(1, 0) * x + Matrix(1, 1) * y + Matrix(1, 2) * z
z = Matrix(2, 0) * x + Matrix(2, 1) * y + Matrix(2, 2) * z
x = x1: y = y1
End Sub

' Rotation um Degrees Grad auf XY-Ebene


Public Sub RotXY(ByVal Degrees As Double)
ReDim m(2, 2) As Double
DegToRad Degrees
m(0, 0) = Cos(Degrees)
m(0, 1) = -Sin(Degrees)
m(1, 0) = Sin(Degrees)
m(1, 1) = Cos(Degrees)
m(2, 2) = 1
RotXYZ m
End Sub

' Rotation um Degrees Grad auf XZ-Ebene


Public Sub RotXZ(ByVal Degrees As Double)
ReDim m(2, 2) As Double
DegToRad Degrees
m(0, 0) = Cos(Degrees)
m(0, 2) = -Sin(Degrees)
m(1, 1) = 1
m(2, 0) = Sin(Degrees)
m(2, 2) = Cos(Degrees)
RotXYZ m
End Sub

' Rotation um Degrees Grad auf YZ-Ebene


Public Sub RotYZ(ByVal Degrees As Double)
ReDim m(2, 2) As Double
DegToRad Degrees
m(0, 0) = 1
m(1, 1) = Cos(Degrees)
m(1, 2) = -Sin(Degrees)
m(2, 1) = Sin(Degrees)

580
3 DAnimation – Drahtgittermodelle frei im Raum gedreht

m(2, 2) = Cos(Degrees)
RotXYZ m
End Sub

' Grad ins Bogenmaß umrechnen


Private Sub DegToRad(Degrees As Double)
Degrees = Degrees * Pi4 / 45
End Sub

' Initialisierungscode
Private Sub Class_Initialize()

Klassen selbst definieren


Pi4 = Atn(1)
Init
End Sub

' Rotation ist identische Abbildung


Public Sub Init()
ReDim Matrix(2, 2)
Matrix(0, 0) = 1
Matrix(1, 1) = 1
Matrix(2, 2) = 1
End Sub

' Hilfsroutine, multipliziert Matrizen und aufgrund der Wahl und


' Implementation der Standardeigenschaft auch Rotation3D-Objekte
' Aufruf: Dim r1 As Rotation3D, r2 As Rotation3D
' r1.RotXYZ (r2) ' Klammern sind wichtig
Public Sub RotXYZ(Matrix1() As Double)
Dim i As Long, j As Long, k As Long
Dim res(2, 2) As Double
For i = 0 To 2
For j = 0 To 2
For k = 0 To 2
res(i, j) = res(i, j) + Matrix(i, k) * Matrix1(k, j)
Next k, j, i
Matrix = res
End Sub
Über den Code gibt es eigentlich nicht viel zu sagen, was über das Mathematische hinausgeht.
Die Initialisierung der Matrix mit den Werten für die neutralen Drehung erfolgt im Zuge der
Initialize-Behandlung durch Aufruf von Init. Sinnvollerweise gehört Init zu den Methoden
der Klasse, so dass es dem Besitzer eines Objekts jederzeit möglich ist, das Objekt in einen defi-
nierten Zustand zu versetzen. Die drei auf die Ebenendrehung spezialisierten Methoden RotXY,
RotXZ und RotYZ haben eine additive Bedeutung: »Weiterdrehen in der jeweiligen Ebene um so
und soviel Grad«. Dazu errechnen sie jeweils die zu der Drehung um den gegebenen Winkel
passende Matrix und multiplizieren diese dann mit der bereits bestehenden Drehungsmatrix.
Das Resultat ist die Komposition beider Drehungen.
Einzig die Standardeigenschaft Value verbreitet einen gewissen »Flair« – zumindest aus Sicht
der objektorientierten Programmierung – , da sie die folgende Schreibweise gestattet:
Dim r1 As Rotation3D, r2 As Rotation3D
r1.RotXYZ (r2) ' r1.RotXYZ r2 erzeugt Laufzeitfehler!

581
Klassen selbst definieren

Die Klammerung veranlasst Visual Basic zur Auswertung des Objekts und führt somit zum Auf-
ruf der Get Value-Methode. Genauso gut könnte man aber auch schreiben:
r1.RotXYZ r2.Value

So gesehen ist auch die Let Value-Methode etwas Besonderes, weil sie eine echte Kopie der
Matrix anfertigt (was bei Objekten nicht immer der Fall ist!). Man kann also schreiben:
Dim r1 As New Rotation3D, r2 As New Rotation3D
...
r2 = r1
r2.RotXY Winkel ' r1 bleibt unverändert
Klassen selbst definieren

Point3D – ein Punkt im Raum


Die Spezifikation der zu erstellenden Klasse Point3D lautet:
1. Ein Punkt im dreidimensionalen Raum hat drei Koordinaten, so dass sich das Objekt über
drei Double-Variablen X, Y, Z repräsentieren lässt. Die Variablen werden als Public vereinbart,
was den freien Schreib- und Lesezugriff gestattet. Letzteres ist vorteilhaft, weil das Linienob-
jekt später bequem auf die Koordinaten zugreifen kann.
2. Das Objekt soll eine Zeichenfolgendarstellung nach dem Muster »P(x, y, z)« haben, mit der
es auch initialisiert werden kann (Str-Eigenschaft). Darüber hinaus soll es eine Value-Eigen-
schaft haben, die es gestattet, das Objekt einem anderen gleichartigen Objekt als Wert zu-
zuweisen (dafür ist es erforderlich, dass die Eigenschaften X, Y, Z zugänglich sind).
3. An Operationen soll das Objekt eine Konvertierungsoperation unterstützen, die verschiedene
Darstellungen in den eigenen Datentyp überführt (CPoint3D), es soll seinen Wert in einer ge-
öffneten Binärdatei speichern (Save) und lesen (Load) können und natürlich soll es den Punkt,
den es repräsentiert, drehen (Rot3D) und auch zeichnen (Draw) können.
Die Implementation sieht so aus:
'***********************************************************************
' Klasse : Point3D
' Autor : 2000 Rudolf Huttary
' Beschreibung : Repräsentiert Punkt im 3-dimensionalen Raum
' : Standardeigenschaft ist Value
'***********************************************************************

Option Explicit
' Repräsentation
Public x As Double
Public y As Double
Public z As Double

' Echte Zuweisung


Public Property Let Value(New_Value As Point3D)
x = New_Value.x
y = New_Value.y
z = New_Value.z
End Property

' Liefert Referenz auf Objekt


Public Property Get Value() As Point3D

582
Point3D – ein Punkt im Raum

Set Value = Me
End Property

' Liefert eine echte Kopie des Punkts


Public Function Clone() As Point3D
Set Clone = New Point3D
Clone = Me
End Function

' Liefert Zeichenfolgendarstellung des Objekts

Klassen selbst definieren


Public Property Get Str() As String
Str = "P(" & Conversion.Str(Round(x, 4)) & "," & _
Conversion.Str(Round(y, 4)) & "," & _
Conversion.Str(Round(z, 4)) & ")"
End Property

' Initialisiert Punkt über Zeichenfolgendarstellung


Public Property Let Str(s As String)
If Left(s, 1) = "P" Then
x = Val(Mid(s, 3))
y = Val(Mid(s, InStr(s, ",") + 1))
z = Val(Mid(s, InStrRev(s, ",") + 1))
Else
Err.Raise 1000, "Point3D", "Point3D.Str: Falsches Format"
End If
End Property

' Initialisiert Punkt. Akzeptiert verschiedene Formate


Public Function CPoint3D(param1, ParamArray params()) As Point3D
Select Case TypeName(param1)
Case "String"
Str = param1
Case "Point3D"
Me = param1
Case Else
x = param1
y = params(0)
z = params(1)
End Select
Set CPoint3D = Me
End Function

' Punkt in Objekt Target als Kreis zeichnen


Public Sub Draw(Target As Object, Optional Color As Long, _
Optional Radius As Single = 1)
If Radius > 0 Then
Target.Circle (x, y), Radius, Color
End If
End Sub

' Rotiert Punkt unter Verwendung des Rotationsobjekts

583
Klassen selbst definieren

Public Function Rot3D(r As Rotation3D) As Point3D


r.Rot3D x, y, z
Set Rot3D = Me
End Function

' Schreibt Punkt binär in Datei FileNr


Public Sub Save(ByVal FileNr As Integer)
Put FileNr, , x
Put FileNr, , y
Put FileNr, , z
Klassen selbst definieren

End Sub

' Liest Punkt binär aus Datei FileNr


Public Sub Load(ByVal FileNr As Integer)
Get FileNr, , x
Get FileNr, , y
Get FileNr, , z
End Sub

Bei der Durchsicht des Codes werden Sie feststellen, dass die Klasse eine Clone-Methode besitzt.
Sie ist eigentlich nicht notwendig, da Let Value ja bereits die Erstellung echter Kopien ermög-
licht (Clone basiert auf Let Value). Wäre der Lesezugriff für die Eigenschaften X, Y, Z versagt,
was er aufgrund der Public-Deklaration nicht ist, gäbe es noch die Möglichkeit, den Wert über
die Str-Eigenschaft zu kopieren – wenn auch mit Genauigkeitsverlust wegen der Rundung auf
vier Stellen nach dem Komma. Str ist so implementiert, dass Let Str die von Get Str erzeugte
Zeichenfolgenrepräsentation wieder korrekt einliest.
In der Routine Get Str, die zur Ausbügelung von Rechenfehlern im Bereich der 17ten Stelle hin-
ter dem Komma alle Koordinaten mittels Round auf vier Dezimalstellen rundet, würde es einen
Namenskonflikt geben, wenn die für die (nicht gebietsspezifische Zahlenwandlung eingesetzte
Standardfunktion Str zur Namensraumauflösung nicht mit dem Namen ihres Moduls Conver-
sion qualifiziert wäre. (Solche Benennungsprobleme führen zur Laufzeit zu hässlichen Stack-
Überlauf-Fehlern.) Im Projekt 3DAnimation hat die Methode zwar keine direkte Anwendung,
nachdem sie aber die Koordinaten des repräsentierten Punkts im numerischen Zeichenfolgen-
format liefert, sollte sie in einer Klasse wie Point3D nicht fehlen.
Die Konversionsfunktion CPoint3D überführt verschiedene Formate in den Datentyp Point3D
und ermöglicht so die typtolerante Initialisierung. Da die Methode eine Referenz auf das Objekt
liefert, lässt sie sich auch als Linkswert in einer Set-Zuweisung angeben – ganz im Stile der Vor-
bilder CStr, CLng usw. Auch diese Methode ist reicher ausgelegt, als es das Projekt 3DAnimation
erfordern würde, sollte aber gleichfalls in einer Klasse wie Point3D nicht fehlen.
Von der Implementation der Methoden Save und Load ausgehend lässt sich bereits gut auf das
in 3DAnimation verfolgte Gesamtkonzept schließen. Nachdem die beiden Methoden die Über-
gabe einer Dateinummer erwarten, gehen sie davon aus, dass sie in eine bereits geöffnete Binär-
datei schreiben bzw. aus einer solchen lesen. Ihr Code ist natürlich komplementär ausgelegt.
Besonders einfach ist die Methode Rot3D ausgefallen. Sie verlässt sich völlig auf die gleichna-
mige Methode des im Parameter übergebenen Rotation3D-Objekts. Beachten Sie, dass aus den
im übergeordneten Abschnitt bereits erwähnten Gründen ein Einsatz von Rotation3D.Rot3D
nach folgendem Muster eigentlich ausgeschlossen sein sollte:
Dim p As New Point3D
Dim r As New Rotation3D
...
r.Rot3D p.x, p.y, p.z ' Vorsicht!!!!

584
Point3D – ein Punkt im Raum

Dass dieser Aufruf »wider Erwarten« dennoch korrekt funktioniert, liegt an der Public-Verein-
barung der drei Elementvariablen. Er beweist erstens, dass Visual Basic für Public-Variablen
implizit scheinbar keine Let- und Get-Routinen generiert, und zweites, dass in der Semantik von
Visual Basic ein gravierender Fehler existiert – denn woher soll der Besitzer eines Objekts wis-
sen, ob die von ihm benutzte Eigenschaft als Public-Elementvariable oder als Property Get-
Funktion implementiert ist. Die beiden Implementationen verhalten sich aber leider unter-
schiedlich.
Die Methode Draw zeichnet den Punkt als Kreis mittels der Circle-Methode. Damit ein Objekt
einer selbst definierten Klasse jedoch überhaupt eine Zeichenoperation durchführen kann,
benötigt es ein Objekt, das die Ausgabefläche und die Zeichenoperation stellt. In diesem Fall
wird es über den Parameter Target gestellt, der den flexiblen Typ Object trägt.

Klassen selbst definieren


Nun ist ein guter Zeitpunkt für einen Test der beiden Klassen gekommen. Der folgende einfache
Testcode lässt darauf schließen, dass die Implementation soweit in Ordnung ist und das tut,
was sie soll.
Private Sub TestPoint3D() ' Testroutine für Point3D, Rotation3D
Dim p As Point3D
Dim p1 As New Point3D
Dim p2 As New Point3D
Dim p3 As New Point3D
Dim p4 As New Point3D
Dim r As New Rotation3D

' Grundfunktionen
p1.CPoint3D 1, 0, 1 ' Initialisieren
Print p1.Str ' Ausgabe: P(1,0,1)
p2 = p1 ' Kopie erstellen
Print p2.Str ' Ausgabe: P(1,0,1)
Set p = p3.CPoint3D(p2) ' Initialisierung mit Objekt
Print p3.Str ' Ausgabe: P(1,0,1)
p4.CPoint3D "P(2,0,0)" ' Initialisierung mit Zeichenfolge
Print p4.Str ' Ausgabe: P(2,0,0)
p1.Str = p4.Str ' Wertzuweisung über Str (!)
' Drehen
r.RotXY 90 ' 90° auf xy-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(0,2,0)
r.Init ' Rotation zurück setzen
r.RotYZ 90 ' 90° auf yz-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(0,0,-2)
r.Init ' Rotation zurück setzen
r.RotXZ 90 ' 90° auf xz-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(-2,0,0)
r.RotXY 90 ' 90° auf xy-Ebene hinzu
r.RotXZ 90 ' 90° auf xz-Ebene hinzu
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(2,0,0)
r.Rot3D p4.x, p4.y, p4.z ' funktioniert !!!!
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(-2,0,0)
Scale (-3, 3)-(3, -3)
p1.Draw Me, , 0.1
p3.Draw Me, , 0.2
p4.Draw Me, , 0.3
End Sub

585
Klassen selbst definieren

Line3D – eine Linie aus zwei Punkten


Die Spezifikation der Klasse Line3D lautet:
1. Eine Linie im dreidimensionalen Raum wird vollständig durch einen Startpunkt StartP und
einen Endpunkt EndP beschrieben. Die Repräsentation erfolgt durch zwei Private-Element-
variablen mvarStartp und mvarEndP des Typs Point3D, auf die ein Get-Zugriff möglich sein
soll.
2. Das Objekt soll auf den Datentyp Point3D aufbauend eine Zeichenfolgendarstellung nach
dem Muster »L(P(x, y, z), P(x, y, z))« haben, mit der es auch initialisiert werden kann (Str-
Eigenschaft). Darüber hinaus soll es eine Value-Eigenschaft haben, die es gestattet, das Ob-
jekt einem anderen gleichartigen Objekt als Wert zuzuweisen (dafür ist es erforderlich, dass
Klassen selbst definieren

die Eigenschaften StartP und EndP zugänglich sind).


3. An Operationen soll das Objekt eine Konvertierungsoperation CLine3D unterstützen, die ver-
schiedene Darstellungen in den eigenen Datentyp überführt. Außerdem soll es seinen Wert in
einer geöffneten Binärdatei speichern (Save-Methode) und lesen (Load-Methode) können und
natürlich die Linie, die es repräsentiert, drehen (Rot3D-Methode) und – als Projektion auf die
xy-Ebene – zeichnen können (Draw). Darüber hinaus soll das Objekt den Komfort einer Clo-
ne-Methode bieten, die eine Referenz auf eine echte Kopie des Objekts liefert.
Die Implementation der Klasse Line3D profitiert von dem konsequent objektorientierten Layout
der Klasse Point3D. Aus rein prozeduraler Sicht wäre es natürlich genauso gut möglich gewesen,
die Operationen Save, Load, Clone und Rot3D nur auf der Ebene von Line3D zu implementieren,
dann würde sich aber die Frage stellen, wozu man die Klasse Point3D überhaupt braucht,
schließlich könnte Line3D auch sechs Double-Elementvariablen verwenden ... Die objektorien-
tierte Sicht bietet demgegenüber natürlich den Vorteil, dass die Implementation von Point3D
auch für die Gestaltung anderer Klassen, etwa Triangle3D, zur Verfügung steht.
'***********************************************************************
' Klasse : Line3D
' Autor : 2000 Rudolf Huttary
' Beschreibung : Repräsentiert Linie im 3-dimensionalen Raum
' : Standardeigenschaft ist Value
'***********************************************************************
Option Explicit

Private mvarStartP As New Point3D


Private mvarEndP As New Point3D

' Echte Zuweisung


Public Property Let Value(New_Value As Line3D)
mvarStartP = New_Value.StartP
mvarEndP = New_Value.EndP
' Str = New_Value.Str ' Zuweisung wäre auch über Str möglich!!
End Property

Public Property Get Value() As Line3D


Set Value = Me ' Referenz auf sich selbst liefern
End Property

Public Property Get StartP() As Point3D


Set StartP = mvarStartP ' Referenz auf sich selbst liefern
End Property

586
Line3D – eine Linie aus zwei Punkten

Public Property Get EndP() As Point3D


Set EndP = mvarEndP ' Referenz auf sich selbst liefern
End Property

' Initialisiert Objekt über Zeichenfolgendarstellung


Public Property Let Str(s As String) ' Punkte aus Zeichenfolge einlesen
If Left(s, 4) = "L(P(" And Len(s) >= 20 Then
mvarStartP.Str = Mid(s, 3, InStr(4, s, "P(") – 5)
mvarEndP.Str = Mid(s, InStr(4, s, "P("))
Else

Klassen selbst definieren


Err.Raise 1001, "Line3D", "Line3D.Str: Falsches Format"
End If
End Property

' Liefert Zeichenfolgendarstellung des Objekts


Public Property Get Str() As String
Str = "L(" & mvarStartP.Str & "," & mvarEndP.Str & ")"
End Property

' Erzeugt eine Kopie des Objekts und liefert Referenz darauf
Public Function Clone() As Line3D
Set Clone = New Line3D
Clone = Me
End Function

' Initialisiert Objekt (verschiedene Datentypen zulässig)


Public Function CLine3D(param1, ParamArray params()) As Line3D
Select Case TypeName(param1)
Case "String" ' Initialisierung mit Zeichenfolge
Str = param1
Case "Point3D" ' Initialisierung durch anderen Punkt
Set mvarStartP = param1
Set mvarEndP = params(0)
Case Else ' Versuch: Initialisierung mit Koordinaten
If UBound(params) >= 4 Then
mvarStartP.CPoint3D param1, params(0), params(1)
mvarEndP.CPoint3D params(2), params(3), params(4)
Else
Err.Raise 1002, "Line3D", "Line3D: zu wenig Parameter"
End If
End Select
Set CLine3D = Me
End Function

' Linie rotieren


Public Sub Rot3D(r As Rotation3D)
mvarStartP.Rot3D r ' Reduktion auf Punkte
mvarEndP.Rot3D r ' Reduktion auf Punkte
End Sub

587
Klassen selbst definieren

' Linie in Objekt Target zeichnen


Public Sub Draw(Target As Object, Optional Color As Long, _
Optional Radius As Single = 1)
Target.Line (mvarStartP.x, mvarStartP.y)-(mvarEndP.x, mvarEndP.y), _
Color
mvarStartP.Draw Target, Color, Radius
mvarEndP.Draw Target, Color, Radius
End Sub

' Linie in Datei FileNr speichern


Klassen selbst definieren

Public Sub Save(ByVal FileNr)


mvarStartP.Save (FileNr)
mvarEndP.Save (FileNr) ' Reduktion auf Punkte
End Sub

' Linie aus Datei FileNr lesen


Public Sub Load(ByVal FileNr)
mvarStartP.Load (FileNr) ' Reduktion auf Punkte
mvarEndP.Load (FileNr)
End Sub

Der Implementation der Klasse Line3D liegt das gleiche Schema zugrunde wie der von Point3D.
Auch hier ist Value als Standardeigenschaft vereinbart und spielt eine wichtige Rolle, wenn es
darum geht, eine Kopie des Objekts zu erzeugen. Am New-Operator in der Deklaration der Ele-
mentvariablen ist zu erkennen, dass Line3D-Objekte je einen eigenen Satz an Point3D-Objekten
besitzen. Das wäre vom Prinzip her nicht nötig gewesen, weil man eine Linie auch mit Verwei-
sen auf gegebene Point3D-Objekte aufbauen kann, es erleichtert aber die Implementation und
den Umgang mit Linienobjekten. In einem punktorientierten Ansatz, wo ein Liniensystem über
einer bestehenden Punktmenge definiert wird, sollten sich Transformationen der Punktmenge
auch auf das Liniensystem auswirken. Einer solchen Technik verschließt sich die Implementa-
tion jedoch nicht, da die für die typtolerante Initialisierung zuständige Methode CLine3D eine
Set-Initialisierung der Elementvariablen mit bestehenden Punktobjekten ermöglicht.
Interessant ist, wie CLine3D mit einer flexiblen Anzahl an Parametern sowie unterschiedlichen
Typen zurechtkommt. Der erste Teil des Geheimnisses steckt im Zusatz ParamArray bei der
Deklaration des zweiten Parameters.
Public Function CLine3D(param1, ParamArray params()) As Line3D

Damit kann die Methode mit einer beliebigen Parameteranzahl größer 1 aufgerufen werden,
wobei der erste Wert im obligatorischen Parameter param1 landet und alle weiteren optionalen
Werte im dynamischen Array params. Zudem ist für alle Parameter implizit der allumfassende
Typ Variant vereinbart. Für die Typanalyse leistet die TypeName-Funktion beste Dienste. Das für
diesen Zweck eigentlich zuständige TypeOf-Schlüsselwort lässt sich nur für Objektdatentypen
verwenden!
Ansonsten ist die Implementation schon fast business as usual. Die Methoden Load, Save, Str
und Rot3D sind allesamt nach dem gleichen Muster gestrickt: Sie delegieren den wesentlichen,
wenn nicht gesamten Teil der Arbeit an die Klasse Point3D. Hier ein Beispiel:
' Linie in Datei FileNr speichern
Public Sub Save(ByVal FileNr)
mvarStartP.Save (FileNr)
mvarEndP.Save (FileNr) ' Reduktion auf Punkte
End Sub

588
Line3D – eine Linie aus zwei Punkten

Draw zeichnet zunächst die Linie und dann die beiden Punkte. Die Reihenfolge liegt darin
begründet, dass der Besitzer des Objekts die Punkte vielleicht ausgefüllt gezeichnet haben will,
indem er die Eigenschaften FillColor und FillStyle für das Objekt Target geeignet festlegt.
Public Sub Draw(Target As Object, Optional Color As Long, _
Optional Radius As Single = 1)
Target.Line (mvarStartP.x, mvarStartP.y)-(mvarEndP.x, mvarEndP.y), _
Color
mvarStartP.Draw Target, Color, Radius
mvarEndP.Draw Target, Color, Radius
End Sub

Klassen selbst definieren


Der Testcode für die Klasse sieht etwa so aus:
Private Sub TestLine3D()
Dim p1 As New Point3D
Dim p2 As New Point3D
Dim l1 As Line3D
Dim l2 As New Line3D

Set l1 = l2.CLine3D("L(P(0, 0, 0),P(0,10,0))") ' Referenz zuweisen


l2.CLine3D ("L(P(1, 1, 1),P(10,5,0))") ' Wert ändern
Print l1.Str ' Ausgabe: "L(P(1, 1, 1),P(10,5,0))"
Print l2.Str ' Ausgabe: "L(P(1, 1, 1),P(10,5,0))"
' Let l2 = l1.Clone ' Zuweisung einer Kopie von l1 an l1!!!
Set l2 = l1.Clone ' Zuweisung einer Kopie
l2.EndP.CPoint3D -1, -1, -1
Print l1.Str ' Ausgabe: "L(P(1, 1, 1),P(10,10,0))"
Print l2.Str ' Ausgabe: "L(P(1, 1, 1),P(-1,-1,-1))"
Scale (-3, 7)-(12, -2)
l1.Draw Me, , 0.1
l2.Draw Me, , 0.1
Dim r As New Rotation3D
r.RotXY 35
l2.Rot3D r
l2.Draw Me, , 0.1
End Sub

Etwas speziell ist der auskommentierte Aufruf. Man möchte zunächst meinen, dass l2 dadurch
eine Kopie von l1 zugewiesen wird, die ab dann von l1 nicht mehr abhängig ist. Das würde
auch stimmen, wenn l2 nicht dummerweise als Objektvariable auf l1 verweisen würde. Es pas-
siert hier also Folgendes: l1 generiert eine echte Kopie von sich selbst. Diese Kopie wird dem
Wert von l2, also wiederum l1, zugewiesen. Dabei verliert l1 seinen »alten« Wert, erhält ihn
aber von der Kopie zurück. Und l2 verweist als Objektvariable weiterhin auf l1.

Shape3D – ein Drahtgitter aus Linien


Die Spezifikation der Klasse Shape3D wurde ja bereits informal vorweggenommen.
1. Ein Drahtgitter der Klasse Shape3D besteht aus einer Ansammlung von Linien des Typs
Line3D, die ihrerseits durch Punkte des Typs Point3D in einem gemeinsamen Koordinatensys-
tem beschrieben werden. Die Repräsentation der Linien erfolgt in einem dynamischen Array
des Typs Line3D.

589
Klassen selbst definieren

2. Das Objekt soll eine Value-Eigenschaft bieten, die einen Get/Let-Zugriff auf das Array er-
möglicht (Let deshalb, weil Visual Basic dynamische Arrays grundsätzlich en bloc kopiert),
mehr nicht.
3. An Methoden benötigt das Objekt eine Möglichkeit, eine bestehende Beschreibung zu lö-
schen (Clear), eine Linie in eine bestehende Beschreibung einzufügen (Insert), sich darzustel-
len (Draw), sich in einer Datei zu speichern (Save), eine bestehende Repräsentation aus einer
Datei zu laden (Load) und sich zu drehen (Rot3D).
Hier die Implementation:
'***********************************************************************
Klassen selbst definieren

' Klasse : Shape3D


' Autor : 2000 Rudolf Huttary
' Beschreibung : Repräsentiert Figur im 3-dimensionalen Raum
' : Keine Standardeigenschaft definiert
'***********************************************************************
Option Explicit
Const Shape3D = "Shape3D" ' Formatkennung für Dateioperationen
' Repräsentation
Private Lines() As Line3D

Public Property Get Value() As Line3D()


Value = Lines
End Property

Public Property Let Value(vdata() As Line3D)


Lines = vdata ' en bloc-Zuweisung
End Property

' Fügt Kopie der Linie in Figur ein


Public Sub Insert(ByVal Line3D As Line3D)
ReDim Preserve Lines(UBound(Lines) + 1)
Set Lines(UBound(Lines)) = Line3D.Clone
End Sub

' Löscht Figur


Public Sub Clear()
ReDim Lines(0) As Line3D
End Sub

' Rotiert Figur


Public Sub Rot3D(r As Rotation3D)
Dim l As Long
For l = 1 To UBound(Lines) ' Auf einzelne Linien reduzieren
Lines(l).Rot3D r
Next
End Sub

' Zeichnet Figur in Objekt Target


Public Sub Draw(Target As Object, Optional Color As Long)
Dim l As Long
For l = 1 To UBound(Lines)

590
Line3 D – eine Linie aus zwei Punkten

Lines(l).Draw Target, Color


Next
End Sub

' Initalisiert Array


Private Sub Class_Initialize()
ReDim Lines(0) As Line3D
End Sub

' Speichert Figur in bereits geöffneter Datei FileNr

Klassen selbst definieren


Public Function Save(FileNr As Integer) As Boolean
Dim i As Long
On Error GoTo Abbruch
Put 1, , Shape3D ' Formatkennung
Put 1, , UBound(Lines) ' Anzahl der Linien
For i = 1 To UBound(Lines)
Lines(i).Save (FileNr) ' Reduzieren auf Linie speichern
Next
Save = True
Abbruch:
End Function

' Lädt Figur aus bereits geöffneter Datei


Public Function Load(FileNr As Integer) As Boolean
Dim i As Long, count As Long
Dim l As New Line3D ' Variable zu Laden
On Error GoTo Abbruch ' Falls was schieft geht
' Formatkennung OK?
If Input(Len(Shape3D), 1) <> Shape3D Then Exit Function
Get 1, , count ' Anzahl der Linien in der Figur
For i = 1 To count
l.Load (FileNr) ' Reduzieren auf Linie lesen
Insert l
Next
Load = True ' Erfolgreich gelesen
Abbruch:
End Function

Als zentrale Datenstruktur für die Speicherung der Line3D-Objekte fungiert das dynamische
Array Lines. Um die Logik der Methoden Insert und Clear einfach zu halten, wird Lines vom
Konstruktor Class-Initialize der Klasse sowie von Clear auf ein Element dimensioniert, das
ansonsten keinem weiteren Zweck dient. Jeder Insert-Aufruf erweitert das Array um ein neues
Element, wobei die aktuelle Obergrenze UBound(Lines) jeweils den Index liefert. Der Besitzer
eines Shape3D-Objekts kann also davon ausgehen, dass die Methode eine echte Kopie des
Line3D-Objekts erstellt und sich das Objekt ohne die Gefahr von Seiteneffekten weiterverwen-
den lässt.
' Fügt Kopie der Linie in Figur ein
Public Sub Insert(ByVal Line3D As Line3D)
ReDim Preserve Lines(UBound(Lines) + 1)
Set Lines(UBound(Lines)) = Line3D.Clone
End Sub

591
Klassen selbst definieren

Wenig spannend ist der Code der Methoden Draw und Rot3D. Ihr Code durchläuft das Array und
veranlasst jedes einzelne Line3D-Objekt, sich mit der gleichnamigen Methode zu zeichnen bzw.
zu drehen. Nach dem gleichen Prinzip funktionieren auch die Methoden Save und Load, mit
dem Zusatz, dass Save zuvor noch die Formatkennung »Shape3D« sowie die Anzahl der zu
erwartenden Linienobjekte in die Datei schreibt.
Const Shape3D = "Shape3D" ' Formatkennung für Dateioperationen
' Speichert Figur in bereits geöffneter Datei FileNr
Public Function Save(FileNr As Integer) As Boolean
Dim i As Long
On Error GoTo Abbruch
Klassen selbst definieren

Put 1, , Shape3D ' Formatkennung


Put 1, , UBound(Lines) ' Anzahl der Linien
For i = 1 To UBound(Lines)
Lines(i).Save (FileNr) ' Reduzieren auf Linie speichern
Next
Save = True
Abbruch:
End Function

Umgekehrt liest und analysiert die Methode Load als Erstes die Formatkennung Shape3D und
ermittelt dann, sofern die Formatkennung korrekt ist, wie viele Line3D-Objekte eingelesen wer-
den müssen. Den Rest erledigt dann eine Schleife, in der ein eigens für diesen Zweck instanziier-
tes Line3D-Objekt die Lesearbeit verrichtet. Da Insert wie bereits erwähnt eine echte Kopie sei-
nes Parameters anfertigt, kommt die Schleife mit einem einzigen Objekt aus.
' Lädt Figur aus bereits geöffneter Datei
Public Function Load(FileNr As Integer) As Boolean
Dim i As Long, count As Long
Dim l As New Line3D ' Variable zum Laden
On Error GoTo Abbruch ' Falls was schieft geht
' Formatkennung OK?
If Input(Len(Shape3D), 1) <> Shape3D Then Exit Function
Get 1, , count ' Anzahl der Linien in der Figur
For i = 1 To count
l.Load (FileNr) ' Reduzieren auf: Linie lesen
Insert l
Next
Load = True ' Erfolgreich gelesen
Abbruch:
End Function

Animation3D – Das Testformular


Mit der Klasse Shape3D sind nun alle Voraussetzungen vorhanden, um ein Drahtgittermodell zu
definieren und im dreidimensionalen Raum in Bewegung zu versetzen. Es fehlt nur noch ein
halbwegs komfortabler Rahmen, um Tests durchzuführen. Das Projekt 3DAnimation enthält
für diesen Zweck ein Testformular namens Animation3D, das neben dem bereits vorgestellten
Testcode für die einzelnen Klassen mit dem Nötigsten ausgestattet ist, um eine eindrucksvolle
visuelle Demonstration der Objekte zu ermöglichen. Wenn Sie den Testcode ausführen wollen,
müssen Sie nur die Kommentare in der Load-Routine entsprechend ändern – es ist alles vorberei-
tet. Ansonsten verzweigt die Anwendung gleich nach dem Start automatisch zur Würfelanima-
tion, die ein Zeitgeber-Steuerelement vorantreibt. Die Drehwinkel zwischen je zwei Animati-

592
Line3D – eine Linie aus zwei Punkten

onsphasen lassen sich über die drei am oberen Rand des Client-Bereichs befindlichen
Schieberegler-Steuerelemente vorgeben – zur Auswahl stehen Winkel zwischen 0 und 10 Grad.
Im Menü FIGUR stehen drei weitere Drahtgittermodelle im Angebot: eine Pyramide, eine Linie
und eine zufällig erzeugte zusammenhängende Linienschar. Darüber hinaus lässt sich die Ani-
mation per Mausklick anhalten und wieder starten.

Klassen selbst definieren

Die Figuren »Würfel« und »Knäuel«

Hier der Code:


'***********************************************************************
' Formularmodul : Animation3D
' Autor : 2000 Rudolf Huttary
' Beschreibung : Demoprogramm für die Klassen Shape3D, Line3D,
' : Rotation3D und Point3D
'***********************************************************************
Option Explicit

593
Klassen selbst definieren

Dim l As New Line3D


Dim RotObj As New Rotation3D
Dim ShapeObj As New Shape3D
Dim o As Object

Private Sub Form_Click()


mnuTimer_Click
End Sub

Private Sub Form_Load()


Klassen selbst definieren

Dim c As Control
ShowControls False

Width = Width – ScaleWidth + 5000


Height = Height – ScaleHeight + 5000

'TestPoint3D ' Testcode für Klasse Point3D


'TestLine3D ' Testcode für Klasse Line3D
StartAnimation ' Testcode für Drahtgittermodell
End Sub

Private Sub ShowControls(State As Boolean)


Slider1.Visible = State
Slider2.Visible = State
Slider3.Visible = State
Label1.Visible = State
Label2.Visible = State
Label3.Visible = State
End Sub

Private Sub TestPoint3D() ' Testroutine für Point3D, Rotation3D


Dim p As Point3D
Dim p1 As New Point3D
Dim p2 As New Point3D
Dim p3 As New Point3D
Dim p4 As New Point3D
Dim r As New Rotation3D

' Grundfunktionen
p1.CPoint3D 1, 0, 1 ' Initialisieren
Print p1.Str ' Ausgabe: P(1,0,1)
p2 = p1 ' Kopie erstellen
Print p2.Str ' Ausgabe: P(1,0,1)
Set p = p3.CPoint3D(p2) ' Initialisierung mit Objekt
Print p3.Str ' Ausgabe: P(1,0,1)
p4.CPoint3D "P(2,0,0)" ' Initialisierung mit Zeichenfolge
Print p4.Str ' Ausgabe: P(2,0,0)
p1.Str = p4.Str ' Wertzuweisung über Str (!)
' Drehen
r.RotXY 90 ' 90° auf xy-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(0,2,0)

594
Line3D – eine Linie aus zwei Punkten

r.Init ' Rotation zurück setzen


r.RotYZ 90 ' 90° auf yz-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(0,0,-2)
r.Init ' Rotation zurück setzen
r.RotXZ 90 ' 90° auf xz-Ebene drehen
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(-2,0,0)
r.RotXY 90 ' 90° auf xy-Ebene hinzu
r.RotXZ 90 ' 90° auf xz-Ebene hinzu
Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(2,0,0)
r.Rot3D p4.x, p4.y, p4.z ' funktioniert !!!!

Klassen selbst definieren


Print p4.Rot3D(r).Str ' Rotieren, Ausgabe: P(-2,0,0)
Scale (-3, 3)-(3, -3)
p1.Draw Me, , 0.1
p3.Draw Me, , 0.2
p4.Draw Me, , 0.3

End Sub

Private Sub TestLine3D()


Dim p1 As New Point3D
Dim p2 As New Point3D
Dim l1 As Line3D
Dim l2 As New Line3D

Set l1 = l2.CLine3D("L(P(0, 0, 0),P(0,10,0))") ' Referenz zuweisen


l2.CLine3D ("L(P(1, 1, 1),P(10,5,0))") ' Wert ändern
Print l1.Str ' Ausgabe: "L(P(1, 1, 1),P(10,5,0))"
Print l2.Str ' Ausgabe: "L(P(1, 1, 1),P(10,5,0))"
' Let l2 = l1.Clone ' Zuweisung einer Kopie von l1 an l1!!!
Set l2 = l1.Clone ' Zuweisung einer Kopie
l2.EndP.CPoint3D -1, -1, -1
Print l1.Str ' Ausgabe: "L(P(1, 1, 1),P(10,10,0))"
Print l2.Str ' Ausgabe: "L(P(1, 1, 1),P(-1,-1,-1))"
Scale (-3, 7)-(12, -2)
l1.Draw Me, , 0.1
l2.Draw Me, , 0.1
Dim r As New Rotation3D
r.RotXY 35
l2.Rot3D r
l2.Draw Me, , 0.1
End Sub

Private Sub StartAnimation()


Dim c As Control
Scale (-20, 20)-(20, -20)

Slider1 = 1 ' XY-Rotation


Slider2 = 2 ' XZ-Rotation
Slider3 = 3 ' YZ-Rotation
ShowControls True
FillStyle = vbSolid

595
Klassen selbst definieren

FillColor = BackColor
mnuCube_Click ' Würfel anzeigen
Timer1.Interval = 80
End Sub
' Figur aus Datei laden
Private Sub mnuOpen_Click()
SetTimer False
If Not o Is Nothing Then o.Draw Me, BackColor
ShapeObj.Clear
Open App.Path + "\Shape3D.s3d" For Binary As 1
Klassen selbst definieren

ShapeObj.Load 1
Close 1
Set o = ShapeObj
SetTimer True
End Sub

' Figur in Datei speichern


Private Sub mnuSpeichern_Click()
Open App.Path + "\Shape3D.s3d" For Binary As 1
ShapeObj.Save 1
Close 1
End Sub

Private Sub mnuQuitt_Click()


Unload Me
End Sub

Private Sub mnuTimer_Click()


SetTimer (Not mnuTimer.Checked)
End Sub

Private Sub SetTimer(OnOff As Boolean)


mnuTimer.Checked = OnOff
Timer1.Enabled = OnOff
End Sub

' Einzelne Linie


Private Sub mnuLine_Click()
SetTimer False
If Not o Is Nothing Then o.Draw Me, BackColor
ShapeObj.Clear
ShapeObj.Insert l.CLine3D(0, 0, 0, 10, 10, 0)
Set o = ShapeObj
o.Draw Me
SetTimer True
End Sub

' Würfel
Private Sub mnuCube_Click()
SetTimer False
If Not o Is Nothing Then o.Draw Me, BackColor

596
Line3D – eine Linie aus zwei Punkten

ShapeObj.Clear
ShapeObj.Insert l.CLine3D(-10, 10, -10, 10, 10, -10)
ShapeObj.Insert l.CLine3D(10, 10, -10, 10, -10, -10)
ShapeObj.Insert l.CLine3D(10, -10, -10, -10, -10, -10)
ShapeObj.Insert l.CLine3D(-10, -10, -10, -10, 10, -10)

ShapeObj.Insert l.CLine3D(-10, 10, 10, 10, 10, 10)


ShapeObj.Insert l.CLine3D(10, 10, 10, 10, -10, 10)
ShapeObj.Insert l.CLine3D(10, -10, 10, -10, -10, 10)
ShapeObj.Insert l.CLine3D(-10, -10, 10, -10, 10, 10)

Klassen selbst definieren


ShapeObj.Insert l.CLine3D(-10, 10, -10, -10, 10, 10)
ShapeObj.Insert l.CLine3D(10, 10, -10, 10, 10, 10)
ShapeObj.Insert l.CLine3D(10, -10, -10, 10, -10, 10)
ShapeObj.Insert l.CLine3D(-10, -10, -10, -10, -10, 10)
Set o = ShapeObj
o.Draw Me
SetTimer True
End Sub

' Zufällig erzeugtes, zusammenhängendes Linengewirr


Private Sub mnuRandom_Click()
Dim i As Long
Dim x As Double, y As Double, z As Double
Dim p As New Point3D
Dim l As New Line3D
SetTimer False
If Not o Is Nothing Then o.Draw Me, BackColor
ShapeObj.Clear
Randomize Timer
x = ScaleHeight * Rnd – ScaleHeight / 2
y = ScaleHeight * Rnd – ScaleHeight / 2
z = ScaleHeight * Rnd – ScaleHeight / 2
For i = 0 To 10
p.CPoint3D x, y, z
x = ScaleHeight * Rnd – ScaleHeight / 2
y = ScaleHeight * Rnd – ScaleHeight / 2
z = ScaleHeight * Rnd – ScaleHeight / 2
ShapeObj.Insert l.CLine3D(p.x, p.y, p.z, x, y, z)
Next i
Set o = ShapeObj
o.Draw Me
SetTimer True
End Sub

' Pyramide
Private Sub mnuPyramide_Click()
SetTimer False
If Not o Is Nothing Then o.Draw Me, BackColor
ShapeObj.Clear
ShapeObj.Insert l.CLine3D(-10, 10, -10, 10, 10, -10)

597
Klassen selbst definieren

ShapeObj.Insert l.CLine3D(10, 10, -10, 10, -10, -10)


ShapeObj.Insert l.CLine3D(10, -10, -10, -10, -10, -10)
ShapeObj.Insert l.CLine3D(-10, -10, -10, -10, 10, -10)
ShapeObj.Insert l.CLine3D(-10, 10, -10, 0, 0, 10)
ShapeObj.Insert l.CLine3D(10, 10, -10, 0, 0, 10)
ShapeObj.Insert l.CLine3D(10, -10, -10, 0, 0, 10)
ShapeObj.Insert l.CLine3D(-10, -10, -10, 0, 0, 10)
Dim shapeObj1 As New Shape3D
shapeObj1.Value = ShapeObj.Value
Set o = shapeObj1
Klassen selbst definieren

o.Draw Me
SetTimer True
End Sub

Private Sub Slider1_Change()


RotObj.Init
RotObj.RotXY Slider1
RotObj.RotXZ Slider2
RotObj.RotYZ Slider3
End Sub

Private Sub Slider2_Change()


RotObj.Init
RotObj.RotXY Slider1
RotObj.RotXZ Slider2
RotObj.RotYZ Slider3
End Sub

Private Sub Slider3_Change()


RotObj.Init
RotObj.RotXY Slider1
RotObj.RotXZ Slider2
RotObj.RotYZ Slider3
End Sub

Private Sub Timer1_Timer()


If Not o Is Nothing Then
o.Draw Me, BackColor
o.Rot3D RotObj
o.Draw Me
End If
End Sub

Wie man sieht, enthält der Code des Formularmoduls außer den schon zuvor vorgestellten
Testroutinen für die einzelnen Klassen keine besonderen Finessen. Zum Testen der Methoden
Save und Load des zentralen Shape3D-Objekts enthält das Menü DATEI die Befehle LADEN und
SPEICHERN – eine Dateiauswahl ist nicht vorgesehen, ließe sich aber problemlos nachrüsten.

598
ActiveX- Steuerelemente und Benutzersteuerelemente

Zu verbessern gibt es noch einiges. Wer beispielsweise genau hinsieht, wird bemerken, dass das
Programm zuweilen im Hintergrund gelegene Punkte über im Vordergrund gelegene Linien
zeichnet. In diesem Moment kann die Perspektive des Bilds optisch »kippen«, Sie kennen das.
Abhilfe mit einfachen Mitteln für dieses bekannte »Problem der verdeckten Linien« dürfte es
nicht geben. Es führt unweigerlich in die Fänge des ray tracing.

ActiveX- Steuerelemente und Benutzersteuerelemente


Das Thema Benutzersteuerelemente hat in Visual Basic bereits eine lange Tradition und war seit
jeher eines der stärksten Argumente, auf Visual Basic einzuschwenken. Wer mit den Standard-

ActiveX- Steuerelemente und Benutzersteuerelemente


steuerelementen von Visual Basic programmieren kann, hat alles begriffen und wird weder mit
dem Umgang der mitgelieferten ActiveX-Steuerelemente noch mit benutzerdefinierten Steuere-
lementen, die letztlich nichts anderes als ActiveX-Steuerelemente sind, irgendwelche Schwierig-
keiten haben, die sich nicht auf die fehlerhafte Implementation oder Dokumentation des Steuer-
elements zurückführen lassen.
Die Programmierung eigener Benutzersteuerelemente ist da schon eine andere Geschichte. Sie
ist eine Fortsetzung der Programmierung eigener Klassen »mit anderen Mitteln«. Die Mittel
sind in diesem Fall: das allen Benutzersteuerelementen von Visual Basic automatisch zugrunde
gelegte UserControl-Objekt sowie das zugehörige Fenster für die sichtbare Repräsentation des
Steuerelements etwa in einem Formular oder einem anderen ActiveX-Steuerelement.
Dieser Abschnitt stellt Ihnen den Werdegang zweier Benutzersteuerelemente vor, von denen das
eine zur Laufzeit keine sichtbare Repräsentation hat, weil es das Zeitgeber-Steuerelement nach-
bessert und das andere eine Funktionserweiterung des bestehenden Standardsteuerelements
Textfeld bis ins letzte Detail verkörpert.

LongTimer – der Timer mit Ausdauer


So nützlich das Zeitgeber-Steuerelement (Timer) von Visual Basic ist, »größere Sprünge« lassen
sich damit im wahrsten Sinne des Wortes nicht machen – ebenso wenig wie ganz kleine (doch
das ist ein anderes Thema). Zufriedenstellend funktioniert der Zeitgeber nur, wenn Intervalle
zwischen 20 ms und 65 Sekunden gefragt sind.

Anwendung
Was aber, wenn man ein Ereignis auf Minuten, Stunden, Tage oder Monate vorausplanen
möchte, und das auf die Sekunde genau? Die Lösung an sich ist naheliegend, die Umsetzung in
ein für die Zukunft allzeit bereit stehendes Benutzersteuerelement mit dem Namen LongTimer
eher solides »Handwerk«. Beginnen wir mit der Spezifikation.
Das Steuerelement soll:
1. Ein registriertes ActiveX-Steuerelement werden, das fortan allen Anwendungen als Timer zur
Verfügung steht.
2. Wie das Zeitgeber-Steuerelement keine visuelle Darstellung haben.
3. Wahlweise einen Sekundenwert oder einen Datums-/Zeitwert akzeptieren. Die entsprechen-
den Eigenschaften seien LongInterval und TriggerTime. LongInterval soll zur Entwurfszeit
und zur Laufzeit gelesen und geschrieben werden können, TriggerTime nur zur Laufzeit.
4. Bei Setzen eines Sekundenwerts LongInterval ein Timer-Ereignis wiederholt signalisieren, bis
ein Sekundenwert von 0 gesetzt wird.
5. Bei Angabe eines Datums-/Zeitwerts ein Timer-Ereignis einmalig signalisieren (sofern der
Wert in der Zukunft liegt). Die schreibgeschützte Eigenschaft OneShot soll anzeigen, ob das
Ereignis periodisch oder nur einmalig signalisiert wird.
6. Bei Änderung des Sekundenwerts oder des Datums-/Zeitwerts vor Ablauf des aktuellen In-
tervalls ein neues Intervall beginnen.

599
ActiveX- Steuerelemente und Benutzersteuerelemente

Umsetzung
Die programmtechnische Umsetzung dieser Spezifikation in das Projekt LongTimer erfordert
zunächst einmal die strategische Überlegung, das neue Steuerelement auf dem Rücken des alten
Zeitgeber-Steuerelements aufzubauen. Intervalle kleiner als 60 Sekunden lassen sich dann gleich
direkt an das Zeitgeber-Steuerelement delegieren. Größere Intervalle müssen dagegen in Minu-
tenintervalle plus ein Restintervall gestückelt werden. Die Logik ist somit einfach, so dass sich
die vorliegende Beschreibung auf die Feinheiten einer sauberen Implementation konzentrieren
kann. Beginnen Sie wie folgt:
1. Legen Sie eine neues Projekt des Typs »Standard-EXE« an, das als Testanwendung für das
Steuerelement fungieren wird.
ActiveX- Steuerelemente und Benutzersteuerelemente

2. Fügen Sie über den Menübefehl DATEI/PROJEKT HINZUFÜGEN ein neues Projekt des Typs
»ActiveX-Steuerelement« hinzu. Legen Sie im Eigenschaftsfenster den Namen LongTimer für
das Steuerelement fest, setzen Sie die Eigenschaft InvisibleAtRuntime auf True und weisen Sie
dem Steuerelement eine passende Bitmap als Picture- und als ToolboxBitmap-Eigenschaft zu.
3. Schließen Sie das Entwurfsfenster des Benutzersteuerelements. In der Werkzeugsammlung
müsste nun ein neues Steuerelement mit dem gewählten Bitmap als Symbol zu finden sein.
4. Öffnen Sie die Entwurfsansicht des Steuerelements erneut und platzieren Sie ein Zeitgeber-
steuerelement aus der Werkzeugsammlung darauf. Passen Sie gegebenenfalls noch die Größe
des Entwurfsbereichs an die anzeigte Bitmap an – was jedoch nichts weiter zur Sache beiträgt.

Das Benutzersteuerelement in der Entwurfsansicht und in der Werkzeugleiste

Damit haben Sie den passenden Rahmen für die weitere Entwicklung: Das Steuerelement ist
zwar zur Laufzeit unsichtbar, zur Entwurfszeit zeigt es aber die Picture-Eigenschaft an, so dass
Sie es auf dem Formular der Testanwendung platzieren können – und später auch wiederfinden.
Soviel zu Punkt 2 der Spezifikation. Die anderen Punkte betreffen die Implementation der
Eigenschaften und die Signalisierung des Ereignisses.
Beginnen wir mit OneShot. Diese Eigenschaft wird beim Setzen der anderen beiden Eigenschaf-
ten sowie bei der objekteigenen Timer-Behandlung gepflegt. Da sie zur Laufzeit und zur Ent-
wurfszeit schreibgeschützt sein soll, reicht es, nur eine Property Get-Prozedur bereitzustellen.
Damit taucht sie erst gar nicht im Eigenschaftsfenster des Benutzersteuerelements auf.
Private m_OneShot As Boolean

' Nur-Lesen Eigenschaft


Public Property Get OneShot() As Boolean
OneShot = m_OneShot
End Property

Die Eigenschaft LongInterval setzt die Sekunden für den periodischen Timer und erlaubt jede
Form des Zugriffs.
Private m_LongInterval As Long
Private m_TriggerTime As Date

600
LongTimer – der Timer mit Ausdauer

Public Property Get LongInterval() As Long


LongInterval = m_LongInterval
End Property

Public Property Let LongInterval(NewInterval As Long)


m_LongInterval = NewInterval
m_TriggerTime = DateAdd("s", NewInterval, Now)
SetTimer NewInterval
m_OneShot = False ' Timer-Ereignis periodisch

ActiveX- Steuerelemente und Benutzersteuerelemente


End Property

Die Set-Prozedur pflegt die drei Elementvariablen, mit denen das Objekt die Zustände der
Ereignisse intern repräsentiert, und die private SetTimer-Methode aktiviert bzw. deaktiviert das
Zeitgeber-Steuerelement Timer1, das die Zeitbasis liefert. Sie setzt das Intervall von Timer1 auf
die gewünschte Anzahl von Sekunden oder auf eine Minute, wenn das LongTimer-Intervall eine
Minute oder länger dauern soll.
Private Sub SetTimer(Diff As Long)
If Diff <= 0 Then ' Timer stoppen?
Timer1.Interval = 0
m_OneShot = False ' Standardwert setzen
ElseIf Diff < 60 Then ' Weniger als 1 Minute?
Timer1.Interval = Diff * 1000
Else
Timer1.Interval = 60000 ' Großer Zeitraum
End If
End Sub

Diffiziler wird die Angelegenheit bei TriggerTime. Da die Eigenschaft zur Entwurfszeit den
Schreibzugriff ausschließen soll, benötigt sie eine Let-Prozedur, die unterscheiden kann, ob ihr
Aufruf zur Laufzeit oder zur Entwurfszeit des Containers erfolgt ist. Handhabe dafür bietet die
Ambient-Eigenschaft des untergelegten UserControl-Objekts. Sie enthält eine Referenz auf ein
AmbientProperties-Objekt, dessen Aufgabe darin besteht, die Umgebungseigenschaften eines
Containers (meist: Formulars) zu repräsentieren. Dieses Objekt, das wie eine Hülle angelegt ist,
simuliert so etwas wie ein Containerobjekt, indem es das Benutzersteuerelement mit Standard-
werten für bestimmte Eigenschaften (Font, BackColor usw.) versorgt, die dieses zur Laufzeit bei
seinem Container vorfindet. Insbesondere liefert es in der Eigenschaft UserMode auch die Infor-
mation, ob die aktuelle Instanz des Benutzersteuerelements für die Entwurfsansicht des Contai-
ners angelegt wurde (False) oder zu dessen Laufzeit (True) – was natürlich nicht ausschließt,
dass die Instanz dieses Containers wiederum für die Entwurfsansicht eines weiteren Containers
angelegt wurde. Wen das verwirrt, dem sei ins Gedächtnis zurückgerufen, dass die Entwick-
lungsumgebung von Visual Basic für jedes Benutzersteuerelement eine Entwurfsinstanz anlegt,
wenn dieses von der Werkzeugsammlung aus im Entwurfsbereich eines Formulars oder eines
anderen Benutzersteuerelements platziert wird. Diese Entwurfsinstanz wird beim Start des For-
mulars wieder abgebaut und durch eine Laufzeitinstanz ersetzt, wobei natürlich das Ambient-
Properties-Objekt die Änderung der Ausführungsumgebung reflektiert. Um nun einen Schreib-
oder Lesezugriff zur Entwurfs- oder Laufzeit zu verweigern, kann ein Steuerelement die Eigen-
schaft UserMode auswerten (genau das macht übrigens auch die Implementation der Eigenschaft
InvisibleAtRuntime) und gegebenenfalls einen Laufzeitfehler signalisieren. In Visual Basic sind
dafür die folgenden Fehlernummern vorgesehen:

601
ActiveX- Steuerelemente und Benutzersteuerelemente

Fehlernummer Fehlertext
382 (Laufzeit) Set wird zur Laufzeit nicht unterstützt
383 (Entwurfszeit) Set wird nicht unterstützt (schreibgeschützte Eigenschaft)
393 (Laufzeit) Get wird zur Laufzeit nicht unterstützt
394 (Entwurfszeit) Get wird nicht unterstützt (Eigenschaft kann nur gesetzt werden)

Die Implementation der TriggerTime-Eigenschaft sieht damit so aus:


Public Property Get TriggerTime() As Date
ActiveX- Steuerelemente und Benutzersteuerelemente

TriggerTime = m_TriggerTime
End Property

Public Property Let TriggerTime(NewTriggerTime As Date)


If Not Ambient.UserMode Then Err.Raise 382 ' Beim Entwurf nur lesen
m_TriggerTime = NewTriggerTime
SetTimer DateDiff("s", Now, m_TriggerTime)
m_OneShot = True ' Timer-Ereignis einmalig
End Property

Damit wären die Eigenschaften erst einmal unter Dach und Fach. Bleibt noch zu klären, wie die
Implementation des Zeitintervalls an sich aussieht. SetTimer setzt das Intervall des als Basis ver-
wendeten originären Zeitgeber-Steuerelements auf maximal 60 Sekunden. Längere Zeitinter-
valle müssen also minutenweise gestückelt werden. Da das Timer-Ereignis von der tatsächlichen
Intervalllänge her nicht gerade sehr zuverlässig ist, bringt es Vorteile, die Systemzeit zur Berech-
nung der restlichen Sekunden heranzuziehen. Verbleibt weniger als eine Minute, kann Timer1
direkt auf die Restzeit programmiert werden. Ist die Restzeit kleiner gleich 0 geworden, kann
das Steuerelement seinerseits ein Timer-Ereignis signalisieren und in Abhängigkeit von
m_OneShot das Intervall entweder auffrischen oder es bei diesem einen Ereignis belassen:
Event Timer() ' wird vom Benutzersteuerelement signalisiert

Private Sub Timer1_Timer()


Dim Diff As Long
Diff = DateDiff("s", Now, m_TriggerTime)
If Diff < 60 Then ' Weniger als 1 Minute?
If Diff <= 0 Then ' Schon um?
RaiseEvent Timer
If m_OneShot Then ' Timer neu setzen?
Timer1.Interval = 0
m_OneShot = False ' Standardwert setzen
Else
LongInterval = m_LongInterval ' Neu setzen
End If
Else
Timer1.Interval = 1000 * Diff ' Timer auf restliche Sekunden
End If
End If
End Sub

602
LongTimer – der Timer mit Ausdauer

Das war nicht nur das Grobe, sondern auch bereits die eine oder andere Feinheit. Den letzten
Schliff erhält das Steuerelement, wenn sich LongInterval nun auch noch zur Entwurfszeit setzen
lässt. Vom Prinzip her ist es bereits jetzt schon möglich, die Eigenschaft zu setzen, und die Ent-
wurfsinstanz fängt dann auch brav das Ticken an, was sich ganz einfach durch Ergänzen einer
Beep-Anweisung in Timer1_Timer nachweisen lässt. (Setzen Sie dazu das Intervall auf eine oder
zwei Sekunden.) Um der Entwurfsinstanz das Ticken auszutreiben, sollten Sie in SetTimer die
folgende erste Zeile ergänzen:
If Not Ambient.Usermode Then Exit Sub

Da die Entwurfsinstanz, wie bereits ausgeführt, bei Instanziierung des Containers vernichtet
und durch eine Laufzeitinstanz ersetzt wird, muss diese eine Möglichkeit haben, irgendwie an

ActiveX- Steuerelemente und Benutzersteuerelemente


den Wert von LongInterval zu kommen. Genau für diesen Zweck signalisiert das UserControl-
Objekt unmittelbar vor dem Terminate-Ereignis das WriteProperties-Ereignis und unmittelbar
nach dem Initialize-Ereignis das ReadProperties-Ereignis. Beide Ereignisse stellen über ihren
Parameter ein und dasselbe PropertyBag-Objekt bereit, das die besondere Eigenschaft hat, per-
sistent zu sein (d.h.: es behält seinen Wert von Instanz zu Instanz bei), und dem Benutzersteuer-
element wie eine Ressource zugeordnet ist. Das PropertyBag-Objekt kann wie eine »Tasche«
beliebig viele Einträge speichern, die eine Zuordnung zwischen einer Zeichenfolge und einem
beliebigen Wert darstellen, und diese Einträge in der nächsten Instanz des Benutzersteuerele-
ments wieder hervorzaubern. Die Methoden für das Ein- und Auspacken haben die Deklaratio-
nen:
Function Objekt.ReadProperty(Name As String[, Default]]) As Variant
Sub Objekt.WriteProperty(Name As String, Value[, Default])

Für Name geben Sie am besten (jedoch nicht zwingend) den Bezeichner der Eigenschaft als Zei-
chenfolge an und für Value ihren Wert. Den optionalen Parameter Default sollten Sie nach
Möglichkeit mit einem Wert versorgen, der den Standardwert der Eigenschaft darstellt. Falls
die Werte von Value und Default gleich sind, spart sich WriteProperty so nämlich den Eintrag,
und ReadProperty liefert den Wert von Default, wenn der über Name spezifizierte Eintrag nicht
existiert.
Da die Eigenschaft LongInterval zur Entwurfszeit gesetzt werden kann, sollte ihr Wert der
Laufzeitinstanz zugänglich gemacht werden. Das Setzen der anderen Eigenschaften kann die
Set-Prozedur von LongInterval besorgen. Hier der restliche Code:
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
LongInterval = PropBag.ReadProperty("LongInterval", 0)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


PropBag.WriteProperty "LongInterval", m_LongInterval, 0
End Sub

Das Steuerelement veröffentlichen


Im letzten Schritt können Sie das fertige Steuerelement nun noch veröffentlichen, um es fortan
lokal auf dem System oder netzwerkweit in der Komponentenbibliothek zur Verfügung zu
haben.
Klicken Sie dazu im Kontextmenü des Projekts für das Benutzersteuerelement oder im Menü
BEARBEITEN auf den Befehl VERÖFFENTLICHEN und wählen Sie im Untermenü den (vom Namen
her wirklich verhunzten) Eintrag ERSTELLUNGSAUSGABEN. Damit teilen Sie dem Visual Compo-
nent Manager (VCM) Ihres Systems mit, dass Sie eine kompilierte Fassung des Benutzersteuere-
lements als Komponente registrieren wollen, um sie anderen Anwendungen zur Verfügung zu

603
ActiveX- Steuerelemente und Benutzersteuerelemente

stellen. Der VCM kompiliert den Code zuerst in eine OCX-Datei und startet dann den Veröf-
fentlichungs-Assistent. (Wenn Sie Ihre Komponenten in einem speziellen Verzeichnis sammeln
wollen, sollten Sie die Übersetzung manuell über das Menü DATEI unter Angabe des gewünsch-
ten Pfads vornehmen.) Im zweiten Dialog legen Sie den öffentlichen Namen des Steuerelements
fest sowie eine Datenbank, in der die Komponente gespeichert wird. Wählen Sie in der Local
Database den Ordner Visual Basic\Templates\User Controls und folgen Sie den Anweisungen
des Assistenten bis zur Fertigstellung. Wenn Sie nun die Komponentenbibliothek über PROJEKT/
KOMPONENTEN öffnen, sehen Sie das neue ActiveX-Steuerelement.
ActiveX- Steuerelemente und Benutzersteuerelemente

Das Benutzersteuerelement ist nun registriertes Ac tiveX- Steuerelement

Um die Registrierung des Steuerelements wieder loszuwerden oder es an einen anderen Spei-
cherort zu verfrachten, umzubenennen usw. können Sie den VCM auch direkt über Ansicht/
Visual Component Manager starten und in einem im Stile des Explorers gehaltenen Fenster die
gewünschten Änderungen durchführen. Die Bedienung ist recht intuitiv.
Hier noch einmal der vollständige Code:
'***********************************************************************
' Benutzersteuerelement: LongTimer
' Autor : 2000 Rudolf Huttary
' Schnittstelle : LongInterval
' auf periodische Intervallzeit in Sek. setzen
' Wenn 0, dann Timer aus.
' TriggerTime
' auf Zeit(/Datum) setzen, an der ein einzelnes
' Timer-Ereignis auftreten soll
'***********************************************************************

Option Explicit

Event Timer() ' wird vom Benutzersteuerelement signalisiert

Private m_LongInterval As Long


Private m_TriggerTime As Date

604
LongTimer – der Timer mit Ausdauer

Private m_OneShot As Boolean

' Nur-Lesen Eigenschaft


Public Property Get OneShot() As Boolean
OneShot = m_OneShot
End Property

Public Property Get LongInterval() As Long


LongInterval = m_LongInterval
End Property

ActiveX- Steuerelemente und Benutzersteuerelemente


Public Property Let LongInterval(NewInterval As Long)
m_LongInterval = NewInterval
m_TriggerTime = DateAdd("s", NewInterval, Now)
SetTimer NewInterval
m_OneShot = False ' Timer-Ereignis periodisch
End Property

Public Property Get TriggerTime() As Date


TriggerTime = m_TriggerTime
End Property

Public Property Let TriggerTime(NewTriggerTime As Date)


If Not Ambient.UserMode Then Err.Raise 382 ' Beim Entwurf nur lesen
m_TriggerTime = NewTriggerTime
SetTimer DateDiff("s", Now, m_TriggerTime)
m_OneShot = True ' Timer-Ereignis einmalig
End Property

Private Sub SetTimer(Diff As Long)


' If Not Ambient.UserMode Then Exit Sub
If Diff <= 0 Then ' Timer stoppen?
Timer1.Interval = 0
m_OneShot = False ' Standardwert setzen
ElseIf Diff < 60 Then ' Weniger als 1 Minute?
Timer1.Interval = Diff * 1000
Else
Timer1.Interval = 60000 ' Großer Zeitraum
End If
End Sub

Private Sub Timer1_Timer()


Dim Diff As Long
Beep
Diff = DateDiff("s", Now, m_TriggerTime)
If Diff < 60 Then ' Weniger als 1 Minute?
If Diff <= 0 Then ' Schon um?
RaiseEvent Timer
If m_OneShot Then ' Timer neu setzen?
Timer1.Interval = 0
m_OneShot = False ' Standardwert setzen

605
ActiveX- Steuerelemente und Benutzersteuerelemente

Else
LongInterval = m_LongInterval ' Neu setzen
End If
Else
Timer1.Interval = 1000 * Diff ' Timer auf restliche Sekunden
End If
End If
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


ActiveX- Steuerelemente und Benutzersteuerelemente

LongInterval = PropBag.ReadProperty("LongInterval", 0)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


PropBag.WriteProperty "LongInterval", m_LongInterval, 0
End Sub

Transparenz und Drag&Drop


Die Überlagerung mehrerer Bilder mit durchscheinendem Hintergrund war schon immer eine
delikate Aufgabe und fällt seit jeher in den Bereich der Animationsprogrammierung. Wer sich
nicht auf Pixel-Krämerei einlassen und das Problem von der Wurzel her anpacken will oder auf
eine entsprechende Bibliothek zurückgreifen kann, ist darauf angewiesen, mit dem zurechtzu-
kommen, was Visual Basic von sich aus bietet. Das ist zwar nicht gerade viel, reicht aber bei-
spielsweise für die Programmierung einfacher Brettspiele mit Figuren, Puzzles und Ähnlichem.
Die Eigenschaft Picture eines Formularobjekts taugt dazu, ein Hintergrundbild anzuzeigen.
Vor einem solchen Hintergrundbild gegebenenfalls weitere Bilder als Vordergrundbilder einer
Szene einzublenden und/oder zu animieren, ist mit den beiden Standardsteuerelementen Image
und PictureBox zwar möglich, ein Blumentopf lässt sich damit aber nicht gerade gewinnen, da
diese partout darauf bestehen, ihre Bilder als Rechtecke zu zeichnen. Häufig ist aber gerade eine
unregelmäßige Form mit durchsichtigen Bereichen erwünscht. Ist der Hintergrund einfarbig,
gelingt zwar die pseudotransparente Darstellung, da alle Bereiche mit Hintergrundfarbe in
einem über den Hintergrund gezeichneten Bild ohne Rand transparent wirken, doch bereits bei
Verwendung eines Hintergrundbildes oder bei Überlagerung mehrerer Vordergrundbilder führt
diese Methode nicht mehr zum Ziel. Wie also lässt sich die Ausgabe von Bildern mit transpa-
renten Bereichen generell bewerkstelligen?
Ein Weg führt über die MaskColor-Eigenschaft des ImageList-Steuerelements (zu finden in der
Komponente mscomctl.ocx) in Kombination mit der Overlay-Methode. Dieser Ansatz hat aber
den Nachteil, dass die Methode darauf besteht, beide an der Operation beteiligten Bilder auf
die gleiche Größe zu skalieren. Mithin eignet er sich nur für die Kombination von Bildern, die
als Vordergrundbilder in einer Szene eingesetzt werden.
Bei vielen Problemstellungen führt aber ein anderer Ansatz in befriedigender Weise zum Ziel:
die Definition eines Benutzersteuerelements. Da das Benutzersteuerelementmodul auf ein User-
Control-Objekt aufsetzt, das die notwendigen Eigenschaften für eine transparente Darstellung
über einem beliebigen Hintergrund bereits mitbringt, stellt sich nur noch die Frage der Realisie-
rung und welche »Kröten es dabei zu schlucken« gilt.
Die programmtechnische Umsetzung ist geradezu simpel:
1. Fügen Sie in das Projekt ein neues Benutzersteuerelementmodul Figur.ctl ein und sorgen Sie
dafür, dass die Klasse die Eigenschaften MaskPicture und Picture des untergelegten UserCon-
trol-Objekts offenlegt.

606
Transparenz und Drag&Drop

2. Setzen Sie beim Entwurf des Steuerelements (respektive in der Initialisierungsroutine Initia-
lize) die Eigenschaften FillStyle auf vbFSTransparent und BackColor auf vbTransparent.
Weiterhin setzen Sie MaskColor auf die Farbe, die in dem für das Steuerelement vorgesehenen
Bild die transparenten Bereiche markiert.
3. Platzieren Sie das Steuerelement auf das vorgesehene Formular und setzen Sie im Formular-
modul die Eigenschaften MaskPicture und Picture auf ein Bild Ihrer Wahl vom Typ Picture,
dessen Transparenzfarbe mit der Eigenschaft MaskColor des Steuerelements korrespondiert.
4. Passen Sie die Größe des Steuerelements im Formularmodul an die Bildgröße an.
Das war es bereits. Um Ressourcen zu sparen, empfiehlt es sich zudem, die Windowless-Eigen-
schaft des Benutzersteuerelements beim Entwurf auf True zu setzen. Das Steuerelement fordert

ActiveX- Steuerelemente und Benutzersteuerelemente


dann keinen Fenster-Handle hWnd an, der ohnehin nur im Zusammenhang mit Aufrufen der
Win32-API benötigt wird.
Ach ja, die Kröten. Es gibt welche. Mehr dazu aber im Anschluss an die Besprechung des Pro-
grammcodes unter der Überschrift »Diskussion«.

Schach – klare Sicht auf Hintergründliches


Das in Form des Projekts Schach vorliegende Programm zur Illustration dieser Technik ist
etwas komplexer ausgefallen. Es demonstriert nicht nur den Einsatz transparenter Bitmaps,
sondern zudem eine Reihe weiterer Techniken:
1. die Verdrahtung von Menübefehlen
2. die Arbeit mit Steuerelementefeldern
3. das dynamische Generieren von Steuerelementen zur Laufzeit
4. die Arbeit mit dem Bildausschnitt-Steuerelement (PictureClip)
5. Drag&Drop-Operationen mit Steuerelementen.
Das Programm Schach macht seinem Namen alle Ehre: Man kann immerhin damit Schach spie-
len. Wer nun erwartet, in dem kurzen Programm auch einen würdigen Gegner zum Spielen zu
finden, der muss hier leider enttäuscht werden. Die Grundlagen für eine Schach-Engine würden
ein Buch ähnlichen Umfangs füllen, und als Zielsprache für eine Implementation würde man
sicher nicht Visual Basic wählen, weil Laufzeit in einem solchen Programm ein zu kostbares
Gut ist. Für Visual Basic bliebe höchstens der Part der visuellen Darstellung des Spiels. Der Ein-
fachheit halber beschränkt sich das vorliegende Programm auf eben dies, nämlich auf das
nackte Spiel, und verzichtet auch auf jegliche Schiedsrichtertätigkeit wie den Ausschluss fal-
scher Züge, die Ansage von Schach oder die Überwachung des Seitenwechsels. Wird eine Figur
geschlagen, verlässt sie »freiwillig« das Feld. An definierten Stellungen gibt es die Grundstellun-
gen »Weiß unten« und »Schwarz unten« sowie das »Leere Brett«. Geschlagene oder herausge-
stellte Figuren landen außerhalb des Bretts in Gefangenschaft der gegnerischen Farbe. Sie kön-
nen jederzeit zurückgestellt werden.
In dieser einfachen Form eignet sich das Programm ganz gut zum Studieren und Nachspielen
von Stellungen. Da es auf eine Repräsentation der aktuellen Stellung verzichtet, ersetzt es wohl
das Schachbrett und die Figuren – immerhin –, jedoch nicht viel mehr.
Hier zuerst der Quelltext des Benutzersteuerelements:
'***********************************************************************
' Benutzersteuerelementmodul: Figur.ctl
' Autor : 2000 Rudolf Huttary
' Beschreibung : Dummy-Steuerelement, ermöglicht
' transparenten Hintergrund.
' Eigenschaft Windowless muss zur
' Entwurfszeit gesetzt werden
'***********************************************************************

607
ActiveX- Steuerelemente und Benutzersteuerelemente

Public Property Set Picture(new_Image As Picture)


UserControl.Picture = new_Image
End Property

Public Property Set MaskPicture(ByVal New_MaskPicture As Picture)


Set UserControl.MaskPicture = New_MaskPicture
End Property

Private Sub UserControl_Initialize()


UserControl.BackStyle = vbTransparent
ActiveX- Steuerelemente und Benutzersteuerelemente

UserControl.FillStyle = vbFSTransparent
UserControl.MaskColor = vbWhite
End Sub

Damit Sie das Element nach Fertigstellung auf dem Formular platzieren können, schließen Sie
die Fenster mit der Code- und Objektansicht des Steuerelements und öffnen die Objektansicht
des Formulars, in dem Sie das Steuerelement verwenden wollen. In der Werkzeugsammlung
müssten Sie nun ein weiteres Element mit dem Standardsymbol für Benutzersteuerelemente vor-
finden. Platzieren Sie eine Instanz dieses Elements auf dem Formular, geben Sie ihm im Eigen-
schaftsfenster den Namen Figur und setzen Sie die Eigenschaft Index auf den Wert 0. Sobald
Visual Basic im Entwurfsmodus für ein Steuerelement einen Wert für die Eigenschaft Index vor-
findet, generiert es von sich aus ein Steuerelemente-Array mit dem gewählten Namen. Dieses
Array lässt sich dann im Code dynamisch erweitern. Das erste Objekt eines Steuerelementtyps
fungiert dabei als »Samen« für weitere Instanzen und muss zur Entwurfszeit auf dem Formular
platziert werden. Weitere Objekte lassen sich dann zur Laufzeit mittels Load ins Leben rufen.
(Seit Visual Basic 6.0 besteht zwar auch die Möglichkeit, ActiveX-Objekte, also auch ActiveX-
Steuerelemente, aus dem Nichts zur Laufzeit anzulegen, doch das wäre im vorliegenden Fall
sinnlose akademische Disziplin.)
Als zweites Nicht-Standardsteuerelement verwendet das Programm das in der ActiveX-Kompo-
nente Picclip32.ocx enthaltene Bildausschnitt-Steuerelement PictureClip. Es dient als Quelle
für die Einzelbilder der Schachfiguren, die der Einfachheit halber in einer einzigen Bitmap
zusammengefasst sind. Wie der Name schon sagt, ist es die Spezialität des Bildausschnitt-Steue-
relements, Teile einer Bitmap als Einzelbilder zu liefern. Ordnet man dem Steuerelement bereits
zur Entwurfszeit das die Figuren enthaltende Bild zu und gibt ihm auch die Anzahl der Zeilen
und Spalten bekannt, in denen die Einzelbilder organisiert sind (Letzteres ist nur zur Entwurfs-
zeit möglich), sieht der Zugriff auf ein Einzelbild nicht anders aus als der Zugriff auf ein Array-
Element – die GraphicCell-Eigenschaft macht es möglich. Die folgende Abbildung zeigt das For-
mular mit dem Schachbrett und den Figuren.
Neben dem obligatorischen Befehl BEENDEN im DATEI-Menü finden sich im AUFSTELLEN-Menü
drei weitere Befehle: WEIß UNTEN, SCHWARZ UNTEN und LEER. Damit lassen sich die drei
Grundstellungen herbeiführen, um ein Spiel zu beginnen oder eine Stellung aufzustellen. Gezo-
gen wird mit der Maus. Geschlagene Figuren stellt das Programm von sich aus neben das Brett,
von wo sie jederzeit wieder geholt werden können, etwa für die Verwandlung eines durchgebro-
chenen Bauern. Vor der Besprechung weiterer Einzelheiten hier zunächst einmal der Code des
Formularmoduls.
'***********************************************************************
' Projekt : Schach
' Autor : 2000 Rudolf Huttary
' Beschreibung : Demonstriert Transparenz und Drag&Drop
'***********************************************************************

608
Transparenz und Drag&Drop

ActiveX- Steuerelemente und Benutzersteuerelemente


Springer zieht als Verteidigung gegen den guten alten »Schäferzug«

Option Explicit
Private bSchwarzUnten As Boolean
Const FeldBreite = 55
Const FigurBreite = 51
Const FigurHöhe = 51
Const Pfad = "Schach\"

Private Sub Form_Load()


Dim FigIdx()
Dim i As Integer
AutoRedraw = True
BackColor = vbBlack
ScaleMode = vbPixels ' Es rechnet sich besser in Bildpunkten
' Formulargröße gestalten: Height und Width erwarten Twips!
Height = ScaleY(11 * FeldBreite, vbPixels, vbTwips)
Width = ScaleX(13 * FeldBreite, vbPixels, vbTwips)

' Zuordnung zwischen Figur-Bildern und Figur-Steuerelementen


FigIdx = Array(0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 1, 4, 5, 1, 2, 3, _
6, 6, 6, 6, 6, 6, 6, 6, 9, 8, 7, 10, 11, 7, 8, 9)
With PictureClip1
Picture = LoadPicture(App.Path + "\Schachfiguren.bmp")
.Rows = 2
.Cols = 6
End With

For i = 0 To 31 ' Element mit Index 0 ist "Same"


If i > 0 Then Load figur(i) ' Weitere Instanzen des Steuer-

609
ActiveX- Steuerelemente und Benutzersteuerelemente

figur(i).Visible = True ' elements dynamisch laden und


figur(i).Height = FigurHöhe ' initialisieren
figur(i).Width = FigurBreite
figur(i).DragMode = vbAutomatic
' Figur-Bilder aus Bildausschnitt-Steuerelement gewinnen
Set figur(i).MaskPicture = PictureClip1.GraphicCell(FigIdx(i))
Set figur(i).Picture = PictureClip1.GraphicCell(FigIdx(i))
Next i
ActiveX- Steuerelemente und Benutzersteuerelemente

' Image-Steuerelemente initialisieren


With imgWeißunten ' Schachbrett für "Weiß unten" laden
.Visible = False
.Picture = LoadPicture(Pfad + "SchachbrettWU.gif")
.Width = ScaleX(.Picture.Width, vbHimetric, vbPixels)
.Height = ScaleY(.Picture.Height, vbHimetric, vbPixels)
.Left = 0: .Top = 0
End With
With imgSchwarzunten ' Schachbrett für "Schwarz unten" laden
.Visible = False
.Picture = LoadPicture(Pfad + "SchachbrettSU.gif")
.Width = ScaleX(.Picture.Width, vbHimetric, vbPixels)
.Height = ScaleY(.Picture.Height, vbHimetric, vbPixels)
.Left = 0: .Top = 0
End With

mnuAufstellenWeißUnten_Click ' Grundstellung


End Sub

' Figur wird auf neue Position verschoben


Private Sub Form_DragDrop(Source As Control, x As Single, y As Single)
Dim KoordX As Single, KoordY As Single
' exakte Feldposition berechnen
PixelZuFeld x, y
FeldZuPixel x, y, KoordX, KoordY
' Figur verschieben
Source.Left = KoordX
Source.Top = KoordY
End Sub

' Falls Figur über einer anderen abgelegt wird, wird diese geschlagen
Private Sub figur_DragDrop(Index As Integer, Source As Control, _
x As Single, y As Single)
x = figur(Index).Left ' Schlagende Figur nimmt Platz der
y = figur(Index).Top ' geschlagenen ein
FigurRaus Index ' Erst die Figur raus, dann verschieben!
Source.Left = x
Source.Top = y
End Sub

61 0
Transparenz und Drag&Drop

Private Sub FeldZuPixel(ByVal FeldX As Single, ByVal FeldY As Single, _


ByRef x As Single, ByRef y As Single)
If Not bSchwarzUnten Then FeldX = 9 – FeldX ' gelb unten?
y = FeldBreite * FeldX + (FeldBreite – FigurHöhe) / 2
x = FeldBreite * FeldY + (FeldBreite – FigurBreite) / 2
End Sub

Private Sub PixelZuFeld(x As Single, y As Single)


Dim z As Single
z = y \ FeldBreite

ActiveX- Steuerelemente und Benutzersteuerelemente


y = x \ FeldBreite
If bSchwarzUnten Then x = z Else x = 9 – z
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)


Dim i As Integer
For i = 1 To 31 ' Dynamisch angeforderte Steuerelemente freigeben
Unload figur(i)
Next
End Sub

Private Sub mnuAufstellenGrundstellung_Click()


Dim x As Single, y As Single
Dim i As Integer, j As Integer
mnuAufstellenLeer_Click
For j = 1 To 8
i = j
If j = 4 And bSchwarzUnten Then i = 5 ' König/Dame vertauschen?
If j = 5 And bSchwarzUnten Then i = 4 ' König/Dame vertauschen?
FeldZuPixel 8, j, x, y ' rote Bauern
figur(i + 15).Left = x: figur(i + 15).Top = y
FeldZuPixel 2, j, x, y ' gelbe Bauern
figur(i – 1).Left = x: figur(i – 1).Top = y
FeldZuPixel 1, j, x, y ' gelbe Hauptfiguren
figur(i + 7).Left = x: figur(i + 7).Top = y
FeldZuPixel 7, j, x, y ' rote Bauern
figur(i + 15).Left = x: figur(i + 15).Top = y
FeldZuPixel 8, j, x, y ' rote Hauptfiguren
figur(i + 23).Left = x: figur(i + 23).Top = y
Next j
End Sub

Private Sub mnuAufstellenLeer_Click()


Dim i As Integer
For i = 0 To 31 ' Alle Figuren rausstellen
FigurRaus (i)
Next i
End Sub

Private Sub mnuAufstellenSchwarzUnten_Click()


Picture = imgSchwarzunten.Picture

61 1
ActiveX- Steuerelemente und Benutzersteuerelemente

bSchwarzUnten = True
mnuAufstellenGrundstellung_Click
End Sub

Private Sub mnuAufstellenWeißUnten_Click()


Picture = imgWeißunten.Picture
bSchwarzUnten = False
mnuAufstellenGrundstellung_Click
End Sub
ActiveX- Steuerelemente und Benutzersteuerelemente

Private Sub mnuDateiBeenden_Click()


Unload Me ' löst QueryUnload aus!
End Sub

' Figur neben Brett aufstellen


Private Sub FigurRaus(Index As Integer)
figur(Index).Top = FeldBreite * (1 + Index \ 4)
figur(Index).Left = 9.5 * FeldBreite + FigurBreite / 2 * (Index Mod 4)
End Sub

Die Logik des Programms ist relativ einfach. In der Initialisierungsroutine Form_Load findet sich
der gesamte Code für die Initialisierung des Formulars und der darauf platzierten Steuerelemente
PictureClip1 (Bildausschnitt-Steuerelement), imgSchwarzunten und imgWeißunten (Anzeige-Steu-
erelemente) sowie figur (Benutzersteuerelement). Diese Prozedur erweckt insbesondere auch je
Schachfigur ein weiteres figur-Benutzersteuerelement »zum Leben« und ordnet diesem als
Maske sowie als Bild die der Spielfigur entsprechende Zelle des Bildausschnitt-Steuerelements
zu. Der Schlüssel für die Zuordnung steckt in dem dynamisch initialisierten Array FigIdx und
ergibt eine einfache zeilenweise Abzählung der Spielfiguren.
Die Behandlungsroutinen für die Befehle im AUFSTELLEN-Menü bedienen sich für die Berech-
nung der Figurenpositionen verschiedener Hilfsroutinen. Die dabei verwendete Mathematik
und Logik ist etwas knifflig, aber durchaus geradlinig. Zu bemerken wäre, dass das Programm
die Anzeige-Steuerelemente dazu »missbraucht«, die Hintergrundbilder für die beiden Aufstel-
lungen zu liefern. Der Einfachheit halber pflegt das Programm das Hintergrundbild über die
Picture-Eigenschaft des Formulars.
Das Interessante an dem Programm ist, wie einfach letztlich der Mechanismus für die Bewe-
gung und das Schlagen der Figuren geraten ist. Nachdem der Benutzer die Figuren mit der
Maus ziehen und ablegen können soll, bietet sich für die Implementation dieser Funktionalität
der Drag&Drop-Mechanismus geradezu an. Damit eine Instanz des figur-Steuerelements auf
Drag&Drop reagiert, ist nichts weiter zu tun, als die Eigenschaft DragMode auf vbAutomatic zu
setzen – um den Rest kümmert sich Windows. Insbesondere schickt Windows dem Steuerele-
ment bzw. Fenster eine Nachricht, in dem der »Drop« stattfindet. Zieht der Benutzer eine Figur
in ein leeres Feld, ist das Formular Ziel der Benachrichtigung und erhält ein DragDrop-Ereignis.
Die entsprechende Behandlungsroutine Form_DragDrop hat dann nichts weiter zu tun, als die
Positionskoordinaten des über den Parameter Source identifizierbaren Steuerelements geeignet
anzupassen. Ist ein anderes Steuerelement Ziel der Operation, schlägt die gezogene Figur die
Figur dieses Steuerelements. Die dafür zuständige Behandlungsroutine figur_DragDrop
bekommt als zusätzlichen Parameter den Index des Zielobjekts im Steuerelemente-Array über-
geben. Dieses Objekt überlässt dem »schlagenden« Steuerelement (Source) seine Position und
verzieht sich dann in die ihm zugeordnete Leerposition neben dem Brett, die schlicht aus ihrem
Index abgeleitet wird.

61 2
Transparenz und Drag&Drop

Schach1 – unter den Blinden ist der Einäugige König


Haben Sie es gemerkt? Nein? Die Transparenz hat die Programmierung zwar vereinfacht, für
das Ergebnis war sie aber nicht unbedingt nötig. Eigentlich sieht man sie nur da, wo der Fehler
sitzt und wo die Figuren nebeneinander außerhalb des Bretts stehen. Vom Prinzip her, hätte
sich die Geschichte auch mit gewöhnlichen Bitmaps erledigen lassen, wenn man die Bilder der
Figuren immer passend zum Hintergrund auswechselt.
Einfachheit hat jedoch seinen Preis. Es gibt zwei größere Kröten zu schlucken: Erstens, das Sys-
tem spielt einem Benutzersteuerelement das DragDrop-Ereignis nur dann zu, wenn sich der
Mauszeiger beim Loslassen der Maustaste auch wirklich innerhalb der Maske dieses Steuerele-
ments befindet. Zielt der Benutzer auch nur ein wenig daneben, kommen die Figuren überein-

ActiveX- Steuerelemente und Benutzersteuerelemente


ander zu liegen – wir spielen aber Schach und nicht Dame. (Immerhin, hier wird die Transpa-
renz deutlich.) Zweitens, der Benutzer sieht nicht, welche Figur er zieht, da das System während
automatisierter Drag&Drop-Operationen an der aktuellen Ziehposition nicht das Objekt, son-
dern nur seinen Umriss als schlichtes Rechteck zeichnet.
Um es gleich vorwegzunehmen, für das erste Problem gibt es keine »objektorientierte« Lösung
mehr, wenn auf die Drag&Drop-Automatik verzichtet wird. Kam das Programm in der gezeig-
ten Version noch ohne eine explizite Repräsentation der Stellung aus, wird man für die explizite
Trefferprüfung doch eher dazu tendieren, explizit darüber Buch zu führen, auf welchem Feld
welche Figur zu finden ist – das ist für einen weiteren Ausbau des Programms ohnehin unum-
gänglich. Die folgende, verbesserte Version Schach1 scheut diesen Aufwand noch und testet
nur, ob eine der anderen Figuren auf der Zielposition sitzt. Das zweite Problem lässt sich mit
ein wenig Mehraufwand zufriedenstellend in Griff bekommen. Hier der Ansatz:
1 Belassen Sie die Eigenschaft DragMode aller Instanzen des figur-Steuerelements auf vbManual (0).
2. Erweitern Sie das Benutzersteuerelement figur dahingehend, dass es die Ereignisse Mouse-
Down, MouseUp und MouseMove delegiert (d.h. an das Formularobjekt signalisiert).
3. Sehen Sie im Formularobjekt Behandlungsroutinen für die neuen Ereignisse vor. Die Routine
figur_MouseDown überträgt die Startkoordinaten der Operation in globale Variablen und setzt
die Z-Ordnung des Steuerelements so, dass es über allen anderen gezeichnet wird. Die Rou-
tine figur_MouseMove aktualisiert die Position des Steuerelements. Der Routine figur_MouseUp
fällt schließlich die Aufgabe zu, die Zielkoordinaten zu errechnen, zu testen, ob eine Figur
gegebenenfalls geschlagen werden muss, die Z-Ordnung wieder herzustellen (optional) und
schließlich das Steuerelement auf die neue Position zu verschieben.
Der zusätzliche Code hält sich in Grenzen. Für das figur-Steuerelement lautet er:
Event MouseMove(Button As Integer, Shift As Integer, X As Single, _
Y As Single) 'MappingInfo=UserControl,UserControl,-1,MouseMove
Event MouseUp(Button As Integer, Shift As Integer, X As Single, _
Y As Single) 'MappingInfo=UserControl,UserControl,-1,MouseUp
Event MouseDown(Button As Integer, Shift As Integer, X As Single, _
Y As Single) 'MappingInfo=UserControl,UserControl,-1,MouseDown

Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
RaiseEvent MouseDown(Button, Shift, X, Y)
End Sub

Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
RaiseEvent MouseMove(Button, Shift, X, Y)
End Sub

61 3
ActiveX- Steuerelemente und Benutzersteuerelemente

Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
RaiseEvent MouseUp(Button, Shift, X, Y)
End Sub

Anhand der Kommentare erkennt man, dass die Routinen und Ereignisdeklarationen durch den
als Add-In zur Verfügung stehenden ActiveX-Steuerelement-Assistenten eingefügt wurden. (Der
Assistent muss gegebenenfalls vom Add-In-Manager geladen werden.) Um die Routinen zu
»verdrahten«, ordnen Sie den Ereignissen im vierten Dialog des Assistenten das Steuerelement
UserControl zu. Visual Basic ergänzt dann die Deklarationen der Ereignisroutinen.
Im Formularmodul müssen jetzt die Behandlungsroutinen für diese zusätzlichen Ereignisse
ActiveX- Steuerelemente und Benutzersteuerelemente

ergänzt werden. Dafür sind die Routinen Form_DragDrop und figur_DragDrop obsolet geworden.
Private Sub figur_MouseDown(Index As Integer, Button As Integer, _
Shift As Integer, X As Single, Y As Single)
ElemX = X ' Startkoordinaten merken
ElemY = Y
' Z-Ordnung verändern, damit Figur über allen anderen angezeigt wird
figur(Index).ZOrder (0)
End Sub

Private Sub figur_MouseMove(Index As Integer, Button As Integer, _


Shift As Integer, X As Single, Y As Single)
If ElemX Then
figur(Index).Left = figur(Index).Left – ScaleX((ElemX – X), _
vbTwips, vbPixels)
figur(Index).Top = figur(Index).Top – ScaleY((ElemY – Y), _
vbTwips, vbPixels)
End If
End Sub

Private Sub figur_MouseUp(Index As Integer, Button As Integer, _


Shift As Integer, X As Single, Y As Single)
Dim KoordX As Single, KoordY As Single
ElemX = 0 ' Drag-Operation zu Ende
X = figur(Index).Left + ScaleX((X), vbTwips, vbPixels)
Y = figur(Index).Top + ScaleY((Y), vbTwips, vbPixels)
' exakte Feldposition berechnen
PixelZuFeld X, Y
FeldZuPixel X, Y, KoordX, KoordY
' Trefferprüfung: Wird eine Figur geschlagen?
For i = 0 To 31
If figur(i).Left = KoordX Then
If figur(i).Top = KoordY Then
If i <> Index Then FigurRaus i
End If
End If
Next i
' Z-Ordnung wieder herstellen
For i = 31 To 0 Step -1
figur(i).ZOrder (0)
Next i

61 4
MemoryEdit – das Textfeld mit Gedächtnis

' Figur verschieben


figur(Index).Left = KoordX
figur(Index).Top = KoordY

End Sub

Voilà, ab jetzt funktioniert die Trefferprüfung für das gesamte Feld, und die Figur wird auch
während der Ziehoperation laufend gezeichnet. Außerdem erscheint sie vor allen anderen, weil
ein entsprechender ZOrder-Aufruf erfolgt. Vergessen Sie nicht, die Zeile
' figur(i).DragMode = vbAutomatic ' Schalter für verbesserte Version

ActiveX- Steuerelemente und Benutzersteuerelemente


in der Routine Form_Load auszukommentieren, sonst ändert sich nämlich nichts, sofern die Rou-
tinen Form_DragDrop und figur_DragDrop noch vorhanden sind. Das Kommentarzeichen ist der
Schalter zwischen der einfachen und der verbesserten Version – wenn es doch nur immer so
wäre.
Ein wenig exotisch mag die Berechnung der neuen Figurkoordinaten in der Methode
Figur_MouseMove anmuten. Windows liefert die Mauskoordinaten nämlich relativ zur linken
oberen Ecke des Steuerelements und in Twips – da muss man erst einmal drauf kommen. Damit
die Figur dem Mauszeiger folgt, muss die Routine den Offset der Maus innerhalb des Steuerele-
ments aufrechterhalten. Das geht so: Figur_MouseDown speichert die Mausposition als Offset zu
Beginn der Operation in globalen Variablen. Figur_MouseMove berechnet die Differenz zwischen
der aktuellen Mausposition und dem Offset, wandelt diese in das im Formular geltende Maß-
system um und verschiebt das Steuerelement dann um diese Differenz.

»Schach matt« durch den bekannten Schäferzug

MemoryEdit – das Textfeld mit Gedächtnis


Verbesserungswürdig ist es allemal, das gute alte Textfeld. Oder hatten Sie noch nie das Verlan-
gen nach einem Überschreibmodus, einem Hexadezimalmodus, einer Suchfunktion oder der
Möglichkeit, bei einem mehrzeiligen Textfeld Zeilen- und Spalteninformationen bezogen auf

61 5
ActiveX- Steuerelemente und Benutzersteuerelemente

den aktuellen Umbruch ermitteln zu können? Das einzige, was Microsoft in dieser Richtung
bisher »verlauten« ließ, ist das ActiveX-Steuerelement MaskEdBox, ein Versuch, die formatierte
Eingabe in Griff zu bekommen – in Hinblick auf die Datenbankprogrammierung natürlich. Auf
den ersten Blick ist der Funktionsumfang des Steuerelements zwar beeindruckend, bei näherer
Hinsicht muss man sich aber schon wundern, warum die Syntax für die Formatbeschreibung
dann letztlich doch so ausdrucksschwach ausgefallen ist – wo bleiben nur die aus der Unix-Welt
bekannten »regulären Ausdrücke»?
Haben Sie eben bei der »Suchfunktion« gelächelt? So abwegig ist das nicht, auch wenn ein
Instr-Aufruf für die Eigenschaft Text mit nachfolgender Definition von SelStart und SelLength
zum gewünschten Ergebnis führt und ungleich weniger Aufwand bedeutet als die Programmie-
rung eines eigenen Benutzersteuerelements. Nicht mehr in die Kategorie »mit Hausmitteln zu
ActiveX- Steuerelemente und Benutzersteuerelemente

lösen« fällt dagegen das intelligente Textfeld, das sich die letzten 10 oder auch 100 Eingaben
merkt und eifrig vorschlägt, während der Benutzer tippt – Sie kennen das.
Am Beispiel des Projekts MemoryEdit stellt Ihnen dieser Abschnitt nicht nur die Implementa-
tion eigener Benutzersteuerelemente »bis zur letzten Konsequenz«, nämlich dem ultimativen
Einsatz des ActiveX-Schnittstellen-Assistenten, vor, sondern auch den Umgang mit der wirklich
vielseitigen Funktion SendMessage der Win32-API.

Spezifikation
Hier die Spezifikation der zu implementierenden Funktionalität. Das Textfeld soll:
1. die letzten n Eingaben speichern und passende Eingaben nach Möglichkeit während des Tip-
pens als markierten Vorschlag unterbreiten (MemoryEdit),
2. sich nach Möglichkeit so wie jedes andere Textfeld verhalten (MemoryEditX).
Beginnen wir mit Punkt 1, der den fakultativen – zu Neudeutsch: wahlfreien – Teil der Imple-
mentation beschreibt. Vom Prinzip her lässt sich diese Funktionalität auf Basis eines dynami-
schen Arrays oder Collection-Objekts implementieren, das bei jeder Eingabe daraufhin durch-
sucht wird, ob sich eines seiner Elemente als Vorschlag eignet – ein würdiges Finale für dieses
Buch wäre ein solches Vorgehen aber eigentlich nicht. Im festen Glauben, dass Ihnen dieser
Standardansatz in eigener Regie keine Schwierigkeiten bereiten dürfte, begibt sich dieses Bei-
spiel auf einen gewagteren Pfad: Das Benutzersteuerelement verwendet als Speicher ein unsicht-
bares Listenfeld und bedient sich dessen Suchfunktion. Suchfunktion? Ja, Suchfunktion. Auch
wenn die mit Visual Basic vorliegende Implementation des Steuerelements eine solche Methode
nicht kennt, es gibt sie. Um sie von Visual Basic aus aufzurufen, muss man dem Steuerelement
nur eine geeignete Nachricht schicken. Nachricht? Auch dafür gibt es (leider) kein Standardmit-
tel in Visual Basic, so dass ein Ausflug in die Win32-API angesagt ist. Die Funktion trägt den
Bezeichner SendMessage und das gesamte Zubehör für ihren Aufruf lässt sich mit dem API-
Viewer, einem reichlich »dummen«, aber funktionalen Add-In der Visual-Basic-Entwicklungs-
umgebung importieren. Der Rest, also die Kopplung der beiden Steuerelemente in einem Benut-
zersteuerelementmodul, ist wieder einmal solides Handwerk.
Punkt 2 besagt, dass das neue ActiveX-Steuerelement nicht nur die gleichen Eigenschaften und
Methoden wie ein Textfeld haben soll, sondern auch die gleichen Ereignisse. Angesichts der
schieren Fülle dieser Elemente würde »der Spaß« wohl schnell aufhören, hätte Microsoft Visual
Basic 6.0 nicht den ActiveX-Schnittstellen-Assistenten beigepackt, der einem den drögen Teil
der Arbeit erstaunlich gründlich abnimmt, dafür aber mit Code nur so um sich schmeißt. Dem
sofortigen Start des Benutzersteuerelements stehen dann allerdings noch einige Fehler im Wege,
die zum einen aus der wohl zu eifrigen Übersetzung der Konstanten False und True resultieren,
in anders gelagerten Fällen zuweilen aber auch unbekannte Datentypen involvieren können, für
die man noch Verweise auf die jeweiligen Module einrichten muss.

61 6
MemoryEdit – das Textfeld mit Gedächtnis

Die beiden vorgestellten Varianten des Steuerelements in Aktion

Umsetzung der Grundfunktionalität


Wenn es Ihre Zeit erlaubt, sollten Sie das Beispielprojekt schrittweise nachvollziehen, da der

ActiveX- Steuerelemente und Benutzersteuerelemente


Umgang mit den Assistenten ein Learning-by-Doing erfordert. Hier die einzelnen Schritte.
1. Legen Sie ein neues Projekt des Typs »Standard-EXE« an und speichern Sie die Projektdatei
als MemoryEdit.vbp und das Formular als MemoryEditTest.frm.
2. Fügen Sie entweder ein weiteres Projekt mit dem Typ ActiveX-Steuerelement hinzu oder er-
gänzen Sie schlicht in dem ersten Projekt ein Benutzersteuerelementmodul. Nennen Sie das
Steuerelement MemoryEdit und speichern Sie es unter dem gleichen Namen (MemoryEdit.ctl).
3. Ziehen Sie das Textfeld Text1 sowie ein Listenfeld List1 in die Entwurfsansicht des Steuere-
lements. Abmessungen und Position sind egal.
4. Wechseln Sie in die Codeansicht und starten Sie den API-Viewer, den Sie gegebenenfalls über
den Add-In-Manager im Menü ADD-INS erst einmal laden müssen. Damit der API-Viewer
das macht, was er machen soll, ist es erforderlich, dass Sie nach seinem Start die Datei
\Visual Studio\Common\Tools\Winapi\Win32api.txt laden (und zwar dummerweise jedes
Mal wieder, wenn Sie ihn aufrufen). Wählen Sie in der Kategorie (API-TYP) Deklarationen
die Funktion SendMessage und in der Kategorie Konstanten die Bezeichner LB_FINDSTRING so-
wie LB_FINDSTRINGEXACT aus. Dann fügen Sie die entsprechenden Deklarationen mit der Op-
tion PRIVATE in den Quelltext ein.

Auswahl der für SendMessage erforderlic hen API- Deklarationen im API- Viewer

61 7
ActiveX- Steuerelemente und Benutzersteuerelemente

Der vom API-Viewer eingefügte Code lautet:


Option Explicit
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) _
As Long
Private Const LB_FINDSTRING = &H18F
Private Const LB_FINDSTRINGEXACT = &H1A2
5. Ergänzen Sie die Implementation einer Eigenschaft namens MaxRemember, deren Aufgabe es
ist, die Anzahl der Einträge im Listenfeld nach oben hin zu begrenzen. Sehen Sie für die in-
ActiveX- Steuerelemente und Benutzersteuerelemente

terne Darstellung eine Integer-Variable m_MaxRemember und als Standardwert für die Initiali-
sierung der Variable eine Konstante m_def_MaxRemember vor. (Halten Sie sich an das
Benennungsschema, da später noch der ActiveX-Schnittstellen-Assistent in dem Code »her-
ummalt«.) Implementieren Sie weiterhin die einschlägigen Methoden.
Private Const m_def_MaxRemember = 0
Private m_MaxRemember

Public Property Let MaxRemember(New_MaxRemember As Integer)


m_MaxRemember = IIf(New_MaxRemember >= 0, New_MaxRemember, 0)
While m_MaxRemember < List1.ListCount ' ggf. Einträge löschen
List1.RemoveItem (List1.ListCount – 1)
Wend
End Property

Public Property Get MaxRemember() As Integer


MaxRemember = m_MaxRemember
End Property

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


m_MaxRemember = PropBag.ReadProperty("MaxRemember", _
m_def_MaxRemember)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


PropBag.WriteProperty "MaxRemember", m_MaxRemember, _
m_def_MaxRemember
End Sub

Private Sub UserControl_InitProperties()


m_MaxRemember = m_def_MaxRemember
End Sub
6. Ergänzen Sie den obligatorischen Code für die Initialisierung und für Größenänderungen. Da
das Benutzersteuerelement letztlich nur aus dem Textfeld Text1 besteht, sollten die Abmes-
sungen identisch sein.
Private Sub UserControl_Initialize()
List1.Visible = False
Text1.Top = 0
Text1.Left = 0
End Sub

61 8
MemoryEdit – das Textfeld mit Gedächtnis

Private Sub UserControl_Resize()


Text1.Height = Height
Text1.Width = Width
Height = Text1.Height ' Textfeld erzwingt minimale Abmessungen
Width = Text1.Width
End Sub

7. Damit wäre der obligatorische Teil (des fakultativen Teils) erledigt. Nun geht es darum, das
Listenfeld zu pflegen und die Eingaben des Benutzers zu überwachen, um sie gegebenenfalls
durch einen passenden Vorschlag in Form einer Markierung zu ergänzen. Nehmen Sie an, die
Liste enthält bereits Einträge (ein Zustand, der sich ja jederzeit provisorisch herstellen lässt).

ActiveX- Steuerelemente und Benutzersteuerelemente


Für die Überwachung der Eingaben passt man am besten das Change-Ereignis des Textfelds
ab und sucht für den bereits eingegebenen Wert einen passenden Eintrag im Listenfeld. All
dies erledigt ein einziger SendMessage-Aufruf. Die API-Funktion verlangt dazu den Fenster-
Handle hWnd des Listenfelds, die erwartete Aktion LB_FINDSTRING, einen Dummy-Wert, der
vom Listenfeld für diese Aktion nicht beachtet wird, und schließlich die gesuchte Zeichenfol-
ge, also den Wert des Textfelds. Beachten Sie die im Referenzteil unter »Routinen aus DLLs
und der Windows-API einsetzen« (S. 185) näher ausgeführte Besonderheit, dass die Überga-
be der Zeichenfolge hier mit dem Zusatz ByVal erfolgen muss! Ergebnis des Aufrufs ist der
Wert -1, wenn kein Eintrag passt, oder eben der Index des passenden Listeneintrags. Falls ein
Eintrag gefunden wurde, wird er in das Textfeld übernommen und der ergänzte Teil durch
entsprechende Definition der Eigenschaften SelStart und SelLength markiert.
Private Sub Text1_Change()
Dim SelIdx As Integer
Dim ListIdx As Integer
' Bisherige Eingabe in Liste suchen..
ListIdx = SendMessage(List1.hWnd, LB_FINDSTRING, 0, _
ByVal Text1.Text)
If ListIdx > -1 Then ' Gefunden?
SelIdx = Text1.SelStart ' Cursorposition merken
Text1 = List1.List(ListIdx) ' Listeneintrag übernehmen
Text1.SelStart = SelIdx ' Markierung
Text1.SelLength = Len(Text1.Text) – SelIdx
End If
End Sub

8. Diese Routine erledigt zwar die Hauptarbeit, reicht aber nicht für alle Fälle, weil sie dum-
merweise die Taste (Rück) außer Kraft setzt. Abhilfe schafft eine Sonderbehandlung der Tas-
te im Rahmen der Behandlungsroutine für das KeyDown-Ereignis. Und wenn man schon dabei
ist, kann man auch gleich die Tasten (Oben) und (Unten) dahingehend ummünzen, dass sie
ein explizites Durchwandern der Liste vom aktuellen Wert bzw. von Anfang an ermöglichen.
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
Dim SelLen As Integer
Dim ListIdx As Integer
Select Case KeyCode
Case vbKeyBack ' Rück-Taste?
If Text1.SelStart > 0 And Text1.SelLength > 0 Then ' Markierung?
' Markierung um eine Zeichenposition verschieben
SelLen = Text1.SelLength
Text1.SelStart = Text1.SelStart – 1
Text1.SelLength = SelLen + 1

61 9
ActiveX- Steuerelemente und Benutzersteuerelemente

KeyCode = 0
End If
Case vbKeyDown, vbKeyUp ' Unten-/Oben-Taste?
' Aktuellen Wert in Liste suchen
ListIdx = SendMessage(List1.hWnd, LB_FINDSTRING, 0, _
ByVal Text1.Text)
If ListIdx > -1 Then ' Gefunden?
If KeyCode = vbKeyDown Then ' Unten-Taste?
' Ja: nächsten Eintrag nehmen
ListIdx = (ListIdx + 1) Mod List1.ListCount
ActiveX- Steuerelemente und Benutzersteuerelemente

Else
' Nein: vorigen Eintrag nehmen
ListIdx = IIf(ListIdx, ListIdx – 1, List1.ListCount – 1)
End If
Text1 = List1.List(ListIdx)
ElseIf List1.ListCount Then ' Nein: Gibt es Einträge?
Text1 = List1.List(0) ' Ja: Ersten nehmen
End If
KeyCode = 0
End Select
End Sub

9. Bleibt noch zu klären, woher die Liste ihre Einträge erhält. Das ist nicht schwer, weil man
sich dafür des LostFocus-Ereignisses bedienen kann. Um mehrfache Einträge für ein und den-
selben Wert zu vermeiden, lässt die Behandlungsroutine den aktuellen Wert des Textfelds
noch einmal via SendMessage vom Listenfeld suchen und fügt den Wert, sofern er noch nicht
existiert, zuvorderst in die Liste ein – freilich nicht, ohne gegebenenfalls den ältesten Eintrag
zuvor zu löschen, wenn MaxRemember erreicht ist.
Private Sub Text1_LostFocus()
If MaxRemember > 0 Then
' Ist Eintrag bereits in Liste?
If -1 = SendMessage(List1.hWnd, LB_FINDSTRINGEXACT, 0, _
ByVal Text1.Text) _
Then
If List1.ListCount = MaxRemember Then ' Nein: Ist Liste voll?
List1.RemoveItem (List1.ListCount – 1) ' Ja: Letzten Eintrag
End If
List1.AddItem Text1, 0 ' Neuen Eintr. einfügen
End If
End If
End Sub

10. Nun können Sie das Steuerelement testen. Schließen Sie dazu die Entwurfsansicht des Steue-
relements und öffnen Sie die Entwurfsansicht des Formulars. In der Werkzeugleiste müsste
nun ein weiteres Symbol erschienen sein, dessen QuickInfo »MemoryEdit« lautet. Ziehen Sie
eine Instanz des Steuerelements auf das Formular. Falls Sie bei der Implementation einen Feh-
ler gemacht haben, müssten Sie nun die ersten Fehlermeldungen des Compilers erhalten, da
Visual Basic das Steuerelement kompiliert, um eine Entwurfsinstanz davon zu starten. Bevor
Sie das gesamte Projekt starten – Code ist keiner erforderlich –, sollten Sie aber noch ein wei-
teres Steuerelement, am besten ein Textfeld, auf dem Formular platzieren, damit das Lost-
Focus-Ereignis überhaupt auftreten kann. »Wie Sie sehen, sehen Sie nichts.« Oder haben Sie

620
MemoryEdit – das Textfeld mit Gedächtnis

daran gedacht, die Eigenschaft MaxRemember im Eigenschaftsfenster des MemoryEdit-Steuerele-


ments auf einen Wert größer 0 zu setzen? Dass die Laufzeitinstanz des Steuerelements diesen
Wert ebenfalls zu sehen bekommt, liegt wie im Abschnitt »LongTimer – der Timer mit Aus-
dauer« (S. 599) bereits näher ausgeführt, an den Behandlungsroutinen für die Ereignisse Wri-
teProperties und ReadProperties. Spätestens jetzt sollte sich das Steuerelement nicht mehr
gegen seine Natur wehren.

Erweiterung zum vollwertigen Textfeld- Ersatz


Ein Blick auf das Eigenschaftsfenster des neuen Steuerelements verrät es bereits: Ein vollwerti-
ger Ersatz für ein Textfeld ist MemoryEdit noch nicht. Neben der explizit über Property Let/Get
publizierten Eigenschaft MaxRemember finden sich dort nur obligatorische Eigenschaften wie

ActiveX- Steuerelemente und Benutzersteuerelemente


Name, Left, Top, Width, Height usw., die dem untergelegten UserControl-Objekt entstammen.
Eine genauere Analyse dessen, was da ist, ermöglicht die visuelle Hilfestellung des Editors,
wenn Sie den Bezeichner der Steuerelementinstanz im Formularmodul tippen.

Grundausstattung des neuen Steuerelements ermitteln (Bild montiert!)

Natürlich können Sie die Bestandsaufnahme auch anhand des Objektkatalogs durchführen.
Wenn Sie den Katalog der Eigenschaften, Methoden und Ereignisse des Textfelds (vgl. Tabelle)
dagegenhalten, erhalten Sie eine Vorstellung davon, was noch zu implementieren ist.

Eigenschaften Methoden Ereignisse


Alignment, Appearance, BackColor, Drag, LinkExecute, Change, Click,
BorderStyle, CausesValidation, Container, LinkPoke, DblClick, DragDrop,
DataChanged, DataField, DataFormat, LinkRequest, DragOver, GotFocus,
DataMember, DataSource, DragIcon, LinkSend, Move, KeyDown, KeyPress,
DragMode, Enabled, Font, FontBold, OLEDrag, Refresh, KeyUp, LinkClose,
FontItalic, FontName, FontSize, SetFocus, LinkError,
FontStrikethru, FontUnderline, ForeColor, ShowWhatsThis, LinkNotify, LinkOpen,
Height, HelpContextID, HideSelection, ZOrder LostFocus, MouseDown,
hWnd, Index, Left, LinkItem, LinkMode, MouseMove, MouseUp,
LinkTimeout, LinkTopic, Locked, MaxLength, OLECompleteDrag,
MouseIcon, MousePointer, MultiLine, Name, OLEDragDrop,
OLEDragMode, OLEDropMode, Parent, OLEDragOver,
PasswordChar, RightToLeft, ScrollBars, OLEGiveFeedback,
SelLength, SelStart, SelText, TabIndex, OLESetData,
TabStop, Tag, Text, Top, ToolTipText, OLEStartDrag,
Visible, WhatsThisHelpID, Width Validate
Katalog der Eigenschaften, Methoden und Ereignisse eines Textfelds

621
ActiveX- Steuerelemente und Benutzersteuerelemente

Damit Ihnen die Tipparbeit erspart bleibt, hat Microsoft der Entwicklungsumgebung von
Visual Basic 6.0 den VB6 ActiveX-Schnittstellen-Assistenten in Form eines Add-Ins beigepackt.
Nachdem die Leistung des Assistenten beachtlich (wenn auch nicht vollkommen) ist, sollten Sie
auf seinen Einsatz keinesfalls verzichten – selbst wenn Sie auch nur drei oder vier Elemente aus
dem Katalog in die Implementation aufnehmen wollen. Im Folgenden eine Beschreibung der
Vorgehensweise.
1. Da der Assistent nicht nur einen mehrseitigen Wust an Code ausspuckt, sondern auch Ergän-
zungen am bestehenden Code vornimmt, empfiehlt es sich vor seinem Einsatz, eine Kopie des
Codes zu erstellen. Am besten, Sie benennen das Steuerelement in MemoryTextX um, speichern
das Codemodul unter einem anderen Namen (MemoryTextX.ctl) und fügen dem Projekt das
ActiveX- Steuerelemente und Benutzersteuerelemente

alte Steuerelementmodul MemoryText.ctl wieder hinzu, so dass Sie später den Quelltext bei-
der Steuerelemente im Zugriff haben.
2. Starten Sie den Assistenten, den Sie gegebenenfalls zuvor über den Add-In-Manager laden
müssen. Folgen Sie den Anweisungen in den einzelnen Dialogen des Assistenten und seien Sie
gewissenhaft, denn Nachlässigkeiten können später zu verzwickten Fehlern im Code oder zu-
mindest zu erheblichen Ausbesserungsarbeiten führen.
3. Nach Auswahl des Benutzersteuerelements müssen Sie sich dafür entscheiden, welche Ele-
mente Sie aus dem riesigen Fundus der für das Steuerelement verfügbaren Bezeichner in die
Schnittstelle aufnehmen wollen. (Vergessene Bezeichner lassen sich durch einen erneuten
Aufruf des Assistenten später jederzeit noch nachrüsten.) Wählen Sie nur die Bezeichner aus,
die in dem Elementkatalog des Textfelds (vgl. Tabelle) aufgeführt sind – nicht jedoch die Ei-
genschaften DataFormat, DataSource, DataMember, denn Datenbankverbindungen mit Acti-
veX-Steuerelementen werden mit anderen Mitteln ermöglicht. Die Bezeichner der Elemente,
die das UserControl-Objekt bereits standardmäßig beisteuert, stehen nicht zur Auswahl – so
beispielsweise Left, Top, Width, Height, aber auch ZOrder, Move, DragDrop usw. Gegebenenfalls
bieten sich noch die vom Listenfeld stammenden Bezeichner AddItem, RemoveItem List und
ListCount an, wenn die Liste öffentlich zugänglich sein soll.

Elemente für die Schnittstelle auswählen

4. Das nächste Fenster des Assistenten soll die Gestaltung benutzerdefinierter Eigenschaften er-
möglichen. Wie Sie sehen, hat der Assistent die bereits implementierte Eigenschaft MaxRemem-
ber erkannt und bietet sie an. Wechseln Sie in das nächste Fenster, es sei denn, Sie wollen
weitere Größen des Codes publizieren.

622
MemoryEdit – das Textfeld mit Gedächtnis

5. Im nun erscheinenden Dialogfeld des Assistenten legen Sie fest, welches Schnittstellenelement
an welches Objekt (und welches Element dieses Objekts) delegiert wird. Zur Auswahl stehen
die Objekte Text1, List1 und UserControl. Die Standardantwort wird hier Text1 und das vor-
geschlagene Element sein (hier könnte der Assistent einem noch ein wenig Arbeit abnehmen,
wenn er eine Standardvorgabe für das Objekt benutzen würde!), vielleicht außer Eigenschaf-
ten wie Visible oder Enabled, die besser dem UserControl-Objekt zugeordnet werden. Einzig
die vom Code selbst beigesteuerte MaxRemember-Eigenschaft benötigt keine Zuordnung – wie-
wohl der Assistent eine solche vom Prinzip her akzeptieren würde.

ActiveX- Steuerelemente und Benutzersteuerelemente


Delegation der Schnittstellenelemente

6. Das letzte Dialogfeld vor dem Epilog ermöglicht es, die Datentypen sowie Vorgabewerte
nicht zugeordneter Elemente (hier also für MaxRemember) festzulegen. Belassen Sie es bei der
Voreinstellung und klicken Sie auf FERTIG, um den Assistenten auf den Code loszulassen.
Hier das – manuell noch ein wenig nachbearbeitete – Ergebnis (zur Nachbereitung gleich noch
mehr):
'***********************************************************************
' Projekt : MemoryEdit
' Autor : 2000 Rudolf Huttary
' Benutzersteuerelementmodul: MemoryEditX
' Funktion : Wie MemoryEdit, delegiert jedoch
' Eigenschaften, Methoden und Ereignisse
'***********************************************************************

Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long
Private Const LB_FINDSTRING = &H18F
Private Const LB_FINDSTRINGEXACT = &H1A2

'Standard-Eigenschaftswerte:
Const m_def_MaxRemember = 0
'Eigenschaftsvariablen:

623
ActiveX- Steuerelemente und Benutzersteuerelemente

Dim m_MaxRemember As Integer


'Ereignisdeklarationen:
Event Change() 'MappingInfo=Text1,Text1,-1,Change
Event Click() 'MappingInfo=Text1,Text1,-1,Click
Event DblClick() 'MappingInfo=Text1,Text1,-1,DblClick
Event KeyDown(KeyCode As Integer, Shift As Integer) _
'MappingInfo=Text1,Text1,-1,KeyDown
Event KeyPress(KeyAscii As Integer) 'MappingInfo=Text1,Text1,-1,KeyPress
Event KeyUp(KeyCode As Integer, Shift As Integer) _
'MappingInfo=Text1,Text1,-1,KeyUp
ActiveX- Steuerelemente und Benutzersteuerelemente

Event MouseDown(Button As Integer, Shift As Integer, X As Single, _


Y As Single) 'MappingInfo=Text1,Text1,-1,MouseDown
Event MouseMove(Button As Integer, Shift As Integer, X As Single, _
Y As Single) 'MappingInfo=Text1,Text1,-1,MouseMove
Event MouseUp(Button As Integer, Shift As Integer, X As Single, _
Y As Single) 'MappingInfo=Text1,Text1,-1,MouseUp
Event OLECompleteDrag(Effect As Long) _
'MappingInfo=Text1,Text1,-1,OLECompleteDrag
Event OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X
As Single, Y As Single) _
'MappingInfo=Text1,Text1,-1,OLEDragDrop
Event OLEDragOver(Data As DataObject, Effect As Long, _
Button As Integer, Shift As Integer, X As Single, Y As Single, _
State As Integer) 'MappingInfo=Text1,Text1,-1,OLEDragOver
Event OLEGiveFeedback(Effect As Long, DefaultCursors As Boolean) _
'MappingInfo=Text1,Text1,-1,OLEGiveFeedback
Event OLESetData(Data As DataObject, DataFormat As Integer) _
'MappingInfo=Text1,Text1,-1,OLESetData
Event OLEStartDrag(Data As DataObject, AllowedEffects As Long) _
'MappingInfo=Text1,Text1,-1,OLEStartDrag
Event Validate(Cancel As Boolean) 'MappingInfo=Text1,Text1,-1,Validate

Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)


RaiseEvent KeyDown(KeyCode, Shift)
Dim SelLen As Integer
Dim ListIdx As Integer
Select Case KeyCode
Case vbKeyBack ' Rück-Taste?
If Text1.SelStart > 0 And Text1.SelLength > 0 Then ' Markierung?
' Markierung um eine Zeichenposition verschieben
SelLen = Text1.SelLength
Text1.SelStart = Text1.SelStart – 1
Text1.SelLength = SelLen + 1
KeyCode = 0
End If
Case vbKeyDown, vbKeyUp ' Unten-/Oben-Taste?
' Aktuellen Wert in Liste suchen
ListIdx = SendMessage(List1.hWnd, LB_FINDSTRING, -1, _
ByVal Text1.Text)
If ListIdx > -1 Then ' Gefunden?
If KeyCode = vbKeyDown Then ' Unten-Taste?

624
MemoryEdit – das Textfeld mit Gedächtnis

' Ja: nächsten Eintrag nehmen


ListIdx = (ListIdx + 1) Mod List1.ListCount
Else
' Nein: vorigen Eintrag nehmen
ListIdx = IIf(ListIdx, ListIdx – 1, List1.ListCount – 1)
End If
Text1 = List1.List(ListIdx)
ElseIf List1.ListCount Then ' Nein: Gibt es Einträge?
Text1 = List1.List(0) ' Ja: Ersten nehmen
End If

ActiveX- Steuerelemente und Benutzersteuerelemente


KeyCode = 0
End Select
End Sub

Private Sub Text1_LostFocus()


If MaxRemember > 0 Then
' Ist Eintrag bereits in Liste?
If -1 = SendMessage(List1.hWnd, LB_FINDSTRINGEXACT, 0, _
ByVal Text1.Text) _
Then
If List1.ListCount = MaxRemember Then ' Nein: Ist Liste voll?
List1.RemoveItem (List1.ListCount – 1) ' Ja: Letzten Eintrag
End If
List1.AddItem Text1, 0 ' Neuen Eintr. einfügen
End If
End If
End Sub

Private Sub UserControl_Initialize()


List1.Visible = False
Text1.Top = 0
Text1.Left = 0
End Sub

Private Sub UserControl_Resize()


Text1.Height = Height
Text1.Width = Width
Height = Text1.Height ' Textfeld erzwingt minimale Abmessungen
Width = Text1.Width
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


m_MaxRemember = PropBag.ReadProperty("MaxRemember", m_def_MaxRemember)
Text1.Alignment = PropBag.ReadProperty("Alignment", 0)
Text1.Appearance = PropBag.ReadProperty("Appearance", 1)
Text1.BackColor = PropBag.ReadProperty("BackColor", &H80000005)
Text1.BorderStyle = PropBag.ReadProperty("BorderStyle", 1)
Text1.CausesValidation = PropBag.ReadProperty("CausesValidation", _
True)
UserControl.Enabled = PropBag.ReadProperty("Enabled", True)

625
ActiveX- Steuerelemente und Benutzersteuerelemente

Set Text1.Font = PropBag.ReadProperty("Font", Ambient.Font)


Text1.FontBold = PropBag.ReadProperty("FontBold", Ambient.Font.Bold)
Text1.FontItalic = PropBag.ReadProperty("FontItalic",_
Ambient.Font.Italic)
Text1.FontName = PropBag.ReadProperty("FontName", Ambient.Font.Name)
Text1.FontSize = PropBag.ReadProperty("FontSize", Ambient.Font.Size)
Text1.FontStrikethru = PropBag.ReadProperty("FontStrikethru", _
Ambient.Font.Strikethrough)
Text1.FontUnderline = PropBag.ReadProperty("FontUnderline", _
Ambient.Font.Underline)
ActiveX- Steuerelemente und Benutzersteuerelemente

Text1.ForeColor = PropBag.ReadProperty("ForeColor", &H80000008)


Text1.LinkItem = PropBag.ReadProperty("LinkItem", "")
Text1.LinkMode = PropBag.ReadProperty("LinkMode", 0)
Text1.LinkTimeout = PropBag.ReadProperty("LinkTimeout", 50)
Text1.LinkTopic = PropBag.ReadProperty("LinkTopic", "")
Text1.Locked = PropBag.ReadProperty("Locked", False)
Text1.MaxLength = PropBag.ReadProperty("MaxLength", 0)
Set MouseIcon = PropBag.ReadProperty("MouseIcon", Nothing)
Text1.MousePointer = PropBag.ReadProperty("MousePointer", 0)
Text1.OLEDragMode = PropBag.ReadProperty("OLEDragMode", 0)
Text1.OLEDropMode = PropBag.ReadProperty("OLEDropMode", 0)
Text1.PasswordChar = PropBag.ReadProperty("PasswordChar", "")
Text1.SelLength = PropBag.ReadProperty("SelLength", 0)
Text1.SelStart = PropBag.ReadProperty("SelStart", 0)
Text1.SelText = PropBag.ReadProperty("SelText", "")
Text1.Text = PropBag.ReadProperty("Text", Ambient.DisplayName)
Text1.ToolTipText = PropBag.ReadProperty("ToolTipText", "")
Text1.WhatsThisHelpID = PropBag.ReadProperty("WhatsThisHelpID", 0)
End Sub

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


PropBag.WriteProperty "MaxRemember", m_MaxRemember, _
m_def_MaxRemember
Call PropBag.WriteProperty("Alignment", Text1.Alignment, 0)
Call PropBag.WriteProperty("Appearance", Text1.Appearance, 1)
Call PropBag.WriteProperty("BackColor", Text1.BackColor, &H80000005)
Call PropBag.WriteProperty("BorderStyle", Text1.BorderStyle, 1)
Call PropBag.WriteProperty("CausesValidation", _
Text1.CausesValidation True)
Call PropBag.WriteProperty("Enabled", UserControl.Enabled, True)
Call PropBag.WriteProperty("Font", Text1.Font, Ambient.Font)
Call PropBag.WriteProperty("FontBold", Text1.FontBold, 0)
Call PropBag.WriteProperty("FontItalic", Text1.FontItalic, 0)
Call PropBag.WriteProperty("FontName", Text1.FontName, "")
Call PropBag.WriteProperty("FontSize", Text1.FontSize, 0)
Call PropBag.WriteProperty("FontStrikethru", Text1.FontStrikethru, 0)
Call PropBag.WriteProperty("FontUnderline", Text1.FontUnderline, 0)
Call PropBag.WriteProperty("ForeColor", Text1.ForeColor, &H80000008)
Call PropBag.WriteProperty("LinkItem", Text1.LinkItem, "")
Call PropBag.WriteProperty("LinkMode", Text1.LinkMode, 0)
Call PropBag.WriteProperty("LinkTimeout", Text1.LinkTimeout, 50)

626
MemoryEdit – das Textfeld mit Gedächtnis

Call PropBag.WriteProperty("LinkTopic", Text1.LinkTopic, "")


Call PropBag.WriteProperty("Locked", Text1.Locked, False)
Call PropBag.WriteProperty("MaxLength", Text1.MaxLength, 0)
Call PropBag.WriteProperty("MouseIcon", MouseIcon, Nothing)
Call PropBag.WriteProperty("MousePointer", Text1.MousePointer, 0)
Call PropBag.WriteProperty("OLEDragMode", Text1.OLEDragMode, 0)
Call PropBag.WriteProperty("OLEDropMode", Text1.OLEDropMode, 0)
Call PropBag.WriteProperty("PasswordChar", Text1.PasswordChar, "")
Call PropBag.WriteProperty("SelLength", Text1.SelLength, 0)
Call PropBag.WriteProperty("SelStart", Text1.SelStart, 0)

ActiveX- Steuerelemente und Benutzersteuerelemente


Call PropBag.WriteProperty("SelText", Text1.SelText, "")
Call PropBag.WriteProperty("Text", Text1.Text, Ambient.DisplayName)
Call PropBag.WriteProperty("ToolTipText", Text1.ToolTipText, "")
Call PropBag.WriteProperty("WhatsThisHelpID", Text1.WhatsThisHelpID,0)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


' VERÄNDERN!
'MappingInfo=Text1,Text1,-1,Alignment
Public Property Get Alignment() As Integer
Alignment = Text1.Alignment
End Property

Public Property Let Alignment(ByVal New_Alignment As Integer)


Text1.Alignment() = New_Alignment
PropertyChanged "Alignment"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,Appearance
Public Property Get Appearance() As Integer
Appearance = Text1.Appearance
End Property

Public Property Let Appearance(ByVal New_Appearance As Integer)


Text1.Appearance() = New_Appearance
PropertyChanged "Appearance"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,BackColor
Public Property Get BackColor() As OLE_COLOR
BackColor = Text1.BackColor
End Property

Public Property Let BackColor(ByVal New_BackColor As OLE_COLOR)


Text1.BackColor() = New_BackColor
PropertyChanged "BackColor"
End Property

627
ActiveX- Steuerelemente und Benutzersteuerelemente

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,BorderStyle
Public Property Get BorderStyle() As Integer
BorderStyle = Text1.BorderStyle
End Property

Public Property Let BorderStyle(ByVal New_BorderStyle As Integer)


Text1.BorderStyle() = New_BorderStyle
ActiveX- Steuerelemente und Benutzersteuerelemente

PropertyChanged "BorderStyle"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,CausesValidation
Public Property Get CausesValidation() As Boolean
CausesValidation = Text1.CausesValidation
End Property

Public Property Let CausesValidation(ByVal New_CausesValidation _


As Boolean)
Text1.CausesValidation() = New_CausesValidation
PropertyChanged "CausesValidation"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=UserControl,UserControl,-1,Enabled
Public Property Get Enabled() As Boolean
Enabled = UserControl.Enabled
End Property

Public Property Let Enabled(ByVal New_Enabled As Boolean)


UserControl.Enabled() = New_Enabled
PropertyChanged "Enabled"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,Font
Public Property Get Font() As Font
Set Font = Text1.Font
End Property

Public Property Set Font(ByVal New_Font As Font)


Set Text1.Font = New_Font
PropertyChanged "Font"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER

628
MemoryEdit – das Textfeld mit Gedächtnis

'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,FontBold
Public Property Get FontBold() As Boolean
FontBold = Text1.FontBold
End Property

Public Property Let FontBold(ByVal New_FontBold As Boolean)


Text1.FontBold() = New_FontBold
PropertyChanged "FontBold"
End Property

ActiveX- Steuerelemente und Benutzersteuerelemente


'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER
'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,FontItalic
Public Property Get FontItalic() As Boolean
FontItalic = Text1.FontItalic
End Property

Public Property Let FontItalic(ByVal New_FontItalic As Boolean)


Text1.FontItalic() = New_FontItalic
PropertyChanged "FontItalic"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,FontName
Public Property Get FontName() As String
FontName = Text1.FontName
End Property

Public Property Let FontName(ByVal New_FontName As String)


Text1.FontName() = New_FontName
PropertyChanged "FontName"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,FontSize
Public Property Get FontSize() As Single
FontSize = Text1.FontSize
End Property

Public Property Let FontSize(ByVal New_FontSize As Single)


Text1.FontSize() = New_FontSize
PropertyChanged "FontSize"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,FontStrikethru
Public Property Get FontStrikethru() As Boolean

629
ActiveX- Steuerelemente und Benutzersteuerelemente

FontStrikethru = Text1.FontStrikethru
End Property

Public Property Let FontStrikethru(ByVal New_FontStrikethru As Boolean)


Text1.FontStrikethru() = New_FontStrikethru
PropertyChanged "FontStrikethru"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
ActiveX- Steuerelemente und Benutzersteuerelemente

'MappingInfo=Text1,Text1,-1,FontUnderline
Public Property Get FontUnderline() As Boolean
FontUnderline = Text1.FontUnderline
End Property

Public Property Let FontUnderline(ByVal New_FontUnderline As Boolean)


Text1.FontUnderline() = New_FontUnderline
PropertyChanged "FontUnderline"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,ForeColor
Public Property Get ForeColor() As OLE_COLOR
ForeColor = Text1.ForeColor
End Property

Public Property Let ForeColor(ByVal New_ForeColor As OLE_COLOR)


Text1.ForeColor() = New_ForeColor
PropertyChanged "ForeColor"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,HideSelection
Public Property Get HideSelection() As Boolean
HideSelection = Text1.HideSelection
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkItem
Public Property Get LinkItem() As String
LinkItem = Text1.LinkItem
End Property

Public Property Let LinkItem(ByVal New_LinkItem As String)


Text1.LinkItem() = New_LinkItem
PropertyChanged "LinkItem"
End Property

63 0
MemoryEdit – das Textfeld mit Gedächtnis

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkMode
Public Property Get LinkMode() As Integer
LinkMode = Text1.LinkMode
End Property

Public Property Let LinkMode(ByVal New_LinkMode As Integer)


Text1.LinkMode() = New_LinkMode
PropertyChanged "LinkMode"

ActiveX- Steuerelemente und Benutzersteuerelemente


End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkExecute
Public Sub LinkExecute(ByVal Command As String)
Text1.LinkExecute Command
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkPoke
Public Sub LinkPoke()
Text1.LinkPoke
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkRequest
Public Sub LinkRequest()
Text1.LinkRequest
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkSend
Public Sub LinkSend()
Text1.LinkSend
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkTimeout
Public Property Get LinkTimeout() As Integer
LinkTimeout = Text1.LinkTimeout
End Property

Public Property Let LinkTimeout(ByVal New_LinkTimeout As Integer)


Text1.LinkTimeout() = New_LinkTimeout
PropertyChanged "LinkTimeout"
End Property

63 1
ActiveX- Steuerelemente und Benutzersteuerelemente

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,LinkTopic
Public Property Get LinkTopic() As String
LinkTopic = Text1.LinkTopic
End Property

Public Property Let LinkTopic(ByVal New_LinkTopic As String)


Text1.LinkTopic() = New_LinkTopic
PropertyChanged "LinkTopic"
ActiveX- Steuerelemente und Benutzersteuerelemente

End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,Locked
Public Property Get Locked() As Boolean
Locked = Text1.Locked
End Property

Public Property Let Locked(ByVal New_Locked As Boolean)


Text1.Locked() = New_Locked
PropertyChanged "Locked"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,MaxLength
Public Property Get MaxLength() As Long
MaxLength = Text1.MaxLength
End Property

Public Property Let MaxLength(ByVal New_MaxLength As Long)


Text1.MaxLength() = New_MaxLength
PropertyChanged "MaxLength"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,MouseIcon
Public Property Get MouseIcon() As Picture
Set MouseIcon = Text1.MouseIcon
End Property

Public Property Set MouseIcon(ByVal New_MouseIcon As Picture)


Set Text1.MouseIcon = New_MouseIcon
PropertyChanged "MouseIcon"
End Property

Private Sub Text1_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)

63 2
MemoryEdit – das Textfeld mit Gedächtnis

RaiseEvent MouseMove(Button, Shift, X, Y)


End Sub

Private Sub Text1_MouseUp(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
RaiseEvent MouseUp(Button, Shift, X, Y)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!

ActiveX- Steuerelemente und Benutzersteuerelemente


'MappingInfo=Text1,Text1,-1,MousePointer
Public Property Get MousePointer() As Integer
MousePointer = Text1.MousePointer
End Property

Public Property Let MousePointer(ByVal New_MousePointer As Integer)


Text1.MousePointer() = New_MousePointer
PropertyChanged "MousePointer"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,MultiLine
Public Property Get MultiLine() As Boolean
MultiLine = Text1.MultiLine
End Property

Private Sub Text1_OLECompleteDrag(Effect As Long)


RaiseEvent OLECompleteDrag(Effect)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,OLEDrag
Public Sub OLEDrag()
Text1.OLEDrag
End Sub

Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, _


Button As Integer, Shift As Integer, X As Single, Y As Single)
RaiseEvent OLEDragDrop(Data, Effect, Button, Shift, X, Y)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,OLEDragMode
Public Property Get OLEDragMode() As Integer
OLEDragMode = Text1.OLEDragMode
End Property

633
ActiveX- Steuerelemente und Benutzersteuerelemente

Public Property Let OLEDragMode(ByVal New_OLEDragMode As Integer)


Text1.OLEDragMode() = New_OLEDragMode
PropertyChanged "OLEDragMode"
End Property

Private Sub Text1_OLEDragOver(Data As DataObject, Effect As Long, Button As Integer, Shift


As Integer, X As Single, Y As Single, _
State As Integer)
RaiseEvent OLEDragOver(Data, Effect, Button, Shift, X, Y, State)
End Sub
ActiveX- Steuerelemente und Benutzersteuerelemente

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,OLEDropMode
Public Property Get OLEDropMode() As Integer
OLEDropMode = Text1.OLEDropMode
End Property

Public Property Let OLEDropMode(ByVal New_OLEDropMode As Integer)


Text1.OLEDropMode() = New_OLEDropMode
PropertyChanged "OLEDropMode"
End Property

Private Sub Text1_OLEGiveFeedback(Effect As Long, _


DefaultCursors As Boolean)
RaiseEvent OLEGiveFeedback(Effect, DefaultCursors)
End Sub

Private Sub Text1_OLESetData(Data As DataObject, DataFormat As Integer)


RaiseEvent OLESetData(Data, DataFormat)
End Sub

Private Sub Text1_OLEStartDrag(Data As DataObject, _


AllowedEffects As Long)
RaiseEvent OLEStartDrag(Data, AllowedEffects)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,PasswordChar
Public Property Get PasswordChar() As String
PasswordChar = Text1.PasswordChar
End Property

Public Property Let PasswordChar(ByVal New_PasswordChar As String)


Text1.PasswordChar() = New_PasswordChar
PropertyChanged "PasswordChar"
End Property

63 4
MemoryEdit – das Textfeld mit Gedächtnis

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,ScrollBars
Public Property Get ScrollBars() As Integer
ScrollBars = Text1.ScrollBars
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,SelLength

ActiveX- Steuerelemente und Benutzersteuerelemente


Public Property Get SelLength() As Long
SelLength = Text1.SelLength
End Property

Public Property Let SelLength(ByVal New_SelLength As Long)


Text1.SelLength() = New_SelLength
PropertyChanged "SelLength"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,SelStart
Public Property Get SelStart() As Long
SelStart = Text1.SelStart
End Property

Public Property Let SelStart(ByVal New_SelStart As Long)


Text1.SelStart() = New_SelStart
PropertyChanged "SelStart"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,SelText
Public Property Get SelText() As String
SelText = Text1.SelText
End Property

Public Property Let SelText(ByVal New_SelText As String)


Text1.SelText() = New_SelText
PropertyChanged "SelText"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,Text
Public Property Get Text() As String
Text = Text1.Text
End Property

635
ActiveX- Steuerelemente und Benutzersteuerelemente

Public Property Let Text(ByVal New_Text As String)


Text1.Text() = New_Text
PropertyChanged "Text"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,ToolTipText
Public Property Get ToolTipText() As String
ToolTipText = Text1.ToolTipText
ActiveX- Steuerelemente und Benutzersteuerelemente

End Property

Public Property Let ToolTipText(ByVal New_ToolTipText As String)


Text1.ToolTipText() = New_ToolTipText
PropertyChanged "ToolTipText"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,WhatsThisHelpID
Public Property Get WhatsThisHelpID() As Long
WhatsThisHelpID = Text1.WhatsThisHelpID
End Property

Public Property Let WhatsThisHelpID(ByVal New_WhatsThisHelpID As Long)


Text1.WhatsThisHelpID() = New_WhatsThisHelpID
PropertyChanged "WhatsThisHelpID"
End Property

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MappingInfo=Text1,Text1,-1,hWnd
Public Property Get hWnd() As Long
hWnd = Text1.hWnd
End Property

Private Sub Text1_Change()


RaiseEvent Change
Dim SelIdx As Integer
Dim ListIdx As Integer
' Bisherige Eingabe in Liste suchen..
ListIdx = SendMessage(List1.hWnd, LB_FINDSTRING, 0, _
ByVal Text1.Text)
If ListIdx > -1 Then ' Gefunden?
SelIdx = Text1.SelStart ' Cursorpositon merken
Text1 = List1.List(ListIdx) ' Listeneintrag übernehmen
Text1.SelStart = SelIdx ' Markierung
Text1.SelLength = Len(Text1.Text) – SelIdx
End If
End Sub

63 6
MemoryEdit – das Textfeld mit Gedächtnis

Private Sub Text1_Click()


RaiseEvent Click
End Sub

Private Sub Text1_DblClick()


RaiseEvent DblClick
End Sub

Private Sub Text1_KeyUp(KeyCode As Integer, Shift As Integer)


RaiseEvent KeyUp(KeyCode, Shift)

ActiveX- Steuerelemente und Benutzersteuerelemente


End Sub

Private Sub Text1_KeyPress(KeyAscii As Integer)


RaiseEvent KeyPress(KeyAscii)
End Sub

Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, _


X As Single, Y As Single)
RaiseEvent MouseDown(Button, Shift, X, Y)
End Sub

Private Sub Text1_Validate(Cancel As Boolean)


RaiseEvent Validate(Cancel)
End Sub

'ACHTUNG! DIE FOLGENDEN KOMMENTIERTEN ZEILEN NICHT ENTFERNEN ODER


'VERÄNDERN!
'MemberInfo=7,0,0,0
Public Property Get MaxRemember() As Integer
MaxRemember = m_MaxRemember
End Property

Public Property Let MaxRemember(ByVal New_MaxRemember As Integer)


m_MaxRemember = IIf(New_MaxRemember >= 0, New_MaxRemember, 0)
While m_MaxRemember < List1.ListCount ' ggf. Einträge löschen
List1.RemoveItem (List1.ListCount – 1)
Wend
PropertyChanged "MaxRemember"
End Property

'Eigenschaften für Benutzersteuerelement initialisieren


Private Sub UserControl_InitProperties()
m_MaxRemember = m_def_MaxRemember
If Not Ambient.UserMode Then
Set Text1.Font = Ambient.Font
End If
Text1 = Ambient.DisplayName
End Sub

Abgesehen von einigen »Flüchtigkeitsfehlern« ist das Ergebnis des Assistenten ganz brauchbar.
Der Compiler weist Sie der Reihe nach auf die Fehler hin, wenn Sie versuchen, eine Instanz des

637
ActiveX- Steuerelemente und Benutzersteuerelemente

MemoryEditX-Steuerelements in das Formular zu platzieren. Als Erstes fällt auf, dass jemand Flei-
ßiges bei der Lokalisierung der Datenbasis des Assistenten ins Deutsche die Konstanten True
und False scheinbar »mitlokalisiert« hat. Dem lässt sich entweder durch Nachholen der Defini-
tionen oder durch schlichtes Rückübersetzen entgegenwirken. Als weitere Nachlässigkeit
bemängelt der Compiler ungültige Vorgabewerte für die Eigenschaften FontName und FontSize
in der Routine UserControl_ReadProperties – während die Eigenschaft Font dagegen korrekt
mit Ambient.Font versorgt wurde. Tragen Sie die entsprechenden Eigenschaften des Ambient-
Objekts als Vorgabe ein:
Text1.FontBold = PropBag.ReadProperty("FontBold", Ambient.Font.Bold)
Text1.FontItalic = PropBag.ReadProperty("FontItalic",_
ActiveX- Steuerelemente und Benutzersteuerelemente

Ambient.Font.Italic)
Text1.FontName = PropBag.ReadProperty("FontName", Ambient.Font.Name)
Text1.FontSize = PropBag.ReadProperty("FontSize", Ambient.Font.Size)
Text1.FontStrikethru = PropBag.ReadProperty("FontStrikethru", _
Ambient.Font.Strikethrough)
Text1.FontUnderline = PropBag.ReadProperty("FontUnderline", _
Ambient.Font.Underline)

Falls Sie das Programm dafür beendet haben, entfernen Sie das Steuerelement noch einmal vom
Formular und fügen es wieder neu ein – ansonsten starten Sie den vom Debugger unterbroche-
nen Code einfach wieder. Nun müsste sowohl die Entwurfsinstanz als auch die Laufzeitinstanz
des Steuerelements problemfrei starten, und wenn Sie einen Blick auf das Eigenschaftsfenster
werfen, werden Sie feststellen, dass dieses nun gut gefüllt ist. Gleiches gilt für das Methoden-
und Ereignisangebot.
Zwei Nachbesserungen gibt es jedoch noch: Erstens zeigt das Textfeld nach dem Einfügen nicht
in der gewohnten Weise den Namen des Steuerelements plus Instanzzählung an, sondern eben
stur »Text1« (das ist kein Wunder, denn das ist der vom Assistenten vergebene Vorgabewert),
und zweitens übernimmt das Steuerelement die Vorgaben für die Schrifteinstellungen des aktu-
ellen Containers nicht. Ersteres liegt daran, dass das Textfeld eben seit dem Entwurf »Text1«
heißt, was auch dem PropertyBag-Objekt als Standardwert kundgetan wird. Den richtigen
Namen der Entwurfsinstanz liefert das Ambient-Objekt über seine Eigenschaft DisplayName und
die Schrifteinstellungen über seine Font-Eigenschaft. Der richtige Ort für Initialisierungen dieser
Art ist die Behandlungsroutine UserControl_InitProperties. Nehmen Sie die Änderung auch in
den Routinen UserControl_ReadProperties und UserControl_WriteProperties vor.
...
Text1.Text = PropBag.ReadProperty("Text", Ambient.DisplayName)
...
Call PropBag.WriteProperty("Text", Text1.Text, Ambient.DisplayName)
...

Private Sub UserControl_InitProperties()


m_MaxRemember = m_def_MaxRemember
If Not Ambient.UserMode Then
Set Text1.Font = Ambient.Font
End If
Text1 = Name
Text1 = Ambient.DisplayName
End Sub

Wenn Sie das Steuerelement nun auf einem Formular mit veränderten Schrifteinstellungen plat-
zieren, erhält das Textfeld als Vorgabewert den vom Entwurfseditor für das Steuerelement

63 8
MemoryEdit – das Textfeld mit Gedächtnis

automatisch generierten Namen in der Schrift des Formulars. Natürlich darf dies nur zur Ent-
wurfszeit geschehen, Laufzeitinstanzen erhalten ihre Schrifteinstellungen aus dem PropertyBag-
Objekt, dafür sorgt nicht zuletzt der Zustand der Eigenschaft Ambient.UserMode.

ActiveX- Steuerelemente und Benutzersteuerelemente


Ausgabe des Testcodes für das Emulationsmodul

Einige letzte Schönheitsoperationen noch. Das Steuerelement hat noch keine Standardeigenschaft,
und falls Sie die Eigenschaft Text im Eigenschaftsfenster mit einem neuen Wert versorgen, werden
Sie bemerken, dass der Wert erst dann in das Steuerelement MemoryEditX übernommen wird,
wenn das Eingabefeld den Fokus abgibt, nicht bereits während des Tippens, wie Sie es vom Text-
feld her gewohnt sind. Auch fehlen MemoryEditX die Eigenschaften für die Datenanbindung und
last but not least erscheinen im Eigenschaftsfenster überflüssigerweise die Eigenschaften FontName,
FontSize, FontBold, FontItalic, FontStrikethru, FontUnderline, was beim Textfeld nicht der Fall
ist. Alle diese Schönheitsfehler lassen sich gewissermaßen in einem Streich – im wahrsten Sinne
des Wortes – abhaken, indem Sie die folgenden Schritte nachvollziehen:
1. Schalten Sie in die Entwurfsansicht des MemoryEditX-Steuerelements und öffnen Sie über das
Menü EXTRAS das Dialogfeld PROZEDURATTRIBUTE.
2. Stellen Sie im Listenfeld NAME die Eigenschaft Text ein und suchen Sie dafür im Kombina-
tionsfeld PROZEDUR-ID den gleichlautenden Eintrag »Text«. Das sichert die Synchronisation
zwischen dem Eigenschaftsfenster und der Entwurfsansicht, hat aber den Nachteil, dass Sie
die Eigenschaft nicht mehr als Standardeigenschaft definieren können, denn dafür müssen Sie
den Wert »(Voreinstellung)« im Kombinationsfeld PROZEDUR-ID auswählen – Letzteres
dürfte wahrscheinlich der »höhere Zweck« sein. Wenn Sie zudem die Kontrollkästchen DA-
TENGEBUNDENE EIGENSCHAFT und AN DATENFELD GEBUNDEN mit einem Häkchen verse-
hen, eröffnen Sie dem Steuerelement die Möglichkeit einer Bindung an eine Datenquelle und
zwar wie Sie es vom Textfeld her gewohnt sind: über die Eigenschaften DataField, DataSour-
ce, DataMember und DataFormat. Das Kontrollkästchen ZUR ENTWURFSZEIT IN DATABIN-
DINGS-AUFLISTUNG ANZEIGEN beschert dem Steuerelement dagegen eine DataBindings-
Eigenschaft, die ähnlich wie das Font-Objekt ein Sammelobjekt für die genannten DataXXX-
Eigenschaften darstellt und die Gestaltung der Anbindung im Rahmen eines Eigenschafts-
fensters ermöglicht. Es macht wenig Sinn, beide Kontrollkästchen abzuhaken, da die Eigen-
schaften redundant sind. Über die restlichen beiden Kontrollkästchen regeln Sie das »Wie«
der Bindung.
3. Stellen Sie im Listenfeld NAME der Reihe nach die Eigenschaften FontName, FontSize, Font-
Bold, FontItalic, Fontstrikthru, FontUnderline ein und spendieren Sie ihnen je ein Häkchen
im Kontrollkästchen IM EIGENSCHAFTENKATALOG NICHT ANZEIGEN. Das hat den Effekt,
dass diese Eigenschaften aus dem Eigenschaftsfenster verschwinden, in der vom Code-Editor
eingeblendeten Hilfeliste mit den Eigenschaften und Methoden für das Steuerelementobjekt
aber noch geführt werden – wie beim Textfeld eben. Falls Sie wollen, dass ein Element weder
im Eigenschaftsfenster noch in der Liste erscheint, können Sie es über das Kontrollkästchen
DIESES MITGLIED AUSBLENDEN verschwinden lassen. Als geheimgehaltenes Public-Element
ist es dann zwar noch ansprechbar, aber eben nicht mehr für jedermann sichtbar (seit Visual
Basic 6.0 arbeitet man besser mit Friend-Deklarationen).

639
ActiveX- Steuerelemente und Benutzersteuerelemente
ActiveX- Steuerelemente und Benutzersteuerelemente

Die Qual der Wahl: s ofortige Anzeige im Entwurfsmodus oder Standardeigensc haft?

Das wäre es gewesen. MemoryEditX lässt sich von nun an nach Belieben anstelle eines Textfelds
verwenden und verhält sich auch so, abgesehen von dem zusätzlichen Komfort. Um das Steuer-
element zu veröffentlichen, folgen Sie der Anleitung im Abschnitt »Das Steuerelement veröf-
fentlichen« (S. 603).

640
MemoryEdit – das Textfeld mit Gedächtnis

ActiveX- Steuerelemente und Benutzersteuerelemente

Die Eigenschaftsfenster des Textfelds und des MemoryEditX-Textfelds im Vergleich

641
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


Eine Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic kann eine große Hilfe für den
schnellen Umstieg in die Programmierung mit Visual Basic sein. Wer vergessenes Wissen schnell
auffrischen will oder Basic noch von früher her kennt, dem gibt die Tabelle nicht nur einen
schnellen Überblick über den sprachspezifischen Befehlsvorrat, sondern auch wichtige Hinweise
über einen gegebenenfalls erfolgten Bedeutungswandel.

Befehl QBasic Visual Basic


$DYNAMIC Metabefehl, der festlegt, wie Verschwunden (ersatzlos)
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Arrays standardmäßig gespei-


chert werden
$STATIC Metabefehl für statische Erzeu- Verschwunden
gung von statischen Arrays und
Zeichenfolgen
Abs Liefert den Absolutwert eines Unverändert
Zahlenwerts.
ABSOLUTE Ruft maschinensprachliche Rou- Verschwunden (Anbindung an
tine auf DLL-Routinen jetzt mittels
Declare)
Access Gibt die Art der Zugriffsberechti- Unverändert
gung beim Öffnen einer Datei an.
Zur Auswahl stehen die Zusätze
Read, Write oder Read Write
Any Steht bei der expliziten Deklara- Unverändert, allerdings hat sich
tion einer Funktion/Prozedur im die Bedeutung von Declare
Rahmen Declare für jeden belie- gewandelt
bigen Datentyp
Append Zusatz bei der Open-Anweisung, Unverändert
der spezifiziert, dass die Datei im
Textmodus mit Dateizeiger am
Ende geöffnet wird
Array Fehlt Liefert Aufrufparameter als Array
As Deklariert einen Datentyp für Unverändert
einen Bezeichner
Asc Liefert den ANSI-Code des ersten Unverändert
Zeichens einer Zeichenfolge (auf
DBCS-Systemen, DBCS-Code)
AscB Fehlt (jedoch wie ASC) Liefert ANSI-Code des ersten
Bytes einer Zeichenfolge
AscW Fehlt Liefert Unicode des ersten Dop-
pel-Bytes einer Zeichenfolge
Atn Liefert den Arcustangens einer Unverändert
Zahl als Winkel im Bogenmaß

642
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Beep Gibt einen Piepser über den Sys- Gibt den Klang »Standardsignal«
temlautsprecher aus über den Systemlautsprecher aus
Binary Zusatz bei der Open-Anweisung, Unverändert
der spezifiziert, dass die Datei im
binären Modus geöffnet wird
BLOAD Lädt eine Binärdatei in einen Verschwunden (für Bilddateien ist
Speicherbereich jetzt LoadPicture zuständig)

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


BSAVE Speichert den Inhalt eines Verschwunden (für Bilddateien ist
Speicherbereichs in eine Datei jetzt SavePicture zuständig)
Byte Fehlt Datentyp für und Ganzzahlen
zwischen 0 und 255
Call Aufruf einer Prozedur nach der Unverändert
Syntax von Funktionen
CALL ABSOLUTE Übergabe der Kontrolle an eine Verschwunden (Anbindung an
maschinensprachliche Routine DLL-Routinen jetzt mittels
Declare)
Case Fallunterscheidung in Select- Unverändert
Konstrukten
CDate Fehlt, da Datentyp Date fehlt Interpretiert Zeichenfolge oder
Zahlenwert als Datums-/Zeitwert
CDbl Wandelt numerischen Ausdruck Unverändert
in Double um
CHAIN Übergibt die Kontrolle an ein Verschwunden (Aufruf anderer
anderes Basic-Programm Visual-Basic-Programme jetzt mit-
tels Shell als eigenständige
Instanz möglich)
CHAIN Lädt anderes Programm und Verschwunden, lässt sich durch
übergibt Kontrolle modulare Programmierung erset-
zen
ChDir Ändert aktuelles Arbeitsverzeich- Unverändert
nis
ChDrive Fehlt (nur über SHELL) Setzt aktuelles logisches Laufwerk
Chr Liefert ANSI-Zeichen zu ANSI- Liefert Unicode-Zeichen zu ANSI-
Code Code
ChrB Fehlt (jedoch wie Chr) Liefert ANSI-Zeichen zu ANSI-
Code
ChrW Fehlt Liefert Unicode-Zeichen zu Uni-
code
CInt Wandelt numerischen Ausdruck Unverändert
in Intger um
Circle Zeichnet Kreis, Ellipse oder Aus- Unverändert
schnitt davon

643
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


CLEAR Schließt alle Dateien, gibt alle Verschwunden (nur noch als
Puffer und initialisiert alle globa- Methode verschiedener Objekte
len Variablen erneut mit dem zu finden; löscht dann Elemente
Standardwert des Objekts)
CLng Wandelt numerischen Ausdruck Unverändert
in Long um
Close Unverändert Schließt eine oder mehrere zuvor
geöffnete Dateien
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Cls Löscht den Bildschirm Löscht den Client-Bereich des


jeweiligen Objekts
Color Setzt Vordergrund und Hinter- Verschwunden (Farbraum wurde
grundfarbe für die Text- und Gra- verändert, vgl. die Eigenschaften
fikausgabe Backcolor, ForeColor und FillCo-
lor)
COM Steuert Ereignisverfolgung der Verschwunden (Zugriff und Steu-
seriellen Schnittstelle erung der seriellen Schnittstellen
über MS Comm Control 6.0 mög-
lich)
COMMON Deklaration globaler Variablen, Verschwunden; bedingt vergleich-
die von mehreren Modulen glei- bar mit Public
chermaßen genutzt werden kön-
nen; erweitert Geltungsbereich
von Variablen auf mehrere Pro-
gramm-Module
Const Vereinbarung einer Konstanten Unverändert
Cos Liefert den Cosinus zu einem Unverändert
Winkel im Bogenmaß
CSng Wandelt numerischen Ausdruck Unverändert
in Single um
CSRLIN Liefert die Zeile, in der sich der Verschwunden (bedingt vergleich-
Cursor für die Ein-/Ausgabe bar: CurrentY)
befindet
CurDir Fehlt (nur über SHELL) Liefert das aktuelle Arbeitsver-
zeichnis auf dem angegebenen
logischen Laufwerk
Currency Fehlt Datentyp für Ganzzahl mit Skalie-
rung in 10.000stel
CV... Typumwandlungen für datensatz- Bedingt vergleichbar mit implizi-
orientierte Dateioperationen ter Funktionalität von LSet
CVD, CVDMBF, CVI, CVL, Konvertierungsfunktionen für die Verschwunden (Datensatzoperati-
CVS, CVSMBF Entnahme von Daten im Zusam- onen sind jetzt direkt mit Type-
menhang mit der Field-Anwei- Datentypen möglich)
sung

644
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


DATA Definiert Daten für das Einlesen Verschwunden (ersatzlos)
mit READ
Date (Datentyp) Fehlt Datentyp für Datums- und Zeit-
angaben
Date (Funktion) Fehlt, da Datentyp Date fehlt. Via Liefert das aktuelle Systemdatum
Zeichenfolge, siehe DATE$ als Datums-/Zeitwert
Date (Anweisung) Fehlt, da Datentyp Date fehlt. Via Setzt Datumsanteil von Datums-/

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


Zeichenfolge, siehe DATE$ Zeitwert als aktuelles Systemda-
tum
DATE$ Liefert oder setzt das aktuelle Sys- Verschwunden
temdatum via Zeichenfolge
DateSerial Fehlt Setzt Datums-/Zeitwert aus Ganz-
zahlwerten (Tag, Monat und Jahr)
zusammen
DateValue Fehlt Interpretiert Zeichenfolge oder
Zahlenwert als Datumsanteil von
Datums-/Zeitwert
Day Fehlt Liefert Tag in einem Datums-/
Zeitwert als Zahlenwert (1 – 31).
DDB Fehlt Liefert den Abschreibungswert
eines Vermögenswerts über einen
bestimmten Zeitraum bei geomet-
risch degressiver Abschreibung
Decimal Fehlt Datentyp für 29-stellige Dezimal-
zahl ohne Exponent, aber mit
Komma
Declare Deklariert BASIC-Funktionen Verändert – deklariert Funktionen
und Prozeduren in einem Modul und Prozeduren für den Import
aus einer DLL
DEF FN Definiert Funktion, deren Verschwunden, bedingt vergleich-
Bezeichner einen FN-Präfix trägt bar mit Function
DEF SEG Definiert aktuelle Segmentadresse Verschwunden (ersatzlos)
DefType Einem Bezeichnerbereich den Unverändert
Datentyp Type für implizite
Deklaration zuordnen.
Dim Explizite Deklaration von Arrays Variablendeklaration auf Modul-
mit mehr als zehn Elementen und und Prozedurebene. Auf Module-
explizite Typdeklaration für Vari- bene durch Public zu ersetzen
ablen auf Hauptmodul- und Pro-
zedurebene
Dir Fehlt (nur über SHELL) Liefert den nächsten Dateinamen,
der auf Suchmuster passt
Do...Loop Allgemeine Schleife Unverändert

645
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Double Unverändert Datentyp für Fließkommazahlen
doppelter Genauigkeit
DRAW Interpretiert Zeichenfolge Anwei- Verschwunden (ersatzlos)
sungsfolge für Zeichenbefehle
End Beendet Programm ordentlich Beendet Programm unordentlich
unter Ausführung von Clear (lässt beispielsweise Formulare
stehen)
ENVIRON$ liefert eine oder alle Unverändert
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Environ, Environ$
Umgebungsvariablen, ENVIRON
setzt Umgebungsvariable
EOF Testet, ob Dateiende erreicht ist Unverändert
Eqv Äquivalenz-Operator Unverändert
Erase Reinitialisiert statisches Array Unverändert
oder gibt Speicher für dynami-
sches Array frei
ERDEV, ERDEF$ Liefert letzten Fehlercode, den ein Verschwunden (bedingt mit Err-
Gerät ERDEF$ produziert hat Objekt vergleichbar)
ERL Liefert Zeile des letzten Laufzeit- Verschwunden (ersatzlos)
fehlers, wenn Zeilennummern
vorhanden
ERR Liefert Fehlercode des letzten Verschwunden (bedingt mit Err-
Laufzeitfehlers Objekt vergleichbar)
Error Löst Laufzeitfehler aus Unverändert
Exit Beendet DEF-, Do-, For-, Function- Beendet Do-, For-, For Each-
und Sub-Konstrukte Function-, Property- und Sub-Kon-
strukte
Exp Liefert den Wert der Exponential- Unverändert
funktion (mit Basis e) zu einer
Zahl.
FIELD Reserviert Speicher für Datensatz Verschwunden, jede String-Vari-
in indexsequenzielle Datei able kann Puffer sein; Datensatz-
operationen sind auch direkt mit
Type-Datentypen möglich
FileAttr Ermittelt den Öffnungsmodus Unverändert
einer Datei
FileCopy Fehlt (nur via SHELL) Kopiert eine Datei
FileDateTime Fehlt (nur via SHELL) Liefert den Zeitpunkt der Erstel-
lung bzw. letzten Änderung einer
Datei als Datums-/Zeitwert
FileLen Fehlt (nur via SHELL) Liefert die Länge einer Datei in
Bytes

646
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


FILES Listet Inhalt von Verzeichnis Verschwunden (bedingt vergleich-
CHDIR$ auf bar mit FileListBox-Steuerele-
ment)
Filter Fehlt Durchsucht String-Array nach
Zeichenfolge und liefert die
Array-Elemente, in denen die Zei-
chenfolge enthalten ist.
Fix Liefert den Vorkommaanteil einer Unverändert

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


Dezimalzahl als Ganzzahl.
For...Next Zählschleife Unverändert
Format Fehlt, bedingt vergleichbar mit Liefert Zeichenfolgendarstellung
USING eines Werts im spezifizierten For-
mat
FormatCurreny Fehlt Liefert Darstellung eines Wäh-
rungswerts im spezifizierten For-
mat
FormatDateTime Fehlt Liefert Darstellung eines Datums-/
Zeitwerts als Zeichenfolge im spe-
zifizierten Format
FormatDateTime Fehlt Liefert Darstellung eines Datums-
werts im spezifizierten Format
FormatNumber Fehlt Liefert Darstellung eines Zahlen-
werts im spezifizierten Format
FormatPercent Fehlt Liefert Darstellung eines Prozent-
werts im spezifizierten Format
FRE Liefert Größe des verfügbaren Verschwunden (ersatzlos)
Freispeichers
FreeFile Liefert die nächste freie Datei- Liefert die nächste freie Datei-
nummer nummer
Function Definiert Funktion Unverändert (Geltungsbereichs-
vereinbarungen für Variablen ver-
ändert)
Function...End Definiert Funktion Wie gehabt, jedoch mit zusätzli-
Function chen Möglichkeiten bei der Para-
metervereinbarung und anderen
Geltungsbereichen
FV Fehlt Liefert den künftigen Wert einer
Annuität (Ansparung oder Kredit)
bei konstanter Zahlung, konstan-
tem Zins und fester Laufzeit
Get Liest Daten aus einer indexse- Unverändert
quenziellen Datei oder Binärdatei

647
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


GET Schnelles Kopieren von Grafik- Verschwunden (bedingt vergleich-
ausschnitten bar mit PaintPicture)
GetAttr Fehlt (nur via SHELL) Liefert die Attribute einer Datei
oder eines Ordners bzw. Verzeich-
nisses
GoSub Verzweigt in Subroutine, Rück- Unverändert
sprung mit Return
Unterprogrammaufruf Unverändert
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

GoSub...Return
GoTo Setzt Programmausführung an Unverändert
der über Zeilennummer oder
Sprungmarke definierten Anwei-
sung fort
GoTo Unbedingter Sprung Unverändert
Hex, Hex$ Liefert die hexadezimale Nota- Unverändert
tion eines Werts
Hour Fehlt Liefert Stunde in einem Datums-/
Zeitwert als Zahlenwert (0 bis 23)
If...Then...Else Konstrukt für die bedingte Aus- Unverändert
führung von Programmcode
Imp Implikationsoperator Unverändert
INKEY$ Liefert nächstes Zeichen aus dem Verschwunden (KeyXXX-Ereignisse
Tastaturpuffer bedingt vergleichbar)
INP Liest Port aus Verschwunden
INPUT Liest den Wert einer oder mehre- Verschwunden (Tastatureingabe
rer Variablen aus einer Textdatei jetzt via Steuerelemente und Ereig-
nisroutinen)
Input # Liest den Wert einer oder mehre- Unverändert
rer Variablen aus einer Textdatei
Input, Input$ Liest die angegebene Anzahl an Liest die angegebene Anzahl an
Zeichen aus einer Datei und lie- Zeichen aus einer Datei und liefert
fert diese als ANSI-Zeichenfolge diese als Unicode-Zeichenfolge
InputB Fehlt (jedoch wie INPUT$) Liest die angegebene Anzahl an
Bytes aus einer Datei und liefert
diese als Byte-Array (ANSI-Zei-
chenfolge).
InStr, InStr$ Liefert Startposition einer Zei- Unverändert
chenfolge in einer anderen Zei-
chenfolge
InStrB Fehlt (jedoch wie INSTR) Liefert Startposition einer ANSI-
Zeichenfolge in einer anderen
ANSI-Zeichenfolge

648
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


InStrRev Fehlt Wie InStr, beginnt die Suche aber
von hinten
Int Liefert den nächsten ganzzahligen Unverändert
Wert kleiner oder gleich einer
Zahl
Integer Datentyp für Ganzzahlen zwi- Unverändert
schen -32.768 bis 32.767

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


IOCTL, IOCTL$ Überträgt Steuerzeichenfolge an Verschwunden (ersatzlos)
Gerätetreiber IOCTL$
IPmt Fehlt Liefert den Zinsanteil für eine
bestimmte Periode bei Abzahlung
oder Ansparung mit konstanten
Raten und konstantem Zinssatz
IRR Fehlt Liefert internen Ertragssatz für
eine Folge regelmäßiger Ein- und
Auszahlungen
Is Vergleichsoperator für Select Vergleichsoperator für Select
Case-Ausdrücke Case-Ausdrücke und Objektrefe-
renzen
IsArray Fehlt Testet, ob Variablenwert ein
Array ist
Join Fehlt Setzt alle Zeichenfolgen eines
Arrays zu einer einzigen Zeichen-
folge zusammen (Trennzeichen
optional); Umkehrfunktion zu
Split
KEY Steuert Ereignisverfolgung für Verschwunden (bedingt vergleich-
Tastatureingabe bar mit KeyXXX-Ereignissen)
Kill Löscht Dateien, die auf das ange- Unverändert
gebene Suchmuster passen
LBound Liefert unter Indexgrenze für eine Unverändert
Array-Dimension
LCase, LCase$ Übersetzt Zeichenfolge in Klein- Unverändert
schreibung
Left, Left$ Liefert linken Teil einer Zeichen- Unverändert
folge
LeftB Fehlt (jedoch wie LEFT$) Liefert linken Teil einer ANSI-Zei-
chenfolge

649
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Len Liefert Anzahl der Zeichen in Zei- Unverändert
chenfolge. Trägt der Parameter
nicht den Typ String, liefert die
Funktion die Anzahl der zum
Speichern dieses Werts erforderli-
chen Bytes
LenB Fehlt (jedoch wie LEN) Liefert Anzahl der Bytes, die für
die Darstellung des Werts (zum
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Beispiel bei Speichern) erforder-


lich ist. Liefert damit auch die
Länge einer ANSI-Zeichenfolge
Line Input # Liest eine Zeile aus einer geöffne- Unverändert
ten sequenziellen Datei in eine
Variable vom Typ String ein
Loc Liefert die aktuelle Schreib- bzw. Unverändert
Leseposition einer geöffneten
Datei
LOCATE Setzt die Position für die Textein- Verschwunden (vgl. die Eigen-
und -ausgabe schaften CurrentX und CurrentY
des Formulars)
Lock Regelt die Zugriffsmöglichkeiten Unverändert
anderer Programm auf eine
bereits geöffnete Datei
LOF Liefert die Länge einer Datei in Unverändert
Bytes
Log Liefert den natürlichen Logarith- Unverändert
mus einer Zahl
Long Datentyp für lange Ganzzahlen Unverändert
zwischen -2.147.483.648 und
2.147.483.647
LPOS Liefert die Anzahl der Zeichen, Verschwunden (vgl. die Eigen-
die seit dem letzten Wagenrück- schaften CurrentX und CurrentY
lauf an den Drucker gesendet des Printer-Objekts)
wurden
LPRINT Unformatierte Ausgabe auf Dru- Verschwunden (vgl. Printer-
ckerschnittstelle LPT Objekt)
LPRINT USING Formatierte Ausgabe auf Dru- Verschwunden (vgl. Printer-
ckerschnittstelle LPT Objekt)
LSet Byteorientierte, linksbündige Unverändert
Zuweisungsoperation für belie-
bige Datentypen, ohne Längenan-
passung des Linkswerts;
Linkswert ist Zeichenfolgenvari-
able oder benutzerdefinierter Typ

650
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


LTrim, LTrim$ Liefert Zeichenfolge ohne füh- Unverändert
rende Leerzeichen zurück
Mid Zuweisungsoperation für mittle- Zuweisungsoperation für mittle-
ren Teil einer ANSI-Zeichenfolge ren Teil einer Unicode-Zeichen-
folge
Mid, Mid$ Liefert mittleren Teil einer Zei- Unverändert
chenfolge

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


MidB Fehlt (jedoch wie MID$) Liefert mittleren Teil einer Zei-
chenfolge als ANSI-Zeichenfolge
MidB Fehlt (jedoch wie MID) Zuweisungsoperation für mittle-
ren Teil einer ANSI-Zeichenfolge
Minute Fehlt Liefert Minute in einem Datums-/
Zeitwert als Zahlenwert (0 bis 59)
MIRR Fehlt Liefert den modifizierten internen
Ertragssatz für eine Folge regel-
mäßiger, mit unterschiedlichen
Zinssätzen behafteten Ein- und
Auszahlungen
MkDir Generiert ein neues Verzeichnis Unverändert
MKD, MKI, MKL, MKS, Byteorientierte Typumwandlung Wird nun von LSet übernommen
MKSMBF, MKDMBF numerischer Werte in Zeichenfol-
gen
Mod Operator für Restwertdivision Unverändert
Month Fehlt Liefert Monat in einem Datums-/
Zeitwert als Zahlenwert (1-12)
MonthName Fehlt Liefert Monatsname als Zeichen-
folge für Zahlenwert zwischen 1
und 12
Name Unverändert (jedoch Verschieben Benennt eine Datei um oder ver-
auf logisches Laufwerk schiebt diese in ein anderes Ver-
beschränkt) zeichnis
Now Fehlt Liefert Systemdatum und -zeit als
Datums-/Zeitwert
Not Operator für logische und bit- Unverändert
weise Negation
NPer Fehlt Liefert die Anzahl der Zeiträume
für eine Annuität (Ansparung
oder Kredit) bei konstanter Zah-
lung und konstantem Zins
NPV Fehlt Liefert den Netto-Barwert einer
Investition bei regelmäßigen Aus-
und Einzahlungen und konstan-
tem Diskontsatz

651
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Object Fehlt Datentyp für Objektreferenz
Oct, Oct$ Liefert die oktale Notation eines Unverändert
Werts
On...GoSub Fallunterscheidung mit beding- Unverändert
tem Unterprogrammaufruf
On...GoTo Fallunterscheidung mit beding- Unverändert
tem Sprung, Fehlerbehandlung
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

ON COM, ON KEY, ON Installiert Ereignisbehandlung für Verschwunden; Gerätezugriff nun


PEN, ON PLAY, ON Gerät über Steuerelemente
STRIG, ON TIMER
Open Öffnet eine Datei zum Lesen oder Unverändert
Schreiben
Option Base Setzt untere Indexgrenze für Unverändert
Arrays auf 0 oder 1
Option Compare Fehlt Standardvorgabe für Zeichenfol-
genvergleiche auf binären Ver-
gleich oder Textvergleich (ohne
Beachtung der Großschreibung)
setzen
Or Operator für logische und bit- Unverändert
weise ODER-Operation
OUT Schreibt Wert in Port Verschwunden
PAINT Füllt einen Grafikbereich mit Verschwunden; vgl. FillColor-
einer Farbe aus Eigenschaft
PALETTE Wechselt die Farbzuweisungen Verschwunden; vgl. Palette-
der Farbattribute für den aktuel- Eigenschaft
len Bildschirmmodus
PCOPY Kopiert eine Seite des Video-Spei- Ersatzlos verschwunden
chers in eine andere
PEEK Liefert das unter einer Speichera- Ersatzlos verschwunden
dresse im Hauptspeicher befindli-
che Datenbyte
PEN Liefert/setzt Einstellungen des Ersatzlos verschwunden
Lichtgriffels
PLAY (Anweisung) Spielt Noten ab Ersatzlos verschwunden
PLAY (Funktion) Liefert Anzahl der Noten in War- Ersatzlos verschwunden
teschlange
PMAP Rechnet Fensterkoordinaten in Verschwunden (bedingt vergleich-
WINDOW-Koordinaten um bar mit ScaleX, ScaleY)

652
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Point Liefert die Koordinaten des grafi- Als solche verschwunden; Koordi-
schen Cursors oder den Farbwert naten der Grafikausgabe lassen
eines Bildpunkts sich über die Eigenschaften Cur-
rentX und CurrentY ermitteln, der
Farbwert eines Bildpunkts im
Ausgabebereich eines Objekts
über die Methode Point
POKE Schreibt Datenbyte an der spezifi- Ersatzlos verschwunden

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


zierten Adresse in den Hauptspei-
cher
POS Liefert aktuelle Spalte des Text- Ersatzlos verschwunden; Koordi-
cursors naten der Grafikausgabe (gelten
auch für Print) lassen sich über
die Eigenschaften CurrentX und
CurrentY ermitteln
PPmt Fehlt Liefert den Kapitalanteil (bei Kre-
dit: Tilgung) eines bestimmten
Zeitraums für eine Annuität
(Ansparung oder Kredit) mit einer
festen Anzahl von Zeiträumen,
konstanter Zahlung und konstan-
tem Zins
PRESET Ausgabe eines Bildpunkts (stan- Verschwunden; nur noch als PSet-
dardmäßig in Hintergrundfarbe) Methode vorhanden
Print Gibt Text zeilenorientiert auf Gibt Text zeilenorientiert in Fens-
Bildschirm aus, mit Umbruch am ter aus, ohne Umbruch am Zeilen-
Zeilenende ende
Print # Schreibt Daten im gebietsspezifi- Unverändert
schen Format in sequenzielle
Datei
Private Entspricht DIM Deklaration lokaler Variablen auf
Modulebene; entspricht Dim
PSet Ausgabe eines Bildpunkts Jetzt als Methode von Objekt mit
Ausgabebereich; Farbmodell ist
verändert
Public Bedingt vergleichbar mit COMMON Deklaration globaler Variablen
auf Modulebene
Put Schreibt Daten in eine indexse- Unverändert
quenzielle Datei oder Binärdatei
PV Fehlt Liefert den Barwert für eine
Annuität (Ansparung oder Kredit)
bei konstanter Zahlung, konstan-
tem Zins und fester Laufzeit

653
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Randomize Initialisiert den Zufallsgenerator Unverändert
mit einem Startwert
Rate Fehlt Liefert den Zinssatz zu einer
Annuität (Anzahlung oder Kre-
dit) mit einer festen Anzahl von
Zeiträumen, konstanter Zahlung
und konstantem Zins
READ Liest das nächste Datum aus einer Verschwunden
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Data-Zeile
ReDim Ändert Dimensionen und Index- Unverändert
bereiche dynamischer Arrays
Rem Anweisung wird als Kommentar Unverändert
behandelt
Replace Fehlt Sucht Vorkommen einer Suchzei-
chenfolge in Zeichenfolge, ersetzt
diese gegen Ersatzzeichenfolge
und liefert resultierende Zeichen-
folge
Reset Schließt alle geöffneten Dateien Unverändert
RESTORE Legt aktuelle DATA-Zeile fest Verschwunden
Resume Rücksprung aus Fehlerbehand- Unverändert
lungsroutine
Return Rücksprung aus GoSub-Routine Unverändert
Right, Right$ Liefert rechten Teil einer ANSI- Liefert rechten Teil einer Unicode-
Zeichenfolge Zeichenfolge
RightB Fehlt (eigentlich Right$) Liefert rechten Teil einer ANSI-
Zeichenfolge
RmDir Löscht ein Verzeichnis Unverändert
Rnd Liefert eine gleichverteilte Unverändert
Zufallszahl zwischen 0 und 1
Round Liefert den Wert einer Zahl auf Unverändert
eine bestimmte Dezimalstelle
gerundet
RSet Rechtsbündige Zuweisungsopera- Unverändert
tion für Zeichenfolgen ohne Län-
genänderung des Linkswerts.
Füllt mit Leerzeichen auf oder
schneidet ab
RTrim, RTrim$ Liefert Zeichenfolge ohne Unverändert
abschließende Leerzeichen zurück

654
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


RUN Startet anderes Basic-Programm Verschwunden (vgl. Shell)
und übergibt diesem die Kon-
trolle
SCREEN (Funktion) Liefert das Farbattribut des Zei- Verschwunden (ersatzlos)
chens, das an der angegebenen
Position im Textbildschirm dar-
gestellt wird
SCREEN (Anweisung) Schaltet zwischen verschiedenen Verschwunden (ersatzlos)

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


Bildschirmmodi und -seiten um
Second Fehlt Liefert Sekunde in einem Datums-/
Zeitwert als Zahlenwert (0 bis 59)
Seek Liefert/setzt die aktuelle Schreib- Unverändert
oder Leseposition in einer geöff-
neten Datei
Select Case Fallunterscheidung Unverändert
SetAttr Fehlt Setzt ein oder mehrere Attribute
für eine Datei oder ein Verzeichnis
Sgn Liefert das Vorzeichen eines Unverändert
Werts als Faktor (-1, 0 oder 1)
SHARED Macht Variablen des Hauptpro- Bedingt vergleichbar mit Private
gramms in Funktionen und Pro-
zeduren sichtbar
Shell Führt eine Kommandozeile im Startet eine andere Anwendung
DOS-Kommandointerpreter aus und liefert deren Task-ID als
Funktionswert
Sin Liefert den Sinus zu einem Winkel Unverändert
im Bogenmaß
Single Datentyp für Fließkommazahlen Unverändert
einfacher Genauigkeit
SLEEP Unterbricht die Programmausfüh- Verschwunden (vgl. Zeitgeber-
rung für die angebebene Anzahl steuerelement)
an Sekunden
SLN Fehlt Liefert den periodischen Abschrei-
bungswert eines Vermögenswerts
bei linearer Abschreibung über
einen bestimmten Zeitraum
SOUND Erzeugt einen Ton mit einer frei Verschwunden
wählbaren Frequenz im Lautspre-
cher
Space, Space$ Liefert Zeichenfolge mit der Unverändert
gewünschten Anzahl von Leerzei-
chen

655
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


Spc Fügt Leerzeichen in die Print- Unverändert
Ausgabe ein
Split Fehlt Durchsucht Zeichenfolge nach
Trennzeichen und liefert die Zei-
chenfolgenabschnitte als Array;
Umkehrfunktion zu Join
Sqr Liefert die Quadratwurzel eines Unverändert
positiven Zahlenwerts
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Static Deklaration statischer Variablen Deklaration statischer Variablen


auf Prozedurebene auf Prozedurebene sowie stati-
scher Funktionen und Prozeduren.
Alle lokalen Variablen statischer
Prozeduren und Funktion sind
statisch
$Static Metabefehl für Speicherung von Verschwunden
Arrays
Stop Unterbricht die Programmausfüh- Unverändert
rung (wie Haltepunkt im Debug-
ger)
Str, Str$ Liefert standardmäßige Repräsen- Liefert standardmäßige Repräsen-
tation eines Zahlenwerts als tation eines Zahlenwerts als Uni-
ANSI-Zeichenfolge code-Zeichenfolge
StrComp Fehlt (ersatzweise: <-Operator) Führt alphanumerischen Zeichen-
folgenvergleich durch und unter-
scheidet dabei vier Fälle
StrConv Fehlt Konvertiert Zeichenfolge nach
einem von sieben möglichen Kon-
vertierungsschemata und liefert
konvertierte Version
String (Datentyp) Datentyp für Zeichenfolgen vari- Datentyp für Zeichenfolgen vari-
abler oder fester Länge ohne Uni- abler oder fester Länge mit Uni-
code code-Unterstützung
String (Funktion) Fehlt als Funktion Liefert Zeichenfolge mit der
gewünschten Anzahl eines einzel-
nen Zeichencodes
StrReverse Fehlt Liefert Zeichenfolge mit rück-
wärts verkehrter Zeichenfolge
Sub...End Sub Definiert Prozedur Wie gehabt, jedoch mit zusätzli-
chen Möglichkeiten bei der Para-
metervereinbarung und anderen
Geltungsbereichen
SWAP Tauscht die Werte zweier Variab- Verschwunden (ersatzlos)
len

656
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


SYD Fehlt Liefert den Abschreibungswert
eines Vermögenswerts für eine
bestimmte Periode nach dem
Modell der Jahresummengewich-
tung
SYSTEM Schließt alle geöffneten Dateien Verschwunden (ersatzlos)
und gibt die Kontrolle an das
Betriebssystem zurück

Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic


Tab Ermöglicht die Positionierung Unverändert
eines Werts an eine bestimme
Spaltenposition; nur in Print-
Anweisung zulässig
Tan Liefert den Tangens zu einem Unverändert
Winkel im Bogenmaß
Time Fehlt, da Datentyp Date fehlt. Via Setzt/liefert die aktuelle Systemzeit
Zeichenfolge, siehe Time$. als Datums-/Zeitwert.
TIME$ Liefert bzw. setzt die aktuelle Sys- Verschwunden
temzeit via Zeichenfolge
Timer Liefert den Wert des System- Unverändert
Timers (Sekunden seit Mitter-
nacht)
TIMER ON/OFF/STOP Steuert Timer-Interrupt Fehlt (jetzt via Zeitgeber-Steuer-
element Timer)
TimeSerial Fehlt Setzt Datums-/Zeitwert aus Ganz-
zahlwerten (Sekunde, Minute,
Stunde) zusammen
TimeValue Fehlt Interpretiert Zeichenfolge oder
Zahlenwert als Zeitanteil von
Datums-/Zeitwert
Trim Fehlt (ersatzweise: RTRIM$ und Liefert Zeichenfolge ohne füh-
LTRIM$) rende und abschließende Leerzei-
chen
TRON, TROFF1 Schalten die Verfolgung von Pro- Verschwunden (vgl. Debug-
grammanweisungen ein und aus Objekt)
Type...End Type Definition eines benutzerdefinier- Wie gehabt, jedoch mit erweiter-
ten Datentypen ten Möglichkeiten
UBound Liefert obere Indexgrenze für eine Unverändert
Array-Dimension
UCase, UCase$ Übersetzt Zeichenfolge in Groß- Unverändert
schreibung
Unlock Regelt die Zugriffsmöglichkeiten Unverändert
anderer Programme auf eine
bereits geöffnete Datei

657
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

Befehl QBasic Visual Basic


USING Formatierte Print-Ausgabe Verschwunden; bedingt vergleich-
bar mit Format-Funktion
Val Liefert den Zahlenwert einer Zei- Unverändert
chenfolge
Variant Fehlt Allgemeiner Datentyp, der Werte
aller Datentypen annehmen kann
VARPTR, VARSEG Liefert die Offset- und Segment- Ersatzlos verschwunden
adresse einer Variablen
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic

VIEW Definert einen Fensterbereich Ersatzlos verschwunden; bedingt


(Teilbereich) für die Grafikaus- vergleichbar mit Bildfeld-Steuer-
gabe element, das auf Formular plat-
ziert wird
WAIT Wartet, bis an Port ein bestimm- Ersatzlos verschwunden
tes Bitmuster anliegt
WeekDay Fehlt Liefert Wochentag in einem
Datums-/Zeitwert als Zahlenwert
(1-7)
WeekDayName Fehlt Liefert Wochentag als Zeichen-
folge für Zahlenwert zwischen 1
und 7
While...Wend Abweisende Schleife Unverändert
WIDTH Setzt eine maximale Zeilenlänge Verschwunden
für die Bildschirmausgabe
WIDTH # Setzt eine maximale Zeilenlänge Verschwunden
für eine sequenzielle Datei
WINDOW Legt ein Koordinatensystem für Verschwunden; bedingt vergleich-
die Grafikausgabe fest bar mit Scale-Methode
Write Schreibt Werte in standardisier- Verschwunden
tem Format auf den Bildschirm
Write # Schreibt Werte in standardisier- Unverändert
tem Format in eine sequenzielle
Datei
Xor Operator für logische und bit- Unverändert
weise Exclusiv-Oder-Operation
Year Fehlt Liefert Jahr in einem Datums-/
Zeitwert als Zahlenwert

658
Tabellenindex

659
Tabellenindex

Funktion / Befehl Referenz Praxis


!
$ 63
' (Operator) 33
^ (Operator) 54 484
_ (Operator) 33
A
Abbildungsliste-Steuerelement (ImageList) 435, 436
Abs-Funktion 94 487
abstrakter Datentyp 567
Access 150
Activate-Ereignis 208, 212
ActiveControl-Eigenschaft 308
ActiveX-DLL 274
ActiveX-EXE 274
ActiveX-Steuerelemente 322, 433, 440 599
Add-Methode 304
AddressOf 186
Adodc-Steuerelement 340
Aktivierreihenfolge 375
Algorithmus 477
Alignment-Eigenschaft 327
Ambient-Eigenschaft 601
AmbientProperties-Objekt 601
And 54 503
Anführungszeichen als literales Zeichen 29
Animation-Steuerelement 435
anonyme Instanziierung 525
Ansicht
– Bildansicht 511, 545
– Textansicht 551
ANSI-Code 63
Anweisung 33
Anzeige-Steuerelement (Image) 388, 390 532, 606
Apfelmann 494
API-Viewer 616
AppActivate-Methode 158, 224
Appearance-Eigenschaft 328
App-Objekt 264
Arbeitsverzeichnis
– aktuelles 131, 134
– standardmäßiges 134

660
Tabellenindex

Funktion / Befehl Referenz Praxis


arithmetische Operatoren 54
Arrays 56 488, 529
AscB-Funktion 66 560
Asc-Funktion 66 469
AscW-Funktion 66
Atn-Funktion 95 579
AufAb-Steuerelement 435
Auflistungen 304 509
Aufzählungen 62
Ausdruck 27, 29
Ausgabeparameter 178 574
Automatisierungsobjekt
– aufrufen 269
Automatisierungsschnittstelle 273
AutoRedraw-Eigenschaft 212, 308 488
AutoSize-Eigenschaft 329
B
BackColor-Eigenschaft 330 460, 562
BackStyle-Eigenschaft 331 607
bedingte Verzweigung 37
Befehl 27, 33
Befehlsschaltfläche-Steuerelement
(CommandButton) 388, 392 497, 562
Benannte Argumente 176
benutzerdefiniertes Koordinatensystem 370 461
Benutzerschnittstelle 542
Benutzersteuerelement 599
– veröffentlichen 603
Benutzersteuerelementmodul 26 567
Bezeichner 34, 161
Bezeichnerbereich 167
Bezeichnungsfeld-Steuerelement (Label) 388, 393 495
Bildansicht 511, 545
Bildausschnitt-Steuerelement (PictureClip) 442 608
Bildfeld-Steuerelement (PictureBox) 388, 395 562, 606
Bildlaufleisten 544
Bildlaufleisten-Steuerelemente (HScrollBar,
VScrollBar) 388, 398 545, 551
Bildschirmmodus 300
Binärdatei 130 557, 584
Binary 150 557

661
Tabellenindex

Funktion / Befehl Referenz Praxis


bitweise Operatoren 54
Boolean 49, 52 527
BorderStyle-Eigenschaft 332 457, 525, 537
BSTR 189
Bubble-Sort-Algorithmus 184
ByRef 178
Byte 49, 52
ByVal 178 534
C
Calendar-Eigenschaft 261
CallByName-Methode 262, 269
Caption-Eigenschaft 334 484, 526
Case 38 542
CausesValidation-Eigenschaft 223, 335
CBool-Funktion 57
CByte-Funktion 57
CCur-Funktion 57
CDate-Funktion 57, 116
CDbl-Funktion 57
CDec-Funktion 57
Change-Ereignis 214 551, 558, 619
ChDir-Anweisung 131
ChDrive-Anweisung 132
CheckBox-Steuerelement 387, 392, 409
Choose 38
ChrB-Funktion 67
Chr-Funktion 67 469, 560
ChrW-Funktion 67
CInt-Funktion 57 460
Circle-Methode 311 585
ClassModul-Schnittstelle 320 567
Click-Ereignis 208, 215 489, 542
Clipboard-Objekt 270
ClipControls-Eigenschaft 308
CLng-Funktion 58 584
Close-Anweisung 133 557, 598
Cls-Methode 311 487, 488
Collection-Objekt 304
ComboBox-Steuerelement 387, 407
CommandButton-Steuerelement 387 497, 562
Command-Methode 262, 273

662
Tabellenindex

Funktion / Befehl Referenz Praxis


Common Controls 433
CommonDialog-Steuerelement 489, 527, 551,
444 562
COM-Objekte, frühe vs. späte Bindung 269
Compiler 23 458, 574
Compileranweisung 33
Container-Eigenschaft 335
ControlBox-Eigenschaft 308 537
Controls-Auflistung 304, 308
CoolBar-Steuerelement 435
Cos-Funktion 95 469
Count-Eigenschaft 305 506, 514
CreateObject-Methode 262, 273 506
CSng-Funktion 58
CStr-Funktion 58 584
CurDir-Funktion 134, 431
Currency 49, 52
– Funktionen und Anweisungen 92
CurrentX-Eigenschaft 308 461
CurrentY-Eigenschaft 308 461
CVar-Funktion 58
CVDate-Funktion 58
CVErr-Funktion 44
D
Data Access Objects 404
DataChanged-Eigenschaft 336
Data-Environment-Designer 26
DataEnvironment-Komponenten 340
DataField-Eigenschaft 336 639
DataFormat-Eigenschaft 338 639
DataMember-Eigenschaft 339 639
DataObject-Objekt 501
Data-Report-Designer 26
DataSource-Eigenschaft 339, 405 639
Data-Steuerelement 340, 387
Date 49
– Funktionen und Anweisungen 114
DateAdd-Funktion 116 600
Date-Anweisung 116
DateDiff-Funktion 117
Date-Funktion 116

663
Tabellenindex

Funktion / Befehl Referenz Praxis


Dateilistenfeld-Steuerelement (FileListBox) 388, 400 510
Dateinummer 149 584
Dateizeiger 149
Dateizugriff, Funktionen und Anweisungen 126
Datenquelle 339 639
Datensteuerelement (Data) 388, 402
Datentypen, einfache vs. komplexe 161 572
DatePart-Funktion 118
DateSerial-Funktion 119
DateTimePicker-Steuerelement 435
DateValue-Funktion 120
Day-Funktion 121
DBCS (Double-Byte Character Set) 63
DblClick-Ereignis 208, 217
DCOM 196
DDB-Funktion 96
DDE 495
Deactivate-Ereignis 208, 212
Decimal 49, 53
– Funktionen und Anweisungen 92
Declare 185 455
DefBool 167
DefByte 167
DefCur 167
DefDate 167
DefDbl 167
DefDec 167
DefInt 167
DefLng 167
DefObj 167
DefSng 167
DefStr 167
DefTyp 167
DefVar 167
Delegation 525
DeleteSetting-Methode 262, 275 562
Designermodul 26
dezimale Literale 29
DHTML-Designer 26
Dim 162, 196 456
Direktfenster, Ausgeben in 454

664
Tabellenindex

Funktion / Befehl Referenz Praxis


Direkthilfe 353
Dir-Funktion 135 529
DirListBox-Steuerelement 387, 431
DisabledPicture-Eigenschaft 341
DLLs, Anbindung an 618
Do...Loop 41 469
DoEvents-Methode 43, 206, 262, 276 459, 485, 533
Double 49, 51 484
– Funktionen und Anweisungen 92
DownPicture-Eigenschaft 341
Drag&Drop-Operation 218, 221 606
DragDrop-Ereignis 208, 218 612, 613
DragIcon-Eigenschaft 222, 342
Drag-Methode 219, 379
DragMode-Eigenschaft 219, 343 612
DragOver-Ereignis 208, 221
DrawMode-Eigenschaft 344 480
DrawStyle-Eigenschaft 346
Drehfeld-Steuerelement 435
DriveListBox-Steuerelement 387, 410
Drucker 284
Druckvorschau 294
DTPicker-Steuerelement 435
dynamische Arrays 56 488
Dynamischer Datenaustausch 495
E
Eigenschaften 202
Eigenschaftsseitenmodul 26
einfache Datentypen 161
Einfügereihenfolge 387
Eingabeparameter 178
Elementare Datentypen 49
ElseIf 36 527
Empty 50, 169 562
Enabled-Eigenschaft 347 527
– Menübefehle 531
Endlosschleifen 41 459
Entwurfsinstanz 601
Enum-Aufzählungen 62 461, 531
Environ-Funktion 136
Eqv 54

665
Tabellenindex

Funktion / Befehl Referenz Praxis


Ereignisbehandlung 491
Ereignisroutinen 204 485
Ereignisse 207 568
Err-Objekt 44, 277 461, 499, 570
Error 43, 50
Event 204
Exit Function 181 455
Exit Property 572
Exit Sub 183 486, 532
Exp-Funktion 97
ExtractIcon-Methode 437
F
False 39, 52
Fehlerbehandlung 44 535
Figur-Steuerelement (Shape) 388, 406
FileAttr-Funktion 138
FileCopy-Anweisung 138
FileDateTime-Funktion 121, 139
FileLen-Funktion 139
FileListBox-Steuerelement 387, 400 510
FileName-Eigenschaft 528
FileSystemObject-Objekt 269 529
FileTitle-Eigenschaft 528
FillColor-Eigenschaft 348 589
FillStyle-Eigenschaft 349 589
Filter-Funktion 68
FindClose 135
FindFirstFile 135
FindNextFile 135
Fix-Funktion 97
Flache Bildlaufleiste-Steuerelement 435 544
FlatScrollBar-Steuerelement 435 544
Folder 529
FontBold-Eigenschaft 350 639
Font-Eigenschaft 349 637
FontItalic-Eigenschaft 350 639
FontName-Eigenschaft 350 463, 556, 639
Fonts-Auflistung 304
FontSize-Eigenschaft 350 463, 639
FontStrikethru-Eigenschaft 350 639
FontUnderline-Eigenschaft 350 639

666
Tabellenindex

Funktion / Befehl Referenz Praxis


For Each...Next 40 529
For...Next 40 469, 484
ForeColor-Eigenschaft 330 456, 460
Form_MouseDown 492
Form_MouseMove 492
Form_MouseUp 492
FormatCurrency-Funktion 73
FormatDateTime-Funktion 74, 121
Format-Funktion 69 551
FormatNumber-Funktion 75
FormatPercent-Funktion 75
Form-Objekt 307 463, 537
Forms-Auflistung 279, 304
Formular 306 491
– Ereignis zusätzliches 206
– gebundenes 525
Formularmodul 25 463, 567
Fortschrittsleiste-Steuerelement 435
Frame-Steuerelement 387, 426
FreeFile-Funktion 139
Function 137, 181 454, 455
Funktionsaufruf 176
Funktionszeiger 192
FV-Funktion 98
G
Gebietsschema 60, 89
gebundenes Formular 525
GetAllSettings-Methode 262, 279 562
Get-Anweisung 140 584
GetAttr-Funktion 142
GetFolder 529
GetObject-Methode 262, 280
GetSetting-Methode 262, 281 562
GoSub 36
GotFocus-Ereignis 208, 222
GoTo 36
H
HasDC-Eigenschaft 350
hDC-Eigenschaft 287, 351
Height-Eigenschaft 351 461, 549
HelpContextID-Eigenschaft 353

667
Tabellenindex

Funktion / Befehl Referenz Praxis


hexadezimale Literale 29
Hex-Funktion 76 560
Hide-Methode 259, 311 457, 537
Hintergrundbild 253 469
Hour-Funktion 121 488
HScrollBar-Steuerelement 387, 398
hWnd-Eigenschaft 354 545, 551
I 607, 618, 619
If...Then...Else 36
IIf-Funktion 38 487, 532
ImageCombo-Steuerelement 435 462, 549
Image-Eigenschaft 354
ImageList-Steuerelement 435, 436 488
Image-Steuerelement 387, 390
Imp 54 505
Implements 319
Importdeklaration 175
Index-Eigenschaft 356
Info-Dialog
Initialize-Ereignis 208, 224 525
Input #-Anweisung 143 527, 567, 581
InputB-Funktion 142
InputBox-Methode 262, 281, 429 560
Input-Funktion 142 455
Instanziierung 196 560
– anonyme 567
InStrB-Funktion 76 525
InStr-Funktion 76
InStrRev-Funktion 77 529
Integer 49, 51 527
– Funktionen und Anweisungen 92
Interpreter 23
Int-Funktion 99
InvisibleAtRuntime-Eigenschaft 514
IPmt-Funktion 99 600
IRR-Funktion 100
Is 54
IsArray-Funktion 55 502
IsDate-Funktion 58
IsEmpty-Funktion 49
IsError-Funktion 44, 49 562

668
Tabellenindex

Funktion / Befehl Referenz Praxis


IsMissing-Funktion 178, 179
IsNull-Funktion 49
IsNumeric-Funktion 49, 91
IsObject-Funktion 49
J
Join-Funktion 78
K
Kalender-Steuerelement 435
KeyDown-Ereignis 209, 225
KeyPress-Ereignis 459, 525, 542,
209, 228 619
KeyPreview-Eigenschaft 308 459
KeyUp-Ereignis 209, 225 459
Kill-Anweisung 144
Klassen 196 567
Klassenbegriff 195
Klassenmodul 26 567
Kombinationsfeld-Steuerelement (ComboBox) 388, 407, 435
Kommandozeilenparameter 273
Kommentar 33
komplexe Datentypen 161
Konstante 27
Kontextbezogene Hilfe 353
Kontextmenü 538, 540
Kontrollkästchen-Steuerelement (CheckBox) 388, 409
Kontrollstrukturen 33
Koordinatensystem 367, 368, 369 461, 462, 477
– drehen 472
L
Label-Steuerelement 387, 393
Ländereinstellung 169
länderspezifische Darstellung 60
Laufwerk, standardmäßiges 132
Laufwerklistenfeld-Steuerelement (DriveListBox) 388, 410 510
Laufwerkspfad 129
Laufzeitfehler behandeln 44
Laufzeitmessung 111 484
LBound-Funktion 55 488
LCase-Funktion 79
LeftB-Funktion 79
Left-Eigenschaft 357 456

669
Tabellenindex

Funktion / Befehl Referenz Praxis


Left-Funktion 79 527
LenB-Funktion 79
Len-Funktion 79 619
Let 33, 168
Line Input #-Anweisung 145
Line-Methode 311 461, 462, 469
Linie-Steuerelement (Line) 388, 411
LinkClose-Ereignis 209, 230 495
Linker 23
LinkError-Ereignis 209, 231 495
LinkExecute-Ereignis 209, 232 495
LinkExecute-Methode 380 495
LinkItem-Methode 495
LinkMode-Eigenschaft 230, 234, 382 495
LinkNotify-Ereignis 233 495
LinkOpen-Ereignis 209, 233 495
LinkPoke-Methode 381 495
LinkRequest-Methode 382 495
LinkSend-Methode 382
LinkTopic-Methode 495
ListBox-Steuerelement 616
Listenfeld-Steuerelement (ListBox) 388, 412 616
ListImages-Auflistung 436
ListView-Steuerelement 435
Literal 27, 28
literaler Ausdruck 29
Load-Ereignis 209, 236 486, 527
Load-Methode 263, 282 484
LoadPicture-Methode 263, 283 535
LoadResData-Methode 263, 284
LoadResPicture-Methode 263, 284
LoadResString-Methode 263, 284
Loc-Funktion 146
Lock-Anweisung 146
LOF-Funktion 147 557
Log-Funktion 101
logische Operatoren 54
Long 49, 51 529
– Funktionen und Anweisungen 92
LostFocus-Ereignis 209, 222 620

670
Tabellenindex

Funktion / Befehl Referenz Praxis


LSet-Anweisung 80, 148
LTrim-Funktion 81
M
Main 24, 183 455
MaskColor-Eigenschaft 358, 437 606
MaskEdBox-Steuerelement 615
MaskPicture-Eigenschaft 359 606
Mauszeigerkontrolle durch Screen-Objekt 300 502
MaxButton-Eigenschaft 308
MDIChild-Eigenschaft 309
MDIForm-Objekt 313
MDI-Formularmodul 25, 315
Me (Objektvariable für Ich-Bezug) 201 463, 526
Mehrfachauswahl 402, 448 528
Menü 489, 538
Menübefehle 542
– pflegen 530
Methode 200 568
Microsoft Jet-Engine 404
Mid-Anweisung 82
MidB-Anweisung 82
MidB-Funktion 81 560
Mid-Funktion 81 560
MinButton-Eigenschaft 308
Minute-Funktion 121
MIRR-Funktion 102
MkDir-Anweisung 148
Mod 54
Module 24
– Arten 25
– Benutzersteuerelement 26 567
– Designer 26
– Eigenschaftsseiten 26
– Formular 25 463
– Klassen 26 567
– MDI-Formular 25
– Standardmodul 25 464
Month-Funktion 122
MonthName-Funktion 82, 122
MonthView-Steuerelement 435
MouseDown-Ereignis 209, 237 487, 525

67 1
Tabellenindex

Funktion / Befehl Referenz Praxis


MouseIcon-Eigenschaft 359 502
MouseMove-Ereignis 209, 239 480, 492
MousePointer-Eigenschaft 360 502
MouseUp-Ereignis 209, 237 487
Moveable-Eigenschaft 309
Move-Methode 383
MultiLine-Eigenschaft 361
N
Nachrichtenschleife 204
Name-Anweisung 148
Name-Eigenschaft 361 514
Namensraum 24, 34 526, 584
New 163, 169, 196 526
Not 54 540
Nothing 50, 168, 196 526, 540
Now-Funktion 122
NPer-Funktion 103
NPV-Funktion 104
Null 50
O
Object 49, 169, 197 585
Objektbegriff 195
Objektdatentypen 196 568
Objektkatalog 199
objektorientierte Programmierung 567
Objektvariable 196 568
Oct-Funktion 82
OCX-Datei 603
oktale Literale 29
OLE 2.0 196 503
OLECompleteDrag-Ereignis 209, 241 503
OLE-Container-Steuerelement (OLE) 387, 388, 415
OLE-Drag&Drop-Operation 363 501
OLEDragDrop-Ereignis 209, 242
OLEDrag-Methode 383 503
OLEDragMode-Eigenschaft 501
OLEDragOver-Ereignis 210, 245 502
OLEDropAllowed-Eigenschaft 362
OLEDropMode-Eigenschaft 363 501
OLEGiveFeedback-Ereignis 210, 247 502
OLESetData-Ereignis 210, 248 502

672
Tabellenindex

Funktion / Befehl Referenz Praxis


OLEStartDrag-Ereignis 250 501
OLETypeAllowed-Eigenschaft 362
On Error GoTo 44 527, 535
On Error Resume Next 44 506
On...GoSub 38
On...GoTo 38
Open-Anweisung 149 557, 598
Operand 29
Operationen 27
Operatoren 29, 54
Optimierung 111 484, 485
Option Compare-Anweisung 83
Option Explicit 166 455
Option Private 201
Optional 178 531, 532, 535
optionale Argumente 176 525
OptionButton-Steuerelement 387, 424
Optionsfeld-Steuerelement (OptionButton) 388, 424
Or 54 480
Overlay-Methode 437 606
P
Paint-Ereignis 210, 253
PaintPicture-Methode 311 488, 535, 550
Palette-Eigenschaft 309
PaletteMode-Eigenschaft 309
ParamArray 179 588
Parameterübergabe 178 574
Parent-Eigenschaft 364
Partition-Funktion 85
P-Code 24
Pfad 129
PICCLP32.OCX 272
PictureBox-Steuerelement 387, 395
PictureClip-Steuerelement 442 608
Picture-Eigenschaft 365 488, 532
Pmt-Funktion 105
Point-Methode 311
PopupMenu-Methode 311 540
Portierung älterer Programme 457
PPmt-Funktion 106
Print #-Anweisung 151

67 3
Tabellenindex

Funktion / Befehl Referenz Praxis


Printer-Objekt 284
Printers-Auflistung 297, 304
PrintForm-Methode 294, 312
Print-Methode 312 454, 460
Private 34, 162, 196 492
Programm 23
– portieren 453
ProgressBar-Steuerelement 435
Projekt 24 454
Property Let/Get/Set 201 573
Property Let/Get/Set-Funktion 600
PropertyBag-Objekt 603
Prozedur 175
Prozeduraufruf 176
PSet-Methode 312 469, 484
Pseudotransparenz 359
Public 196 525
Punkt/Komma-Problematik 169
Put-Anweisung 153 584
PV-Funktion 106
Q
QBColor-Methode 263, 298 461, 484
Qualifizierungskontext 61
Quellkomponente 501
QueryUnload-Ereignis 210, 256 506
QuickInfo 353, 371, 377
R
Rahmen-Steuerelement (Frame) 388, 426
RaiseEvent 204 602, 613
Random 149
Randomize-Anweisung 107 593
Rate 108
ReadProperties-Ereignis 603
ReDim 56 488, 529
Reentranz 206 486
Refresh-Methode 384 559
Rekursion 43, 177, 206 486, 534
rekursive Funktion/Prozedur 175 486
Rem 33 454
RemoteData-Steuerelement 340
Remove-Methode 305

674
Tabellenindex

Funktion / Befehl Referenz Praxis


Replace-Funktion 84
Reset-Anweisung 154
Resize-Ereignis 210, 257 514, 533, 557
Return 36
RGB-Methode 263, 299 485
RICHTX32.OCX 272
RightB-Funktion 85
Right-Funktion 85 472, 559
RightToLeft-Eigenschaft 366
RmDir-Anweisung 155
Rnd-Anweisung 109
Rnd-Funktion 109 593
Round-Funktion 110 584
RSet-Anweisung 86
RTF-Format 270
RTrim-Funktion 86
Rückruffunktion 192
S
SavePicture-Methode 263, 299 489
SaveSetting-Methode 263, 300 561, 562
ScaleHeight-Eigenschaft 368
ScaleLeft-Eigenschaft 366 460, 462
Scale-Methode 461, 462, 477,
312 487
ScaleMode-Eigenschaft 369 461, 462
ScaleTop-Eigenschaft 366 460, 462
ScaleWidth-Eigenschaft 368
ScaleX-Methode 312 462
ScaleY-Methode 312 462
Schaltflächen 392 497, 562
Schieberegler-Steuerelement (Slider) 436 592
Schleifen 41 484
Schlüsselwörter 34
Screen-Objekt 300 456, 502
Scroll-Ereignis 551
Second-Funktion 122
Seek-Anweisung 156 559
Seek-Funktion 156
selbst definierte Klassen 318 567
Select Case 38 469, 542
SendKeys-Methode 263, 302

675
Tabellenindex

Funktion / Befehl Referenz Praxis


SendMessage-Funktion 295 616, 619
sequenzielle Datei 130
Set 168, 169, 196 526
SetAttr-Anweisung 157
SetFocus-Methode 223, 385 545
Sgn-Funktion 110 487
Shape-Steuerelement 387, 406
Shell-Anweisung 158
ShowInTaskbar-Eigenschaft 309
Show-Methode 212, 259, 312 457, 525, 526
ShowTips-Eigenschaft 371
ShowWhatsThis-Methode 386
Sin-Funktion 112 469
Single 49, 51 535
– Funktionen und Anweisungen 92
Slider-Steuerelement 436
SLN-Funktion 112
Space-Funktion 86 551
Spc 152, 160
Split-Funktion 87 527
Sprungmarke 37 528
Sqr-Funktion 113 469
Sqr-Methode 484
Stack 488
Standarddialoge-Steuerelement (CommonDialog) 489, 527, 551,
444 562
– Öffnen, Mehrfachauswahl 528
Standardeigenschaft 200, 319 570, 575, 639
Standard-EXE 25, 26
Standardmodul 25 454, 464
Standardparameter 574
Standardschaltfläche 392 497, 562
Standardsteuerelemente 322, 387
Startobjekt 24 527
StartupPosition-Eigenschaft 309
Static 162, 196, 200 486, 526, 532
statische Arrays 56
Statusanzeige 353
StatusBar-Steuerelement 436
Steuerelemente-Arrays 356 608
StrComp-Funktion 88

676
Tabellenindex

Funktion / Befehl Referenz Praxis


StrConv-Funktion 89, 169
Str-Funktion 87 584
String 49 529
String-Funktion 90
StrReverse-Funktion 90
Strukturansicht-Steuerelement 436
strukturierte Programmierung 175 567
Style-Eigenschaft 372
Sub 183
Sub Main 24, 183 455
Subroutine 24
Switch 38
SYD-Funktion 113
Symbolleiste-Steuerelement 436
Systemregistrierung 263, 275, 279,
300 561
T
Tab 152, 160
TabIndex-Eigenschaft 223, 375
TabStop-Eigenschaft 376
TabStrip-Steuerelement 435
Tabulatorordnung 375
Tabulatorreihenfolge 223, 387
Tag-Eigenschaft 376
Tan-Funktion 114
Tastenkürzel 538, 542
Terminate-Ereignis 210, 258 567, 603
Textansicht 551
TextBox-Steuerelement 387 456, 615
Textdatei 130 506
Textfeld-Steuerelement (TextBox) 388, 427 456, 615
TextHeight-Methode 312 460, 535
TextWidth-Methode 312 460, 535
Time-Anweisung 123
Time-Funktion 123
Timer-Ereignis 599
Timer-Funktion 124
Timer-Steuerelement 387, 432 475, 540, 599
TimeSerial-Funktion 124
TimeValue-Funktion 125
ToolBar-Steuerelement 436

677
Tabellenindex

Funktion / Befehl Referenz Praxis


ToolboxBitmap-Eigenschaft 600
ToolTipText-Eigenschaft 377
Top-Eigenschaft 357 456
Transparenz 359 606
TreeView-Steuerelement 436
Trim-Funktion 90
True 39, 52
Type-Datentypen 61 567
TypeName-Funktion 168 588
TypeOf 54 588
Typkennzeichen 167
U
UBound-Funktion 55 488
UCase-Funktion 91 529
UNC-Pfad 129
ungarische Notation 35
Unicode 63
Unload-Ereignis 210, 259 526, 564
Unload-Methode 236, 259, 263, 497, 499, 525,
303 526
Unlock-Anweisung 159
Unterprogramm 37
UpDown-Steuerelement 435
UseMaskColor-Eigenschaft 377, 437
UserControl-Objekt 599
UserMode-Eigenschaft 601
V
Val-Funktion 91
ValidateControls-Methode 312
Validate-Ereignis 210, 260 455
Variablen 27, 28, 161
– deklarieren 162
– initialisieren 168 471
– statische vs. automatische 162
Variant 49, 50 488
VBA 195
VBX 195
Vergleichsoperatoren 54
Verkapselung 567
Verzeichnislistenfeld-Steuerelement (DirListBox) 388, 431 510
Visible-Eigenschaft 259, 378 526, 533

678
Tabellenindex

Funktion / Befehl Referenz Praxis


Visual Component Manager 603
VScrollBar-Steuerelement 387, 398 545, 551
W
WebClass-Designer 26
Weekday-Funktion 125
WeekdayName-Funktion 92, 126
Werkzeugsammlung erweitern 434
WhatsThisButton-Eigenschaft 310
WhatsThisHelp-Eigenschaft 378
WhatsThisHelpID-Eigenschaft 353
WhatsThisMode-Methode 312
While...Wend 40 487
Width-Eigenschaft 351 461, 549
Win32-API 616
Win32api.txt 187
Windows-Standardsteuerelemente 322, 433
WindowState-Eigenschaft 310 557
With...End With 61 534
WithEvents 162, 196, 204
Wrapper-Klasse 206
Write #-Anweisung 159
WriteProperties-Ereignis 603
X
Xor 54
Y
Year-Funktion 126
Z
Zahlenliterale 29
Zählschleifen 41 484
Zeichenfolgenliterale 29
Zeichenfolgenoperator 54
Zeilennummer 37
Zeit, Funktionen für 114
Zeitgeber-Steuerelement (Timer) 388, 432 475, 599
Zielkomponente 501
ZOrder-Methode 254, 386 615
Z-Ordnung 387 613
Zugriffstaste 375 538, 542, 543
Zuweisung 29, 33 572
Zwischenablage 270 501

679

Das könnte Ihnen auch gefallen