Carsten Kelling 1997 ([EMail senden]); letzte Änderung: 20. Januar 1998


4.12 Unterstützungsklassen zur freien Verwendung

Neben den Klassen, die die eigentlichen Rechnerkomponenten darstellen, sind während der Entwicklung des Rechner-Baukastens auch andere Klassen entstanden, die der Autor für nützlich hält. Da mit ihrer Hilfe die Entwicklung eigener Demonstrations-Applets leichter von der Hand gehen kann und diese Applets leistungsfähiger, verständlicher und attraktiver werden können, gehören untenstehende Klassen ebenso in den Rechner-Baukasten:

Abbildung 36 zeigt die Klassenhierarchie der Unterstützungsklassen. Die Anwendung der einzelnen Klassen wird in den folgenden Abschnitten praxisnah erläutert.



Abbildung 36: Klassenhierarchie der Unterstützungsklassen

4.12.1 AboutRechnerDialog

Verwendungszweck

Zeigt in einem Fenster Informationen zu dem laufenden Applet an, entsprechend einem Menüpunkt wie "Über dieses Programm", "About" oder "Info" im "Hilfe"-Menü der meisten Programme, die unter einer graphischen Benutzeroberfläche laufen.

Initialisierung

Aus einer von java.awt.Frame abgeleiteten Klasse, wie SimControl (siehe 4.12.7), genügt ein Aufruf der Form

	(new AboutRechnerDialog(parent, this)).show();

wobei parent eine Instanz von Rechner sein muß.

Gebrauch

Kein weiterer Code ist notwendig; AboutRechnerDialog zeigt, von oben nach unten, die Ausgaben der Methoden getVersionString(), getAppletInfo() und getAuthorString() des übergebenen Rechner-Objekts (erster Parameter) an. Das Fenster zentriert sich automatisch über dem aufrufenden Fenster (zweiter Parameter) und ist nicht modal (blockiert nicht andere Fenster).

Sonstiges

Diese Klasse wird von SimControl (siehe 4.12.7) für den Menüpunkt "Info" aus dem "Hilfe"-Menü verwendet.

4.12.2 ConsoleWindow

Verwendungszweck

Stellt ein Konsolenfenster dar (ein Fenster, in dem Text ausgegeben werden kann, um Vorgänge im Rechner mitzuprotokollieren); verfügt über einen Knopf zum Löschen und einen, um festzulegen, ob das Protokoll "ausführlich" sein soll.

Initialisierung

In Rechner ist schon ein ConsoleWindow vordefiniert:

	public static ConsoleWindow traceWindow;

Dieses wird in initialize() (siehe 4.2 Das Package ckelling.baukasten) auch initialisiert:

	traceWindow = new ConsoleWindow();

Danach ist die Konsole noch unsichtbar. Sie leitet sich von java.awt.Frame ab, die sonstige Behandlung erfolgt wie von diesem gewohnt (Größe per resize() beliebig änderbar, Methoden hide() und show()).

Gebrauch

Die Methode clear() löscht den Inhalt der Konsole, append(String text) fügt einen Text an den vorhandenen an - es wird kein automatischer Zeilenvorschub generiert! setVerbose(boolean b) kann die Konsole "geschwätzig" machen, so daß auch bei Aufrufen von appendIfVerbose(String text) Text hinzugefügt wird. Anderenfalls würden diese Aufrufe ignoriert werden. Der "Geschwätzigkeitsstatus" läßt sich mit isVerbose() abfragen.

Aus Geschwindigkeitsgründen empfiehlt es sich, vor größeren Ausgaben (z.B. Ausführen vieler Maschinenbefehle durch goUntilBreakpoint()), lock() aufzurufen, danach unlock() - der Text wird auf einmal hinzugefügt, auf langsamen Systemen ohne just in time-compiler erspart das sehr viel Wartezeit.

