====== Showcase: Disco-Licht ====== Ein Disco-Licht (DiscoLight) ist ein "Kasten" der mehrere LEDBars beherbergt, welche wiederum jeweils eine Menge bunt und zufällig leuchtender LEDs beherbergen. In der folgenden Abbildung sind zwei DiscoLights mit jeweils drei LEDBars, einer linken, mittleren und rechten LEDBar, zu sehen. {{ :wiki:discolight.png?nolink&400 |}} Eine LEDBar visualisiert ihre LEDs rasterförmig (also angeordnet in Zeilen und Spalten). Jede LED kann separat an- oder ausgeschaltet werden sowie blinken. Aus Effizienzgründen sind Teile der Klassen LED und LEDBar nebenläufig mit Threads programmiert. ===== Klasse LED ===== import geofasc.swing.Circle; import java.awt.Color; /** * Eine LED hat die festgelegten Zustände an, * aus und blinkend. Beim Uebergang und Befinden in * diesen Zustaenden loest eine LED eine passende Aktion aus. */ public class LED extends Circle { private int mState; private Color mOnColor; private Color mOffColor; private Thread mBlinkThread; /** * Erzeugt eine neue LED led. * * @param x * die x-Koordinate von led bez. des Eltercontainers * @param y * die y-Koordinate von led bez. des Eltercontainers * @param diameter * der Durchmesser von led * @param onColor * die An-Farbe von led * @param offColor * die Aus-Farbe von led */ public LED(int x, int y, int diameter, Color onColor, Color offColor) { super(x, y, diameter); setFigureFilled(true); mOnColor = onColor; mOffColor = offColor; mState = 2; actionOff(); } /** * Schaltet die verschiedenen Zustaende dieser LED durch. */ public void doSwitch() { if (mState == 0) { // off -> on mState = mState + 1; actionOn(); } else if (mState == 1) { // on -> blinking mState = mState + 1; actionBlinking(); } else if (mState == 2) { // blinking -> off mState = 0; actionOff(); } } /** * Eine ausgeloeste Aktion. */ private void actionOn() { interruptBlinkingThread(); setFigureFillColor(mOnColor); } /** * Eine ausgeloeste Aktion. */ private void actionOff() { interruptBlinkingThread(); setFigureFillColor(mOffColor); } /** * Eine ausgeloeste Aktion. */ private void actionBlinking() { if (mBlinkThread != null) return; mBlinkThread = new Thread() { public void run() { try { // Bis hierher technischer Code // -------------------------------------- while (mState == 2 && !isInterrupted()) { setFigureFillColor(mOnColor); sleep(100); setFigureFillColor(mOffColor); sleep(300); } // -------------------------------------- // Ab hier wieder technischer Code } catch (Exception e) { } }; }; mBlinkThread.start(); } /** * Loest eine Unterbrechungsanforderung fuer den Thread zum nebenlaeufigen * Blinken aus. */ private void interruptBlinkingThread() { if (mBlinkThread != null) { mBlinkThread.interrupt(); mBlinkThread = null; } } } ===== Klasse LED-Bar ===== import geofasc.swing.Rectangle; import geofasc.swing.tool.Calculator; import java.awt.Color; import java.awt.FlowLayout; /** * Eine LEDBar besteht aus einer Menge von {@link LED}s, die * rasterfoermig angeordnet sind. Eine solche Bar sorgt fuer das zufaellig * verteilte Blinken ihrer {@link LED}s. * * Die rasterförmige Anordnung der {@link LED}s wird über ein {@link FlowLayout} * erreicht. * */ public class LEDBar extends Rectangle { private static final int sLedDiameter = 15; private LED[] mLeds; // Array zum Speichern der Menge von Leds private Thread mLightningThread; // Thread zum nebenlaeufigen Blinken von // Leds /** * Erzeugt eine neue LEDBar bar. * * @param x * die x-Koordinate von bar bez. ihres Eltercontainers * @param y * die y-Koordinate von bar bez. ihres Eltercontainers * @param rows * die Led-Zeilenanzahl von bar * @param cols * die Led-Spaltenanzahl von bar */ public LEDBar(int x, int y, int rows, int cols) { super(x, y, cols * (sLedDiameter + 4), rows * (sLedDiameter + 4)); mLeds = new LED[rows * cols]; setLayout(new FlowLayout(FlowLayout.CENTER, 2, 2)); setFigureFilled(true); setFigureFillColor(Color.BLACK); fillWithLeds(); } /** * Erzeugt die einzelnen Leds und fuegt diese rasterfoermig dieser LEDBar * hinzu. */ private void fillWithLeds() { for (int i = 0; i < mLeds.length; i++) { mLeds[i] = new LED(0, 0, sLedDiameter, getRandomColor(), Color.LIGHT_GRAY); add(mLeds[i]); } } /** * Gibt eine zufaellig erzeugte Farbe wieder. * * @return eine Farbe */ private Color getRandomColor() { Calculator calc = new Calculator(); int r = calc.randomInt(0, 255); int g = calc.randomInt(0, 255); int b = calc.randomInt(0, 255); return new Color(r, g, b); } /** * Startet das Blinken zufaellig ausgewaehlter LEDs. */ public void startBlinking() { if (mLightningThread == null) { mLightningThread = new Thread() { @Override public void run() { try { Calculator calc = new Calculator(); while (true && !isInterrupted()) { // Bis hierher technischer Code // -------------------------------------- int i = calc.randomInt(0, mLeds.length - 1); mLeds[i].doSwitch(); sleep(calc.randomInt(20, 100)); // -------------------------------------- // Ab hier wieder technischer Code } } catch (InterruptedException e) { } } }; mLightningThread.start(); } } /** * Stoppt das Blinken zufaellig ausgewaehlter LEDs. */ public void stopBlinking() { if (mLightningThread != null) { mLightningThread.interrupt(); mLightningThread = null; } } } ===== Klasse DiscoLight ===== import geofasc.swing.Rectangle; import java.awt.Color; /** * Ein DiscoLight komponiert mehrere {@link LEDBar}s, * die zufaellig verteilt blinken. * */ public class DiscoLight extends Rectangle { private LEDBar mLeftElement, mMiddleElement, mRightElement; /** * Erzeugt ein neues DiscoLight. */ public DiscoLight() { super(50, 100, 500, 200); setFigureFilled(true); setFigureFillColor(Color.BLACK); mLeftElement = new LEDBar(5, 5, 10, 3); mMiddleElement = new LEDBar(150, 50, 5, 10); mRightElement = new LEDBar(430, 5, 10, 3); add(mLeftElement); add(mMiddleElement); add(mRightElement); } /** * Startet dieses DiscoLight und bringt * die {@link LEDBar}s zum Leuchten. */ public void startDisco() { mLeftElement.startBlinking(); mMiddleElement.startBlinking(); mRightElement.startBlinking(); } /** * Stoppt dieses DiscoLight und bringt * die {@link LEDBar}s zum Erloeschen. */ public void stopDisco() { mLeftElement.stopBlinking(); mMiddleElement.stopBlinking(); mRightElement.stopBlinking(); } } ===== Klasse DiscoLightDemo (Hauptprogramm) ===== import geofasc.swing.tool.Frame; import java.awt.FlowLayout; import java.awt.HeadlessException; import javax.swing.SwingUtilities; /** * Ein DiscoLightDemo stellt ein Hauptprogramm dar, * in dem mehrere {@link DiscoLight}s erzeugt und dargestellt * werden. * */ public class DiscoLightDemo extends Frame { /** * Erzeugt ein neues DiscoLightDemo. * * @param title der Titel dieses Fensters */ public DiscoLightDemo(String title) throws HeadlessException { super(title); } /** * Erzeugt und stellt mehrere {@link Discolight}s dar. */ public void demo() { DiscoLight discoLight1 = new DiscoLight(); DiscoLight discoLight2 = new DiscoLight(); DiscoLight discoLight3 = new DiscoLight(); getCanvas().setLayout(new FlowLayout()); getCanvas().add(discoLight1, discoLight2, discoLight3); discoLight1.startDisco(); discoLight2.startDisco(); discoLight3.startDisco(); } /** * Hauptmethode zum Ausfuehren des Programms. */ public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { DiscoLightDemo frame = new DiscoLightDemo( "Disco lights demo based on GeoFaSC"); frame.setCenterLocation(); frame.setVisible(true); frame.demo(); } }); } }