Der ADFC-Stormarn e.V. verwendet Klebeetiketten zur Codierung von Fahrrädern.
Auf diesen Etiketten ist ein EIN-Code (Eigentümer-Identifizierungs-Nummer) aufgedruckt, die es der Polizei, den Fundbüros und dem ADFC erlauben, den Eigentümer eines Fahrrads zu ermitteln. Eine über aufgeklebte Etikett angebrachte Plombierfolie schützt dieses vor dem Ablösen.
Dieses Verfahren eignet sich auch für andere Gegenstände, wie Kameras, Fahrrad-Akkus, Kinderwagen, Pferdesättel, etc.
Die Codier-Aktionen finden häufig j.w.d. statt und nicht immer gibt es dort einen verlässlichen Zugang zum Internet. Die Daten zur Generierung der EIN-Codes werden deshalb in einer lokal zur Verfügung stehenden SQLite-Datenbank abgelegt.
Diese Seite beschreibt den Hauptbildschirm Screen1 für die Code-Generierung.
Hauptbildschirm Screen1: Code-Generierung
Bereich Druckerauswahl / Anzahl Drucke
Eventhandler tbGemeinde.TextChanged
Eventhandler listGemeinden.AfterPicking
Bereich Hausnummer und Initialen
Eventhandler tbHausNr.TextChanged
Eventhandler tbInitialen.TextChanged
Eventhandler KeyboardControl.ActionButtonClicked
Bereich EIN-Codeermittlung und -anzeige
Der Kopf des Dialogbildschirms wird von einer Aktionsleiste gebildet. Deren Implementierung und Funktion ist im Kapitel ActionBar beschrieben. Die Funktionen zum Etikettendrucken sind im Kapitel Klebeetikett drucken dokumentiert.
![]() Startdialog Code-Generierung Erfassung des Ortsnamen |
![]() Erfassung des Straßennamen |
![]() Erfassung der Hausnummer und der Initialen |
![]() Komplett generierter EIN-Code mit Barcode |
Hinweis: nach Erstellung dieser Screenshots, wurde die Schaltfläche zur Online-Abfrage verschoben.
Die Erfassung der Adressdaten erfolgt in mehreren Stufen: Eingabe des Ortsnamens, des Straßennamens der Hausnummer und der Initialen. Der Orts- und der Straßenname wird gegen eine Datenbank geprüft, bzw. kann aus der Datenbank selektiert werden. Der zugehörige EIN-Code wird nach jeder Eingabe aktualisiert. Der Barcode wird erst dann angezeigt, wenn die Adresserfassung vollständig ist.
nicht
alle Felder sind von Beginn an sichtbar. Sie werden im Laufe der Adresserfassung an- und abgeschaltet.
Der Code ist recht umfangreich. Zur besseren Übersicht wurden logisch zusammenhängende Blöcke auch zusammenhängend angeordnet.
Die Diagramme stellen den Ablauf in vereinfachter Form dar. Nur die für das Verständnis wesentlichen Elemente sind enthalten.
Für beide Diagramme ist ein Link zu einer Grafik-Datei im SVG-Format angefügt. Damit können die Grafiken verzerrungsfrei skaliert werden. Die Grafiken wurden mit PlantUML erstellt. Der Code zur Generierung der Grafiken ist ebenfalls downloadbar.
Das linke Diagramm zeigt den vorgesehenen Ablauf. Im rechten Diagramm sind zusätzlich die möglichen Rücksprünge integriert.
![]() |
![]() |
|
Einfache Darstellung | Darstellung mit Rücksprüngen | |
im SVG-Format | im SVG-Format | |
PlantULM-Code | PlantULM-Code |
Typ | Name | Verwendung | Referenziert von |
---|---|---|---|
Global | GemeindeID | Interne Datenbank-ID der aktuell selektierten Gemeinde. | Get: Procedure: AfterSelectGemeinde Get: Procedure: FillStraßenListe Set: Procedure: AfterSelectGemeinde |
Global | GemeindeSchluessel | Gemeindeschlüssel der aktuell selektierten Gemeinde oder "xxx" (GemeindeSchluesselInit). | Get: Function: getCode Get: Function: isCodeComplete Get: Procedure: ComputeCode Set: Procedure: AfterSelectGemeinde Set: Procedure: BeforeSelectGemeinde |
Global | GemeindeSchluesselInit | Initialwert für Gemeindeschlüssel ("xxx"). Dient zur Voreinstellung und zum Vergleich. | Get: Function: isCodeComplete Get: Procedure: BeforeSelectGemeinde |
Global | Hausnummer | Aktuell erfasste Hausnummer oder "xxx" (Hausnummer). | Get: Function: getCode Get: Function: isCodeComplete Get: Procedure: ComputeCode Set: Event: tbHausNr.TextChanged Set: Procedure: BeforeInputHausnr Set: Procedure: BeforeSelectGemeinde Set: Procedure: BeforeSelectStrasse |
Global | HausnummerInit | Initialwert für Hausnummer ("xxx"). Dient zur Voreinstellung und zum Vergleich. | Get: Event: tbHausNr.TextChanged Get: Function: isCodeComplete Get: Procedure: BeforeInputHausnr Get: Procedure: BeforeSelectGemeinde Get: Procedure: BeforeSelectStrasse |
Global | Initialen | Aktuell erfasste Initialen oder "xx" (InitialenInit). | Get: Function: getCode Get: Function: isCodeComplete Get: Procedure: ComputeCode Set: Event: cmdDelInitials.Click Set: Event: tbInitialen.TextChanged Set: Procedure: BeforeInputHausnr Set: Procedure: BeforeSelectGemeinde Set: Procedure: BeforeSelectStrasse |
Global | InitialenInit | Initialwert für Initialen ("xx"). Dient zur Voreinstellung und zum Vergleich. | Get: Event: cmdDelInitials.Click Get: Event: tbInitialen.TextChanged Get: Function: isCodeComplete Get: Procedure: BeforeInputHausnr Get: Procedure: BeforeSelectGemeinde Get: Procedure: BeforeSelectStrasse |
Global | Jahr | Aktuelle Jahreszahl, zweistellig. | Get: Function: getCode Get: Procedure: ComputeCode Set: Event: Screen1.Initialize |
Global | Kfz | Aktuell ermitteltes Kfz-Kennzeichen oder "xx" (KfzInit). | Get: Function: getCode Get: Function: isCodeComplete Get: Procedure: ComputeCode Set: Procedure: AfterSelectGemeinde Set: Procedure: BeforeSelectGemeinde |
Global | KfzInit | Initialwert für Kfz ("xx"). Dient zur Voreinstellung und zum Vergleich. | Get: Function: isCodeComplete Get: Procedure: BeforeSelectGemeinde |
Global | PrintCount | Anzahl am aktuellen Tag gedruckte Etiketten. | Get: Event: Pte560.AfterDataPrinted Get: Event: Screen1.Initialize Get: Event: Screen1.OtherScreenClosed Set: Event: Pte560.AfterDataPrinted Set: Event: Screen1.Initialize Set: Event: Screen1.OtherScreenClosed |
Global | StrassenSchluessel | Straßenschlüssel der aktuell selektierten Straße oder "xxxxx" (StrassenSchluesselInit). | Get: Function: getCode Get: Function: isCodeComplete Get: Procedure: ComputeCode Set: Procedure: AfterSelectStrasse Set: Procedure: BeforeSelectGemeinde Set: Procedure: BeforeSelectStrasse |
Global | StrassenSchluesselInit | Initialwert für StrassenSchluessel ("xxxxx"). Dient zur Voreinstellung und zum Vergleich. | Get: Function: isCodeComplete Get: Procedure: BeforeSelectGemeinde Get: Procedure: BeforeSelectStrasse |
Global | Today | Tagesdatum im Format "yyyy-MM-dd" zum Zugriff auf eine TinyDB. | Get: Event: Pte560.AfterDataPrinted Get: Event: Screen1.Initialize Get: Event: Screen1.OtherScreenClosed Set: Event: Screen1.Initialize |
Global | WakeLock | Gibt an, ob aktuell ein WakeLock gesetzt ist. | Get: Event: ActionBar.Button1Click Set: Event: ActionBar.Button1Click |
Function | FormatHausNr | Formatiert die Hausnummer auf drei Stellen mit führenden Nullen. | Call: Event: tbHausNr.TextChanged |
Function | GetChecksum | Berechnet die Checksumme für den Barcode (Code-128). | Call: Procedure: ComputeCode |
Function | getCode | Liefert den EIN-Code. | Call: Event: Util.DelayedEvent Call: Procedure: ComputeCode |
Function | getGemeindeID | Ermittelt die interne Datenbank-ID der in der ListView listGemeinde selektierten Gemeinde. | Call: Event: listGemeinden.AfterPicking Call: Procedure: AfterSelectGemeinde |
Function | getSrassenID | Ermittelt die interne Datenbank-ID der in der ListView listStrasse selektierten Straße. | Call: Event: listStrassen.AfterPicking Call: Procedure: AfterSelectStrasse |
Function | isCodeComplete | Ermittelt, ob alle Felder für die Codegenerierung erfasst wurden. | Call: Event: cmdPrint.Click Call: Procedure: ComputeCode |
Procedure | AfterSelectGemeinde | Wertet die erfasste Gemeinde aus und schaltet zur Selektion der Straße weiter. | Call: Event: listGemeinden.AfterPicking Call: Procedure: FillGemeindeListe |
Procedure | AfterSelectStrasse | Wertet die erfasste Straße aus und schaltet zur Erfassung der Hausnummer weiter. | Call: Event: listStrassen.AfterPicking Call: Procedure: FillStraßenListe |
Procedure | BeforeInputHausnr | Bereitet die Erfassung der Hausnummer und der Initialen vor. | Call: Event: cmdDelHausNr.Click Call: Procedure: AfterSelectStrasse |
Procedure | BeforeSelectGemeinde | Bereitet die Selektion der Gemeinde vor. | Call: Event: cmdDelGemeindeDisp.Click Call: Event: cmdDelGemeindeInp.Click Call: Event: Screen1.Initialize |
Procedure | BeforeSelectStrasse | Bereitet die Selektion der Straße vor. | Call: Event: cmdDelStraßeDisp.Click Call: Event: cmdDelStraßeInp.Click Call: Procedure: AfterSelectGemeinde |
Procedure | CheckPrinters | Prüft, ob nur ein Drucker gekoppelt ist und schlägt diesen zur Verwendung vor. | Call: Event: Screen1.Initialize Call: Event: Screen1.PermissionGranted |
Procedure | ComputeCode |
Berechnet den EIN-Code mir Leerzeichen zwischen den Elementen. Falls alle Daten vorliegen:
|
Call: Event: cmdDelInitials.Click Call: Event: tbHausNr.TextChanged Call: Event: tbInitialen.TextChanged Call: Procedure: AfterSelectStrasse Call: Procedure: BeforeSelectGemeinde Call: Procedure: BeforeSelectStrasse |
Procedure | EnableButton | (De-) Aktiviert eine der cmdDel...-Schaltflächen und stellt deren Farbe ein. | Call: Procedure: AfterSelectStrasse Call: Procedure: BeforeInputHausnr Call: Procedure: BeforeSelectGemeinde Call: Procedure: BeforeSelectStrasse |
Procedure | FillGemeindeListe | Füllt das ListView listGemeinden mit den Gemeindenamen, die mit der Zeichenfolge beginnt, wie sie Global Gemeinde hinterlegt ist. | Call: Event: tbGemeinde.TextChanged Call: Procedure: BeforeSelectGemeinde |
Procedure | FillStraßenListe | Füllt das ListView listStrassen mit den Straßennamen, die mit der Zeichenfolge beginnt, wie sie Global Strasse hinterlegt ist. | Call: Event: tbStrasse.TextChanged Call: Procedure: BeforeSelectStrasse |
Procedure | RequestBTPermissions | Fordert bei Android die Erlaubnis zur Benutzung der Bluetooth-Funktionen an. | Call: Event: Screen1.Initialize |
Dieser Bereich ist immer sichtbar. lblAnzahlDrucke ist in ein separates HorizontalArrangement mit schwarzem Hintergrund eingebunden. Das Label ist etwa kleiner dimensioniert, so dass sich in der Ansicht ein schwarzer Rand darum ergibt. Zur Implementierung dieses Bereichs siehe Implementierung: Klebeetikett drucken.
Es folgt ein HorizontalArrangement (Spacer1) zur Erzeugung eines Abstands zum nachfolgenden Bereich.
Das Design für die Gemeindeauswahl besteht aus den beiden Blöcken vaInpGemeinde (gelb hinterlegt) zur Selektion der Gemeinde und vaDispGemeinde (grün hinterlegt) zur Anzeige der selektierten Gemeinde mit zugehörigem Kfz-Kennzeichen und dem Bundesland. Jeweils nur einer der Bereiche ist sichtbar geschaltet.
Prozedur BeforeSelectGemeinde bereitet die Selektion der Gemeinde vor und deaktiviert alle anderen Bereiche. Insbesondere wird vaInpGemeinde sichtbar und vaDispGemeinde unsichtbar geschaltet. FillGemeindeListe selektiert die Gemeinden, deren Namen mit der Zeichenkette beginnt, und prüft, ob die Auswahl bereits eindeutig ist. AfterSelectGemeinde wertet die Selektierte Gemeinde aus und befüllt die Felder in vaDispGemeinde. vaDispGemeinde wird sichtbar und vaInpGemeinde unsichtbar geschaltet.
![]() |
![]() |
Die folgende Grafik zeigt exemplarisch der Block zur Vorbereitung der Gemeindeauswahl. Die Vorbereitung zur Straßenauswahl und zur Eingabe der Hausnummer und der Initialen erfolgt analog.
Diese Prozedur wird immer dann aufgerufen, wenn sich die Kriterien für die Selektion der Gemeinde geändert haben. Also zu Beginn der Gemeindeauswahl und wenn sich die Eingabe in der TextBox zur Erfassung des Gemeindenamens (tbGemeinde) geändert hat.
Zuerst werden die zum eingegeben Text in der TextBox tbGemeinde passenden Gemeinden selektiert und die ListView-Komponente listGemeinden mit der resultierenden Menge gefüllt (siehe UrsAI2SQLiteEIN._Gemeinden). Danach wird geprüft, ob die Selektion eindeutig ist, d.h. die Liste der abgerufenen Geimden enthält nur ein Element. Ist dies der Fall, wird dieses Element in der ListView-Komponente selektiert (dies entspricht dem Antippen einer Zeile in der Liste). Es wird ein Sound abgespielt, um dem Anwender den Hinweis zu geben, dass automatisch auf die Eingabe der Straße weiter geschaltet wird.
Zuletzt wird die Prozedur AfterSelectGemeinde aufgerufen. Dies ist die gleiche Prozedur, die auch beim Ereignis listGemeinden.AfterPicking aufgerufen wird.
Immer dann, wenn sich die Eingabe in der TextBox zur Erfassung des Gemeindenamens (tbGemeinde) geändert hat, muss die Liste der passenden Gemeinden aktualisiert werden.
Wenn die Liste der passenden Gemeinden zu lang ist, wird diese abgeschnitten und eine Zeile mit "..." als Gemeindename angefügt (siehe UrsAI2SQLiteEIN._Gemeinden). Dann ist die hinterlegte interne ID der Gemeinde 0 (Missing Value). Dieses Listenelement darf nicht selektiert werden.
Wurde ein gültiges Listenelement ausgewählt, wird, wie nach einer eindeutigen Selektion (siehe Prozedur FillGemeindeListe) die Prozedur AfterSelectGemeinde aufgerufen.
Diese Funktion ruft die im Image-Feld des selektierten ListView-Elements hinterlegte ID der Gemeinde ab. Dies geht leider nicht direkt, sondern muss über die Elements-Eigenschaft erfolgen.
Diese Prozedur wird aufgerufen, wenn eine eindeutige Auswahl der Gemeinde erfolgt ist. Die globalen Variablen werden zur weiteren Verwendung mit den Daten der Gemeinde belegt. Ebenso die Felder zur Anzeige im Block vaDispGemeinde. vaDispGemeinde wird sichtbar und vaInpGemeinde unsichtbar geschaltet.
Damit ist die Selektion der Gemeinde abgeschlossen und es wird mit der Selektion der Straße fortgefahren.
Das Design für die Straßenauswahl besteht aus den beiden Blöcken vaInpStrassee (grün hinterlegt) zur Selektion der Straße und haDispStrasse (gelb hinterlegt) zur Anzeige der selektierten Straße. Jeweils nur einer der Bereiche ist sichtbar geschaltet.
Prozedur BeforeSelectStrasse bereitet die Selektion der Gemeinde vor und deaktiviert alle anderen Bereiche. Insbesondere wird vaInpStrasse sichtbar und haDispStrasse unsichtbar geschaltet. FillStrassenListe selektiert die Gemeinden, deren Namen mit der Zeichenkette beginnt, und prüft, ob die Auswahl bereits eindeutig ist. AfterSelectStrasse wertet die Selektierte Straße aus und befüllt die Felder in vaDispStrasse. haDispStrasse wird sichtbar und vaInpStrasse unsichtbar geschaltet.
![]() |
![]() |
Der Code der einzelnen Blöcke ist im Wesentlichen analog zu den zur Gemeindeauswahl.
Die Hausnummer und die Initialen werden zusammenerfasst. Die Blöcke zur Erfassung dieser beiden Daten werden im übergeordneten Block vaWeitereDaten zusammengefasst.
![]() |
![]() |
Die Funktionalität in diesem Bereich steckt in den TextChanged-Ereignissen der TextBoxen.
![]() |
![]() |
Die Hausnummer muss dreistellig angegeben werden. Die Funktion FormatHausNr fügt führende Nullen ein. Werden mehr als drei Stellen eingegeben, wird der Hintergrund der TextBox auf rot gesetzt. Der globalen Variablen Hausnummer wird der Wert HausnummerInit ("xxx") zugewiesen, als Hinweis, dass keine gültige Hausnummer eingegeben wurde.
Für die Initialen sind zwei Stellen vorgesehen. Werden mehr als zwei Stellen eingegeben, wird der Hintergrund der TextBox auf rot gesetzt. Ist die Anzahl der eingegebenen Zeichen nicht genau zwei, wird der globalen Variablen Initialen der Wert InitialenInit ("xx") zugewiesen, als Hinweis, dass keine gültigen Initialen eingegeben wurden.
Die Aktionsschaltfläche der Tastatur ist bei der Eingebe der Hausnummer und Initialen mit Zusatzfunktionen belegt:
Wenn die Aktionsschaltfläche während der Eingabe der Hausnummer (tbHausNr) angetippt wird, wird zur Eingabe der Initialen weiter geschaltet. Während der Eingabe der Initialen (tbInitialen) bewirkt die Aktionsschaltfläche, dass die Tastatur ausgeblendet wird und damit die in der Ansicht nachfolgenden Elemente, z.B. die Anzeige des generierten Codes nicht mehr durch die Tastatur verdeckt werden.
In dem Label lblCode wird der bei jeder Eingabe aktualisierte Code angezeigt. Dies übernimmt die Prozedur ComputeCode, die an vielen Stellen eingebunden wird (s. Referenz). Wenn alle für die Codegenerierung notwendigen Elemente korrekt erfasst wurden, wird außerdem der Code als Barcode angezeigt und die Schaltfläche cmdPrint zum Druck des Etiketts freigegeben.
getCode stellt aus den in den globalen Variablen angelegten Code-Elementen den Ein-Code zusammen.
computeCode stellt aus den in den globalen Variablen angelegten Code-Elementen den Ein-Code für die Anzeige im Label lblCode zusammen. Für noch nicht erfasste Elemente enthalten die Variablen eine entsprechende Anzahl von "x". Die einzelnen Elemente werden zur besseren Übersicht, wenn man sie ablesen muss, durch Leerzeichen getrennt.
Ist der Code komplett, d.h. alle notwendigen Elemente wurden korrekt erfasst, wird ein Barcode erzeugt und angezeigt und die Schaltfläche cmdPrint zum Etikettendruck wird freigeschaltet.
Die Funktion überprüft, ob die globalen Variablen Hausnummer und Initialen gültige Werte besitzen.
Wenn das gerät eine Weile nicht benutzt wird, schaltet Android normalerweise das Gerät aus. Um es wieder zu aktivieren, muss man sich neu anmelden. Das ist besonders dann störend, wenn das Gerät von mehreren Personen benutzt wird. Dann muss entweder die Pin weiter gegeben werden oder der Eigentümer des Geräts zum erneuten Anmelden verfügbar sein.
Über die Extension UrsAI2KeepAwake wird ein ScreenDimWakeLock gesetzt, der das Wechseln in den Standby-Modus verhindert, es aber erlaubt, dass Android das Gerät zur Akkuschonung abdunkeln darf. Bei der Initialisierung von Screen1 wird bereits ein ScreenDimWakeLock als Voreinstellung gesetzt. Über den AktionButton1 der ActionBar kann der WakeLock gelöscht oder neu gesetzt werden:
Ein gesetzter WakeLock wird durch das Symbol
in der
AktionBar angezeigt. Wenn kein WakeLock gesetzt ist wechselt das Symbol auf
.
Der Aufruf weiterer Funktionsdialoge erfolgt über das Menü der Actionbar:
Beim Initialisieren des Screens wird das Menü aufgebaut:
Wird ein Menüpunkt angetippt, wird das Ereignis ActionBar.MenuItemSelected ausgelöst. Der zugehörige Funktionsdialog wird geöffnet. Wenn die Funktion Online-Abfrage gestartet werden soll, werden die bereits erfassten Daten als Liste zusammengestellt und dem Dialog als Startwert zur Verfügung gestellt.
Die Funktionen sind auf der Seite EIN-Code: Drucken beschrieben.