Analog dazu geht Text, der an eine gerade nicht sichtbare Konsole geschickt wird, nicht verloren, wird aber erst bei Wiedererscheinen der Konsole durch einen einzigen Methodenaufruf dargestellt.

Sonstiges

SimControl (siehe 4.12.7) besitzt bereits den Menüpunkt "Befehlsgeschichte anzeigen", um Rechner.traceWindow ein- und auszublenden; Rechner selbst stellt folgende Methoden zur Verfügung:

public static void outToTrace(String message)
{
  traceWindow.append(message);  // Text in Konsole ausgeben
}

public static void outToTraceln(String message)
{
  traceWindow.append(message + "\n");  // Text ausgeben und neue Zeile anfangen
}

public static void outToTraceS(String message)
{
  traceWindow.appendIfVerbose(message);  // Text nur ausgeben, falls
}                                        // "ausführlich" eingestellt

public static void outToTracelnS(String message)
{
  traceWindow.appendIfVerbose(message + "\n");  // wie outToTraceS(),
}                                               // aber neue Zeile beginnen
public void outToTrace(String always, String supplement)
// Falls Konsole nicht "ausführlich" nur String always ausgeben und neue
// Zeile beginnen, sonst erst always, dann String supplement ausgeben und
// keine neue Zeile beginnen.
{
  if (! traceWindow.isVerbose())
    traceWindow.append(always + "\n");
  else
    traceWindow.appendIfVerbose(always + supplement);
}

4.12.3 DemonstrationStep

Verwendungszweck

Falls es nötig sein sollte, Unterdemonstrationsschritte einzuführen, ist es sicherer und komfortabler, eine Instanz von DemonstrationStep statt zweier int-Variablen zu verwenden.

Initialisierung

demonstrationStep = new DemonstrationStep((Rechner) this);

Gebrauch

private void demonstrate()
{
  if (demonstrationReady)
  {
    demonstrationReady = false;
    c_state = n_state;
    demonstrationStep.reset();  // Setzt Schritt auf 1, Unterschritte aus.
  }
  else
  {
  switch(c_state)
  {
    case READ:
      switch(demonstrationStep.get())  // Liefert den Schritt, egal,
                                       // ob Unterschritte aktiviert.
      {
        case 1:
          ...
          break;
        case 2:
          if (tagResult == READ_HIT)
          {...}
          else if (tagResult == READ_MISS_SYNC)
          // Unterschritte sind notwendig, weil hier mehr zu erklären ist.
          {
            if (! demonstrationStep.subStepEnabled())
              demonstrationStep.subStep(3);
              // Drei Unterschritte machen, dann werden Unterschritte
              // automatisch wieder ausgeschaltet; subStep() bei schon
              // aktivierten Unterschritten produziert sicherheitshalber
              // eine Fehlermeldung.

             switch(demonstrationStep.getSub())  // Liefert den Unterschritt
             {
             ...
             }  // Ende Verzweigung nach Demonstrationsunterschritt
          }
          break;
        ...
      }  // Ende Verzweigung nach Demonstrationsschritt
    ...
  }  // Ende Verzweigung nach c_state

  demonstrationStep.inc();  // erhöht Schritt ODER Unterschritt

  }  // Ende "else"-Fall (demonstrationReady == false)
}  // Ende von demonstrate()

Neben inc() gibt es noch dec(), welches automatisch Schritt oder Unterschritt um eins vermindert. Zusätzlich kann noch die Methode stepsSinceReset() nützlich sein - sie liefert die Anzahl der nach dem letzten Aufruf von reset() gemachten Schritte, also die Anzahl der Aufrufe von inc() weniger die von dec(), zurück.

Sonstiges

Eine Instanz hiervon wird in der Klasse Speicherhierarchie (der Cache-Demonstration) verwendet.

4.12.4 Error_Message

Verwendungszweck

Mit ErrorMessage können Applets standardisierte Fehlermeldungen mit beliebig langem Text ausgeben. Dieses fällt mehr ins Auge, als eine Ausgabe in der Java-Konsole (die im übrigen im MS Internet Explorer gar nicht existiert).

