Ein VBA-Programm in Excel
Ein VBA-Programm in Excel
Ein VBA-Programm in Excel
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Inhaltsverzeichnis<br />
1 Vorwort .................................................................................................................................. 3<br />
1.1 Wie alles begann ........................................................................................................ 3<br />
1.2 Was leistet das <strong>Programm</strong> ......................................................................................... 4<br />
1.3 Inhalt und Ziele der Ausarbeitung .............................................................................. 5<br />
1.4 <strong>Programm</strong>-Umgebung ............................................................................................... 6<br />
1.5 Weitere (persönliche) Anmerkungen ......................................................................... 6<br />
2 Das <strong>Programm</strong> ...................................................................................................................... 6<br />
2.1 Grundsätzliches zur <strong>Programm</strong>ierung <strong>in</strong> <strong>VBA</strong> ............................................................ 6<br />
2.1.1 Variablendeklarationen ......................................................................................... 6<br />
2.1.2 Makros ................................................................................................................... 8<br />
2.1.3 Unterprogrammtechnik ....................................................................................... 10<br />
2.1.4 Objekte, Eigenschaften und Methoden ............................................................... 10<br />
2.1.4.1 Objekte und ihre Hierarchie ........................................................................ 11<br />
2.1.4.2 Eigenschaften ............................................................................................. 13<br />
2.1.4.3 Methoden ................................................................................................... 13<br />
2.2 Die Gäste kommen ................................................................................................... 14<br />
2.3 Die Entwicklungsumgebung von <strong>VBA</strong> ...................................................................... 16<br />
2.4 Ereignisse <strong>in</strong> <strong>VBA</strong> ...................................................................................................... 17<br />
2.5 Der Kern des <strong>Programm</strong>s: die Auslosung ................................................................. 20<br />
2.5.1 Eigene Dialoge entwerfen und programmieren................................................. 23<br />
2.5.2 Die neuen Tabellenblätter ................................................................................... 32<br />
2.5.2.1 Das Tabellenblatt "Liste" ........................................................................... 32<br />
2.5.2.2 Pro Durchgang je e<strong>in</strong> Tabellenblatt ............................................................ 33<br />
2.5.2.3 Das Tabellenblatt "Ergebnis" ...................................................................... 34<br />
2.5.3 Das Mischprogramm: wer kommt <strong>in</strong> welchem Durchgang an welchem Tisch an<br />
welchem Platz? ................................................................................................................. 36<br />
2.5.4 Zusatzfunktionen ................................................................................................. 41<br />
3 Ausblick/Nachbetrachtung ................................................................................................ 49<br />
3.1 Neuralgische Punkte ................................................................................................ 49<br />
3.2 Mögliche Weiterentwicklungen ............................................................................... 51<br />
4 Literatur- und Quellenverzeichnis ..................................................................................... 52<br />
2
1 Vorwort<br />
1.1 Wie alles begann<br />
Jedes Jahr zwischen Weihnachten und Silvester f<strong>in</strong>det bei me<strong>in</strong>em<br />
Schwager e<strong>in</strong> privates Doppelkopfturnier statt. Seit ca. 20 Jahren erfreut<br />
es sich e<strong>in</strong>er immer größeren Beliebtheit; es ist zur Tradition geworden.<br />
Die ersten Jahre fand das Turnier noch <strong>in</strong> e<strong>in</strong>em kle<strong>in</strong>en<br />
Rahmen – jeder kannte jeden – statt. In der Zwischenzeit hat es sich<br />
zu e<strong>in</strong>er Mammutveranstaltung ausgeweitet - das Turnier zählte im<br />
letzten Jahr genau 101 Teilnehmer. Da bei e<strong>in</strong>er Tischanzahl von maximal<br />
25 die räumlichen Kapazitäten restlos ausgeschöpft s<strong>in</strong>d, ist damit<br />
dann wohl auch das Ende der Fahnenstange erreicht. Die e<strong>in</strong>ladende<br />
Raumatmosphäre sowie die ausgezeichnete Organisation (als<br />
e<strong>in</strong> Beispiel sei nur die erstklassige Verpflegung mit Speisen und Getränken<br />
genannt) haben dafür gesorgt, dass sich der Teilnehmerkreis<br />
Jahr für Jahr erweitert hat. Dieser permanente Zuwachs an Teilnehmern<br />
hat aber auch dazu geführt, dass der manuelle Aufwand für die<br />
anfallenden Tätigkeiten - von der Auslosung über die Erfassung der<br />
Punktzahlen bis h<strong>in</strong> zur Auswertung der Spielergebnisse - immer größer<br />
wurde. Das wiederum veranlasste me<strong>in</strong>en Schwager als Ausrichter<br />
des Turniers nach möglichen Alternativen im PC-Bereich Ausschau zu<br />
halten, um diese manuellen Tätigkeiten durch Automatismen zu ersetzen.<br />
So kam es, dass er vor 10 Jahren auf mich zukam mit der Bitte,<br />
mir hierüber mal Gedanken zu machen.<br />
Als spontane Idee, per <strong>Programm</strong> e<strong>in</strong>e Verbesserung zu erzielen, fielen<br />
mir - wie konnte es auch anders se<strong>in</strong> - die Möglichkeiten von Microsoft<br />
<strong>Excel</strong> e<strong>in</strong>. Das, was mir dabei zunächst vorschwebte, war allerd<strong>in</strong>gs<br />
noch recht rudimentär. Der e<strong>in</strong>zige Fortschritt, den <strong>Excel</strong> mir <strong>in</strong> me<strong>in</strong>en<br />
ersten Überlegungen bot, schien dar<strong>in</strong> zu bestehen,<br />
‣ e<strong>in</strong>e Liste mit allen Teilnehmern zu erstellen,<br />
‣ diese Liste zu e<strong>in</strong>er Tabelle zu erweitern, <strong>in</strong>dem pro Durchgang e<strong>in</strong>e<br />
zusätzliche Spalte genutzt wurde, <strong>in</strong> der die Punktzahlen der<br />
Teilnehmer pro Durchgang e<strong>in</strong>getragen wurden,<br />
‣ um <strong>Excel</strong> danach diese Punktzahlen für jeden Teilnehmer addieren<br />
zu lassen,<br />
‣ und die Liste anschließend nach erreichter Gesamtpunktzahl zu<br />
sortieren.<br />
Nun hätte ich es natürlich auch dabei bewenden lassen können. Die<br />
Umsetzung <strong>in</strong> <strong>Excel</strong> wäre <strong>in</strong> wenigen M<strong>in</strong>uten fertig gewesen. Der<br />
größte Aufwand hätte wohl noch dar<strong>in</strong> bestanden, die Teilnehmerliste<br />
e<strong>in</strong>zutippen. Das kam mir aber alles e<strong>in</strong> bisschen "zu mager" vor. <strong>E<strong>in</strong></strong>e<br />
deutliche Verbesserung gegenüber Bleistift und Papier hätte das zudem<br />
auch nicht bedeutet.<br />
H<strong>in</strong>weis/Bemerkung 1<br />
Die gute Stimmung der Teilnehmer<br />
sorgt für e<strong>in</strong>e hohe<br />
Spendenbereitschaft. Das an<br />
den Tischen e<strong>in</strong>gespielte<br />
Geld wandert - neben zusätzlichen<br />
freiwilligen Beiträgen -<br />
als Spende <strong>in</strong> e<strong>in</strong>en geme<strong>in</strong>samen<br />
Topf und wird e<strong>in</strong>er<br />
geme<strong>in</strong>nützigen<br />
humanitären<br />
Organisation <strong>in</strong> Afrika<br />
zugeführt.<br />
3
Ich beschäftigte mich nun fortan <strong>in</strong>tensiver mit den Möglichkeiten von<br />
<strong>Excel</strong> und deren <strong>Programm</strong>iermöglichkeiten und kam letztendlich zu<br />
dem Entschluss, es nicht bei dieser e<strong>in</strong>fachen Liste bewenden zu lassen.<br />
Ich kannte zwar weder die <strong>VBA</strong>-Umgebung für <strong>Excel</strong> (<strong>VBA</strong> = Visual<br />
Basic for Applications), noch dessen Sprachkern Visual Basic,<br />
hatte aber zum<strong>in</strong>dest <strong>Programm</strong>iererfahrung <strong>in</strong> prozeduraler <strong>Programm</strong>iertechnik.<br />
Außerdem bot mir <strong>Excel</strong> ja bekanntermaßen die<br />
Möglichkeit, viele Tätigkeiten durch den <strong>E<strong>in</strong></strong>satz des Makrorekorders<br />
zu automatisieren. Der dabei erzeugte Quellcode der Makros half mir<br />
zudem beim <strong>E<strong>in</strong></strong>stig <strong>in</strong> <strong>VBA</strong>. Zusätzliche Literatur sowie Recherchen<br />
im Internet trugen zusätzlich dazu bei, mich recht schnell <strong>in</strong> der Umgebung<br />
zurechtzuf<strong>in</strong>den.<br />
Fortan machte ich mich an die Arbeit; herausgekommen ist dabei e<strong>in</strong><br />
komplettes Turnierprogramm, 2002 erstmalig erstellt und 2010 verbessert<br />
und um e<strong>in</strong>ige Funktionen erweitert. Das <strong>Programm</strong> wird mittlerweile<br />
nicht nur e<strong>in</strong>mal im Jahr bei dem besagten Turnier e<strong>in</strong>gesetzt,<br />
sondern auch immer dann, wenn im Freundes- und Bekanntenkreis<br />
e<strong>in</strong>e derartige Veranstaltung angesagt ist.<br />
1.2 Was leistet das <strong>Programm</strong><br />
Kurz zusammengefasst bietet das <strong>Programm</strong> folgende Funktionen:<br />
‣ Mischprogramm bei der Auslosung: die Teilnehmer bekommen per<br />
Zufallsgenerator e<strong>in</strong>en Tischplatz zugewiesen<br />
‣ Anzahl der Durchgänge sowie Anzahl der Runden pro Durchgang<br />
jeweils zwischen 1 und 10 frei wählbar<br />
‣ die Gesamtanzahl der Tische kann durch e<strong>in</strong>e vermehrte Anzahl an<br />
5er-Tischen reduziert werden (für den Fall, dass die Räumlichkeiten<br />
ke<strong>in</strong>e weiteren Tische mehr zulassen)<br />
‣ Generierung neuer <strong>Excel</strong>-Tabellenblätter nach der Auslosung:<br />
<br />
<br />
<br />
e<strong>in</strong>e alphabetisch sortierte Liste aller Teilnehmer zum Ausdrucken,<br />
aus der jeder für sich ablesen kann, <strong>in</strong> welchem Durchgang<br />
er an welchem Tisch an welchem Platz spielt<br />
pro Durchgang e<strong>in</strong> Tabellenblatt für die <strong>E<strong>in</strong></strong>tragung der erreichten<br />
Punktzahl pro Spieler; die Tische (mit ihren Teilnehmern)<br />
werden nach Tisch-Nr sortiert aufgelistet<br />
e<strong>in</strong> Ergebnis-Tabellenblatt mit e<strong>in</strong>er Liste aller Teilnehmer, <strong>in</strong><br />
der nach Spielende (oder auch schon früher, um Zwischenstände<br />
abzurufen) per Knopfdruck die Ergebnisse aus den e<strong>in</strong>zelnen<br />
Durchgängen übernommen werden<br />
4
‣ die Spielzettel s<strong>in</strong>d komplett vorformatiert und enthalten bereits die<br />
Namen der Spieler. Für den Ausdruck stehen zwei Varianten zur<br />
Auswahl:<br />
<br />
<br />
e<strong>in</strong>fache Version für den Privatgebrauch und<br />
offizielle Spielzettel-Version vom Deutschen Doppelkopf Verband<br />
für gehobene Ansprüche<br />
1.3 Inhalt und Ziele der Ausarbeitung<br />
Bei der vorliegenden Arbeit stehen die folgenden drei Aspekte im Vordergrund:<br />
‣ Darstellung der Bestandteile des Turnierprogramms<br />
‣ Kurze<strong>in</strong>weisung <strong>in</strong> <strong>VBA</strong><br />
‣ Workshop-Charakter<br />
Im Focus steht dabei natürlich die Absicht, die wesentlichen<br />
Bestandteile des <strong>Programm</strong>s vorzustellen, verbunden mit dem Ziel,<br />
deren Implementierung <strong>in</strong> <strong>VBA</strong> herauszuarbeiten. Auf e<strong>in</strong> komplettes<br />
Code-List<strong>in</strong>g wird allerd<strong>in</strong>gs verzichtet (e<strong>in</strong> Workshop soll auch e<strong>in</strong><br />
Workshop bleiben); bei Interesse kann es aber natürlich auf Anfrage<br />
(email: hehrenbr<strong>in</strong>k@yahoo.de) von mir bezogen werden.<br />
Denjenigen Lesern, die bisher noch ke<strong>in</strong>erlei Erfahrungen <strong>in</strong> <strong>VBA</strong> gesammelt<br />
haben, aber Interesse daran haben, das <strong>Programm</strong> nachzuvollziehen,<br />
soll der <strong>E<strong>in</strong></strong>stieg dadurch erleichtert werden, dass <strong>in</strong> groben Zügen<br />
die wesentlichen Sprachelemente und <strong>Programm</strong>iertechniken <strong>in</strong><br />
<strong>VBA</strong> vorgestellt werden, (Kapitel 2.1) und dass auch auf die Bedienung<br />
der Entwicklungsumgebung (Kapitel 2.3) sowie auf den <strong>E<strong>in</strong></strong>satz von<br />
Dialogtechniken (Kapitel 2.5.1) e<strong>in</strong>gegangen wird.<br />
Den Hauptteil dieser Abhandlung bildet zwangsläufig das Ma<strong>in</strong>-<br />
<strong>Programm</strong> Sub Auslosung(): Struktur und wesentliche Bestandteile<br />
werden thematisiert.<br />
Abschließend werden noch e<strong>in</strong>ige <strong>in</strong>teressante Zusatzfunktionen des<br />
<strong>Programm</strong>s vorgestellt.<br />
Der Intention e<strong>in</strong>es Workshops entsprechend, s<strong>in</strong>d für diejenigen Leser,<br />
die Interesse an dem <strong>Programm</strong> gefunden haben und sich mit der Materie<br />
vertraut machen wollen, am Ende e<strong>in</strong>iger Kapitel/Abschnitte e<strong>in</strong>ige<br />
Übungen (ohne Lösungen) e<strong>in</strong>gestreut.<br />
5
1.4 <strong>Programm</strong>-Umgebung<br />
Die erste Version des <strong>Programm</strong>s wurde von mir <strong>in</strong> VBE Office XP erstellt.<br />
Lauffähig war das <strong>Programm</strong> auch – ohne jegliche Anpassungen<br />
– <strong>in</strong> den Nachfolge-Versionen Office <strong>Excel</strong> 2003 und 2007. Unter Office<br />
<strong>Excel</strong> 2007 erfolgte im Jahr 2010 e<strong>in</strong>e Ergänzung/Verbesserung. Auf<br />
diese Office-Version beziehen sich auch alle <strong>in</strong> diesem Workshop verwendeten<br />
<strong>VBA</strong>-/<strong>Excel</strong>-Elemente.<br />
Als Betriebssystemumgebungen des Turnier-<strong>Programm</strong>s wurden bisher<br />
W<strong>in</strong>dows XP und Microsoft W<strong>in</strong>dows 7 Professional e<strong>in</strong>gesetzt.<br />
H<strong>in</strong>weis 2<br />
VBE (= Visual Basic Editor) ist<br />
das Entwicklertool der <strong>VBA</strong>-<br />
<strong>Programm</strong>ierung. Mit der<br />
Tastenkomb<strong>in</strong>ation<br />
gelangt man <strong>in</strong><br />
die Entwicklungsumgebung<br />
(und wieder zurück).<br />
1.5 Weitere (persönliche) Anmerkungen<br />
Wenn im Folgenden von "den Spielern" oder "den Teilnehmern" die<br />
Rede ist, so ist damit natürlich das weibliche Geschlecht implizit immer<br />
mit e<strong>in</strong>geschlossen. Würde ich stattdessen jedesmal von "den SpielerInnen"<br />
oder "den Spielern und Spieler<strong>in</strong>nen" bzw. von "den TeilnehmerInnen"<br />
oder "den Teilnehmern und Teilnehmer<strong>in</strong>nen" sprechen, so<br />
hätte darunter die Lesbarkeit des Dokumentes zu leiden. <strong>E<strong>in</strong></strong>e Diskrim<strong>in</strong>ierung<br />
des weiblichen Personenkreises bzgl. des Doppelkopfspiels<br />
liegt mir absolut fern.<br />
Zusätzlich sei noch angemerkt, dass alle Namen der <strong>in</strong> diesem Dokument<br />
erwähnten Personen frei erfunden s<strong>in</strong>d.<br />
2 Das <strong>Programm</strong><br />
2.1 Grundsätzliches zur <strong>Programm</strong>ierung <strong>in</strong> <strong>VBA</strong><br />
2.1.1 Variablendeklarationen<br />
<strong>E<strong>in</strong></strong>e Variablendeklaration beg<strong>in</strong>nt mit der Anweisung Dim, gefolgt von<br />
dem frei wählbaren Variablen-Namen. Danach gibt man mit dem<br />
Schlüsselwort As an, welchen Datentyp die Variable enthalten soll.<br />
Konstante Größen lassen sich noch e<strong>in</strong>facher deklarieren, da sie ke<strong>in</strong>en<br />
Datentyp besitzen. Statt mit der Anweisung Dim beg<strong>in</strong>nen sie mit<br />
Const.<br />
6
Möchte man e<strong>in</strong>en array anlegen, so geschieht das ebenfalls mit Dim,<br />
gefolgt von dem Variablennamen und anschließender Klammerung ().<br />
Damit lässt man sich aber die Dimensionierung und die Länge des<br />
arrays noch offen.<br />
Beispiele:<br />
Dim Zahl1 As Integer 'Integer-Variable namens Zahl<br />
Const Zahl2 = 10 'Speicherplatz Zahl2 mit festem Wert 10<br />
Dim Zahl() As Integer 'Integer-array ohne Dimension und ohne Länge<br />
Es gibt drei mögliche Gültigkeitsbereiche für e<strong>in</strong>e Variable:<br />
a) Wird die Variable nur <strong>in</strong>nerhalb e<strong>in</strong>er Prozedur benötigt, handelt es<br />
sich um e<strong>in</strong>e lokale Variable. Die Deklaration steht dann am Anfang<br />
e<strong>in</strong>er Prozedur.<br />
Sub Test()<br />
Dim Me<strong>in</strong>eVariable As Long<br />
gültig<br />
Anweisung<br />
...<br />
Anweisung<br />
End Sub<br />
'Me<strong>in</strong>eVariable ist nur <strong>in</strong>nerhalb der Prozedur Test()<br />
b) Wird die Variable <strong>in</strong> mehreren Prozeduren e<strong>in</strong>es Moduls benötigt, so<br />
muss sie als globale Variable am Anfang des Moduls deklariert werden<br />
mit Dim oder Private als Anweisung. Unter dem Begriff "Modul"<br />
muss man sich e<strong>in</strong>fach e<strong>in</strong>en Conta<strong>in</strong>er vorstellen, der Quellcode<br />
enthält – der Code muss ja schließlich irgendwo untergebracht se<strong>in</strong>. Je<br />
nachdem, wofür so e<strong>in</strong> Modul genutzt wird, wird unterschieden z.B.<br />
zwischen e<strong>in</strong>em Modul für Userformen (siehe 2.5.1 Eigene Dialoge entwerfen<br />
und programmieren) oder e<strong>in</strong>em Modul für e<strong>in</strong> Tabellenblatt<br />
(siehe 2.5 Der Kern des <strong>Programm</strong>s: die Auslosung) oder e<strong>in</strong>em Modul<br />
für die Ereignissteuerung (siehe 2.4 Ereignisse <strong>in</strong> VBE) oder ...<br />
Dim Me<strong>in</strong>eVariable As Long 'Me<strong>in</strong>eVariable ist auf Modulebene gültig<br />
Private Me<strong>in</strong>eVariable1 As Long 'ebenso Me<strong>in</strong>eVariable1<br />
Sub Test()<br />
Anweisung<br />
...<br />
Anweisung<br />
End Sub<br />
c) Soll die Variable auch <strong>in</strong> anderen Modulen des Projektes Gültigkeit<br />
haben, muss sie als öffentliche Variable mit Public deklariert werden.<br />
Public Me<strong>in</strong>eVariable As Long 'Me<strong>in</strong>eVariable ist im ganzen Projekt gültig<br />
Sub Test()<br />
Anweisung<br />
...<br />
Anweisung<br />
End Sub<br />
7
2.1.2 Makros<br />
Der e<strong>in</strong>fachste Weg, sich e<strong>in</strong>en ersten <strong>E<strong>in</strong></strong>blick <strong>in</strong> die <strong>VBA</strong>-<br />
<strong>Programm</strong>ierung zu verschaffen, ist der, dass man sich die Makro-<br />
<strong>Programm</strong>ierung e<strong>in</strong>mal näher anschaut.<br />
Im folgenden Beispiel wird per Makro-Recorder (Aufruf über<br />
"ENTWICKLERTOOLS/MAKRO AUFZEICHNEN") der Zellenbereich<br />
"A1:C2" mit Inhalt gefüllt:<br />
Abbildung 1<br />
Makro MwSt<br />
Die Schaltfläche Bearbeiten<br />
öffnet die Entwicklungsumgebung<br />
und man gelangt<br />
direkt <strong>in</strong> den Quellcode des<br />
Makros<br />
Das aufgezeichnete Makro lässt sich nun nachträglich weiter bearbeiten.<br />
Durch den Aufruf der Schaltfläche Bearbeiten ersche<strong>in</strong>t allerd<strong>in</strong>gs<br />
nicht mehr der Makro-Recorder, sondern man hat den <strong>VBA</strong>-Quellcode<br />
<strong>in</strong> der Entwicklungsumgebung vor sich. Für obiges Beispiel wurden folgende<br />
Zeilen generiert:<br />
Sub MwSt()<br />
Range("A1").Select<br />
ActiveCell.FormulaR1C1 = "MwSt"<br />
Range("B1").Select<br />
ActiveCell.FormulaR1C1 = "Brutto"<br />
Range("C1").Select<br />
ActiveCell.FormulaR1C1 = "Netto"<br />
Range("A2").Select<br />
ActiveCell.FormulaR1C1 = "0.19"<br />
Range("B2").Select<br />
ActiveCell.FormulaR1C1 = "50"<br />
Range("C2").Select<br />
ActiveCell.FormulaR1C1 = "=RC[-1]*(1+RC[-2])"<br />
Range("A1:C1").Select<br />
'Name des Makros<br />
'Netto-Berechnung <strong>in</strong><br />
Zelle C2<br />
List<strong>in</strong>g 1<br />
Makro MwSt<br />
Die <strong>in</strong> grün gehaltenen Bemerkungen<br />
s<strong>in</strong>d Kommentare<br />
8
2.1.3 Unterprogrammtechnik<br />
Um den <strong>Programm</strong>code <strong>in</strong> kle<strong>in</strong>e unabhängige und überschaubare <strong>E<strong>in</strong></strong>heiten<br />
zu unterteilen, stehen <strong>in</strong> <strong>VBA</strong> zwei Varianten zur Verfügung –<br />
Prozeduren und Funktionen.<br />
Prozeduren beg<strong>in</strong>nen, wie im vorherigen Beispiel e<strong>in</strong>es Makros zu sehen,<br />
immer mit Sub, gefolgt von dem Prozedurnamen, und enden immer<br />
mit End Sub.<br />
Sub Prozedurname [(Argumente)]<br />
Anweisung<br />
...<br />
Anweisung<br />
End Sub<br />
Die (optionalen) Argumente können Referenzen (nicht der Wert selber<br />
wird übergeben, sondern der Zeiger, also die Adresse im Arbeitsspeicher)<br />
oder Werte se<strong>in</strong>. Zudem kann ihnen der Datentyp mitgegeben<br />
werden.<br />
Beispiel:<br />
Sub TestProzedur (ByRef Argument1 As Integer, ByVal Argument2 As Long)<br />
Zeiger = Argument1<br />
Wert = Argument2<br />
End Sub<br />
Der Aufruf dieser Prozedur sieht dann entweder so aus:<br />
TestProzedur Parameter1, Parameter2 oder so:<br />
Call TestProzedur(Parameter1, Parameter2)<br />
Prozeduren können Aktionen unterschiedlicher Art ausführen, sie können<br />
aber ke<strong>in</strong>e Werte zurückgeben. Hierzu bedarf es e<strong>in</strong>er Funktion.<br />
Die Syntax e<strong>in</strong>er Funktion ist ähnlich wie bei e<strong>in</strong>er Sub: sie beg<strong>in</strong>nen<br />
mit Function und enden mit End Function:<br />
[Public] [Private] [Static] Function Funktionsname [(Argumente)] [As<br />
Typ]<br />
Anweisung<br />
...<br />
Anweisung<br />
End Function<br />
2.1.4 Objekte, Eigenschaften und Methoden<br />
An dieser Stelle möchte ich die Gelegenheit nutzen, herauszustellen,<br />
warum <strong>VBA</strong> für viele Anwendungen e<strong>in</strong>e gute Alternative zu den etab-<br />
10
lierten Sprachen wie etwa C++ oder Java ist. Hierfür gibt es i.w. zwei<br />
handfeste Gründe:<br />
‣ Zum e<strong>in</strong>en s<strong>in</strong>d es die Makros, die dem <strong>Programm</strong>ierer nicht nur<br />
viel Arbeit abnehmen können, sondern die auch – wie bereits erwähnt<br />
– die Möglichkeit bieten, sich der Skriptsprache <strong>VBA</strong> Schritt<br />
für Schritt zu nähern.<br />
‣ Der zweite Grund ist der, dass <strong>in</strong> vielen Anwendungen – wie z.B. <strong>in</strong><br />
diesem <strong>Programm</strong> – fast ausschließlich mit Tabellen gearbeitet<br />
wird. Da bietet e<strong>in</strong>e Tabellenverarbeitung wie <strong>Excel</strong>, die etwa die<br />
200 wichtigsten Objekte mit ihren Eigenschaften und Methoden für<br />
jedermann frei zugänglich macht, e<strong>in</strong>e ideale Plattform für eigene<br />
Entwicklungen. <strong>E<strong>in</strong></strong> Großteil der Arbeit, die bei der Software-<br />
Entwicklung anfällt, nämlich die Planung der Objekte (Tabellenblätter,<br />
Zellen etc.), ist bereits erledigt, bevor man überhaupt damit angefangen<br />
hat, da sie bereits vorhanden s<strong>in</strong>d und genutzt werden<br />
können.<br />
Nun aber zum Thema - Objekte, Eigenschaften und Methoden <strong>in</strong> <strong>VBA</strong>.<br />
Was verbirgt sich eigentlich h<strong>in</strong>ter diesen Begriffen und – noch wichtiger<br />
- wie kann man diese Bauste<strong>in</strong>e für sich nutzen? Für den <strong>in</strong> der Objektorientierung<br />
erfahrenen Entwickler s<strong>in</strong>d die Begrifflichkeiten natürlich<br />
klar, dennoch profitiert auch der unerfahrene <strong>Programm</strong>ierer<br />
von den folgenden Ausführungen, da er praktisch gar ke<strong>in</strong>e Klassen<br />
und Objekte selbst def<strong>in</strong>ieren muss, weil ja alle notwendigen Bauteile<br />
bereits vorhanden s<strong>in</strong>d.<br />
2.1.4.1 Objekte und ihre Hierarchie<br />
Da <strong>VBA</strong> e<strong>in</strong>e - zum<strong>in</strong>dest teilweise - objektorientierte <strong>Programm</strong>iersprache<br />
(fehlende Implementierungsvererbung) ist, lassen sich natürlich<br />
eigene Klassen def<strong>in</strong>ieren und somit eigene Objekte erstellen. In<br />
den allerhäufigsten Fällen (so auch <strong>in</strong> diesem <strong>Programm</strong>) s<strong>in</strong>d es jedoch<br />
die MS-Office eigenen Objekte mit ihren Eigenschaften und Methoden,<br />
die <strong>in</strong> der Anwendung zum <strong>E<strong>in</strong></strong>satz kommen. Sie sollen hier <strong>in</strong> Kurzform<br />
dargestellt werden.<br />
Zu den wichtigsten Objekten zählen:<br />
APPLICATION <strong>Excel</strong> selbst / <strong>Excel</strong> – Fenster<br />
WORKBOOK Die <strong>Excel</strong> – Arbeitsmappe<br />
WORKSHEET <strong>E<strong>in</strong></strong> Tabellenblatt<br />
RANGE<br />
Zellenbereich , bestehend aus e<strong>in</strong>er oder mehrerer<br />
Zellen<br />
11
Die Objekte stehen <strong>in</strong> hierarchischer Abhängigkeit zue<strong>in</strong>ander. Objekte<br />
höherer Stufe be<strong>in</strong>halten Objekte untergeordneter Stufe(n). Für o.g.<br />
Objekte gilt die Hierarchieordnung.<br />
Application<br />
Workbook<br />
Worksheet<br />
Range<br />
Die gesamte Objekthierarchie ist natürlich wesentlich komplizierter und<br />
umfangreicher. Für die <strong>Programm</strong>ierung ist es wichtig zu wissen, dass<br />
die Objekthierarchie nicht nur e<strong>in</strong> willkürliches Ordnungsschema ist.<br />
Die Kenntnis der festgelegten Position e<strong>in</strong>es Objektes <strong>in</strong> der Hierarchie<br />
ist nötig, um das Objekt zu referenzieren – darauf zuzugreifen.<br />
Beispiel: Worksheets(list).Range("A1").EntireColumn.ColumnWidth = 22<br />
Der Objektkatalog enthält e<strong>in</strong>e Übersicht aller <strong>Excel</strong>-Objekte, ihrer Eigenschaften<br />
und Methoden. So rufen Sie den Objektkatalog auf:<br />
1. Öffnen Sie den <strong>VBA</strong>-Editor über die Tastenkomb<strong>in</strong>ation <br />
.<br />
2. Drücken Sie die Taste , um den Objektkatalog aufzurufen.<br />
3. Stellen Sie <strong>in</strong> der oberen Auswahlliste den <strong>E<strong>in</strong></strong>trag <strong>Excel</strong> e<strong>in</strong>.<br />
H<strong>in</strong>weis 3<br />
In dem Tabellenblatt Liste<br />
(Const list = "Liste") wird für<br />
die Spalte der Zelle "A1" die<br />
Spaltenbreite auf den Wert<br />
22 gesetzt.<br />
Abbildung 2<br />
Der Objektkatalog<br />
12
2.1.4.2 Eigenschaften<br />
Eigenschaften s<strong>in</strong>d die Attribute, die das Objekt beschreiben. Sie legen<br />
z.B. fest, wie das Objekt aussieht, welche Farbe oder welchen Wert es<br />
hat, ob es sichtbar ist oder nicht, usw. Es gibt Eigenschaften, die lesbar<br />
und veränderbar s<strong>in</strong>d, z.B. Value (Wert) oder Name (Name), andere<br />
lassen sich nur abfragen, aber nicht verändern.<br />
Beispiel:<br />
Sp_Name = Worksheets(1).Range("M" & (Zuf_Nr(d, n))).Value<br />
2.1.4.3 Methoden<br />
Zu den Objekten gehören neben Eigenschaften auch METHODEN. Über<br />
Methoden lässt sich das Verhalten von Objekten steuern / verändern.<br />
<strong>E<strong>in</strong></strong>e Methode ist e<strong>in</strong>e Aktion, die e<strong>in</strong>e Operation auf e<strong>in</strong>em Objekt ausführen<br />
kann. Zu den am häufigsten benutzten Methoden gehören:<br />
‣ OPEN öffnet e<strong>in</strong>e Arbeitsmappe<br />
‣ CLOSE schließt e<strong>in</strong>e Arbeitsmappe (e<strong>in</strong> Workbook-Objekt)<br />
oder <strong>Excel</strong> (e<strong>in</strong> Application-Objekt).<br />
‣ CLEAR löscht e<strong>in</strong>en Zellbereich oder e<strong>in</strong> Diagramm.<br />
‣ ACTIVATE<br />
‣ SELECT<br />
aktiviert e<strong>in</strong> Objekt<br />
wählt e<strong>in</strong> Objekt aus<br />
H<strong>in</strong>weis 4<br />
Der Variablen Sp_Name wird<br />
der Wert zugewiesen, der<br />
sich <strong>in</strong> Spalte "M" <strong>in</strong> der Zeile<br />
Zuf_Nr(d, n) bef<strong>in</strong>det<br />
Für den <strong>E<strong>in</strong></strong>steiger ist es oft problematisch zwischen Eigenschaften und<br />
Methoden zu unterscheiden (<strong>in</strong>sbesondere wenn Methoden die gleichen<br />
Namen tragen wie beispielsweise Auflistungen). So s<strong>in</strong>d beispielsweise<br />
die beiden Anweisungen<br />
Assistant.Visible = true<br />
Assistant.Move 250,275<br />
zum<strong>in</strong>dest optisch sehr ähnlich. Es stellt sich die Frage - s<strong>in</strong>d Visible<br />
und Move Eigenschaften oder Methoden und wenn nicht, welches Element<br />
von beiden ist e<strong>in</strong>e Methode und welches e<strong>in</strong>e Eigenschaft. Die<br />
Antwort ist hier relativ e<strong>in</strong>fach: Bei Zuweisungen von Eigenschaften<br />
wird das Gleichheitszeichen benutzt, bei Methoden benutzt man (optionale)<br />
Parameter ohne Gleichheitszeichen.<br />
13
Füllen Sie den Tabellenbereich "A1:A10" mit beliebigen Zahlen. Markieren<br />
Sie e<strong>in</strong>ige Zellen dieses Bereiches mit der H<strong>in</strong>tergrundfarbe "Rot".<br />
Fügen Sie <strong>in</strong> der Entwicklungsumgebung e<strong>in</strong> neues Modul e<strong>in</strong>, <strong>in</strong>dem<br />
Sie im Projekt-Explorer mit der rechten Maustaste klicken und den<br />
Kontextmenübefehl EINFÜGEN/MODUL wählen.<br />
Übung 2<br />
Benutzerdef<strong>in</strong>ierte Funktion<br />
schreiben<br />
Schreiben Sie e<strong>in</strong>e Funktion Function SummeRoteZellen(Zelle<br />
As Range), die nur die Zellen mit roter H<strong>in</strong>tergrundfarbe addiert.<br />
H<strong>in</strong>weise:<br />
1) Setzen Sie als erstes die Anweisung Application.Volatile.<br />
Hierdurch wird bewirkt, dass die Funktion immer neu berechnet<br />
wird, wenn <strong>in</strong> e<strong>in</strong>er beliebigen Zelle des Tabellenblattes e<strong>in</strong>e Berechnung<br />
durchgeführt wird<br />
2) Um jede Zelle e<strong>in</strong>es Bereiches zu erreichen, verwenden Sie die<br />
for-Schleife: For Each Zelle In Zelle.Cells<br />
3) Addieren Sie nur dann, wenn die Zelle e<strong>in</strong>en numerischen Wert<br />
enthält: If IsNumeric(Zelle)<br />
4) Abfrage der H<strong>in</strong>tergrundfarbe e<strong>in</strong>er Zelle des Bereiches auf die<br />
Farbe "Rot" mit If Zelle.Interior.ColorIndex = 3<br />
5) Addition der Funktionswerte: SummeRoteZellen = Summe-<br />
RoteZellen + Zelle.Value<br />
6) Prüfen Sie die Funktion, <strong>in</strong>dem Sie <strong>in</strong> Zelle "A11" die Formel e<strong>in</strong>geben<br />
"=SummeRoteZellen(A1:A10)"<br />
2.2 Die Gäste kommen<br />
Nun wieder zurück zu unserem Doppelkopfturnierprogramm. Die Teilnehmer<br />
melden sich größtenteils vor dem Turnier telefonisch oder per<br />
Mail, so dass sie bereits vorab <strong>in</strong> e<strong>in</strong>er Liste im <strong>Programm</strong> (<strong>in</strong> Spalte<br />
"A") aufgenommen werden können (das gesamte <strong>Excel</strong>-Sheet besteht zu<br />
diesem Zeitpunkt lediglich aus e<strong>in</strong>em Tabellenblatt). Es genügt dann<br />
am Turnierabend nur e<strong>in</strong> Klick, um die betreffende Person real am Turnier<br />
teilnehmen zu lassen.<br />
14
Abbildung 3<br />
Die Teilnehmerliste <strong>in</strong> Spalte<br />
"F"<br />
Rechtsklick oder Doppelklick <strong>in</strong><br />
e<strong>in</strong>e Zelle der Spalte "B" oder<br />
"C" aktiviert das ereignisgesteuerte<br />
Makro<br />
Sub<br />
Worksheet_BeforeRightClick<br />
bzw.<br />
Sub<br />
Worksheet_BeforeRightClick (s.<br />
2.4)<br />
H<strong>in</strong>weis 5<br />
Die "Häkchen" <strong>in</strong> Spalte B und<br />
C werden erzeugt mit dem<br />
Zeichen "ü" (= Chr (252)) <strong>in</strong> der<br />
Schriftart W<strong>in</strong>gd<strong>in</strong>gs (siehe<br />
auch List<strong>in</strong>g 2)<br />
Dieser Tabellenausschnitt macht deutlich, wie die Teilnehmerliste realisiert<br />
wird. In Spalte "A" können bereits vor Turnierbeg<strong>in</strong>n die Namen<br />
der möglichen Teilnehmer, sofern bekannt, e<strong>in</strong>getragen werden. Es genügt<br />
dann nur noch e<strong>in</strong> Doppelklick (oder Rechtsklick) <strong>in</strong> Spalte "B" (=<br />
bezahlt) oder "C" (= anwesend), um die betreffende Person <strong>in</strong> die tatsächliche<br />
Teilnehmerliste (Spalte "F") aufzunehmen. Die Teilnehmer<br />
werden mit e<strong>in</strong>er Spieler-Nummer (Spalte "E") versehen, welche aber<br />
im weiteren Verlauf des Turniers seitens des Teilnehmers nicht benötigt<br />
wird; die Spieler-Nr dient lediglich programm<strong>in</strong>ternen Zwecken (s. 2.4<br />
Ereignisse <strong>in</strong> <strong>VBA</strong>).<br />
Die programmtechnische Umsetzung dieses Vorgangs - die Erstellung<br />
der Spielerliste <strong>in</strong> Spalte "F" - muss noch e<strong>in</strong> wenig warten (2.4 Ereignisse<br />
<strong>in</strong> <strong>VBA</strong>).<br />
Vielmehr soll für all diejenigen, die bisher noch ke<strong>in</strong>erlei <strong>VBA</strong>-<br />
Erfahrung besitzen, im Folgenden e<strong>in</strong>e weitere kurze <strong>E<strong>in</strong></strong>führung <strong>in</strong><br />
<strong>VBA</strong> und der Entwicklungsumgebung gegeben werden.<br />
15
Der Projekt-Explorer: er enthält – hierarchisch gegliedert – alle Objekte,<br />
die zum <strong>VBA</strong>-Projekt "DokoTurnier.xlsx" gehören.<br />
Das Eigenschaftenfenster: <strong>in</strong> ihm werden alle Eigenschaften des ausgewählten<br />
Steuerelements angezeigt - <strong>in</strong> obiger Abbildung die Eigenschaften<br />
der Tabelle3. In der l<strong>in</strong>ken Spalte dieses Fensters steht der Name<br />
der Eigenschaft und <strong>in</strong> der rechten Spalte der zugehörige aktuelle Wert.<br />
Diese Werte können, wie wir bei den Steuerelementen von Formularen<br />
noch sehen werden, den eigenen Bedürfnissen angepasst werden, und<br />
zwar entweder durch das Überschreiben im Eigenschaftenfenster selbst<br />
oder aber per Quellcode-<strong>Programm</strong>ierung.<br />
Das Code-Fenster: <strong>in</strong> diesem Fenster (meistens werden mehrere gleichzeitig<br />
bearbeitet) bef<strong>in</strong>det sich der Quelltext des <strong>Programm</strong>s aus dem<br />
betreffenden Modul. Wie bereits <strong>in</strong> obigem Beispiel gesehen, ist der<br />
Makro-Recorder - <strong>in</strong>sbesondere für den <strong>VBA</strong>-Neul<strong>in</strong>g - e<strong>in</strong>e sehr gute<br />
Hilfe bei der Generierung des List<strong>in</strong>gs. Ohne jegliche VB-Kenntnisse zu<br />
besitzen, kann man sich so auf e<strong>in</strong>fache und schnelle Art und Weise e<strong>in</strong>en<br />
ersten Überblick über die gängigen Befehle verschaffen.<br />
Für darüber h<strong>in</strong>ausgehende Anpassungen s<strong>in</strong>d dann natürlich tiefergehende<br />
VB/<strong>VBA</strong>-Kenntnisse notwendig. Die wichtigsten Elemente hatte<br />
ich bereits <strong>in</strong> Kapitel 2.1 Grundsätzliches zur <strong>Programm</strong>ierung <strong>in</strong> <strong>VBA</strong><br />
vorgestellt. Ich halte es allerd<strong>in</strong>gs für unverhältnismäßig, im Rahmen<br />
dieses Workshops noch tiefer <strong>in</strong> diese Materie e<strong>in</strong>zusteigen. Für formale<br />
Elemente wie Datentypen, Variablen sowie sprachliche Konstrukte wie<br />
Schleifen, Verzweigungen etc. verweise ich zum e<strong>in</strong>en auf Onl<strong>in</strong>e-<br />
Recherchen im Internet sowie natürlich auf die <strong>in</strong> ausreichendem Maße<br />
vorhandene Literatur zur <strong>Excel</strong>-<strong>VBA</strong>-<strong>Programm</strong>ierung an. Nicht zuletzt<br />
können auch die List<strong>in</strong>gs hierzu e<strong>in</strong>en guten Beitrag leisten.<br />
2.4 Ereignisse <strong>in</strong> <strong>VBA</strong><br />
Nun aber wie versprochen zur Realisierung der Teilnehmerliste <strong>in</strong> <strong>VBA</strong>.<br />
Benötigt wird zu diesem Zweck e<strong>in</strong> bstimmtes technisches Hilfsmittel,<br />
und zwar die ereignisgesteuerte <strong>E<strong>in</strong></strong>gabemöglichkeit, z.B. per Rechtsklick<br />
(Sub Worksheet_BeforeRightClick) oder per Doppelklick (Sub<br />
Worksheet_BeforeDoubleClick). Diese beiden Funktionen überwachen<br />
die betreffenden Mausklicks und es lassen sich die gewünschten Aktionen<br />
mit ihnen verb<strong>in</strong>den. Schauen wir uns beispielhaft e<strong>in</strong>mal den<br />
Worksheet_BeforeDoubleClick an (die Tastenkomb<strong>in</strong>ation für die Entwicklungsumgebung<br />
ist uns nun bereits geläufig: < F11>):<br />
17
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel<br />
As Boolean)<br />
Cancel = True<br />
Dim rng As Range<br />
If Intersect(Target, Worksheets(1).Range("B:C")) Is Noth<strong>in</strong>g Then<br />
Exit Sub<br />
If Target.Row = 1 Then Exit Sub<br />
If Target.Column = 2 Then<br />
If Target.Interior.ColorIndex = 4 Then<br />
'Color 4 = Farbe Grün<br />
Cells(Target.Offset(0, 2) + 1, 6) = "" 'Sp-Name löschen<br />
Cells(Target.Offset(0, 2) + 1, 5) = "" 'Sp-Nr löschen<br />
Target.Offset(0, 2).Value = ""<br />
'Nr <strong>in</strong> Spalte D löschen<br />
Target.Interior.ColorIndex = 0<br />
'Farbe zurücksetzen<br />
Target.Offset(0, 1).Interior.ColorIndex = 0<br />
Target.Offset(0, 1).Value = ""<br />
Target.Value = ""<br />
Range("I8").Value = Range("I8").Value - 1 'Anzahl Spieler<br />
Range("I9").Value = Range("I8").Value \ 4 'Anzahl Tische<br />
Range("I10").Value = Range("I8").Value Mod 4 'Anzahl 5er-Tische<br />
Else<br />
'<strong>in</strong> Liste aufnehmen<br />
If Target.Offset(0, 2) "" Then<br />
Target.Interior.ColorIndex = 4<br />
Target.Value = Chr(252)<br />
Exit Sub<br />
Else<br />
If Target.Offset(0, -1).Value = "" Then<br />
Exit Sub<br />
End If<br />
End If<br />
For Each rng In Worksheets(1).Range("F:F").Cells<br />
If IsEmpty(rng) Then<br />
lz = rng.Row<br />
rng = Target.Offset(0, -1).Value<br />
Target.Offset(0, 2).Value = lz - 1<br />
Cells(lz, 5).Value = lz - 1<br />
Target.Value = Chr(252)<br />
Target.Offset(0, 1).Value = Chr(252)<br />
Target.Interior.ColorIndex = 4<br />
Target.Offset(0, 1).Interior.ColorIndex = 4<br />
Range("I8").Value = Range("I8").Value + 1<br />
'erste freie Zelle <strong>in</strong><br />
Spalte "F"<br />
'Anzahl Spieler<br />
'Anzahl Tische<br />
Range("I9").Value = Range("I8").Value \ 4<br />
Range("I10").Value = Range("I8").Value Mod 4 'Anzahl<br />
5er-Tische<br />
End<br />
End If<br />
Next rng<br />
End If<br />
List<strong>in</strong>g 2<br />
Sub<br />
Worksheet_BeforeDouble<br />
Click(ByVal Target As<br />
Range, Cancel As<br />
Boolean)<br />
Abfrage e<strong>in</strong>er angeklickten<br />
Zelle <strong>in</strong> Spalte "B" auf Farbh<strong>in</strong>tergrund:<br />
falls grün (ColorIndex=4),<br />
dann Teilnehmer aus Liste <strong>in</strong><br />
Spalte "F"<br />
löschen, sonst<br />
Spieler neu <strong>in</strong> Spalte "F"<br />
aufnehmen<br />
Zu diesem List<strong>in</strong>g bedarf es nun e<strong>in</strong>iger Erläuterungen.<br />
Mit der Methode Intersect wird sichergestellt, dass nur dann weitere<br />
Aktionen stattf<strong>in</strong>den, wenn sich die aktuell markierte Zelle im Zielbereich<br />
Range("B:C") bef<strong>in</strong>det. Auch der Doppelklick <strong>in</strong> die 1. Zeile Target.Row<br />
= 1 soll ke<strong>in</strong>e weitere Aktion nach sich ziehen.<br />
Was passiert nun aber, wenn <strong>in</strong> Spalte "B" oder "C" e<strong>in</strong>e Zelle angeklickt<br />
wird? Der <strong>E<strong>in</strong></strong>fachheit halber soll hier nur das Vorgehen für die Spalte<br />
"B" (= bezahlt) erläutert werden: If Target.Column = 2 . Die Codierung<br />
für Spalte "C" (= anwesend") kann als Übung (s. Übung 3) dienen.<br />
18
Wird nun beispielsweise die Zelle "B88" rechtsgeklickt und ist die Zelle<br />
"A88" leer, so ist wiederum nichts zu tun: If Target.Offset(0, -1).Value =<br />
"" Then Exit Sub. Gibt es aber <strong>in</strong> Zelle "A88" e<strong>in</strong>en Teilnehmere<strong>in</strong>trag,<br />
so müssen zwei Fälle unterschieden werden: entweder die Zelle "B88"<br />
ist bereits mit e<strong>in</strong>em Häkchen markiert und mit grüner H<strong>in</strong>tergrundfarbe<br />
versehen, d.h. der Teilnehmer ist bereits aufgenommen und soll<br />
jetzt wieder gelöscht werden, oder die Zelle ist nicht markiert und der<br />
Teilnehmer aus "A88" muss noch <strong>in</strong> die Teilnehmerliste, also <strong>in</strong> Spalte<br />
"F" aufgenommen werden.<br />
Fall A: <strong>E<strong>in</strong></strong> Teilnehmer wird neu aufgenommen, Beispiel "Tanja Evers"<br />
durch Doppelklick <strong>in</strong> "B13"<br />
Es wird zunächst nach der ersten freien Zelle <strong>in</strong> Spalte "F" Ausschau<br />
gehalten For Each rng In Worksheets(1).Range("F:F").Cells If IsEmpty(rng)<br />
und die entsprechende Zeilennummer <strong>in</strong> der Variablen lz (steht<br />
für leerzelle) gespeichert lz = rng.Row. Der Spielername "Tanja Evers"<br />
wird aus "A13" <strong>in</strong> der Variablen rng zwischengespeichert rng = Target.Offset(0,<br />
-1).Value, und die - nur <strong>in</strong>tern vorgehaltene - Spielernummer<br />
<strong>in</strong> der Zelle "D13" (nicht sichtbar im Tabellenblatt, da für den Anwender<br />
ohne Belang) gemerkt (Target.Offset(0, 2).Value = lz - 1), um<br />
die Möglichkeit e<strong>in</strong>es Löschvorgangs nicht zu verbauen. Anschließend<br />
werden lediglich noch die Zellen "B13" und "C13" mit e<strong>in</strong>em Häkchen<br />
Target.Value = Chr(252) sowie der grünen Füllfarbe Target.Interior.ColorIndex<br />
= 4 versehen und es werden e<strong>in</strong>ige weitere Zellen<br />
("I8", "I9" und "I10" für die spätere Auslosung bereits mit Werten<br />
gefüllt, und zwar enthalten<br />
‣ "I8" die Anzahl der Spieler (bisherigen Wert um 1 erhöhen)<br />
Range("I8").Value = Range("I8").Value + 1<br />
‣ "I9" die Anzahl der benötigten Tische (= Anzahl der Spieler dividiert<br />
durch 4 als Integer-Wert)<br />
Range("I9").Value = Range("I8").Value \ 4<br />
‣ "I10" die Anzahl der benötigten 5er Tische (als Restwert der Division<br />
durch 4)<br />
Range("I10").Value = Range("I8").Value Mod 4<br />
H<strong>in</strong>weis 6<br />
Chr (252) entspricht dem<br />
Zeichen "ü" und liefert <strong>in</strong> der<br />
Schriftart W<strong>in</strong>gd<strong>in</strong>gs das<br />
Häkchen<br />
Fall B: <strong>E<strong>in</strong></strong> bereits aufgenommener Teilnehmer wird wieder aus der<br />
Liste entfernt, Beispiel "Gerd Förster" (etwa weil man sich "verklickt"<br />
hat)<br />
In diesem Fall ist die Zelle "B18" grün markiert: If Target.Interior.ColorIndex<br />
= 4. Der Spieler muss nun wieder aus der Liste<br />
<strong>in</strong> Spalte "F" gelöscht werden.<br />
19
Die Zeile, <strong>in</strong> der er <strong>in</strong> Spalte "F" e<strong>in</strong>getragen wurde, ist leicht wieder<br />
auff<strong>in</strong>dbar, da die Spieler-Nummer <strong>in</strong> "D13" zwischengespeichert wurde:<br />
Offset(0, 2). Der Löschvorgang wird ausgelöst über die Anweisung<br />
Cells(Target.Offset(0, 2) + 1, 6) = "", also das Löschen derjenigen Zelle,<br />
dessen Zeile um den Wert 1 erhöht <strong>in</strong> "D13" steht und dessen Spalte<br />
gleich 6 ist. Ebenso muss die <strong>in</strong> "C13" vorgenommene Markierung wieder<br />
entfernt werden, und es muss die Anzahl der Spieler, die Anzahl der<br />
Tische und die Anzahl der 5er-Tische korrigiert werden.<br />
Vervollständigen Sie den Quellcode für den Doppelklick auf e<strong>in</strong> Zelle<br />
<strong>in</strong> Spalte "C".<br />
Übung 3<br />
Ereignissteuerung<br />
2.5 Der Kern des <strong>Programm</strong>s: die Auslosung<br />
Nachdem sich die Teilnehmer angemeldet haben und <strong>in</strong> die Spielerliste<br />
<strong>in</strong> Spalte "F" aufgenommen wurden, erfolgt die<br />
Auslosung, d.h. die Zuordnung der e<strong>in</strong>zelnen<br />
Spieler zu den Spieltischen. Hierfür steht im<br />
Tabellenblatt Auslosung e<strong>in</strong> Button mit dem Text Auslosung starten<br />
bereit (erstellen lässt er sich über die Menüleiste mit<br />
ENTWICKLERTOOLS, EINFÜGEN aus der Gruppe<br />
STEUERELEMENTE, Element BEFEHLSSCHALTFLÄCHE). <strong>E<strong>in</strong></strong><br />
Klick auf diesen Button startet das Ma<strong>in</strong>-<strong>Programm</strong> Sub Auslosung() im<br />
Modul des Tabellenblattes Auslosung.<br />
An dieser Stelle ist nun der Zeitpunkt gekommen, den Aufbau und die<br />
wesentlichen Bestandteile des Auslosungsprogramms zunächst e<strong>in</strong>mal<br />
<strong>in</strong> groben Zügen vorzustellen, um anschließend <strong>in</strong> den Kapiteln 2.5.1 bis<br />
2.5.3 auf die e<strong>in</strong>zelnen Teile näher e<strong>in</strong>zugehen.<br />
Zu Beg<strong>in</strong>n des <strong>Programm</strong>s Sub Auslosung() sollen vom Anwender über<br />
e<strong>in</strong>en Dialog (s. Abbildung 5, Seite 22) die Startparameter "Anzahl der<br />
Durchgänge" und "Anzahl der Runden pro Durchgang" festgelegt werden.<br />
Anschließend besteht die wesentliche Aufgabe des <strong>Programm</strong>s dar<strong>in</strong><br />
‣ e<strong>in</strong> Tabellenblatt Liste zu erstellen, aus der hervorgeht, wer <strong>in</strong> welchem<br />
Durchgang an welchem Tisch mit welcher Platz-Nr teilnimmt<br />
(s. 2.5.2.1 Das Tabellenblatt "Liste")<br />
‣ pro Durchgang e<strong>in</strong> Tabellenblatt für die <strong>E<strong>in</strong></strong>gabe der erreichten<br />
Punkte zu erstellen (s. 2.5.2.2 Pro Durchgang je e<strong>in</strong> Tabellenblatt)<br />
20
‣ den Teilnehmern per Mischprogramm e<strong>in</strong>en Platz an e<strong>in</strong>em Tisch<br />
zuzuweisen: Sub Tischzuweisung() (s. 2.5.3 Das Mischprogramm)<br />
‣ e<strong>in</strong> Tabellenblatt Ergebnis mit e<strong>in</strong>er sortierten Rangfolge der Teilnehmer<br />
zu erzeugen: Sub ergebnis() (s. 2.5.2.3 Das Tabellenblatt "Ergebnis")<br />
Diese vier Aspekte werden – wie erwähnt - ausführlich als <strong>E<strong>in</strong></strong>zelthemen<br />
<strong>in</strong> den genannten Abschnitten gesondert behandelt.<br />
Um mit dem Ma<strong>in</strong>-<strong>Programm</strong> vertraut zu werden, werfen wir zunächst<br />
e<strong>in</strong>en Blick<br />
a) auf die global def<strong>in</strong>ierten Variablen und<br />
b) auf die <strong>E<strong>in</strong></strong>gabemaske für die Startparameter<br />
Zu a) Die global def<strong>in</strong>ierten Variablen und Konstanten stehen ganz am<br />
Anfang des Moduls (Modul des Tabellenblattes Auslosung) und s<strong>in</strong>d<br />
für alle <strong>in</strong> diesem Modul e<strong>in</strong>gesetzten Prozeduren verfügbar.<br />
Const MaxAnzDg = 10<br />
Const MaxAnzRd = 10<br />
Const ZeilBeg = 3<br />
Const SpBeg = 2<br />
Const HGrFaSp = 6<br />
Const HGrFaTi = 32<br />
Const list = "Liste"<br />
Const dg = "Durchgang"<br />
Const erg = "Ergebnis"<br />
Const wf4e = "Wert-Form4e"<br />
Const wf4v = "Wert-Form4v"<br />
Const wf5e = "Wert-Form5e"<br />
Const wf5v = "Wert-Form5v"<br />
Const AnzTiProBlock = 4<br />
'maximale Anzahl Durchgänge<br />
'maximale Anzahl Runden pro Durchgang<br />
'<strong>in</strong> den Durchgangsblättern beg<strong>in</strong>nen<br />
die Tischüberschriften ab Zeile 3<br />
'und Spalte B<br />
'H<strong>in</strong>tergrundfarbe <strong>in</strong> SpielerZelle<br />
(Durchgangs-Tabelle)<br />
'H<strong>in</strong>tergrundfarbe <strong>in</strong> TischüberschriftZelle<br />
(Durchgangs-Tabelle)<br />
'Name des Tabellenblattes "Liste"<br />
'Name für Durchgangs-Tabellenblätter<br />
'Name des Tabellenblattes "Ergebnis"<br />
'Name der Tabellenblätter für die<br />
Standard-Spielzettel mit 4 Spielern<br />
'Name der Tabellenblätter für die<br />
DDV-Spielzettel mit 4 Spielern<br />
'Name der Tabellenblätter für die<br />
Standard-Spielzettel mit 5 Spielern<br />
'Name der Tabellenblätter für die<br />
DDV-Spielzettel mit 5 Spielern<br />
'Anzahl Tische im 16-er Block<br />
List<strong>in</strong>g 3<br />
Globale <strong>Programm</strong>-Variable<br />
des Auslosungsprogramms<br />
Public Anz_Dg As Integer 'Anzahl Durchgänge<br />
Public DurchBeg As Integer 'Bei welchem Durchgang soll begonnen<br />
werden<br />
Dim Zuf_Nr() As Integer '2-dimensionale Tabelle, enthält<br />
Zufalls-Nr und Durchgangs-Nr<br />
Dim Anz_Sp() As Integer 'e<strong>in</strong>dimensionale Tabelle mit Anzahl<br />
Spielern pro Durchgang<br />
Dim Max_AnzSp As Variant 'maximale Anzahl an Spielern<br />
(alle Durchgänge)<br />
Dim Anz_5erTi() As Integer 'Anzahl der 5-er Tische pro Durchgang<br />
Dim Max_Anz_5erTi() As Integer 'max. Anzahl an möglichen 5-er Tischen<br />
pro Durchgang<br />
Dim Anz_16Bl() As Integer 'Anzahl 16-er Blöcke<br />
Dim Anz_Tische() As Integer 'Anzahl benötigter Tische<br />
...<br />
21
Leicht zu erkennen an der Variablen-Deklaration Const MaxAnzDg = 10<br />
sowie Const MaxAnzRd = 10 ist die Festlegung auf maximal 10 Durchgänge<br />
sowie 10 Runden pro Durchgang. Bei e<strong>in</strong>em "normalen" Turnier<br />
s<strong>in</strong>d i.A. nicht mehr als 4 Durchgänge und 4 Runden pro Durchgang<br />
üblich, so dass diese Werte allemal ausreichend s<strong>in</strong>d.<br />
Alle weiteren Deklarationen s<strong>in</strong>d h<strong>in</strong>sichtlich ihrer Funktion anhand<br />
der Kommentierung zu erkennen bzw. werden noch im weiteren Verlauf<br />
im jeweiligen Zusammenhang erläutert.<br />
Zu b) Nun wieder zurück zum Auslosungsprogramm. Wie bereits erwähnt,<br />
ersche<strong>in</strong>t nach dem Start für den Anwender e<strong>in</strong>e <strong>E<strong>in</strong></strong>gabemaske<br />
mit der Abfrage nach der gewünschten Anzahl der Durchgänge und der<br />
Anzahl der Runden pro Durchgang (s. Abbildung 5).<br />
H<strong>in</strong>weis 7<br />
Im List<strong>in</strong>g 3 wird deutlich,<br />
wie Kommentare im Queltext<br />
<strong>in</strong>nerhalb e<strong>in</strong>er Zeile<br />
gesetzt werden: durch e<strong>in</strong>en<br />
Apostroph<br />
Abbildung 5<br />
Die Userform Startparameter<br />
Auslosung<br />
Zusätzlich lässt sich, falls die Vore<strong>in</strong>stellung nicht übernommen werden<br />
soll, die Anzahl der <strong>in</strong>sgesamt benötigten Tische durch e<strong>in</strong>e Erhöhung<br />
der 5er-Tische verr<strong>in</strong>gern (s. 2.5.4 Zusatzfunktionen, Punkt (2)).<br />
Aktiviert wird diese selbst erstellte <strong>E<strong>in</strong></strong>gabemaske, e<strong>in</strong>e sogenannte<br />
UserForm, im <strong>Programm</strong> durch den Befehl StartAuslosung.Show.<br />
StartAuslosung ist hierbei der Name dieser Dialogmaske. Dieser Name<br />
f<strong>in</strong>det sich wieder im Eigenschaftenfenster dieser UserForm <strong>in</strong> der Entwicklungsumgebung<br />
(s. Abbildung 9).<br />
Das ist ja nun soweit alles gut und schön, wirft aber viele neue Fragen<br />
auf, wie z.B. "womit und wie lässt sich so e<strong>in</strong>e Dialog-Box erstellen",<br />
"wie lässt sie sich im <strong>Programm</strong> anzeigen/aktivieren", "wie kann man<br />
22
sie programmieren", "wie werden Daten entgegengenommen und wieder<br />
zurückgegeben", usw.<br />
Diesem Thema wollen wir uns nun <strong>in</strong> 2.5.1 Schritt für Schritt nähern.<br />
2.5.1 Eigene Dialoge entwerfen und programmieren<br />
Zunächst e<strong>in</strong>mal muss e<strong>in</strong>e sogenannte Userform erzeugt und anschließend<br />
den eigenen Bedürfnissen entsprechend angepasst werden. Hierfür<br />
wechselt man wieder <strong>in</strong> die Entwicklungsumgebung (Tastenkomb<strong>in</strong>ation<br />
wie gehabt ).<br />
Abbildung 6<br />
Der Projekt-Explorer<br />
Im Projekt-Explorer (wird standardmäßig <strong>in</strong> der Entwicklunksumgebung<br />
oben l<strong>in</strong>ks e<strong>in</strong>geblendet, siehe auch 2.3 Die Entwicklungsumgebung<br />
von <strong>VBA</strong> sowie Abbildung 2) werden die Objekte und Dateien angezeigt,<br />
die zum Projekt gehören. Man sieht, dass die Arbeitsmappe zurzeit nur<br />
aus e<strong>in</strong>er Tabelle (mit dem Namen Auslosung) und zwei Formularen<br />
(DruckenSpielzettel und StartAuslosung) besteht. Der Doppelklick<br />
auf e<strong>in</strong> Objekt öffnet die Möglichkeit zu ihrer Bearbeitung, beispielsweise<br />
öffnet sich beim Tabellenmodul Tabelle1(Auslosung) der Editor mit<br />
dem Quellcode des Hauptprogramms.<br />
Hier <strong>in</strong> diesen Bereich des Projekt-Explorers klickt man mit der rechten<br />
Maustaste; falls der Projekt-Explorer nicht ersche<strong>in</strong>t, muss er noch über<br />
den Menüpunkt ANSICHT aufgerufen werden (alternativ Tastenkomb<strong>in</strong>ation<br />
).<br />
23
In dem darauffolgenden Kontextmenü wählt man den Befehl<br />
EINFÜGEN/USERFORM (Abbildung 7).<br />
Abbildung 7<br />
UserForm e<strong>in</strong>fügen<br />
Nun bekommt man e<strong>in</strong> leeres Formular namens UserForm1 zur Verfügung<br />
gestellt, zusammen mit e<strong>in</strong>er Werkzeugsammlung, die die wichtigsten<br />
Steuerelemente enthält (Abbildung 8). Über das Menü<br />
EXTRAS/ZUSÄTZLICHE STEUERELEMENTE können bei Bedarf<br />
weitere Elemente h<strong>in</strong>zugefügt werden. Damit steht dem Entwickler e<strong>in</strong><br />
großes Repertoire an Hilfsmitteln zur Verfügung, mit denen er sich se<strong>in</strong>e<br />
Dialogmaske den eigenen Vorstellungen entsprechend zusammenbasteln<br />
kann.<br />
Abbildung 8<br />
UserForm mit<br />
Werkzeugsammlung<br />
Für unsere Userform StartAuslosung (die derzeit noch UserForm1<br />
heißt), werden folgende Steuerelemente benötigt:<br />
24
‣ sechs Bezeichnungsfelder (Label) für die Beschriftungen "Wieviel<br />
Durchgänge <strong>in</strong>sgesamt", "Tische gesamt", etc.<br />
‣ fünf Textfelder (TextBox) für die Anzeige und <strong>E<strong>in</strong></strong>gabe von Daten<br />
wie z.B. Anzahl der Durchgänge<br />
‣ für drei der fünf Textfelder (s. Abbildung 5) jeweils e<strong>in</strong> Drehfeld<br />
(Sp<strong>in</strong>Button) für das schrittweise Hochzählen der Werte <strong>in</strong> den<br />
Textfeldern<br />
‣ zwei Befehlsschaltflächen<br />
(CommandButton) für die Ausführung<br />
von Befehlen (z.B. )<br />
<strong>E<strong>in</strong></strong> e<strong>in</strong>zelnes Steuerelement kann, nachdem es <strong>in</strong> der Werkzeugsammlung<br />
ausgewählt wurde, <strong>in</strong> der Userform platziert und den eigenen Bedürfnissen<br />
angepasst werden. Die Anpassungen erfolgen zum e<strong>in</strong>en<br />
über die Mausoperationen, um etwa das Element zu vergrößern oder zu<br />
verkle<strong>in</strong>ern und an die richtige Stelle zu setzen, zum anderen aber auch<br />
über das Editieren im zugehörigen Eigenschaften-Fenster (sichtbar unterhalb<br />
des Projektexplorers per oder Menü ANSICHT/<br />
EIGENSCHAFTENFENSTER).<br />
Die beiden folgenden Abbildungen 9 und 10 zeigen <strong>in</strong> Ausschnitten zwei<br />
Beispiele von Eigenschaften-Fenstern.<br />
Beispiel 1: Das Eigenschaften-Fenster StartAuslosung<br />
Abbildung 9<br />
Eigenschaftenfenster<br />
StartAuslosung<br />
Hier handelt es sich um die Userform selbst. Der von <strong>VBA</strong> bei der Erstellung<br />
der UserForm vorgeschlagene Name UserForm1 wurde <strong>in</strong>zwischen<br />
<strong>in</strong> StartAuslosung geändert.<br />
25
Beispiel 2: Das Eigenschaften-Fenster TextBox3<br />
Abbildung 10<br />
Eigenschaftenfenster<br />
TextBox3<br />
Diese TextBox enthält das Steuerelement zur <strong>E<strong>in</strong></strong>gabe der Tischanzahl.<br />
In diesem Fall wurde der von <strong>VBA</strong> vorgeschlagene Name Text-<br />
Box3 beibehalten.<br />
Kommen wir nun zur Makro-<strong>Programm</strong>ierung dieser Steuerelemente,<br />
also der Möglichkeit, sie per Quellcode zu bearbeiten/"steuern".<br />
Um das Formular StartAuslosung zu <strong>in</strong>itialisieren bzw. zu ändern,<br />
führen wir zunächst e<strong>in</strong>en Doppelklick <strong>in</strong>nerhalb des Formulars (oder<br />
Kontextmenü CODE ANZEIGEN) aus. <strong>Excel</strong> generiert automatisch<br />
e<strong>in</strong>en leeren <strong>Programm</strong>rahmen zum Editieren(Abbildung 11).<br />
Abbildung 11<br />
<strong>Programm</strong>rahmen e<strong>in</strong>er User-<br />
Form<br />
Am oberen Rand sieht man<br />
zwei Listenfelder. Im rechten<br />
Listenfeld hat man neben dem<br />
(ereignisgesteuerten) Click<br />
u.a. auch die Möglichkeit e<strong>in</strong>er<br />
Initialisierung. Die Auswahl<br />
dieses Elementes erzeugt<br />
automatisch den Text<br />
Private Sub userform_<strong>in</strong>itialize()<br />
Die Textboxen der <strong>in</strong> Abbildung 5 (Seite 22) dargestellten UserForm<br />
(TextBox1 = Anzahl der Durchgänge, TextBox2 = Anzahl der Runden<br />
und TextBox3 = Anzahl der Tische) sollten nun mit Standard-Werten<br />
<strong>in</strong>itialisiert werden. Während die Textboxen 1 und 2 bereits im jeweiligen<br />
Eigenschaftenfenster mit den Anfangswerten 3 (= Anzahl Durch-<br />
End Sub<br />
26
gänge) und 4 (= Anzahl Runden) versehen werden können, ist dies bei<br />
der Anzahl der Tische nicht möglich; die Anzahl der Tische ist abhängig<br />
von der Anzahl der Teilnehmer und muss daher per Quellcode-<br />
<strong>Programm</strong>ierung berechnet werden:<br />
Private Sub userform_<strong>in</strong>itialize()<br />
Dim AnzSp As Integer<br />
Dim MaxAnzTi As Integer<br />
...<br />
If Worksheets(1).Range("M1").Value = "" Then<br />
AnzSp = 0<br />
Else<br />
AnzSp = Range Worksheets(1).Range("I8").Value 'Anzahl Spieler<br />
End If<br />
List<strong>in</strong>g 4<br />
Sub<br />
userform_<strong>in</strong>itialize()<br />
Vorbelegung Anzahl der<br />
Tische <strong>in</strong> TextBox3 mit dem<br />
maximal möglichen Wert<br />
MaxAnzTi = AnzSp \ 4<br />
Sp<strong>in</strong>Button3.Value = MaxAnzTi<br />
TextBox3.Value = Sp<strong>in</strong>Button3.Value<br />
Sp<strong>in</strong>Button1.M<strong>in</strong> = Worksheets(1).Range("I11").Value + 1<br />
End Sub<br />
Im nächsten Schritt geht es darum, e<strong>in</strong> Makro für die Änderung der<br />
Tischanzahl zu schreiben. Da die Änderung über das nebenstehende<br />
Drehfeld Sp<strong>in</strong>Button3 erfolgen soll, ist für die TextBox3 selber ke<strong>in</strong>e<br />
Codierung notwendig, wohl aber für das nebenstehende Drehfeld. Führen<br />
wir zunächst e<strong>in</strong>en Doppelklick auf die Schaltfläche Sp<strong>in</strong>Button3 <strong>in</strong><br />
der Userform StartAuslosung aus, generiert <strong>Excel</strong> wiederum automatisch<br />
e<strong>in</strong>en leeren <strong>Programm</strong>rahmen, diesmal mit der Option Change:<br />
Private Sub Sp<strong>in</strong>Button3_Change()<br />
End Sub<br />
In diesem Rahmen werden nun die gewünschten Anpassungen bzw.<br />
Berechnungen vorgenommen (s. auch List<strong>in</strong>g 16, Seite 43):<br />
Private Sub Sp<strong>in</strong>Button3_Change()<br />
Dim Max_AnzSp As Integer<br />
Dim AnzSp As Integer<br />
Dim i As Integer<br />
Dim MaxAnzTi As Integer<br />
Dim M<strong>in</strong>AnzTi As Integer<br />
Dim Anz5erTi() As Integer<br />
Dim Anz4erTi() As Integer<br />
Dim Anz_Tische() As Integer<br />
'Max-Anzahl Spieler alle Durchgänge<br />
'Anzahl Spieler <strong>in</strong> e<strong>in</strong>em Durchgang<br />
'Anzahl Tische Maximum<br />
'Anzahl Tische M<strong>in</strong>imum<br />
'Anzahl 5er-Tische<br />
'Anzahl 4er-Tische<br />
'Anzahl benötigter Tische <strong>in</strong>sgesamt<br />
List<strong>in</strong>g 5<br />
Sub<br />
Sp<strong>in</strong>Button3_Change()<br />
If Worksheets(1).Range("M1").Value = "" Then<br />
AnzSp = 0<br />
Else<br />
AnzSp = Worksheets(1).Range("I8").Value 'Anzahl Spieler<br />
End If<br />
27
If AnzSp > Max_AnzSp Then<br />
Max_AnzSp = AnzSp<br />
Worksheets(1).Range("H3").Value = Max_AnzSp<br />
End If<br />
MaxAnzTi = AnzSp \ 4<br />
If AnzSp Mod 5 = 0 Then<br />
M<strong>in</strong>AnzTi = AnzSp \ 5<br />
Else<br />
M<strong>in</strong>AnzTi = AnzSp \ 5 + 1<br />
End If<br />
Sp<strong>in</strong>Button3.M<strong>in</strong> = M<strong>in</strong>AnzTi<br />
Sp<strong>in</strong>Button3.Max = MaxAnzTi<br />
TextBox3.Text = Sp<strong>in</strong>Button3.Value<br />
ReDim Preserve Anz5erTi(M<strong>in</strong>AnzTi To MaxAnzTi)<br />
ReDim Preserve Anz4erTi(M<strong>in</strong>AnzTi To MaxAnzTi)<br />
For i = M<strong>in</strong>AnzTi To MaxAnzTi<br />
Anz4erTi(i) = 5 * i - AnzSp<br />
Anz5erTi(i) = i - Anz4erTi(i)<br />
Next i<br />
TextBox4.Value = Anz5erTi(Sp<strong>in</strong>Button3.Value)<br />
TextBox5.Value = Anz4erTi(Sp<strong>in</strong>Button3.Value)<br />
End Sub<br />
Durch die Variablen Max_AnzSp und AnzSp soll man sich nicht irritieren<br />
lassen. Sie dienen im <strong>Programm</strong> nur zur Differenzierung nach Anzahl<br />
der Spieler pro Durchgang, falls mal jemand nach e<strong>in</strong>em Durchgang<br />
aussteigt oder neu dazu kommt (s. 2.5.4 Zusatzfunktionen). Es soll<br />
hier eigentlich nur deutlich werden, wie die Eigenschaften dieses Elementes<br />
durch die Makro-<strong>Programm</strong>ierung gesteuert werden können.<br />
Zunächst e<strong>in</strong>mal werden die maximale und m<strong>in</strong>imale Anzahl an benötigten<br />
Tischen berechnet (MaxAnzTi und M<strong>in</strong>AnzTi) und ihre Werte<br />
den Variablen Sp<strong>in</strong>Button3.M<strong>in</strong> und Sp<strong>in</strong>Button3.Max zugewiesen.<br />
Damit hat das Drehfeld Sp<strong>in</strong>Button3 die Eigenschaften maximal möglicher<br />
Wert und m<strong>in</strong>imal möglicher Wert zugewiesen bekommen. Da<br />
über die Anweisung TextBox3.Text = Sp<strong>in</strong>Button3.Value die TextBox3<br />
mit dem Drehfeld Sp<strong>in</strong>Button3 verbunden ist, kann somit die Text-<br />
Box3 jetzt nur noch Werte <strong>in</strong>nerhalb dieses Intervalls annehmen. Aus<br />
diesen Ausführungen wird auch deutlich, dass <strong>in</strong> diesem Fall e<strong>in</strong>e<br />
Quellcode-<strong>Programm</strong>ierung unumgänglich ist, da Maximal- und M<strong>in</strong>imal-Wert<br />
jeweils variabel s<strong>in</strong>d. <strong>E<strong>in</strong></strong> <strong>E<strong>in</strong></strong>trag im Eigenschaften-Fenster<br />
macht somit ke<strong>in</strong>en S<strong>in</strong>n, auch wenn diese Optionen im Eigenschaftenfenster<br />
von Sp<strong>in</strong>Button3 mit Max bzw. M<strong>in</strong> vorgesehen s<strong>in</strong>d und somit<br />
auch möglich wären.<br />
Aus dem Quelltext geht ferner hervor, dass für jeden möglichen Wert<br />
zwischen der m<strong>in</strong>imalen und maximalen Anzahl an Tischen e<strong>in</strong>e Aufteilung<br />
<strong>in</strong> Anzahl 4er-Tische (= TextBox4) und Anzahl 5er-Tische (=<br />
28
2.5.2 Die neuen Tabellenblätter<br />
Zu Beg<strong>in</strong>n des <strong>Programm</strong>s existiert lediglich das Tabellenblatt mit dem<br />
Namen Auslosung. Es besteht i.w. aus der Teilnehmerliste (s. Abbildung<br />
3) und dem Button Auslosung starten. Mit dem Klick auf diesen<br />
Button wird das <strong>Programm</strong> Sub Auslosung() ausgeführt. Es ist das<br />
Haupt-<strong>Programm</strong>. Es sorgt zunächst e<strong>in</strong>mal dafür, dass jeder Teilnehmer<br />
für jeden e<strong>in</strong>zelnen Durchgang e<strong>in</strong>en zufällig ausgewählten Tisch-<br />
Platz zugewiesen bekommt. Nachdem das erfolgt ist, können neue zusätzliche<br />
Tabellenblätter generiert werden, und zwar<br />
‣ e<strong>in</strong> Tabellenblatt Liste als Übersicht<br />
‣ je e<strong>in</strong> Tabellenblatt pro Durchgang zur <strong>E<strong>in</strong></strong>gabe der erreichten<br />
Punktzahl pro Spieler<br />
‣ e<strong>in</strong> Tabellenblatt Ergebnis, <strong>in</strong> dem die Punktzahlen e<strong>in</strong>es jeden<br />
Teilnehmers übersichtlich dargestellt werden<br />
<strong>E<strong>in</strong></strong> neues Tabellenblatt wird <strong>in</strong> <strong>VBA</strong> mit der Funktion Worksheets.Add<br />
erzeugt.<br />
2.5.2.1 Das Tabellenblatt "Liste"<br />
Dieses Tabellenblatt enthält e<strong>in</strong>e übersichtliche Liste aller Teilnehmer,<br />
aus der hervorgeht, welcher Spieler <strong>in</strong> welchem Durchgang an welchem<br />
Tisch mit welcher Tisch-Nr spielt.<br />
Mit der Anweisung Worksheets.Add<br />
After:=Worksheets(Worksheets.Count) wird h<strong>in</strong>ter dem letzten Tabellenblatt<br />
e<strong>in</strong> neues angehängt. Es bekommt den Namen Liste. list ist<br />
e<strong>in</strong>e globale Konstante: Const list = "Liste".<br />
Worksheets(1).Cells(2, 9).Value = Anz_Dg<br />
Worksheets(1).Cells(1, 9).Value = Worksheets(1).Cells(11, 9).Value<br />
Worksheets.Add After:=Worksheets(Worksheets.Count)<br />
Worksheets(Worksheets.Count).Name = list 'Erstellung des Tabellenblattes<br />
"Liste"<br />
Worksheets(1).Range("M:M").Copy<br />
Dest<strong>in</strong>ation:=Worksheets(list).Range("A:A")<br />
Worksheets(list).Range("A1").Insert<br />
Worksheets(list).Range("A1").EntireColumn.ColumnWidth = 22<br />
Dieses Tabellenblatt dient dazu, e<strong>in</strong>e übersichtliche, alphabetisch sortierte<br />
Liste zu erstellen, aus der für jeden Spieler hervorgeht, <strong>in</strong> welchem<br />
Durchgang er an welchem Tisch spielt. Aus dieser Liste kann z.B.<br />
die Teilnehmer<strong>in</strong> Marlies Bäumer erkennen, dass sie im ersten Durchgang<br />
am Tisch 4 spielt mit der Tisch-Nr 2 (s. Abbildung 13).<br />
List<strong>in</strong>g 7<br />
Tabellenblatt Liste h<strong>in</strong>zufügen<br />
H<strong>in</strong>weis 10<br />
Die Spielerliste wurde <strong>in</strong> der<br />
Zwischenzeit im Tabellenblatt<br />
Auslosung<br />
(=Worksheets(1) von Spalte<br />
"F" nach Spalte "M" kopiert.<br />
32
Durch e<strong>in</strong>en Klick auf den Button Liste drucken kann die Liste (evtl.<br />
mehrfach) ausgedruckt werden und als Aushang (an evtl. verschiedenen<br />
Örtlichkeiten) angebracht werden.<br />
Abbildung 13<br />
Tabellenblatt Liste<br />
bereits vorformatiert und<br />
nach Namen sortiert<br />
2.5.2.2 Pro Durchgang je e<strong>in</strong> Tabellenblatt<br />
Im Anschluss an das Listentabellenblatt folgt pro Durchgang je e<strong>in</strong> weiteres<br />
Tabellenblatt für die <strong>E<strong>in</strong></strong>gabe der erreichten Punkte jedes e<strong>in</strong>zelnen<br />
Spielers.<br />
For d = DurchBeg To Anz_Dg<br />
'Erstellung der<br />
Durchgangstabellenblätter<br />
Worksheets.Add After:=Worksheets(Worksheets.Count)<br />
Worksheets(d + 2).Name = d & ". " & dg 'Name des Durchgangs-<br />
Tabellenblattes: const dg = Durchgang<br />
Sheets(d + 2).Range("A1").EntireColumn.ColumnWidth = 5 'es folgen<br />
weitere Formatierungen<br />
Sheets(d + 2).Range("B1").EntireColumn.ColumnWidth = 22<br />
...<br />
...<br />
Next d<br />
List<strong>in</strong>g 8<br />
Je e<strong>in</strong> Tabellenblatt pro<br />
Durchgang h<strong>in</strong>zufügen<br />
<strong>E<strong>in</strong></strong> komplett durchformatiertes Tabellenblatt hat dann folgendes Aussehen<br />
(Abbildung 14):<br />
Abbildung 14<br />
Tabellenblatt 1. Durchgang<br />
33
Aus der Abbildung lässt sich schon mal grob erkennen, was bei der Codierung<br />
alles zu beachten ist:<br />
‣ Spaltenbreiten festlegen<br />
‣ Überschriften berücksichtigen<br />
‣ Unterscheidung zwischen 5er- und 4er-Tischen<br />
‣ Werden alle Tische nebene<strong>in</strong>ander auf dem Bildschirm platziert,<br />
wird die spätere <strong>E<strong>in</strong></strong>gabe der Punkte umständlich; übersichtlicher<br />
wird es, wenn jeweils 4 Tische zu e<strong>in</strong>em Block zusammengefasst<br />
werden, und die Blöcke jeweils untere<strong>in</strong>ander zu stehen<br />
‣ Neben den Formatierungen der e<strong>in</strong>zelnen Zellen erfolgt die Zuweisung<br />
der Teilnehmer zu den e<strong>in</strong>zelnen Tischen. Auf die Implementierung<br />
dieses Vorganges, dem Mischvorgang, wird im<br />
Abschnitt "2.5.3 Wer kommt <strong>in</strong> welchem Durchgang an welchem<br />
Platz?" näher e<strong>in</strong>gegangen.<br />
‣ Die Zellen mit dem Wert 0 enthalten als Formel die Summe aller<br />
Punkte pro Tisch<br />
Worksheets(d + 2).Cells(zeile, spalte + 1).FormulaR1C1 =<br />
"=SUM(R[-5]C:R[-1]C)"<br />
Sie muss <strong>in</strong> jedem Falle als Ergebnis den Wert 0 ergeben (sofern<br />
an den Tischen die Punkte mit Plus/M<strong>in</strong>us notiert werden). Der<br />
Nutzen dieser Summenformel liegt dar<strong>in</strong>, dass direkt bei <strong>E<strong>in</strong></strong>gabe<br />
der Punktzahl ersichtlich wird, ob an dem betreffenden Tisch<br />
korrekt gezählt wurde.<br />
H<strong>in</strong>weis 11<br />
Anzahl der Tische pro Block<br />
s. List<strong>in</strong>g 3 (Glob. Variable)<br />
Const AnzTiProBlock=4<br />
'Anzahl Tische im 16-er Block<br />
List<strong>in</strong>g 9<br />
Summenformel pro Tisch<br />
2.5.2.3 Das Tabellenblatt "Ergebnis"<br />
Nachdem der Anwender die Punktzahlen der Spieler <strong>in</strong> die Durchgangs-<br />
Tabellenblätter e<strong>in</strong>getragen hat, möchte er sich natürlich die Gesamtergebnisse<br />
<strong>in</strong> e<strong>in</strong>er Übersicht anschauen können. Hierzu dient das Tabellenblatt<br />
Ergebnis, welches als letztes vom Haupt-<strong>Programm</strong> Sub Auslosung<br />
erzeugt wird (s. Abbildung 15).<br />
Worksheets.Add After:=Worksheets(Worksheets.Count)<br />
Worksheets(Worksheets.Count).Name = erg<br />
'Tabellenblatt "Ergebnis"<br />
ganz am Ende<br />
Worksheets(erg).Range("A1").EntireColumn.ColumnWidth = 4.43<br />
Worksheets(1).Range("M:M").Copy<br />
Dest<strong>in</strong>ation:=Worksheets(erg).Range("B:B")<br />
...<br />
List<strong>in</strong>g 10<br />
Tabellenblatt Ergebnis h<strong>in</strong>zufügen<br />
34
Abbildung 15<br />
Tabellenblatt Ergebnis<br />
Die Formatierung der Zellen hält sich hier <strong>in</strong> Grenzen. Es werden i.w.<br />
lediglich die Teilnehmer nach Spalte "B" kopiert und es wird e<strong>in</strong> Button<br />
Punkte aus allen Durchgängen generiert. H<strong>in</strong>ter diesem Button verbirgt<br />
sich das Unterprogramm Sub Ergebnis. Dieser <strong>Programm</strong>teil sorgt<br />
dafür, dass die Punktzahlen e<strong>in</strong>es jeden Spielers aus den e<strong>in</strong>zelnen<br />
Durchgängen <strong>in</strong> die Ergebnisliste übernommen werden. Die Spalte "B"<br />
<strong>in</strong> dem Ergebnis-Tabellenblatt mit den Spielernamen wird Zeile für Zeile<br />
abgearbeitet, wobei für jeden Durchgang nach dem entsprechenden<br />
Namen <strong>in</strong> der Spalte "K" der Durchgangstabelle (s. auch "2.5.3 Wer<br />
kommt <strong>in</strong> welchem Durchgang an welchem Platz?") gesucht wird; wurde<br />
er gefunden, wird die betreffende Punktzahl für den Spieler <strong>in</strong> die Ergebnisliste<br />
übernommen.<br />
H<strong>in</strong>weis 12<br />
Spalte "A" ist reserviert für<br />
die Rangfolge (s. Abbildung<br />
16, Seite 36)<br />
Außerdem werden noch zwei weitere Buttons generiert:<br />
ErgSortRangButtonErstellen<br />
ErgDruckButtonErstellen<br />
'Ergebnisliste nach Punktzahl sortieren<br />
'Ergebnisliste ausdrucken<br />
Die sich h<strong>in</strong>ter ihnen verbergenden Makros s<strong>in</strong>d selbsterklärend und<br />
recht e<strong>in</strong>fach zu implemetieren.<br />
Der Quellcode der Ergebnis-Prozedur sieht nun wie folgt aus:<br />
Sub ergebnis()<br />
ErgSortNameButtonErstellen<br />
ErgSortRangButtonErstellen<br />
ErgDruckButtonErstellen<br />
List<strong>in</strong>g 11<br />
Quellcode Sub Ergebnis()<br />
Anz_Dg = Worksheets(1).Range("I6")<br />
Max_AnzSp = Worksheets(1).Range("H3").Value<br />
Sheets(list).Range("A:A").Copy Dest<strong>in</strong>ation:=Sheets(erg).Range("B:B")<br />
For n = 1 To Anz_Dg + 3<br />
'und noch e<strong>in</strong> bisschen die<br />
Tabelle formatieren<br />
Worksheets(erg).Cells(1, n).Interior.ColorIndex = HGrFaSp<br />
Worksheets(erg).Cells(1, n).Font.Bold = True<br />
35
For m = 1 To Worksheets(erg).Range("B" &<br />
Rows.Count).End(xlUp).Row<br />
Worksheets(erg).Cells(m, n).Borders.L<strong>in</strong>eStyle = xlCont<strong>in</strong>uous<br />
Next m<br />
Next n<br />
Worksheets(erg).Cells(1, 2).Value = "Name Vorname"<br />
With Worksheets(erg)<br />
Set bereich = .Range(.Cells(2, 3), .Cells(Max_AnzSp + 1, Anz_Dg<br />
+ 2))<br />
bereich.Value = ""<br />
End With<br />
Sheets(erg).Range("A2:A" & Max_AnzSp + 1).Value = ""<br />
Dim Mat As Variant<br />
For d = 1 To Anz_Dg<br />
For n = 2 To Max_AnzSp + 1<br />
Mat = Application.Match(Sheets(erg).Range("B" & n), Sheets(d &<br />
". " & dg).Range("K:K"), 0)<br />
If Not IsError(Mat) Then<br />
Sheets(erg).Cells(n, d + 2).Value = Sheets(d & ". " &<br />
dg).Range("L" & Mat).Value<br />
End If<br />
Next n<br />
Next d<br />
H<strong>in</strong>weis 13<br />
Übernahme der Punktzahl<br />
aus den Durchgangs-<br />
Tabellenblättern<br />
Die Ergebnis-Tabelle könnte nach der Übernahme der Punktzahl und<br />
anschließender Sortierung etwa folgendes Aussehen haben:<br />
Abbildung 16<br />
Tabellenblatt Ergebnis<br />
komplett durch formatiert<br />
2.5.3 Das Mischprogramm: wer kommt <strong>in</strong> welchem Durchgang an welchem<br />
Tisch an welchem Platz?<br />
Machen wir nun wieder e<strong>in</strong>en Sprung zurück zum Haupt-<strong>Programm</strong><br />
Sub Auslosung() und kommen zum eigentlichen Kern.<br />
Nachdem der Anwender im Start-Dialog StartAuslosung (s. Abbildung<br />
5) se<strong>in</strong>e <strong>E<strong>in</strong></strong>gaben gemacht hat, steht nun für das Turnier fest, wie viel<br />
Durchgänge gespielt werden, wie viel Runden pro Durchgang gespielt<br />
werden und wie viel Personen auf wie viel 4er-Tische und 5er-Tische<br />
verteilt werden müssen. Die eigentliche Auslosung kann nun beg<strong>in</strong>nen.<br />
36
Im Mischprogramm Sub Tischzuweiung bekommt jeder e<strong>in</strong>zelne Teilnehmer<br />
für jeden e<strong>in</strong>zelnen Durchgang per Zufallsgenerator e<strong>in</strong>en Platz<br />
an e<strong>in</strong>em Tisch zugewiesen.<br />
Sub Tischzuweisung()<br />
ReDim Zuf_Nr(1 To Anz_Dg, 1 To Anz_Sp(d))<br />
Dim q As Integer, z As Integer, tmp As Integer<br />
For q = 1 To Anz_Sp(d)<br />
Zuf_Nr(d, q) = q<br />
Next<br />
For q = Anz_Sp(d) To 1 Step -1<br />
Randomize<br />
z = Int(Rnd * q) + 1<br />
'Vorbelegung der Zuf_Nr-Tabelle<br />
mit 1, 2, 3,...,q<br />
'neuer Startwert für Rnd-Funktion<br />
'z = Zufallszahl zwischen 1 und q<br />
tmp = Zuf_Nr(d, z) 'tausche Zuf_Nr(d, z)<br />
Zuf_Nr(d, z) = Zuf_Nr(d, q) 'mit<br />
Zuf_Nr(d, q) = tmp 'Zuf_Nr(d, q)<br />
Next<br />
...<br />
List<strong>in</strong>g 12<br />
Quellcode Sub Tischzuweisung<br />
Mit der ReDim-Anweisung wird der bereits deklarierte array Zuf_Nr()<br />
zum e<strong>in</strong>en als 2-dimensionale Tabelle deklariert und zum zweiten wird<br />
die array-Länge def<strong>in</strong>iert ( Länge der 1.Dimension = Anz_Dg = Anzahl<br />
der Durchgänge, Länge der 2.Dimension = Anz_Sp(d)= Anzahl Spieler<br />
<strong>in</strong> Durchgang d).<br />
Der Mischalgorithmus br<strong>in</strong>gt e<strong>in</strong>e Zahlenfolge von 1 bis Anz_Sp(d) <strong>in</strong><br />
e<strong>in</strong>e zufällige Anordnung. Dies kann man sich wie folgt vorstellen: man<br />
hat e<strong>in</strong>en Kartenstapel vor sich mit Anz_Sp(d) (=Anzahl Spieler pro<br />
Durchgang) Karten. Nun wird die unterste Karte mit e<strong>in</strong>er zufälligen<br />
anderen über ihr liegenden Karte getauscht, dann die zweit-unterste,<br />
danach die dritt-unterste usw.<br />
Anschließend hat man also pro Durchgang e<strong>in</strong>e Zahlenfolge von 1 bis<br />
Anz_Sp(d) generiert, die per Zufallsgenerator <strong>in</strong> e<strong>in</strong>e zufällig angeordnete<br />
Reihenfolge gebracht wurde. Jetzt kann man daran gehen, diese<br />
Liste sukzessive von vorne bis h<strong>in</strong>ten abzuarbeiten und dabei die Teilnehmer<br />
(sie s<strong>in</strong>d <strong>in</strong> der Zwischenzeit nach Spalte "M" kopiert worden)<br />
<strong>in</strong> dieser zufällig ausgewählten Reihenfolge auf die e<strong>in</strong>zelnen Tische zu<br />
verteilen:<br />
Sp_Name = Worksheets(1).Range("M" & (Zuf_Nr(d, n))).Value (s.<br />
Quellcode <strong>in</strong> der Unterprozedur Sub ZelleMitNameFuellen() <strong>in</strong> List<strong>in</strong>g<br />
13)<br />
In dieser Reihenfolge werden nun die Spieler auf die e<strong>in</strong>zelnen Tische<br />
verteilt, zuerst die 5er-Tische, danach die 4er-Tische.<br />
37
Optisch aufbereitet sollen die Durchgangs-Tabellenblätter das <strong>in</strong> der<br />
Abbildung 14 (Seite 33) dargestellte Aussehen haben. Vier Tische, nebene<strong>in</strong>ander<br />
dargestellt – jeder Tisch besteht aus zwei Spalten, nämlich<br />
Name und Punktzahl – bilden dabei jeweils e<strong>in</strong>en Block. Die Blöcke<br />
wiederum werden untere<strong>in</strong>ander platziert, wobei zwischen zwei Blöcken<br />
jeweils zwei Zeilen frei gelassen werden (aus der Abbildung 14 nicht ersichtlich,<br />
da <strong>in</strong> unserem Beispiel nur e<strong>in</strong> Block benötigt wurde).<br />
Die Implementierung erfolgt naturgemäß über mehrere Schleifen:<br />
‣ ganz außen die Schleife der Blöcke For i16b = 1 To Anz_16Bl(d)<br />
‣ <strong>in</strong>nerhalb e<strong>in</strong>es Blockes 4 Tische For itb = 1 To AnzTiProBlock<br />
(beachte globale Konstante Const AnzTiProBlock = 4)<br />
‣ <strong>in</strong>nerhalb e<strong>in</strong>es Tisches 7 Zeilen For j = 1 To 7 'bei den<br />
4er-Tischen 6 Zeilen<br />
Es folgt nun der komplette Quellcode für die 5er-Tische <strong>in</strong> der Prozedur<br />
Sub Tischzuweisung() (= Fortsetzug von List<strong>in</strong>g 12):<br />
n = 1<br />
'Zähler für Spieler<br />
it = 1<br />
'Laufvariable für Tische<br />
i5t = 1<br />
'Laufvariable für 5er-Tische<br />
(für 4er-Tische nicht erforderlich, da es nur diese beiden Möglichkeiten gibt)<br />
For i16b = 1 To Anz_16Bl(d)<br />
'Abarbeitung blockweise: mehrere Tische<br />
pro Block (Vore<strong>in</strong>stellung = 4)<br />
For itb = 1 To AnzTiProBlock<br />
'weitere Abarbeitung tischweise<br />
(AnzTiProBlock = 4)<br />
spalte = SpBeg + 2 * (itb - 1) 'Festlegung der Spalte pro Tisch<br />
If it
Case 2 To 6<br />
ZelleMitNameFuellen<br />
'Zeile 2 bis 6 = Befüllung mit Namen<br />
'<strong>E<strong>in</strong></strong>trag des Teilnehmers <strong>in</strong> die<br />
entsprechende Zelle<br />
Case 7 '7.Zeile = Summ-formel für Zeilen 2 bis 6<br />
Worksheets(d + 2).Cells(zeile, spalte + 1).FormulaR1C1 =<br />
"=SUM(R[-5]C:R[-1]C)"<br />
Worksheets(d + 2).Cells(zeile, spalte +<br />
1).FormatConditions.Delete<br />
Worksheets(d + 2).Cells(zeile, spalte +<br />
1).FormatConditions.Add _<br />
Type:=xlCellValue, Operator:=xlNotEqual, Formula1:="0"<br />
With Worksheets(d + 2).Cells(zeile, spalte +<br />
1).FormatConditions(1).Font<br />
.Bold = True<br />
.Italic = False<br />
.ColorIndex = 3<br />
End With<br />
Worksheets(d + 2).Cells(zeile, spalte +<br />
1).FormatConditions(1).Interior.ColorIndex = 5<br />
Worksheets(d + 2).Cells(zeile, spalte +<br />
1).HorizontalAlignment = xlCenter<br />
End Select<br />
Next j<br />
i5t = i5t + 1 'nach Abarbeitung 5er-Tisch Zähler um 1<br />
erhöhen<br />
Else ... 'Abarbeitung der 4er-Tische nach dem<br />
gleichen Schema<br />
Sub ZelleMitNameFuellen()<br />
Dim Sp_Name As Str<strong>in</strong>g<br />
Dim MatchZeile As Variant<br />
Sp_Name = Worksheets(1).Range("M" & (Zuf_Nr(d, n))).Value 'Zeile aus<br />
Spalte "M" entspricht Zufallszahl<br />
Worksheets(d + 2).Cells(zeile, spalte) = Sp_Name<br />
'<strong>E<strong>in</strong></strong>tragung<br />
des Spielers <strong>in</strong> der Durchgangs-Tabelle<br />
Worksheets(d + 2).Cells(zeile, spalte).Locked = True 'entsprechende<br />
Zelle sperren<br />
Worksheets(d + 2).Cells(zeile, spalte).Borders.L<strong>in</strong>eStyle =<br />
xlCont<strong>in</strong>uous<br />
Worksheets(d + 2).Cells(zeile, spalte).HorizontalAlignment =<br />
xlCenter<br />
Worksheets(d + 2).Cells(zeile, spalte).Interior.ColorIndex = HGrFaSp<br />
Worksheets(d + 2).Cells(zeile, spalte + 1).Borders.L<strong>in</strong>eStyle =<br />
xlCont<strong>in</strong>uous<br />
Worksheets(d + 2).Cells(zeile, spalte + 1).HorizontalAlignment =<br />
xlCenter<br />
Worksheets(d + 2).Cells(zeile, spalte + 1).Interior.ColorIndex =<br />
HGrFaSp<br />
Worksheets(d + 2).Cells(n, 11).Value = Sp_Name 'zusätzlich<br />
den Namen <strong>in</strong> Spalte "K" der Durchgangstabelle e<strong>in</strong>tragen<br />
Worksheets(d + 2).Cells(n, 11).Locked = True<br />
'und die<br />
betreffende Zelle sperren<br />
Worksheets(d + 2).Cells(n, 12).Formula = "=R" & zeile & "C" & spalte<br />
+ 1 & "" 'außerdem die Punktzahl des Spielers automatisch übernehmen lassen<br />
Worksheets(d + 2).Cells(n, 12).Locked = True 'und auch diese Zelle<br />
(gleiche Zeile, aber Spalte "L"), sperren lassen<br />
MatchZeile = Application.Match(Sp_Name, Sheets(list).Range("A:A"), 0)<br />
'Spielernamen <strong>in</strong> Tabelle "Liste", Spalte "A" suchen<br />
If IsError(MatchZeile) Then 'falls noch nicht vorhanden<br />
lz = Sheets(list).Range("A" & Rows.Count).End(xlUp).Row + 1<br />
'neue Zeile "aufmachen"<br />
39
Sheets(list).Range("A" & lz).Value = Sp_Name 'und <strong>in</strong> dieser den Namen<br />
e<strong>in</strong>tragen<br />
Worksheets(list).Cells(lz, d + 1).Value = it & "(" & j - 1 & ")"<br />
'mit <strong>E<strong>in</strong></strong>trag der Tisch- und Platz-Nr <strong>in</strong> der betreffenden Durchgangsspalte<br />
Else 'falls schon vorhanden<br />
Worksheets(list).Cells(MatchZeile, d + 1).Value = it & "(" & j - 1<br />
& ")"<br />
'<strong>E<strong>in</strong></strong>trag der Tisch- und Platz-Nr <strong>in</strong> der betreffenden Durchgangsspalte<br />
End If<br />
n = n + 1<br />
'Nach <strong>E<strong>in</strong></strong>tragung <strong>in</strong> Durchgangs-Tabelle<br />
Spierzähler um 1 erhöhen<br />
End Sub<br />
Für jeden Tisch wird zunächst e<strong>in</strong>mal e<strong>in</strong>e Überschrift erzeugt (Case 1),<br />
dann <strong>in</strong> der Unterprozedur ZelleMitNameFuellen() die Spielernamen<br />
e<strong>in</strong>getragen (Case 2 To 6) und zum Schluss (Case 7) noch e<strong>in</strong>e Summenformel<br />
notiert, <strong>in</strong> der die Summe der erreichten Punktzahl pro<br />
Tisch berechnet wird (s. auch List<strong>in</strong>g 9). Sie dient lediglich als Kontrolle,<br />
da bekanntermaßen bei e<strong>in</strong>er Plus-M<strong>in</strong>us-Wertung die Gesamtsumme<br />
immer Null se<strong>in</strong> muss.<br />
Sukzessive holt sich die Unterprozedur ZelleMitNameFuellen() aus dem<br />
1.Tabellenblatt (=Tabellenblatt mit dem Namen Auslosung) e<strong>in</strong>e zuvor<br />
zufällig ausgewählte Zelle der Spalte "M"<br />
Sp_Name = Worksheets(1).Range("M" & (Zuf_Nr(d, n))).Value<br />
und überträgt dessen Inhalt – den Spielernamen – <strong>in</strong> die dafür vorgesehene<br />
Zelle der Durchgangstabelle:<br />
Worksheets(d + 2).Cells(zeile, spalte) = Sp_Name<br />
Der gleiche Spieler(name) wird zusätzlich noch <strong>in</strong> Spalte "K" e<strong>in</strong>getragen,<br />
Worksheets(d + 2).Cells(n, 11).Value = Sp_Name<br />
und mit ihm noch <strong>in</strong> der Zelle rechts daneben, also <strong>in</strong> Spalte "L" der<br />
gleichen Zeile e<strong>in</strong>e Formel zur Übernahme der Punkte; somit werden<br />
alle Änderungen <strong>in</strong> der Punktezahl-Zelle des Spielers mit übernommen:<br />
Worksheets(d + 2).Cells(n, 12).Formula = "=R" & zeile & "C" & spalte +<br />
1 & ""<br />
Die beiden Spalten "K" und "L" spielen später bei Übernahme der<br />
Punktzahl e<strong>in</strong>es Spielers <strong>in</strong> das Tabellenblatt Ergebnis noch e<strong>in</strong>e wichtige<br />
Rolle.<br />
H<strong>in</strong>weis 14<br />
Die Spielerliste wurde bereits<br />
zu Beg<strong>in</strong>n des Ma<strong>in</strong>-<strong>Programm</strong>s<br />
Sub Auslosung von<br />
Spalte "F" nach Spalte "M"<br />
kopiert.<br />
H<strong>in</strong>weis 15<br />
s. List<strong>in</strong>g 11 bzw. H<strong>in</strong>weis<br />
13, Seite 36<br />
Im weiteren Verlauf wird <strong>in</strong> dem Tabellenblatt Liste nach dem betreffenden<br />
Spielernamen gesucht:<br />
MatchZeile = Application.Match(Sp_Name, Sheets(list).Range("A:A"),<br />
0)<br />
40
Wurde er nicht gefunden, wird er neu <strong>in</strong> die Liste mit aufgenommen.<br />
Dies ersche<strong>in</strong>t zunächst e<strong>in</strong>mal umständlich programmiert; es hat lediglich<br />
damit zu tun, dass <strong>in</strong> diesem <strong>Programm</strong> die Möglichkeit berücksichtigt<br />
wird, dass <strong>in</strong> e<strong>in</strong>em Durchgang Spieler neu h<strong>in</strong>zukommen oder<br />
- aus welchen Gründen auch immer - nicht weiter am Turnier teilnehmen<br />
(s. auch das folgende Kapitel 2.5.4 Zusatzfunktionen, Punkt (1)).<br />
2.5.4 Zusatzfunktionen<br />
Die Schwerpunkte des <strong>Programm</strong>s wurden <strong>in</strong> allen wichtigen Punkten<br />
vorgestellt. Das Rüstzeug für die Implementierung <strong>in</strong> <strong>VBA</strong> steht nunmehr<br />
bereit.<br />
Das komplette <strong>Programm</strong> bietet allerd<strong>in</strong>gs noch e<strong>in</strong>ige Sonderfunktionen,<br />
die im Folgenden vorgestellt werden sollen.<br />
(1) Teilnehmer können nach e<strong>in</strong>em gespielten Durchgang ausfallen<br />
oder neu h<strong>in</strong>zukommen.<br />
Abbildung 17<br />
Die Zellen I6 bis I11 im Tabellenblatt<br />
"Auslosung"<br />
Die Zellen I6 und I7 werden<br />
nach <strong>E<strong>in</strong></strong>gabe der Startparameter<br />
gefüllt, die Zellen I8 bis<br />
I10 bereits vor Beg<strong>in</strong>n des<br />
Auslosungsprogramms (s. 2.4<br />
Ereignisse <strong>in</strong> VBE)<br />
In diesem Fall bietet das <strong>Programm</strong> die Möglichkeit, ab e<strong>in</strong>em bestimmten,<br />
selbst gewählten Zeitpunkt e<strong>in</strong>en oder mehrere noch<br />
nicht gespielte Durchgänge neu zu mischen. Hierzu dient im Tabellenblatt<br />
Auslosung die Zelle "I11" (s. Abbildung 17), <strong>in</strong> dem die Anzahl<br />
der bereits gespielten Durchgänge manuell hochgesetzt werden<br />
kann. Wenn dann erneut die Schaltfläche Auslosung starten gedrückt<br />
wird, werden nur noch die nicht gespielten Durchgänge neu<br />
gemischt.<br />
Zu diesem Zweck wird im <strong>Programm</strong> e<strong>in</strong>e Variable DurchBeg deklariert,<br />
die aus der Zelle "I11" e<strong>in</strong>gelesen und um 1 erhöht wird:<br />
DurchBeg = Worksheets(1).Range("I11") + 1<br />
41
Außerdem werden bei Spielbeg<strong>in</strong>n (DurchBeg = 1) alle Tabellenblätter<br />
entfernt, jedoch bei e<strong>in</strong>er erneuten Auslosung ab dem zweiten<br />
Durchgang nur die noch nicht benutzten Durchgangstabellenblätter.<br />
Die Tabellenblätter Liste und Ergebnis werden ohneh<strong>in</strong> <strong>in</strong> jedem<br />
Fall neu generiert.<br />
Public DurchBeg As Integer 'bei welchem Durchgang soll<br />
begonnen werden<br />
...<br />
DurchBeg = Worksheets(1).Range("I11") + 1<br />
...<br />
If DurchBeg = 1 Then<br />
'bei Spielbeg<strong>in</strong>n alle Tabellenblätter löschen bis auf das<br />
"Auslosung"s-Tabellenblatt<br />
For d = 1 To (ActiveWorkbook.Sheets.Count - 1)<br />
Sheets(2).Delete<br />
Next<br />
End If<br />
...<br />
If DurchBeg > 1 Then<br />
On Error Resume Next<br />
For d = DurchBeg To MaxAnzDg<br />
Sheets(d & ". " & dg).Delete<br />
Next<br />
End If<br />
...<br />
'falls erneute Auslosung (ab<br />
Durchgang 2),<br />
'die Durchgangstabellenblätter<br />
löschen,<br />
'die anschließend per Auslosung<br />
'neu erstellt werden<br />
List<strong>in</strong>g 14<br />
Nach e<strong>in</strong>em bereits gespielten<br />
Durchgang soll neu gemischt<br />
werden<br />
(2) Die Gesamtanzahl der Tische lässt sich dadurch reduzieren, dass<br />
die Anzahl der 5er-Tische erhöht wird auf das maximal Mögliche<br />
Die Möglichkeit hierzu wurde bereits bei der Erläuterung der Dialogbox<br />
für die Startparameter der Auslosung im Kapitel 2.5 Der<br />
Kern des <strong>Programm</strong>s: die Auslosung erwähnt.<br />
Die Zellen "I9" = Anzahl 4er-Tische und "I10" = Anzahl 5er-Tische<br />
(s. Abbildung 17) werden direkt bereits bei der (ereignisgesteuerten)<br />
Aufnahme e<strong>in</strong>es Spielers <strong>in</strong> die Teilnehmerliste (s. Kap. "2.4 Ereignisse<br />
<strong>in</strong> VBE") berechnet. Da es sich um ganzzahlig def<strong>in</strong>ierte Zellen<br />
handelt, ist die Berechnung auf recht e<strong>in</strong>fache Weise zu bewerkstelligen:<br />
H<strong>in</strong>weis 16<br />
Im Kapitel "2.4 Ereignisse<br />
<strong>in</strong> VBE" wurden bereits die<br />
<strong>in</strong> Abbildung 17 zu sehenden<br />
Zellen "I8", "I9" und "I10" im<br />
Tabellenblatt "Auslosung"<br />
vorgestellt.<br />
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel<br />
As Boolean)<br />
...<br />
Range("I9").Value = Range("I8").Value \ 4<br />
'I8 = Anzahl der<br />
Teilnehmer<br />
Range("I10").Value = Range("I8").Value Mod 4 'Rest bei Division<br />
durch 4<br />
List<strong>in</strong>g 15<br />
Berechnung der Werte für<br />
Zellen "I9" und "I10"<br />
42
Somit s<strong>in</strong>d die beiden Zellen "I9" und "I10" mit Inhalt gefüllt, bevor<br />
das Hauptprogramm Sub Auslosung startet. Die Sub Auslosung<br />
kann nun diese Zellen e<strong>in</strong>lesen und die entsprechenden Variablen<br />
mit dessen Inhalt <strong>in</strong>itialisieren, z.B.:<br />
Anz_5erTi(d) = Worksheets(1).Cells(10, 9).Value<br />
Für den Anwender besteht nun über die bereits <strong>in</strong> Kapitel 2.5 (siehe<br />
auch Abbildung 5, Seite 22) erwähnte Dialog-Box Startparameter<br />
Auslosung die Möglichkeit, e<strong>in</strong>e Änderung vorzunehmen und zwar<br />
<strong>in</strong> der Textbox TextBox3. Dies geschieht – wir er<strong>in</strong>nern uns – über<br />
das Drehfeld Sp<strong>in</strong>Button3. Die Prozedur zum Ändern lautet Private<br />
Sub Sp<strong>in</strong>Button3_Change(). Sie enthält die Berechnung der 4erund<br />
5er-Tische:<br />
H<strong>in</strong>weis 17<br />
Bzgl. TextBox3 und Sp<strong>in</strong>-<br />
Button3 vgl. die Ausführungen<br />
Seite 26/27<br />
Private Sub Sp<strong>in</strong>Button3_Change()<br />
...<br />
MaxAnzTi = AnzSp \ 4<br />
If AnzSp Mod 5 = 0 Then<br />
M<strong>in</strong>AnzTi = AnzSp \ 5<br />
Else<br />
M<strong>in</strong>AnzTi = AnzSp \ 5 + 1<br />
End If<br />
List<strong>in</strong>g 16<br />
Quellcode zur Änderung der<br />
Tischanzahl (s. auch List<strong>in</strong>g<br />
5)<br />
Sp<strong>in</strong>Button3.M<strong>in</strong> = M<strong>in</strong>AnzTi<br />
Sp<strong>in</strong>Button3.Max = MaxAnzTi<br />
TextBox3.Text = Sp<strong>in</strong>Button3.Value<br />
ReDim Preserve Anz5erTi(M<strong>in</strong>AnzTi To MaxAnzTi)<br />
ReDim Preserve Anz4erTi(M<strong>in</strong>AnzTi To MaxAnzTi)<br />
For i = M<strong>in</strong>AnzTi To MaxAnzTi<br />
Anz4erTi(i) = 5 * i - AnzSp<br />
Anz5erTi(i) = i - Anz4erTi(i)<br />
Next i<br />
TextBox4.Value = Anz5erTi(Sp<strong>in</strong>Button3.Value)<br />
TextBox5.Value = Anz4erTi(Sp<strong>in</strong>Button3.Value)<br />
Hier werden zunächst die m<strong>in</strong>imale und maximale Anzahl der Tische<br />
festgelegt (berechnet) und <strong>in</strong> Sp<strong>in</strong>Button3.M<strong>in</strong> sowie Sp<strong>in</strong>Button3.Max<br />
als Extremwerte e<strong>in</strong>getragen, damit der Anwender diese<br />
Grenzen nicht unter-/überschreiten kann. Innerhalb dieses Intervalls<br />
werden <strong>in</strong> e<strong>in</strong>er M<strong>in</strong>i-Tabelle für jeden e<strong>in</strong>zelnen Wert die Anzahl<br />
der 4er- und 5er-Tische berechnet und <strong>in</strong> den beiden folgenden<br />
Textboxen ausgegeben.<br />
(3) Zwei Spielzettelversionen<br />
Wie aus der Abbildung 13 <strong>in</strong> "2.5.2.1 Das Tabellenblatt Liste" zu ersehen<br />
ist, werden zusammen mit der Generierung des Tabellenblattes<br />
noch zwei Buttons/Makros erzeugt zur Druckausgabe: zum e<strong>in</strong>en die<br />
43
Teilnehmerliste mit Tisch- und Platz-Nr und zum zweiten für jeden<br />
Tisch e<strong>in</strong> vorgefertigter Spielzettel, der die Namen der Teilnehmer<br />
bereits be<strong>in</strong>haltet.<br />
Die Besonderheit dieser Spielzettel liegt nun dar<strong>in</strong>, dass der Anwender<br />
e<strong>in</strong>e Auswahl treffen kann zwischen zwei Varianten, und zwar<br />
zwischen e<strong>in</strong>em recht e<strong>in</strong>fach gehaltenen Spielzettel und dem offiziellen<br />
Spielzettel des DDV (Deutscher Doppelkopf Verband).<br />
Abbildung 18<br />
UserForm Drucken<br />
<strong>E<strong>in</strong></strong>gabemaske für die Auswahl<br />
der Spielzettel<br />
("privat/e<strong>in</strong>fach" oder<br />
"offiziell nach DDV")<br />
Als Gastgeber e<strong>in</strong>es <strong>in</strong>offiziellen privaten Turniers empfiehlt sich die<br />
e<strong>in</strong>fachere Variante. Möchte man jedoch streng nach den Turnierspiel-Regeln<br />
des DDV das Turnier ausrichten, so wählt man den offiziellen<br />
DDV-Spielzettel.<br />
Damit man sich e<strong>in</strong>e Vorstellung von den Spielzetteln machen kann,<br />
werden beide Varianten beispielhaft für e<strong>in</strong>en 5er-Tisch (jeweils für<br />
den 1. Durchgang mit vier Runden bzw. – als Extrembeispiel – mit<br />
zehn Runden) auf den Folgeseiten abgebildet.<br />
44
Die programmtechnische Umsetzung dieser Spielzettel ist – <strong>in</strong>sbesondere<br />
beim DDV-Spielzettel – re<strong>in</strong>e Fleißarbeit. Da für jede Variante<br />
je e<strong>in</strong> Spielzettel für e<strong>in</strong>en 4er- und e<strong>in</strong>en 5er-Tisch benötigt<br />
wird, bedarf es der Generierung von <strong>in</strong>sgesamt 4 Spielzetteln. Auf<br />
die Codierung soll hier <strong>in</strong> diesem Workshop nicht näher e<strong>in</strong>gegangen<br />
werden; zum e<strong>in</strong>en ist sie zu umfangreich und zum anderen entspricht<br />
dies auch nicht der Intention dieses Workshops, die wesentlichen<br />
Elemente des <strong>Programm</strong>s darzustellen und zu erläutern.<br />
Glücklicherweise muss man auch nicht die <strong>VBA</strong>-Befehle für die vielfältigen<br />
Formatierungen im <strong>E<strong>in</strong></strong>zelnen kennen, da man sich ja für<br />
diese Arbeit der Hilfe des Makrorekorders bedienen kann.<br />
Die Spielzettel könnte man natürlich auch auf e<strong>in</strong>fache Weise über<br />
das Internet beziehen und es ließe sich dadurch e<strong>in</strong>e Menge Arbeit<br />
sparen. Allerd<strong>in</strong>gs wäre man damit nicht so flexibel, denn<br />
a) zum e<strong>in</strong>en ist die Anzahl der Runden pro Durchgang bei e<strong>in</strong>er<br />
Spielzettel-Vorlage festgelegt - i.A. auf vier. Im <strong>Programm</strong> jedoch<br />
ist die Anzahl der Runden variierbar; wobei natürlich bei e<strong>in</strong>er<br />
Rundenanzahl von beispielsweise zehn die Darstellung auf e<strong>in</strong>e<br />
DIN-A4-Seite relativ stark komprimiert wird (s. Abbildung Seite<br />
47), aber immerh<strong>in</strong> für den praktischen <strong>E<strong>in</strong></strong>satz noch brauchbar<br />
ist. Dass allerd<strong>in</strong>gs bei e<strong>in</strong>em Turnier so viel Runden gespielt<br />
werden, ist auch wohl eher die große Ausnahme.<br />
b) zum zweiten werden bei dem <strong>Programm</strong> die Namen der Spieler<br />
bereits e<strong>in</strong>getragen. Dies hat neben der besseren Lesbarkeit den<br />
Vorteil, dass die Punkte der Spielzettel der e<strong>in</strong>zelnen Spieler <strong>in</strong><br />
der Reihenfolge von l<strong>in</strong>ks nach rechts auf dem Spielzettel der<br />
Reihenfolge im <strong>Programm</strong> im Durchgangs-Tabellenblatt von<br />
oben nach unten entsprechen. Bei Abgabe der Spielzettel kann<br />
die Übernahme der Punkte vom Spielzettel <strong>in</strong> das <strong>Programm</strong> somit<br />
schneller erfolgen, als wenn die Spieler die <strong>E<strong>in</strong></strong>tragungen<br />
selbst vorgenommen hätten, da dann die korrekte Reihenfolge<br />
nicht mehr gewährleistet ist.<br />
c) zum dritten ist man bzgl. der Ausgestaltung der Spielzettel bei<br />
der selbst programmierten Variante flexibler als bei e<strong>in</strong>er Vorlage.<br />
So pflege ich z.B. bei dem bereits im Vorwort erwähnten Turnier,<br />
welches immer zum Jahresende stattf<strong>in</strong>det, noch zur Auflockerung<br />
e<strong>in</strong> oder zwei Grafiken mit den besten Wünschen für das<br />
neue Jahr im Fußbereich der Spielzettel e<strong>in</strong>.<br />
H<strong>in</strong>weis 18<br />
<strong>E<strong>in</strong></strong> Nachteil bei der Generierung<br />
des Quellcodes per<br />
Makrorecorder ist allerd<strong>in</strong>gs<br />
die Tatsache, dass immer alle<br />
Optionen e<strong>in</strong>es FormatierungsDialogs<br />
übernommen<br />
werden, auch wenn diese<br />
Optionen zum größten Teil<br />
gar nicht genutzt werden.<br />
Viele überflüssige Informationen<br />
machen den Quellcode<br />
dadurch schnell unübersichtlich.<br />
48
3 Ausblick/Nachbetrachtung<br />
Die mit dem Schreiben dieses Dokumentes zwangsläufige verbundene<br />
Beschäftigung mit dem <strong>Programm</strong> hat mir gezeigt, dass an e<strong>in</strong>igen Stellen<br />
des Quelltextes doch noch e<strong>in</strong>iges verbesserungsbedürftig ist. Zwar<br />
läuft das <strong>Programm</strong> fehlerfrei, es s<strong>in</strong>d me<strong>in</strong>es Wissens ke<strong>in</strong>e logischen<br />
Fehler vorhanden. Es ist allerd<strong>in</strong>gs so, dass man – so war es jedenfalls<br />
bei mir – als Entwickler vielfach zufrieden ist, wenn das <strong>Programm</strong> genau<br />
das tut, was es soll. Dass man evtl. dabei e<strong>in</strong> wenig "geschlampt"<br />
hat, kümmert dann gar nicht mehr. Man hat ja, was man wollte.<br />
Um diesbezüglich Abhilfe zu schaffen, habe ich mir vorgenommen, das<br />
komplette <strong>Programm</strong> e<strong>in</strong>mal (wann auch immer das se<strong>in</strong> wird) e<strong>in</strong>er<br />
gründlichen "Re<strong>in</strong>igung" zu unterziehen, <strong>in</strong>sbesondere h<strong>in</strong>sichtlich Datendeklaration,<br />
logischer (Um)Strukturierung sowie Kommentierung.<br />
3.1 Neuralgische Punkte<br />
An dieser Stelle möchte ich auf e<strong>in</strong>ige Punkte für den Anwender h<strong>in</strong>weisen,<br />
die man bei der Bedienung des <strong>Programm</strong>s beachten sollte.<br />
a) Korrekte Erfassung der Teilnehmer<br />
Wie bereits <strong>in</strong> Kapitel 2.2 Die Gäste kommen sowie Kapitel 2.4<br />
Ereignisse <strong>in</strong> VBE) vorgestellt sowie aus Abbildung 3 (Seite 15) ersichtlich,<br />
werden die Teilnehmer an dem Turnier dadurch festgelegt,<br />
dass <strong>in</strong> Spalte "B" oder "C" neben dem Namen e<strong>in</strong> Rechtsklick<br />
oder e<strong>in</strong> Doppelklick ausgeführt wird. Hierbei bedarf es e<strong>in</strong>er<br />
besonderen Achtsamkeit, damit man nicht versehentlich<br />
durch das Klicken <strong>in</strong> e<strong>in</strong>er falschen Zeile e<strong>in</strong>en anderen Spieler <strong>in</strong><br />
die Liste aufnimmt. Wird der Fehler rechtzeitig vor Beg<strong>in</strong>n der<br />
Auslosung bemerkt, so ist das ke<strong>in</strong> Problem: der Zug lässt sich<br />
durch e<strong>in</strong>en erneuten Rechts- oder Doppelklick wieder rückgängig<br />
machen (s. 2.4 Ereignisse <strong>in</strong> <strong>VBA</strong>). Wurde aber bereits ausgelost<br />
und die Spieler begeben sich zu ihren Tischen, gilt es zu<br />
überlegen, e<strong>in</strong>e Korrektur des betreffenden Teilnehmers vorzunehmen<br />
und erneut auszulosen oder – alternativ - den Spieler<br />
unter dem nun falschen Namen spielen zu lassen.<br />
Noch ärgerlicher wird die ganze Geschichte, wenn e<strong>in</strong> Spieler gar<br />
nicht <strong>in</strong> die Liste aufgenommen wurde. Dann hilft nur noch:<br />
Nachträglich Spieler <strong>in</strong> die Teilnehmerliste aufnehmen und erneut<br />
auslosen.<br />
Ist man sich nicht sicher, ob alle Spieler korrekt e<strong>in</strong>getragen s<strong>in</strong>d,<br />
kann man direkt nach der Auslosung und dem Ausdruck der Liste,<br />
noch bevor die ersten beg<strong>in</strong>nen, sich an die Tische zu setzen,<br />
49
die Teilnehmer bitten, zu überprüfen, ob sie <strong>in</strong> der Liste aufgeführt<br />
s<strong>in</strong>d.<br />
Derartige Anwendungsfehler lassen sich me<strong>in</strong>er Me<strong>in</strong>ung nach<br />
auch durch <strong>Programm</strong>änderungen nicht gänzlich vermeiden.<br />
Möchte man hier vorbeugende Maßnahmen treffen, sehe ich die<br />
e<strong>in</strong>zige Möglichkeit, programmtechnische Vorkehrungen zu treffen<br />
dar<strong>in</strong>, dass man nach dem Rechts- oder Doppelklick für den<br />
Anwender e<strong>in</strong> Meldungsfenster (Funktion MsgBox) aufmacht<br />
mit dem H<strong>in</strong>weis: "Möchten Sie wirklich, dass ... <strong>in</strong> die Liste aufgenommen<br />
wird?"<br />
b) Datensicherung<br />
Um möglichen Datenverlusten vorzubeugen, sollte immer wieder<br />
zwischendurch gesichert werden. Man ist ja nie 100%-ig vor<br />
Stromausfällen, System- oder <strong>Programm</strong>hängern (letzteres hoffentlich<br />
nicht) geschützt.<br />
Automatische Sicherungen lassen sich natürlich auch programmtechnisch<br />
umsetzen (ActiveWorkbook.SaveAs Filename :=<br />
"Name der Datei"), z.B. direkt nach der Auslosung. Zudem könnte<br />
man dem Anwender e<strong>in</strong>en Button zur Verfügung stellen zur<br />
zwischenzeitlichen Sicherung, evtl. auch mit e<strong>in</strong>er fortlaufenden<br />
Sicherungsnummer im Date<strong>in</strong>amen. Dies wäre z.B. s<strong>in</strong>nvoll <strong>in</strong><br />
den Durchgangstabellen.<br />
c) Drucker versagt den Dienst<br />
Dass e<strong>in</strong> Drucker streikt, die T<strong>in</strong>te oder der Toner zur Neige geht,<br />
kommt leider <strong>in</strong> der Praxis immer wieder vor. Um dem vorzubeugen,<br />
ist es e<strong>in</strong>e Überlegung wert, sich vorab über e<strong>in</strong>en Ersatzdrucker<br />
mit dem bereits e<strong>in</strong>gespielten passenden Druckertreiber<br />
Gedanken zu machen.<br />
Hat man ke<strong>in</strong>en Ersatzdrucker parat, und sollte es beim Ausdruck<br />
der Spielzettel Probleme geben, ist das nicht ganz so tragisch;<br />
entweder hat man vorgesorgt und passende Vordrucke bereits<br />
mitgebracht oder aber die Teilnehmer fertigen die Spielzettel<br />
selber an ihren Tischen an.<br />
Richtig ärgerlich ist eigentlich nur der Fall, dass sich die Liste aus<br />
dem Tabellenblatt Liste nicht ausdrucken lässt.<br />
<strong>Programm</strong>technisch lassen sich diesbezüglich ke<strong>in</strong>e geeigneten<br />
vorbeugenden Maßnahmen treffen.<br />
50
3.2 Mögliche Weiterentwicklungen<br />
Neben e<strong>in</strong>er "Grundre<strong>in</strong>igung" des Quellcodes s<strong>in</strong>d natürlich auch noch<br />
Weiterentwicklungen des <strong>Programm</strong>s e<strong>in</strong>e zusätzliche Option. Folgende<br />
Varianten wären denkbar:<br />
‣ Das vorliegende <strong>Programm</strong> sieht lediglich e<strong>in</strong>e <strong>E<strong>in</strong></strong>zelwertung der<br />
Spieler vor. Nicht nur bei Vere<strong>in</strong>sturnieren, sondern auch im privaten<br />
Umfeld s<strong>in</strong>d vielfach auch Mannschaftswertungen von<br />
Interesse. Offen gestanden, habe ich mir diesbezüglich über e<strong>in</strong>en<br />
geeigneten Ansatz bisher noch ke<strong>in</strong>e Gedanken gemacht,<br />
würde aber diesen Gesichtspunkt bei e<strong>in</strong>er möglichen Erweiterung<br />
<strong>in</strong> der Prioritätenliste ganz nach oben setzen.<br />
‣ Die Abbildungen <strong>in</strong> diesem Skript lassen erkennen/erahnen, dass<br />
an der <strong>Excel</strong>-Oberfläche ke<strong>in</strong>e Veränderungen vorgenommen<br />
worden s<strong>in</strong>d. Der Funktion an sich tut das natürlich ke<strong>in</strong>en Abbruch,<br />
bzgl. der Optik ist es allerd<strong>in</strong>gs e<strong>in</strong>e Frage des Geschmacks,<br />
ob man das möchte. <strong>VBA</strong> stellt zum<strong>in</strong>dest die Mittel<br />
dafür bereit, die <strong>Excel</strong>-Oberfläche auszublenden, so dass ke<strong>in</strong>e<br />
Statusleiste, ke<strong>in</strong>e Menüleiste, und auch sonst ke<strong>in</strong>e Reste e<strong>in</strong>er<br />
<strong>Excel</strong>-Oberfläche mehr sichtbar s<strong>in</strong>d.<br />
‣ Vom Doppelkopf bis zum Skat ist der Weg zwar relativ weit, nicht<br />
ganz so weit entfernt ist jedoch die Entwicklung e<strong>in</strong>es Skatturnier-<strong>Programm</strong>s,<br />
wenn man die Vorlage für e<strong>in</strong> Doppelkopfturnier<br />
bereits besitzt.<br />
‣ Sehr aufwendig h<strong>in</strong>gegen stelle ich mir die Entwicklung des<br />
<strong>Programm</strong>s <strong>in</strong> e<strong>in</strong>er anderen <strong>Programm</strong>iersprache wie z.B. Java<br />
vor. Alle Objekte mit ihren Eigenschaften und Methoden, die <strong>in</strong><br />
<strong>Excel</strong>/<strong>VBA</strong> bereits vorhanden s<strong>in</strong>d und die der Entwickler nur<br />
noch je nach Bedarf e<strong>in</strong>setzen muss, müssten komplett neu konzipiert<br />
und def<strong>in</strong>iert werden.<br />
51
4 Literatur- und Quellenverzeichnis<br />
Literatur<br />
(1) Bernd Held: <strong>Excel</strong>-<strong>VBA</strong> <strong>Programm</strong>ierung, Markt+Technik Verlag,<br />
ISBN-10: 3827261856<br />
Onl<strong>in</strong>e-Quellen<br />
(1) www.merkwerk.de/files/exvba.pdf<br />
Andreas Kle<strong>in</strong>, Stefanie Friedrich: <strong>Excel</strong> 2003, <strong>Programm</strong>ierung<br />
mit Visual Basic<br />
(2) www.fernuni-hagen.de/imperia/md/content/zmi 2010/b012.pdf<br />
Johannes Gogolok: <strong>VBA</strong>-<strong>Programm</strong>ierung mit <strong>Excel</strong>, Grundlagen<br />
52