Gleisbild zeichnen

Bei kleinen, übersichtlichen Anlagen kann man vielleicht auf ein Gleisbild (Gb.) verzichten.
Gibt es aber auf der Anlage Schattenbahnhöfe, verdeckte Streckenführungen o.ä. ist ein Gb. die optimale Lösung für die Anzeige des jeweiligen Streckenzustandes.
Die meisten der kommerziellen Programme für die Digitalsteuerung bieten deshalb auch die Möglichkeit, ein Gb. zu erstellen.
Oftmals werden die Gleisstrecken dabei aus verschiedenen Modulen wie in einem Baukasten zusammengestellt. Da jede Anlage eine andere Streckenführung hat, ist dies der einzig gangbare Weg.
Dieses System hat jedoch den Nachteil, daß man auf das starre Raster der einzelnen Module festgelegt ist.
Spezielle Probleme, wie z.B. Streckenkreuzungen auf unterschiedlichem Niveau lassen sich oftmals überhaupt nicht darstellen.

Wesentlich flexibler ist man, wenn man sich das Gleisbild selber zeichnet.
Dazu ist kein besonderes Zeichenprogramm erforderlich, das bei jedem Windows mitgelieferte Paint® reicht völlig aus.
Damit können wir u.a. die Stellung von Weichen oder die Belegung von Gleisstrecken optisch signalisieren.

Das folgende einfache Gb. soll uns als Übungsvorlage dienen:

Bild 1
Bild 2
Bild 3

Um ein Gleisbild in Visual Basic anzeigen zu können, brauchen wir das Picture-Steuerelement (PictureBox).
Im Gegensatz zum Image-Steuerelement bildet die PictureBox einen Container.
Das heißt u.a., wenn wir die PictureBox an eine andere Position bringen, verschieben sich auch alle darin vorhandenen Tasten, Bilder usw. automatisch mit.

Um zur Laufzeit des Programms die Weiche zu schalten, senden wir nicht nur den betreffenden Befehl (33 oder 34) an das Interface, sondern machen zusätzlich das Image sichtbar oder unsichtbar (Weiche.Visible = True / False) .
Wenn es sichtbar (Weiche.Visible = True) ist, verdeckt es die Weiche auf der PictureBox.
Bei (Weiche.Visible = False) sehen wir die Original-Zeichnung der PictureBox.
________________________________

Wenn nun ein Zug in ein Gleis eingefahren ist, wie können wir dieses dann als belegt markieren ?
Die Information werden wir wohl meist über ein Rückmeldemodul erhalten, aber auch eine manuelle Markierung des
Streckenbereichs wäre denkbar.

Die einfachste Methode ist das Markieren der Gleistrecke in einer anderen Farbe.
In unserem Beispiel ist Gleis 1 frei und Gleis 2 belegt.
Gleis 1 soll als belegt gekennzeichnet werden. Wir könnten, - wie bei der Weiche -, ein Image darüberlegen und dieses sichtbar oder unsichtbar schalten. Ein sehr umständlicher Weg, vor allem, wenn wir viele Strecken ändern oder überwachen wollen.

Einfacher ist es, wenn wir die Farbe gleich in der PictureBox von grün nach rot ändern.
Visual Basic selbst kann diese Arbeit nicht ausführen, aber es gibt in Windows ein sogenanntes API (Application Programming Interface).
In diesem API sind viele verschiedene Funktionen verfügbar, welche von jedem Programm benutzt werden können.
Wir brauchen die Funktion: FloodFill.

FloodFill funktioniert wie das Werkzeug 'Fläche ausfüllen ' in Paint bzw. anderen Zeichenprogrammen.
In Paint heißt das Werkzeug 'Farbfüller'.

Um die Funktion in Visual Basic benutzen zu können, müssen wir sie in einem Modul (Modul.bas) deklarieren.
Die Deklaration lautet:

Public Declare Function FloodFill Lib "gdi32" Alias "FloodFill" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long

Wie jede Funktion liefert auch FloodFill einen Wert zurück. Wir brauchen ihn nicht und weisen ihn einer
Dummy-Variablen zu.

btnTest
Private Sub btnTest_Click()
Dim Dummy as Variant
...
...
End Sub