Initialisierung

Eine allgemeine Meldung erzeugt die Codezeile

	(new ErrorMessage(title, subTitle, message)).show();

title ist dabei der Titel des Fensters, subTitle wird im Fenster über dem Text der Mitteilung angezeigt. Jede ErrorMessage plaziert sich selbsttätig und sorgt dafür, daß sie sich nicht mit schon existierenden Fehlermeldungen vollständig überdeckt.

Gebrauch

Man verwende statt System.out.println(String message) einfach die als static deklarierte Methode (Rechner.)out(String message). Diese erzeugt eine ErrorMessage mit dem Fenstertitel "FEHLER", der Überschrift "Es ist ein Fehler aufgetreten:" und dem entsprechenden Text unter zwei Bedingungen:

  1. Rechner.errorMessagesEnabled wurde nicht auf false gesetzt.
  2. Es sind noch weniger als Rechner.MAX_ERROR_MESSAGES Fehlermeldungen zu sehen; wird diese Zahl erreicht, erscheint bei dem nächsten Aufruf von out() eine Meldung, die auf diesen Umstand hinweist und empfiehlt, das Programm abzubrechen und zunächst die Ursachen der bereits sichtbar gewordenen Fehler zu beheben. Weitere Meldungen werden unterdrückt, solange die Anzahl geöffneter Fehlermeldungsfenster nicht reduziert wird.

Sonstiges

Die Klasse ErrorMessage wird von allen Komponenten des Rechner-Baukastens und Demonstrations-Applets für diverse Fehlermeldungen benutzt.

4.12.5 RKWrapper

Verwendungszweck

RKWrapper ist ein sogenannter wrapper für die beiden Klassen RechnerKomponente und RechnerKomponentePanel, von denen sich die Elemente des Rechner-Baukastens ableiten (siehe 4.4.4 Die zwei Arten von Komponenten). Eine Instanz von RKWrapper verbirgt in ihrem Inneren eine Instanz der einen oder der anderen Klasse, kennt alle Methoden, die RechnerKomponente und RechnerKomponentePanel gemeinsam sind und ruft bei einem Aufruf einer Methode die korrespondierende Methode des Objektes in ihrem Inneren auf (und liefert gegebenenfalls den Wert zurück, den das "umfaßte" Objekt liefert).

Initialisierung

Es gibt drei Konstruktoren:

	public RKWrapper(RKWrapper source)
	public RKWrapper(RechnerKomponente rk)
	public RKWrapper(RechnerKomponentePanel rkp)

Gebrauch

Folgende Methoden sind RKWrapper bekannt - deren Semantik ist natürlich dieselbe wie bei den Rechner-Komponenten:

	public synchronized void paint(java.awt.Graphics onScreenGC)
	public synchronized void paintActivated(java.awt.Graphics onScreenGC)

	public synchronized void activate()
	public synchronized void deactivate()
	public boolean isActivated()
	public void lock()
	public void unlock()

	public void setValue(int newValue)
	public int getValue()
	public long getMaxValue()

	public void setCoordinates(int x, int y, String grabMode)
	public java.awt.Point getCoordinates(String qualifier)
	public String[] getPossibleQualifiers()
	public void reshape(int x, int y, int width, int height)
	public void reshape(int x, int y, int width, int height, String grabMode)

	public String[] getLabel()
	public void setLabel(String[] newLabel) // bei einer RechnerKomponentePanel
                                        // 'setLabel(newLabel[0])' aufrufen
	public void setLabel(String newLabel)

	public boolean intersectsWith(java.awt.Point p)
	public String getInfoTipText(java.awt.Point p)

Zusätzlich gibt es noch die Methoden

	public RechnerKomponente getRK()
	public RechnerKomponentePanel getRKP()

	public boolean equals(RechnerKomponente toBeCompared)
	public boolean equals(RechnerKomponentePanel toBeCompared)
	public boolean equals(RKWrapper toBeCompared)
	

