Für wen ist dieses Tutorial ?
Dieses Tutorial richtet sich an Entwickler, die Interesse an der Entwicklung eines Chalklets für E-Kreide haben. Etwas Erfahrung bei der Entwicklung von Java Programmen ist empfehlenswert, da grundlegende Kenntnisse im Umgang mit den Java typischen APIs, Jar-Dateien und dem Klassenpfad vorausgesetzt werden.
Was sind Chalklets ?
Die E-Kreide API ist eine Java Programmierschnittstelle, mit deren Hilfe Entwickler in der Lage sind, sogenannte Chalklet-Programme zu entwickeln, die direkt mit der Tafel des E-Kreide Systems kommunizieren können.
Die zu Grunde liegende Idee ist einfach: Chalklets melden sich als Abonnenten für einen bestimmten Tafelbereich an und erhalten dann vom Tafelsystem alle Linienzüge die durch den Benutzer, innerhalb dieses Bereichs gezeichnet wurden. Zusätzlich dürfen die Programme eigene Linienzüge auf dem vorgegebenen Bereich erzeugen. Diese einfache Art der Interaktion mit dem Tafelsystem eröffnet dem Entwickler interessante Möglichkeiten. So kann ein Chalklet zum Beispiel direkt auf die Eingabe eines Linienzuges durch den Benutzer reagieren, oder selbstständig Zeichnungen anfertigen. Chalklets werden in eigenen Jar-Archiven ausgeliefert, die alle notwendigen Klassen enthalten und in E-Kreide, wie in der Benutzerdokumentation unter Lesenzeichen für Chalklets editieren... beschrieben, eingebunden werden können.
Es wurden bereits eine Reihe von Chalklets, im Rahmen verschiedener Bachelor-, Studien- oder Diplomarbeiten entwickelt. Unter Beispiele sind verschiedene Chalklets aufgeführt.
In diesem Tutorial soll die Entwicklung eines Chalklets an einem konkreten Beispiel beschrieben werden. Es wird ein einfaches Chalklet entwickelt, das eingegebene Linienzüge des Benutzers in einer zufälligen Farbe nachzeichnet. Der Benutzer soll dabei auch die Möglichkeit haben falsche Linienzüge über die UNDO-Taste zu korrigieren.
Voraussetzungen
Um ein Chalklet zu entwickeln und zu testen, benötigt man eine funktionierende E-Kreide Installation und die E-Kreide API. Die aktuelle Version von E-Kreide kann hier heruntergeladen werden. Die für die Entwicklung notwendigen Klassen der Chalklet API werden bei der Installation von E-Kreide im Installationsverzeichnis unter "lib/echalk.jar" abgelegt. Um ein Chalklet zu kompilieren, müssen diese Klassen im Classpath der virtuellen Maschine vorhanden sein. Die Dokumentation der Klassen ist im Installationsverzeichnis unter "doc/echalkapi/index.html" zu finden.
Entwicklung
Chalklets werden von E-Kreide über Codereflection gefunden, das heißt E-Kreide sucht in dem Jar-Archiv des Chalklets nach festgelegten Klassen und verwendet diese für die Initialisierung und Ausführung des Chalklets. Damit ein Chalklet korrekt funktioniert, müssen die zwei folgenden Klassen unbedingt vorhanden sein:
- Eine Klasse die von "de.echalk.util.ChalkletKit" erbt - das ChalkletKit wird von E-Kreide erwendet um festzulegen welche Parameter das Chalklet bekommt und diese beim Start zu übergeben
- Eine Klasse die das Interface "de.echalk.util.Chalklet" implementiert - diese Klasse stellt das eigentliche Chalklet dar
1. Das ChalkletKit (Quellcode)
Zeilen 1 - 6, Package und Import Anweisungen.
1 package chalkletexample;
2
3 import de.echalk.util.*;
4 import java.awt.Dimension;
5 import java.util.Locale;
6
Vererbung der Klasse ChalkletKit, diese Klasse liefert Informationen über das jeweilige Chalklet. Der folgende Programmcode verdeutlicht, welche Methoden minimal überschrieben werden sollten.
7 public class ExampleChalkletKit extends ChalkletKit{
Statische Variable, die das KitSetupInfo enthält. Das KitSetupInfo beschreibt welche Parameter das Chalklet erwartet.
8 private static final KitSetupInfo KIT_INFO = new ExampleChalkletKitSetupInfo();
Der Konstruktor der Klasse sollte privat und nach außen, für andere Klassen nicht bekannt sein, da das Chalklet über eine Factory Methode erzeugt wird.
9 private ExampleChalkletKit() {}
10
Zeilen 11 - 31, Definition der vereinbarten Methoden.
11 public static KitSetupInfo getKitSetupInfo() {
12 return KIT_INFO;
13 }
14
Zeilen 15 - 22, konstruieren das eigentliche Chalklet. Der übergebene ChalkletContext aContext, kann später für Zeichenoperationen auf der Tafel verwendet werden, er bezieht sich auf jenes Stück der Tafel, für den das Chalklet registriert ist. Der ChalkletContext stellt die Verbindung vom Chalklet zur Tafel her und kann unter anderem verwendet werden, um festzustellen wieviel Zeit seit dem Start des Chalklets vergangen ist oder welche Hintergrundfarbe die Tafel auf der Chalkletfläche hat.
Die Parameter String[] aStrings enthalten die durch den Benutzer übergebenen Parameter für das Chalklet und müssen entsprechend des KitSetupInfo ausgewertet werden.
15 public static Chalklet getChalklet( ChalkletContext aContext,
String[] aStrings ) {
16 if ( aStrings.length != 1 )
17 throw new IllegalArgumentException("One argument expected but "+
aStrings.length+" found. ");
18 final long _delay = Long.parseLong( aStrings[0] );
19 if ( _delay <= 0 )
20 throw new IllegalArgumentException( "delay is not positive: "+_delay );
21 return new ExampleChalklet(aContext,_delay);
22 }
23
Zeilen 24 - 26, legen die minimale Größe in Pixel für das Chalklet fest.
24 public static Dimension getMinimumChalkletSize( String[] aStrings ) {
25 return new Dimension(200, 100);
26 }
27
Zeilen 28 - 30, legen den Namen für das Chalklet fest, der Name wird in der grafischen Oberfläche von E-Kreide an verschiedenen Stellen angezeigt.
28 public static String getChalkletName( Locale aLocale ) {
29 return Txt.get("Example Chalklet", aLocale);
30 }
31
Zeilen 32 - 46,definieren das KitSetupInfo, welches die benötigten Parameter für das Chalklet festlegt.
32 private static final class ExampleChalkletKitSetupInfo
33 extends KitSetupInfo {
34
Zeilen 35 - 37, geben eine lokalisierte Beschreibung des Chalklets zurück. Wird keine Übersetzung der übergebenen Zeichenkette gefunden, so wird die Zeichenkette selbst zurückgegeben. Übersetzungen können auf Serverseite in "dat/echalk_*.properties" eingetragen werden, wobei * mit durch die jeweilige locale Endung ersetzt wird. (zum Beispiel: _de für Deutsch oder _en_us für US English). Die Lokalisierung ist hauptsächlich wichtig für Chalklets, die fester Bestandteil der E-Kreide Installation werden sollen.
35 public String getDescription( Locale aLocale ) {
36 return Txt.get( "A Simple Chalklet Example...\n", aLocale );
37 }
38
Zeilen 39 - 45, gibt ein Array zurück, welches definiert welche Parameter das Chalklet erwartet. Die Parameter werden in ParamInfo Objekten gekapselt, die jeweils mindestens einen Namen, eine Beschreibung und einen Defaultwert haben. Folgende Parameter sind möglich:
- BooleanParam - boolscher Parameter, kann die Werte wahr oder falsch annehmen.
- EnumParam - Klasse für einen Auswahl Parameter aus einer übergebenen Liste.
- FileParam - Klasse für Dateinamen.
- LongParam - Klasse für einen Long Parameter
- PasswordParam - Bei der Eingabe bleibt das Passwort verborgen. Es wird allerdings lokal unverschlüsselt gespeichert (nicht Zugriffsgesichert gegen lokale Nutzer).
- StringParam - Zeichenketten, ohne Zeilenumbrüche.
- TextParam - Mehrzeilige Texte, in denen Zeilenumbrüche erlaubt sind.
In dem Beispiel wird ein LongParam - "Delay" erzeugt, der angibt wie lange (in ms) das Chalklet mit der Reaktion auf eine Benutzereingabe warten soll. Der Parameter hat den Defaultwert 1 und kann im Bereich von 1 - Long.MAX_LONG liegen.
39 public ParamInfo[] getParamInfo( Locale aLocale ) {
40 final String _aDelayName = Txt.get( "Delay", aLocale );
41 final String _aDelayDescription = Txt.get(
"Delay for strokes moves in ms.",
aLocale );
42 final ParamInfo _aDelayParam =
43 new LongParam( _aDelayName, _aDelayDescription,
new Long(1), new Long(1), null);
44 return new ParamInfo[] { _aDelayParam };
45 }
46 }
47}
2. Das Chalklet (Quellcode)
Zeilen 1 - 7, Package und Import Anweisungen.
1 package chalkletexample;
2
3 import de.echalk.util.*;
4 import java.awt.Color;
5 import java.util.LinkedList;
6 import java.util.*;
7
Zeile 8, Definition der Chalklet Klasse, diese muss das Interface de.echalk.util.Chalklet implementieren.
8 public class ExampleChalklet implements Chalklet {
Zeilen 9 - 12, Definition der vom Chalklet benötigten, privaten Variablen.
9 private final ChalkletContext aContext_;
10 private final long aDelay_;
11 private boolean aliveFlag_;
12 private LinkedList strokeBuffer_;
Zeilen 13 - 18, Konstruktor des Chalklets, dieser wird innerhalb der getChalklet()-Methode aufgerufen um das Chalklet mit den übergebenen Parametern zu erzeugen.
13 public ExampleChalklet(ChalkletContext aContext, long aDelay) {
14 aContext_=aContext;
15 aDelay_=aDelay;
16 strokeBuffer_= new LinkedList();
17 aliveFlag_=true;
18 }
19
Zeilen 20 - 25, diese Methode wird von E-Kreide aufgerufen um dem Chalklet zu signalisieren (durch Benutzerinteraktion oder dem Beenden der Tafel), dass es nicht länger benötigt wird.
20
21 endChalklet
22
23 public void endChalklet() {
24 aliveFlag_=false;
25 }
26
Zeilen 32 - 59, diese Methode wird immer dann aufgerufen wenn ein neuer Stroke durch den Benutzer auf dem Tafelteil, für den sich das Chalklet registriert hat, gezeichnet wurde. In dieser Methode findet die Verarbeitung der Eingaben statt, in dem Beispiel werden alle Strokes die nicht in rot gezeichnet wurden, in einer Liste gespeichert. Verwendet der Benutzer für seine Eingabe die Farbe Rot, so zeichnet das Chalklet alle bis dahin gespeicherten Strokes in einer zufälligen Farbe neu.
Die Eigenschaften von Stroke Objekten können nicht manipuliert werden, um die Strokes in einer neuen Farbe anzuzeigen, müssen neue Objekte über den BoardStroke-Konstruktor erstellt werden.
Bemerkung zur Stroke-Reihenfolge
Bitte beachten Sie, dass die Reihenfolge in der die Strokes gezeichnet werden nicht notwendig die Reihenfolge ist, in der sie vom Chalklet versandt wurden. Die Zeichenreihenfolge wird bestimmt durch die Zeitstempel der Strokes: Die Tafel bearbeitet immer denjenigen Stroke zuerst, der als erster komplett gezeichnet werden kann.
Als Tipp: Um eine bestimmte Reihenfolge der Strokes zu erzwingen, kann man Kopien der Strokes mit manipulierten Zeitstempeln an die Tafel verschicken. Der Konstruktor der Klasse BoardStroke stellt die dafür notwendigen Methoden zur Verfügung.
Bei der Generierung von Linienzügen sollte man zudem darauf achten, nicht zu viele Linienzüge pro Sekunde zu erzeugen. Da E-Kreide als Live System konzipiert ist, wird die maximale Anzahl an gezeichneten Linienzugsegmenten pro Sekunde begrenzt, um sicherzustellen, dass alle Segmente auch korrekt an entfernte Vorlesungsteilnehmer übertragen werden können und eine Überflutung der Clients zu vermeiden. Diese Begrenzung kann bei einer sehr großen Anzahl an zu zeichnenden Linienzügen zu unerwünschten Verzögerungen bei der Darstellung führen und sollte daher berücksichtigt werden. Die genaue Begrenzung kann in der Chalklet API nachgelesen werden.
27
28 pushStroke
29
30 @param boardStroke
31
32 public void pushStroke(BoardStroke boardStroke) {
33 try {
34 Thread.sleep(aDelay_);
35 }
36 catch (InterruptedException ex) { }
37 BoardStroke bs;
38
39
40 if(boardStroke.getColor().equals(Color.red)){
41 Iterator iter = strokeBuffer_.iterator();
42 while (iter.hasNext()) {
43 if(!aliveFlag_) return;
44 bs = (BoardStroke)iter.next();
45
46
47 aContext_.sendStroke(new BoardStroke(bs,
48 0,0,
49 0,
50 0,
51 0,
52 new Color((float)Math.random(),
53 (float)Math.random(),
54 (float)Math.random())));
55 }
56 }
57
58 strokeBuffer_.add(boardStroke);
59 }
60
Zeilen 61 - 68, diese Methode wird aufgerufen wenn der Benutzer den UNDO-Knopf betätigt und der zugehörige letzte Stroke an das Chalklet übergeben wurde. Diese Methode soll dem Chalklet Programmierer erlauben sein Datenmodell konsistent zu halten, und auf die Entfernung von Strokes zu reagieren. In dem Beispiel wird der letzte Stroke einfach nur aus dem Puffer entfernt, so dass er nicht in einer neuen Farbe gezeichnet wird.
Der Stroke muss nicht per Hand von der Tafel gelöscht werden, weil das E-Kreide System den Strich automatisch entfernt. Eine REDO-Operation muss nicht implementiert werden. Betätigt der Benutzer den REDO-Knopf, übergibt E-Kreide den letzte Stroke noch einmal an das Chalklet.
61
62 removeLastStroke
63
64 public void removeLastStroke() {
65 if(strokeBuffer_.isEmpty() || !aliveFlag_) return;
66
67 strokeBuffer_.removeLast();
68 }
69}
Beispiele
Beispiele für Chalklets finden Sie hier.
|