Beruflich Dokumente
Kultur Dokumente
referenz
visual basic 6
referenz
rudolf huttary
new technology
Markt+Technik Verlag
Die Deutsche Bibliothek – CIP-Einheitsaufnahme
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
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
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
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
12
Inhaltsverzeichnis
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.
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.
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
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
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
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).
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
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.
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
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.
27
Literale und Konstanten
Literale und Konstanten
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
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.
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.
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#.
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
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
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
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-
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
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.
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
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
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.
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.
42
Fehlerbehandlung
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
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
Kontrollstrukturen
Open CommonDialog1.FileName For Binary As FreeFile
End Function
...................................................
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
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.
51
Elementare Datentypen
Dim s!
Dim d#
For n% = 1 to 100 ' Deklaration mit Typkennzeichen durch Nennung
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
52
Der Datentyp Decimal
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
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
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
...................................................
54
Arrays
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
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
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
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
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
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
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"
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.
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
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
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.
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.
Verwandte Them en
...................................................
Typumwandlung (S. 57)
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
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()
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
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
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
...................................................
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
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"
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], _
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
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
Verwandte Them en
...................................................
Funktionen und Anweisungen für Zeichenfolgen
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
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.
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
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
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
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.
Beis piel
...................................................
if LCase(sTest1) = LCase(sTest2) Then ' Schreibweise egal
Verwandte Befehle
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
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
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
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
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
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
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
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.
Beis piel
...................................................
Print Oct(77) ' 64+8+5 = "115"
Print Oct(&o1234) ' Oktales Literal: "1234"
Verwandte Befehle
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
Replace- Funktion
Function Replace( _
sDurchsuchterString As String, _
sSuchString As String,_
sErsatzString As String,_
[lStart As Long = 1], _
Funktionen und Anweisungen für Zeichenfolgen
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
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
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: "
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
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
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
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
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
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
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
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.
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
StrConv- Funktion
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.
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
String- Funktion
Function String(lAnz As Long, iANSI As Integer) As String
Funktionen und Anweisungen für Zeichenfolgen
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
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
UCase- Funktion
Function UCase(s As String) As String
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
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
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
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.
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
Atn- Funktion
Function Atn(d As Double) As Double
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
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
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
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.
Beis piel
...................................................
Print Exp(1) ' Ausgabe: 2,71828182845905
Print Exp(Log(10)) ' Ausgabe: 10
Verwandte Befehle
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
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
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
Int- Funktion
Function Int(dZahl As NumTyp) As NumTyp
Beschreibung
Bes c hreibung
...................................................
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
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(!)
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-
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
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
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
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
...................................................
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
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
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
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
...................................................
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
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
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
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
...................................................
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
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
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 €
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
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
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):
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
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
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
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:
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
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
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
115
Funktionen und Anweisungen für Datums- / Zeitwerte
CDate- Funktion
Function CDate(vWert) As Date
Siehe »Typumwandlung« (S. 57).
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
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.
116
DateDiff- Funktion
Anwendung
Anwendung
...................................................
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
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.
117
Funktionen und Anweisungen für Datums- / Zeitwerte
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
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
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
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
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
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.
Beis piel
...................................................
Siehe »Format-Funktion« (S. 69) und das dort vorgestellte Projekt FormatDemo.
Verwandte Befehle
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
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
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
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
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
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
1 23
Funktionen und Anweisungen für Datums- / Zeitwerte
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
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
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-
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
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
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
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
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
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
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.
1 29
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-
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
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
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).
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
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
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
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
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
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) <> ""
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
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
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
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
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
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
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.
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.
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
1 41
Dateiorientierte Funktionen und Anweisungen
Verwandte Befehle
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:
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
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
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
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
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
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
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
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
...................................................
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
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
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
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«.
Beis piel
...................................................
Kill sPfad + "Daten.dat"
Name sPfad + "Daten.tmp" As sPfad + "Daten.dat
Verwandte Befehle
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
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
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
Verwandte Them en
...................................................
Literale und Konstanten (S. 27)
Put- Anweisung
Put [#]iDateiNr, [lSatzNr], Wert
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.
1 53
Dateiorientierte Funktionen und Anweisungen
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
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
RmDir- Anweisung
Sub RmDir(sVerzeichnisname As String)
Beschreibung
Bes c hreibung
...................................................
Die Anweisung RmDir löscht das Verzeichnis sVerzeichnisName.
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
1 55
Dateiorientierte Funktionen und Anweisungen
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
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
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
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
' 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
' 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
' Variant
Variableninitialisierung
' 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
Verwandte Them en
...................................................
Datentypen und ihre Operationen (S. 49); Geltungsbereiche von Variablen (S. 173); Variab-
lendeklaration (S. 162)
1 72
Geltungsbereiche von Variablen
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-
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
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
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)
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-
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
Bes c hreibung
...................................................
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
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
Verwandte Them en
...................................................
Ereignisroutinen (S. 230)
1 82
Prozeduren selbst definieren
Bes c hreibung
...................................................
Die Definition einer eigenen Prozedur (Methode) gliedert sich in zwei Schritte:
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
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
Verwandte Them en
...................................................
Ereignisroutinen (S. 204)
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-
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.
1 88
Routinen aus DLLs und der Windows- API einsetzen
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
1 90
Routinen aus DLLs und der Windows- API einsetzen
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
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
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
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
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.
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.
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.
1 97
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.
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
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.
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
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)
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 Get Betrag() As Double ' Länge des Vektors (wird errechnet!)
Betrag = Sqr(x * x + y * y + z * z)
End Property
203
Klassen als Datentypen für Objektvariablen
End Function
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
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.
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
Standardereignisse
End Property
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.
208
Standardereignisse
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
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
21 1
Standardereignisse
End Sub
Wird das Formular sofort nach dem Erscheinen wieder geschlossen, lautet die Ausgabe:
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.
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
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
Verwandte Ereignisse
Verwandte Ereignis s e
...................................................
GotFocus, LostFocus
Change- Ereignis
Sub Objekt_Change([Index As Integer])
Betroffene Objekte
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
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
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
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
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
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
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
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
220
DragOver- Ereignis
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
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
222
GotFocus- Ereignis und LostFocus- Ereignis
Betroffene Objekte
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:
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
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
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:
Sub Form_Initialize()
AutoRedraw = True ' Wenn False oder fehlt, Laufzeitfehler!
Print "Initialize"
a = 1
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
225
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
227
Standardereignisse
Case vbKeyEnd
PosX = MaxX: PosY = MaxY
End Select
Picture1.Left = PosX
Picture1.Top = PosY
End Sub
Verwandte Befehle
KeyPress- Ereignis
Sub Form_KeyPress(KeyAscii As Integer)
Sub Objekt_KeyPress([Index As Integer], KeyAscii As Integer)
Betroffene Objekte
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
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
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
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
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
Bes c hreibung
...................................................
Das LinkExecute-Ereignis tritt im Verlauf einer DDE-Verbindung aufseiten des Quellobjekts auf
Standardereignisse
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")
...
232
LinkNotify- Ereignis
LinkNotify- Ereignis
Sub Objekt_LinkNotify([Index As Integer])
Betroffene Objekte
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
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
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
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
Standardereignisse
MsgBox "Form_Load"
End Sub
Verwandte Ereignis s e
...................................................
Initialize, Terminate, Unload
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
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
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
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
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
Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)
OLECompleteDrag- Ereignis
Private Sub Objekt_OLECompleteDrag(Effect As Long)
Betroffene Objekte
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
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
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.
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
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
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
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
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
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
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
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
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:
250
OLEStartDrag- Ereignis
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
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
252
Paint- Ereignis
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
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.
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
255
Standardereignisse
QueryUnload- Ereignis
Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
MIDForm_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Betroffene Objekte
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
Verwandte Ereignis s e
...................................................
Standardereignisse
Unload
Resize- Ereignis
Sub Form_Resize()
Sub Objekt_Resize([HeightNew As Single, WidthNew As Single])
Betroffene Objekte
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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:
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
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
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:
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
PrintForm
End Sub
' Ü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
Global- Objekt
obj.CurrentX = -obj.TextWidth(CStr(x))
obj.CurrentY = x – obj.TextHeight(CStr(x)) / 2
obj.Print CStr(x)
Next x
End Sub
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:
Beispiel
Beis piel
...................................................
Line (0, 0)-(1000, 1000), QBColor(6)
Verwandte Befehle
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
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
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
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.
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
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
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
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
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
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
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
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
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:
322
Gemeinsame Eigenschaften
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
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
326
Alignment- Eigenschaft
Alignment- Eigenschaft
Objekt.Alignment As Integer
Betroffene Objekte
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:
3 27
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
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.
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
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
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:
330
BackStyle- Eigenschaft
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
Bes c hreibung
...................................................
Die BackStyle-Eigenschaft bestimmt, ob ein Steuerelement mit durchsichtigem Hintergrund
angezeigt wird oder nicht.
331
Gemeinsame Eigenschaften
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
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.
332
BorderStyle- Eigenschaft
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
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
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
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
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
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
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
Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)
DataFormat- Eigenschaft
Objekt.DataFormat As IStdDataFormatDisp
Gemeinsame Eigenschaften
Betroffene Objekte
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
Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)
338
DataMember- Eigenschaft
DataMember- Eigenschaft
Objekt.DataMember As String
Betroffene Objekte
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
Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)
DataSource- Eigenschaft
Objekt_DataSource = DatenquelleObjekt
Betroffene Objekte
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
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
Verwandte Them en
...................................................
Data-Datensteuerelement (Data) (S. 402)
340
DisabledPicture- Eigenschaft
DisabledPicture- Eigenschaft
Objekt.DisabledPicture As Picture
Betroffene Objekte
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
DownPicture- Eigenschaft
Objekt.DownPicture As Picture
Betroffene Objekte
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
DragIcon- Eigenschaft
Objekt.DragIcon As Picture
Betroffene Objekte
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
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
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
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
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:
344
DrawMode- Eigenschaft
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
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
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
Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)
DrawStyle- Eigenschaft
Objekt.DrawStyle As Integer
Betroffene Objekte
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:
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
Verwandte Them en
...................................................
Gummiband – Bereiche interaktiv auswählen (S. 492)
Enabled- Eigenschaft
Objekt.Enabled As Boolean
Betroffene Objekte
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
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
348
FillStyle- Eigenschaft
FillStyle- Eigenschaft
Objekt.FillStyle As Integer
Betroffene Objekte
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
Font- Eigenschaft
Objekt.Font As Font
Betroffene Objekte
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
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
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.
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)
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
352
HelpContextID- Eigenschaft und WhatsThisHelpID- Eigenschaft
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
3 53
Gemeinsame Eigenschaften
hWnd- Eigenschaft
Objekt.hWnd As Long
Betroffene Objekte
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
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
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
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
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
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
Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)
MouseIcon- Eigenschaft
Objekt.MouseIcon As Picture
Betroffene Objekte
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
MousePointer- Eigenschaft
Objekt.MousePointer As Integer
Betroffene Objekte
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.
360
MultiLine- 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
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
Name- Eigenschaft
Objekt.Name As String
Betroffene Objekte
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.
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
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:
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
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
Picture- Eigenschaft
Objekt.Picture As Picture
Betroffene Objekte
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
Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)
RightToLeft- Eigenschaft
Objekt.RightToLeft As Boolean
Betroffene Objekte
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.
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
3 67
Gemeinsame Eigenschaften
Verwandte Methoden
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
Gemeinsame Eigenschaften
ScaleMode, ScaleLeft, ScaleTop
Verwandte Methoden
ScaleMode- Eigenschaft
Objekt.ScaleMode As Integer
Betroffene Objekte
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:
3 69
Gemeinsame Eigenschaften
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
Verwandte Eigenschaften
ShowTips- Eigenschaft
Objekt.ShowTips As Boolean
Betroffene Objekte
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
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.
372
Style- Eigenschaft
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
Verwandte Eigenschaften
...................................................
Verwa ndte Eigens c ha ften
BorderStyle
37 4
TabIndex- Eigenschaft
TabIndex- Eigenschaft
Objekt.TabIndex As Integer
Betroffene Objekte
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
TabStop- Eigenschaft
Gemeinsame Eigenschaften
Objekt.TabStop As Boolean
Betroffene Objekte
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
Tag- Eigenschaft
Objekt.Tag As String
Betroffene Objekte
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
ToolTipText- Eigenschaft
Objekt.ToolTipText As String
Betroffene Objekte
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
UseMaskColor- Eigenschaft
Objekt.UseMaskColor As Boolean
Betroffene Objekte
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
Visible- Eigenschaft
Objekt.Visible As Boolean
Betroffene Objekte
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
WhatsThisHelp- Eigenschaft
Objekt.WhatsThisHelp As Boolean
Betroffene Objekte
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
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
Verwandte Them en
...................................................
Transparenz und Drag&Drop (S. 606)
LinkExecute- Methode
Sub Objekt.LinkExecute (Command As String) As Boolean
Betroffene Objekte
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
...
Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)
LinkPoke- Methode
Sub Objekt.Poke()
Betroffene Objekte
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
Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)
LinkRequest- Methode
Sub Objekt.LinkRequest()
Gemeinsame Methoden
Betroffene Objekte
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
Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)
LinkSend- Methode
Sub Objekt.LinkSend()
Betroffene Objekte
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
Verwandte Them en
...................................................
DDE-Verbindungen (S. 495)
Move- Methode
Sub Objekt.Move(Left, [Top], [Width], [Height])
Betroffene Objekte
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
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
Verwandte Them en
...................................................
OLE-Drag&Drop (S. 501)
Refresh- Methode
Sub Objekt.Refresh()
Betroffene Objekte
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
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
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.
Verwandte Them en
...................................................
HelpContextID-Eigenschaft und WhatsThisHelpID-Eigenschaft (S. 353)
ZOrder- Methode
Sub Objekt.ZOrder([Position])
Betroffene Objekte
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.
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
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).
388
Standardsteuerelemente
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
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
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
Verwandte Steuerelemente
...................................................
Button, CheckBox, OptionButton
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
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
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
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
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
396
Bildfeld- Steuerelement (PictureBox)
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
...................................................
Verwandte S teuerelemente
Image, Form, RptImage, UserControl, UserDocument
Verwandte Themen
...................................................
Verwa ndte Them en
Formulare (S. 306)
3 97
Standardsteuerelemente
Standardsteuerelemente
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
...
3 99
Standardsteuerelemente
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)
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)
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
Verwandte Steuerelemente
...................................................
CommonDialog, DirListBox, DriveListBox, ListBox
Verwandte Themen
Verwandte Them en
...................................................
Listenfeld-Steuerelement (ListBox) (S. 412)
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)
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
Verwandte Steuerelemente
...................................................
Adodc, RemoteData
Standardsteuerelemente
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:
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)
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
Verwandte Steuerelemente
...................................................
Button, CommandButton, OptionButton
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
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)
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
Verwandte Steuerelemente
...................................................
ComboBox, CommonDialog, DirListBox, DriveListBox, ImageCombo, ListView
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
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
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
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)
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
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
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
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
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
430
Verzeichnislistenfeld- Steuerelement ( DirListBox)
Verwandte Steuerelemente
Verwandte Steuerelemente
...................................................
ComboBox, DataList, DBCombo, MaskEDBox, RichTextBox, RptTextBox
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
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
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
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)
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
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
43 5
ActiveX- Steuerelemente ( OCX) Windows- Standardsteuerelemente
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.
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
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
43 8
Weitere ActiveX- Steuerelemente
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:
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
43 9
Weitere ActiveX- Steuerelemente
440
Weitere ActiveX- Steuerelemente
441
Weitere ActiveX- Steuerelemente
Die vorliegende Ausgabe dieser Referenz stellt in der Folge nur die zwei sehr grundlegenden
ActiveX-Steuerelemente PictureClip und CommonDialog ausführlicher vor.
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
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
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
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
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
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
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
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.
453
Wie importiert man den Quelltext?
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.
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.
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.
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
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
Damit das funktioniert, ist allerdings eine gewisse Vorbereitung notwendig: das Setzen einer
nichtproportionalen Schrift sowie geeigneter Formularabmessungen.
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.
460
Koordinatensystem und Grafikmodus
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
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
463
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
464
Zusammenfassung der Emulation als Standardmodul
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 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
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
466
Zusammenfassung der Emulation als Standardmodul
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
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)
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
468
Von WANKEL. BAS zur WankelAnimation
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
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
47 0
Von WANKEL. BAS zur WankelAnimation
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.
47 2
Die portierte Fassung
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
47 3
Von WANKEL. BAS zur WankelAnimation
47 4
Die portierte Fassung
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
478
ApfelmannZoom eine Fahrt durch die Mandelbrotmenge
479
ApfelmannZoom eine Fahrt durch die Mandelbrotmenge
ApfelmannZoom – eine Fahrt durch die Mandelbrotmenge
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
480
ApfelmannZoom eine Fahrt durch die Mandelbrotmenge
481
ApfelmannZoom eine Fahrt durch die Mandelbrotmenge
482
ApfelmannZoom eine Fahrt durch die Mandelbrotmenge
483
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.
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)
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
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
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
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.
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
'***********************************************************************
493
Ereignisbehandlung
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
494
DDE- Verbindungen
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.
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.
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
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
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
Exit Sub
StarteAnwendung:
MsgBox ("Fehler " & Err.Number & " " & Err.Description & vbCrLf & _
" Abhilfe: Weitere Instanz des Programms starten")
Exit Sub
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
502
OLE- Drag&Drop
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
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 ).
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
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
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
' 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
Then
Effect = vbDropEffectNone ' ablehnen,da OLE-Format unbekannt
End If
End Sub
508
OLE- Drag&Drop
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
'***********************************************************************
' 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
51 0
DiaProjektor SDI- Formulare synchronisieren
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
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
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
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
'***********************************************************************
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
51 5
DiaProjektor SDI- Formulare synchronisieren
'***********************************************************************
' Code für Menübefehle
'***********************************************************************
Private Sub mnuDateiErstes_Click()
mnuBildErstes_Click
End Sub
51 6
Das Programmdesign
StopTimer
51 7
DiaProjektor SDI- Formulare synchronisieren
FileNames(1) = dlgDateiOpen.FileTitle
bIndexView = True ' Einzeldiaansicht vorbereiten
End If
mnuTimer5.Enabled = bArrayNichtLeer
DiaIndex cNoCaching ' Bild(er) Anzeigen
Abbruch:
End Sub
51 8
Das Programmdesign
Mod UBound(FileNames) + 1
End If
Anzeigen cCaching
End Sub
'***********************************************************************
' Code für Hilfsroutinen
'***********************************************************************
51 9
DiaProjektor SDI- Formulare synchronisieren
Timer1.Enabled = False
Timer1.Enabled = True
End If
End Sub
mnuDateiTimer3.Checked = False
mnuDateiTimer5.Checked = False
mnuTimer3.Enabled = False
mnuTimer5.Enabled = False
mnuDateiTimer3.Enabled = False
mnuDateiTimer5.Enabled = False
End Sub
520
Das Programmdesign
Fehlerbehandlung:
Dim Text As String
With Ansicht
If Not bIndexView Then
Text = "Bildformat nicht erkannt"
' Fehlertext mittig ausgeben
.Cls
' 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
' 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
521
DiaProjektor SDI- Formulare synchronisieren
With Ansicht
' Vorbereitungen
statCount = (statCount + 1) Mod 10000 ' stat. Rekursionsz. pflegen
dynCount = statCount ' dyn. Rekursionszähler init.
522
Das Programmdesign
' 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
523
DiaProjektor SDI- Formulare synchronisieren
& FileNames(FileIndex)
Else
ShowDia FileIndex, ActualForm ' Einzeldiaansicht
End If
End Sub
524
Info- Dialog als gebundenes Formular aufrufen
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.
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
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
527
DiaProjektor SDI- Formulare synchronisieren
ReDim FileNames(0 To 1)
FileNames(1) = dlgDateiOpen.FileTitle
bIndexView = True ' Einzeldiaansicht vorbereiten
End If
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
' 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
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.
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
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
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
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.
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
With Ansicht
' Vorbereitungen
statCount = (statCount + 1) Mod 10000 ' stat. Rekursionsz. pflegen
dynCount = statCount ' dyn. Rekursionszähler init.
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
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.
535
DiaProjektor SDI- Formulare synchronisieren
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
537
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
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.
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
540
Menü und Kontextmenü
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
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
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.
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
543
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
End Sub
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.
545
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
546
Bildlauf ein kleiner Betrachter für große Bilder
547
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
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 _
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
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
551
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen
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
552
HexView eine schnelle Textansicht für große Dateien
Lines = cLines
mnuDateiÖffnen_Click
End Sub
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
554
HexView eine schnelle Textansicht für große Dateien
555
Bildlaufleisten für Ansichten einsetzen und auf Größenänderungen reagieren
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
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
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
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
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
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
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
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\
561
Registrierung
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
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
563
Registrierung
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.
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.
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).
568
Ring eine einfache Klasse demonstriert Grundlegendes
569
Klassen selbst definieren
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.
570
Ring eine einfache Klasse demonstriert Grundlegendes
57 1
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
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.
r = 5
End Sub
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
575
Klassen selbst definieren
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
576
3DAnimation Drahtgittermodelle frei im Raum gedreht
add = a + b
End Function
57 7
Klassen selbst definieren
Klassen selbst definieren
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.
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:
−
−
−
Für die Multiplikation zweier Matrizen M und N gilt die Formel:
=∑
⋅
=∑
⋅
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
57 9
Klassen selbst definieren
580
3 DAnimation Drahtgittermodelle frei im Raum gedreht
m(2, 2) = Cos(Degrees)
RotXYZ m
End Sub
' Initialisierungscode
Private Sub Class_Initialize()
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
Option Explicit
' Repräsentation
Public x As Double
Public y As Double
Public z As Double
582
Point3D ein Punkt im Raum
Set Value = Me
End Property
583
Klassen selbst definieren
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.
' 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
586
Line3D eine Linie aus zwei Punkten
' Erzeugt eine Kopie des Objekts und liefert Referenz darauf
Public Function Clone() As Line3D
Set Clone = New Line3D
Clone = Me
End Function
587
Klassen selbst definieren
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
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.
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
590
Line3 D eine Linie aus zwei Punkten
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
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
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.
593
Klassen selbst definieren
Dim c As Control
ShowControls False
' 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
End Sub
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
' 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)
' 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
o.Draw Me
SetTimer True
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.
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.
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
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
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)
TriggerTime = m_TriggerTime
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
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
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
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
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
604
LongTimer der Timer mit Ausdauer
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
LongInterval = PropBag.ReadProperty("LongInterval", 0)
End Sub
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
607
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
Option Explicit
Private bSchwarzUnten As Boolean
Const FeldBreite = 55
Const FigurBreite = 51
Const FigurHöhe = 51
Const Pfad = "Schach\"
609
ActiveX- Steuerelemente und Benutzersteuerelemente
' 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
61 1
ActiveX- Steuerelemente und Benutzersteuerelemente
bSchwarzUnten = True
mnuAufstellenGrundstellung_Click
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
61 3
ActiveX- Steuerelemente und Benutzersteuerelemente
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
61 4
MemoryEdit das Textfeld mit Gedächtnis
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
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
Auswahl der für SendMessage erforderlic hen API- Deklarationen im API- Viewer
61 7
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
61 8
MemoryEdit das Textfeld mit Gedächtnis
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).
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
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.
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.
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.
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
624
MemoryEdit das Textfeld mit Gedächtnis
625
ActiveX- Steuerelemente und Benutzersteuerelemente
626
MemoryEdit das Textfeld mit Gedächtnis
627
ActiveX- Steuerelemente und Benutzersteuerelemente
PropertyChanged "BorderStyle"
End Property
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
629
ActiveX- Steuerelemente und Benutzersteuerelemente
FontStrikethru = Text1.FontStrikethru
End Property
'MappingInfo=Text1,Text1,-1,FontUnderline
Public Property Get FontUnderline() As Boolean
FontUnderline = Text1.FontUnderline
End Property
63 0
MemoryEdit das Textfeld mit Gedächtnis
63 1
ActiveX- Steuerelemente und Benutzersteuerelemente
End Property
63 2
MemoryEdit das Textfeld mit Gedächtnis
633
ActiveX- Steuerelemente und Benutzersteuerelemente
63 4
MemoryEdit das Textfeld mit Gedächtnis
635
ActiveX- Steuerelemente und Benutzersteuerelemente
End Property
63 6
MemoryEdit das Textfeld mit Gedächtnis
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)
...
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.
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
641
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
642
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
643
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
644
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
645
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
647
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
649
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
650
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
651
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
652
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
653
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
655
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
656
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
657
Kurzreferenz der Schlüsselwörter mit Vergleich zu QBasic
658
Tabellenindex
659
Tabellenindex
660
Tabellenindex
661
Tabellenindex
662
Tabellenindex
663
Tabellenindex
664
Tabellenindex
665
Tabellenindex
666
Tabellenindex
667
Tabellenindex
668
Tabellenindex
669
Tabellenindex
670
Tabellenindex
67 1
Tabellenindex
672
Tabellenindex
67 3
Tabellenindex
674
Tabellenindex
675
Tabellenindex
676
Tabellenindex
677
Tabellenindex
678
Tabellenindex
679