Mit Hilfe der ersten beiden kann man das "umfaßte" Objekt direkt ansprechen. Diese Vorgehensweise ist dann sinnvoll, wenn man genau weiß, daß es sich beispielsweise um eine ALU handelt - dann kann man (bei einer Instanz source von RKWrapper) mit der Zeile

	((ALU) source.getRK()).calculate(...);

auch auf Methoden zurückgreifen, die RKWrapper nicht, das enthaltene Objekt aber sehr wohl kennt.

Mit den nächsten beiden Methoden läßt sich das "umfaßte" Objekt mit einer anderen Rechnerkomponente vergleichen; beide liefern false, falls eine Instanz von RechnerKomponente mit einer von RechnerKomponentePanel verglichen wird. Die letzte Methode vergleicht selbsttätig nur RechnerKomponente mit RechnerKomponente und RechnerKomponentePanel mit RechnerKomponentePanel (sofern jeweils vorhanden).

Sonstiges

RKWrapper wird ausgiebig von dem Editor-Applet verwendet.
1.1-Nachtrag 20.01.98 :

4.12.6 RTFTextArea

Verwendungszweck

Anzeigen von längeren Texten; der Text wird wortweise umgebrochen und erscheint auf Wunsch im Blocksatz. Sollte der Text nicht in den Ausgabebereich der RTFTextArea passen, erscheint ein Scrollbalken, um sich im Text zu bewegen. Text kann fett und kursiv ausgezeichnet werden, die dazu notwendigen Formatanweisungen entsprechen denen von HTML. Die relativ aufwendigen Umbruch- und Formatinformationen werden selbsttätig in einem internen Cache abgelegt.

Initialisierung

Der Hilfetext im Von-Neumann-Rechner-Applet wird mit einer folgendermaßen initialisierten RTFTextArea realisiert:

helpText = new RTFTextArea(SMALLFONT);
// Diese Schriftart wird kleiner, falls der Bildschirm kleiner als 800x600
// Pixel ist und ist andernfalls identisch mit NORMALFONT
// (Helvetica, 12 Punkt, nicht fett).

add(helpText);  // RTFTextArea leitet sich von java.awt.Panel ab.

coord = dbus.getCoordinates("end");
helpText.setLocation(0, coord.y + 10);
helpText.setSize(Math.min(WIDTH, getScreenSize().width), HEIGHT - coord.y - 10);

helpText.setText("Hier werden Hilfetexte erscheinen.");

Gebrauch

Die Methoden setText(String text) und appendText(String text) funktionieren wie zu erwarten und zeichnen obendrein den Text neu (Neuzeichnen kann aber auch durch repaint() erzwungen werden). Der Blocksatz wird über setBlockMode(boolean b) und isBlockMode() kontrolliert. Unterstützte Formatanweisungen im Text sind:

Formatanweisung

Bedeutung

<I> Text ab hier kursiv
</I> Text ab hier nicht kursiv
<B> Text ab hier fett
</B> Text ab hier nicht fett
<BR> oder <P> Neue Zeile beginnen
&< Das Zeichen "<"
Tabelle 18: Von RTFTextArea verstandene Formatanweisungen

Sonstiges

Alle Hilfetexte der Demonstrations-Applets sind Instanzen von RTFTextArea. Diese Klasse wird außerdem für die Anzeige der Fehlerbeschreibung in ErrorMessage verwendet. Sie benutzt Instanzen von RTFParsedText für den internen Cache. Nach einem setText() wird die erste Zeile des neuen Textes angezeigt, appendText() hingegen scrollt nicht.

4.12.7 SimControl

Verwendungszweck