Damit die Funktion arbeiten kann, braucht sie 4 Werte:

hdc Handle der PictureBox (handle ist ein vom Betriebssystem an die PictureBox vergebener einmaliger ganzzahliger Wert)
X waagerechte Position
Y senkrechte Position
crColor Farbe, welche den Rand der einzufärbenden Fläche bildet

Ich muß zugeben, das sieht alles ziemlich kompliziert aus. Ist es aber wirklich nicht.

Am schlimmsten erscheint die Sache mit dem handle (hdc).
Die Funktion braucht die genaue Bezeichnung des Steuerelementes, in welchem die Änderung durchgeführt werden soll.
Das betreffende Steuerelement ' weiß' natürlich seinen Handle: in der Eigenschaft .hdc könnten wir ihn auslesen.
Einfacher ist jedoch die indirekte Adressierung.
Der erste Teil des Funktions-Aufrufs lautet damit:

btnTest
Private Sub btnTest_Click()
Dim Dummy as Variant
...
Dummy = FloodFill(Gleisbild.hdc, .... )
End Sub

Als weiteres braucht FloodFill die Position, an der die Änderung beginnen soll.
Um die Koordinaten X und Y zu ermitteln, brauchen wir lediglich 1 Zeile Code:

Gleisbild
Private Sub Gleisbild_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
MsgBox "X = " & Str(X) & ", Y =" & Str(Y)
End Sub

Wenn wir zur Laufzeit des Programms mit der Maus auf die grüne Fläche von Gleis 1 zeigen, erscheint nach dem Mausklick eine MsgBox mit den Werten von X und Y.
Beispiel: X = 196, Y = 12 .
Bei unserem Gleisbild liegt der Wert von X zwischen 120 und 220 und Y zwischen 11 und 13.

Wir erweitern unseren Funktions-Aufruf um X und Y:

btnTest
Private Sub btnTest_Click()
Dim Dummy as Variant
...
Dummy = FloodFill(Gleisbild.hdc, 196,12 .... )
End Sub

Zum Schluß muß FloodFill noch wissen, wie weit die 'Farbe fließen' darf oder, anders ausgedrückt, an welcher Farbe haltgemacht werden soll.
Wir haben die Strecke schwarz umrandet.
Folglich lautet die komplette Zeile zum Aufruf von FloodFill:

btnTest
Private Sub btnTest_Click()
Dim Dummy as Variant
...
Dummy = FloodFill(Gleisbild.hdc, 196,12, vbBlack)
End Sub

Aber noch wird FloodFill nicht zufriedenstellend arbeiten, denn bisher haben wir dem Programm wir noch nicht gesagt,
welche Farbe wir einsetzen wollen. Die Auswahl treffen wir mit der PictureBox-Eigenschaft FillColor.

btnTest
Private Sub btnTest_Click()
Dim Dummy as Variant
Gleisbild.FillColor = vbRed
Dummy = FloodFill(Gleisbild.hdc, 196,12, vbBlack)
End Sub

Nun endlich sollte es klappen: Gleis 1 wechselt von grün nach rot.

Um wieder auf grün zurückzuschalten installieren wir eine weitere Taste mit Name btnTest2.
Sie erhält folgende Code:

btnTest2
Private Sub btnTest_Click()
Dim Dummy as Variant
Gleisbild.FillColor = vbGreen
Dummy = FloodFill(Gleisbild.hdc, 196,12, vbBlack)
End Sub


Hinweis:
Der Rand, bis zu welchem die Farbe fließen soll, muß absolut dicht sein, wenn nur ein einziges Pixel fehlt,
füllt die Farbe ggf. die gesamte PictureBox aus.

Tip:
Wer nicht sicher ist, ob die Koordinaten X und Y korrekt sind, kann sich mit der folgenden Methode helfen:

Gleisbild.Pset(196,12), vbBlack

Visual Basic zeichnet dann an die angegebene Position einen winzigen schwarzen Punkt.
Man sollte dabei jedoch beachten, daß dieser Punkt auch mal im (schwarzen) Rand der Gleisstrecke landen kann
(und unsichtbar bleibt), in solchen Fällen sollte man mit einer anderen Farbe arbeiten.