SimControl stellt das aus den Demonstrations-Applets bekannte Fenster zum Steuern der Simulationen über Schaltflächen und Menüs dar. Bei einigen der Knöpfe läßt sich verhindern, daß sie angezeigt werden, so daß die Leser erst nach und nach mit allen Steuerfunktionen bekannt gemacht werden können (wie in 3.3.2 Simulation des Von-Neumann-Rechners getan). Abbildung 37 zeigt einen "Vollausbau" einer Instanz von SimControl sowie die beiden Menüs; im "Einstellungen"-Menü sind dabei die Standardwerte gezeigt, welche während der Initialisierung und durch einen Klick auf "Standardwerte benutzen" eingestellt werden.




Abbildung 37: Das von SimControl erzeugte Fenster mit Inhalt der Menüs

Initialisierung

Eine Zeile der Form

	scrollControl = new SimControl((Rechner) this);

ist ausreichend; das Steuerfenster wird angezeigt und bei der rechten oberen Ecke des aufrufenden Applets plaziert.

Für die fünf obersten Knöpfe werden, von links nach rechts, folgende Bilddateien benötigt: "Bilder/Pfeile/doppellinks.gif", "links.gif", "rechts.gif", "doppelrechts.gif" und "breakpoint.gif".

Die nachstehende Tabelle zeigt, welche Variablen aus Rechner vor dem Erzeugen einer SimControl auf false gesetzt werden können, damit bestimmte Elemente nicht erscheinen:

Auf false gesetzte Variable

Nicht erscheinende(s) Element(e)

buttonFast , und
manualRedraw Knöpfe "Repaint" und "Update"
programChoice Auswahlfeld für Programme ("Bubble Sort" oben)
buttonDecode Auswahlknopf "DECODE-Phase zeigen"
buttonOpcodes Auswahlknopf "Opcodes anzeigen"
Tabelle 19: Variablen aus Rechner, die von SimControl ausgewertet werden.

Gebrauch

Angeklicktes Objekt

Ausgeführter Code
("parent" ist die übergebene Instanz von Rechner)

if (parent.firstTime == true) // allererster Klick
{
parent.firstTime = false;
parent.demonstrate(false);
parent.demonstrate(true);
}
else
parent.demonstrate(true);

parent.paintActivated(parent.onScreenGC);

parent.firstTime = false;
parent.demonstrateBack();

if (parent.firstTime == true)
{
parent.firstTime = false;
parent.demonstrate(true);
}
parent.singleInstruction();

parent.firstTime = false;
parent.singleInstructionBack();

if (parent.firstTime == true)
{
parent.firstTime = false;
parent.demonstrate(true);
}
parent.goUntilBreakpoint();
Knopf "Simulation neu starten" parent.stopSimulation()
parent.updateAll();
parent.deactivateAll();
parent.paint(parent.onScreenGC);
Knöpfe "Repaint" oder "Update" parent.scrollThread neu starten

if (<Knopf "Update" gedrückt>)
{
parent.updateAll();
parent.deactivateAll();
}
parent.paint(parent.onScreenGC);
Auswahlknopf "DECODE-Phase zeigen" parent.showDecodeCycle wird entsprechend gesetzt.
Auswahlknopf "Opcodes anzeigen" Die Methode parent.showAllOpcodes mit entsprechendem booleschen Parameter wird aufgerufen.
Menüpunkt "Auf n Stellen erweitern" parent.expandNumbers wird entsprechend gesetzt.

parent.updateAll();
parent.paint(parent.onScreenGC);
Menüpunkt "Dezimalzahlen" parent.NUMBERBASE wird entsprechend auf 10 oder 16 gesetzt.

parent.updateAll();
parent.paint(parent.onScreenGC);
Menüpunkt "Standardwerte benutzen" parent.expandNumbers = true;
parent.NUMBERBASE = 16;


Setzen oder Entfernen der Häkchen vor den beiden Menüpunkten.

parent.updateAll();
parent.paint(parent.onScreenGC);
Menüpunkt "Befehlsgeschichte anzeigen" Rechner.traceWindow wird (bei Bedarf initialisiert und) entweder angezeigt oder versteckt.
Menüpunkt "Info" (new AboutRechnerDialog(parent, this)).show(); (siehe 4.12.1)
Auswahlfeld für Programme

Die Methode initRam() ist in Rechner leer vordefiniert; im Von-Neumann-Rechner-Applet lautet sie

protected void initRam(String program)
{
PROGRAM = program;
ram.initRam(program);
}


wobei ram der Hauptspeicher (eine Instanz von EditableMemory) ist.
parent.stopSimulation();

Die Zeichenkette label entspricht der angeklickten Zeile.

if (label.equals("Alles 0000"))
parent.PROGRAM = "zero";
else if (label.equals("Alles 00ff"))
parent.PROGRAM = "";
else if (label.equals("Nur LDA abs."))
parent.PROGRAM = "vnr_loadabs";
else if (label.equals("Alle Lade-/Speicherbefehle"))
parent.PROGRAM = "vnr_loadstore";
else if (label.equals("Einfaches Rechnen"))
parent.PROGRAM = "vnr_calculate";
else if (label.equals("Sprungbefehle"))
parent.PROGRAM = "vnr_jump";
else if (label.equals("Alle Befehle"))
parent.PROGRAM = "allcommands";
else if (label.equals("Cachetest 1"))
parent.PROGRAM = "cachetest";
else if (label.equals("Cachetest 2"))
parent.PROGRAM = "cachetest2";
else if (label.equals("Verdrängungstest"))
parent.PROGRAM = "replacetest";
else if (label.equals("Bubble Sort"))
parent.PROGRAM = "bubblesort";
else if (label.equals("Laden/Speichern"))
parent.PROGRAM = "loadstore";
else if (label.equals("Laden/Speichern 2"))
parent.PROGRAM = "loadstore2";

parent.initRam(parent.PROGRAM);
parent.paint(parent.onScreenGC);
Tabelle 20: Funktionen von SimControl

Sonstiges

SimControl verwendet die Klasse AboutRechnerDialog (siehe 4.12.1).

4.12.8 LoadProgress

Verwendungszweck

Zeigt ein einfaches Fenster an, um zu verdeutlichen, wie lange es noch dauern wird, bis alle Klassen für ein Applet geladen sein werden - ein Rechteck füllt sich allmählich von links nach rechts mit senkrechten Strichen.

Initialisierung

wm = new LoadProgress("Bitte warten, die Klassen für das Applet\n'" +
                       VERSIONSTRING + "'\nwerden geladen.", 1.
                       LoadProgress.WAITLENGTH, 2.
                       (Rechner) this);  3.

Zu den Parametern:

  1. Für den Umbruch des darzustellenden Textes ist durch Einfügen von Zeilenumbrüchen ("\n") selbst zu sorgen.
  2. Mit der Methode inc(int n) läßt man die Warteanzeige proportional zu n fortschreiten. Der LoadProgress ist mit dem zweiten Parameter mitzuteilen, wie groß die Summe aller n sein wird (damit sie die Anzeige bis 100 Prozent füllen kann). Es ist LoadProgress "bekannt", daß WAITLENGTH = 90 Striche in diese Anzeige passen; setzt man nun den zweiten Parameter auch auf WAITLENGTH, ist gewährleistet, daß bei inc(1) auch wirklich ein Strich erscheint (und nicht beispielsweise 0,8 = 0 Striche). Selbstverständlich muß man dann aber die Summe der n im eigenen Code tatsächlich (etwa) 90 betragen.
  3. Benutzt, um die LoadProgress auf dem Bildschirm zu zentrieren.

Gebrauch

Vorrangiges Entwicklungsziel war die Einfachheit dieser Klasse, damit sie schnell geladen und möglichst früh angezeigt werden kann. Es gibt aber auf jeden Fall kaum einen praktikablen Automatismus, um die gesamte oder verbleibende Wartezeit zu ermitteln; LoadProgress führt deswegen empirische Messungen der Wartezeit durch und ist darauf angewiesen, daß der Programmautor diese in Anweisungen im Code, wann die Warteanzeige wie weit fortzuschreiten habe, umsetzt:

public void init()
{
  wm = new LoadProgress(...);

  initialize(new Dimension(510, 490), new Dimension(510, 380));
  wm.inc(9);

  ...

  scrollControl = new SimControl((Rechner) this);
  wm.inc(47);

  ...

  dbus = new SimpleBus("Datenbus", dbusStartX, dbusStartY, 0, 185, (Rechner) this);
  wm.inc(1);

  ...

  wm.hide();
  wm.dispose(false);  // "true" während der Testphase, um Statistik auszugeben
}

Wird dispose() mit true als Parameter aufgerufen, gibt die LoadProgress, vor ihrer Auflösung, eine Statistik darüber aus, wann inc() mit welchem Parameter aufgerufen wurde, und welcher Parameter am besten zu der ermittelten Wartezeit gepaßt hätte. Achtung, diese Werte sind natürlich von dem verwendeten Computer (Geschwindigkeit, Betriebssystem und VM) und der Herkunft des Bytecodes (von einer lokalen Festplatte oder über eine Netzanbindung) abhängig! Hier gilt es, einen Kompromiß zu finden.

Sonstiges

Diese Klasse wird von den Applets Von_Neumann_Rechner und Speicherhierarchie benutzt.

4.12.9 TimerThread

Verwendungszweck

Ein TimerThread kann verwendet werden, um in gleichen Abständen bestimmte Methoden "anzustoßen", damit z.B. die Punkte auf allen aktivierten Bussen sich gleichmäßig weiterbewegen: Eine Instanz von TimerThread hat einen Namen und kennt eine Wartezeit und eine Instanz von Rechner. Sie "schläft" immer wieder für die Dauer der Wartezeit und ruft dann timerWokeUp(String timerTitle) des Rechner-Objektes auf, wobei sie als timerTitle ihren Namen übergibt.

Initialisierung

scrollThread = new TimerThread(SCROLLTIME, "scrolltimer", (Rechner) this);
scrollThread.start();

Der erste Parameter ist die Zeit (in ms) die der TimerThread "schläft", der zweite sein Titel, der dritte das zu benachrichtigende Rechner-Objekt. Angehalten wird ein TimerThread über Code wie diesen:

if ((scrollThread != null) && (scrollThread.isAlive()))
  scrollThread.stop();
scrollThread = null;

Gebrauch

Modifizieren sie timerWokeUp() ihres Rechners nach Wunsch:

public synchronized void timerWokeUp(String title)
{
  if (title.equalsIgnoreCase("scrolltimer"))
    scrollAll();
  else if (title.equalsIgnoreCase("blinktimer"))
  {
    blinkAll();
    onScreenGC.drawImage(offScreenImage, 0, 0, this);
  }
} /* end timerWokeUp */

Sonstiges

Damit sich Punkte auf den Bussen Ihres Rechneraufbaus bewegen, benötigen Sie lediglich eine Methode scrollAll() nach folgender Art:

public synchronized void scrollAll()
{
  dbus.scroll();  // hier alle Busse aufführen
  abus.scroll();

  abus.paintActivated(offScreenGC);  // hier alle Busse aufführen
  dbus.paintActivated(offScreenGC);

  onScreenGC.drawImage(offScreenImage, 0, 0, this);
} /* end scrollAll */

In Rechner ist bereits der TimerThread scrollThread wie oben aufgeführt vordefiniert, d.h. seine Wartezeit beträgt Rechner.SCROLLTIME (100 ms), nach welcher Zeitdauer er timerWokeUp( "scrolltimer") aufruft, welche Methode ebenfalls vordefiniert ist, und zwar eben so, daß scrollAll() aufgerufen wird.

Falls sich die Punkte langsamer oder schneller bewegen sollen, verändern sie einfach SCROLLTIME, bevor sie initialize() aufrufen.


Carsten Kelling 1997 ([EMail senden]); letzte Änderung: 17. September 1997