Wie kann man eine Statusanzeige erzeugen, deren Farbigkeit sich in Abhängigkeit vom angezeigten Statuswert ändert?

Eine Statusanzeige kann mit Java recht einfach mit Hilfe der Klasse javax.swing.JProgressBar erzeugt werden, deren Erscheinungsbild jedoch angepasst werden muss. Die Klasse JProgressBar stellt bereits einige Methoden zur Anpassung der Komponente bereit, eine Einfärbung des Statusbalkens ist jedoch leider nicht vorgesehen. Ein Blick in den Quelltext verrät, dass eine JProgressBar ihre Erscheinung üblicherweise von der Klasse javax.swing.plaf.basic.BasicProgressBarUI erhält. Zur Anpassung muss diese somit überschrieben werden.

Farbige Statusanzeige

Die Klasse FarbigeProgressBar erweitert JProgressBar. Im Konstruktor, dem der Minimum- und Maximumwert der Anzeige übergeben wird, wird eine Instanz des BasicProgressBarUIcode> erzeugt. Zur Demonstration überschreibt sie die beiden Methoden getSelectionForeground() und getSelectionBackground(), mit denen die Farben des Textes im Statusbalken angepasst werden können. Die erste Methode ist für die Textfarbe über dem "gefüllten" Balken, die zweite für die Textfarbe vor dem leeren Hintergrund des Balkens verantwortlich.
Das UI wird mittels setUI() der JProgressBar zugeordnet. Die anderen im Konstruktor der Klasse aufgerufenen Methoden stellen einige gängige Möglichkeiten dar, eine JProgressBar den eigenen Bedürfnissen anzupassen.

class FarbigeProgressBar extends JProgressBar {

    public FarbigeProgressBar(int start, int end) {
        [...]
        BasicProgressBarUI ui = new BasicProgressBarUI() {
            protected Color getSelectionForeground(){
                return Color.BLACK;
            }
            protected Color getSelectionBackground(){
                return Color.BLACK;
            }
        };
        setUI(ui);
    }
}

Die Klasse FarbigeStatusAnzeige stellt innerhalb von init() neben einem JButton zum Start des kleinen Programms den JFrame bereit, auf dem die ProgressBar angezeigt wird. Außer der main()-Methode zum Aufruf der Applikation und dem Konstruktor ist als einzige Methode nur init() vorhanden. Neben den üblichen Konfigurationen des JFrame wird in ihr ein Runnable-Objekt gebildet, das es ermöglicht, die Statusanzeige in einem eigenen Thread laufen zu lassen, um andere Kompomenten, wie z.B. den Button bedienbar zu halten.
Hier werden zunächst zwei Variablen für die Farbsteuerung deklariert und mit entsprechenden Werten initialisiert. Ziel ist eine Anzeigefarbigkeit, die von Grün über Gelb nach Rot läuft. Grün erhält somit zunächst den Maximal-, Rot den Minimalwert. Das Gelb ergibt sich aus der additiven Mischung von Rot und Grün. Blau ist gar nicht beteiligt und wird somit durchgängig auf 0 gesetzt. Um ein Ein- und Ausblenden der jeweiligen Farben zu erreichen wird ein konstanter Faktor definiert, der im farbigen Übergangsbereich addiert bzw. subtrahiert wird.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicProgressBarUI;

public class FarbigeStatusAnzeige {

    private final static int MAX = 4000, MIN = 0;

    public FarbigeStatusAnzeige() {
        init();
    }

    private void init() {
        FarbigeProgressBar bar = new FarbigeProgressBar(MIN, MAX);
        bar.setValue(MAX);
        bar.setStringPainted(true);

        final Runnable runnable = new Runnable() {
            int rot = 0, gruen = 255;
            double faktor = MAX / 255 / 2;

            public void run() {
                for (int i = MAX; i >= MIN; i--) {
                    if (i < MAX / 5 * 2) {
                        rot += faktor / 5;
                    }
                    if (i < MAX / 10) {
                        gruen -= faktor / 25;
                        rot += faktor / 15;
                    }

                    rot = rot > 255 ? 255 : rot;
                    rot = rot < 0 ? 0 : rot;
                    gruen = gruen > 255 ? 255 : gruen;
                    gruen = gruen < 0 ? 0 : gruen;
                    bar.setForeground(new Color(rot, gruen, 0));
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException ex) {
                    }
                    bar.setValue(i);
                }
                // Farbigkeit auf Ausgangswert zuruecksetzen
                rot = 0;
                gruen = 255;
                bar.updateUI();
            }
        };

        JButton button = new JButton("start");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Thread thread = new Thread(runnable);
                thread.start();
            }
        });
        JFrame frame = new JFrame("Farbige Statusanzeige");
        frame.setLayout(new BorderLayout());
        frame.add(button, BorderLayout.SOUTH);
        frame.add(bar, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new FarbigeStatusAnzeige());
    }
}

class FarbigeProgressBar extends JProgressBar {

    public FarbigeProgressBar(int start, int end) {
        setMinimum(start);
        setMaximum(end);
        setForeground(SystemColor.window);
        setBackground(SystemColor.window);
        setBorder(new EmptyBorder(3, 5, 3, 5));
        Dimension size = new Dimension(300, 20);
        setPreferredSize(size);
        setMaximumSize(size);
        setMinimumSize(size);
        BasicProgressBarUI ui = new BasicProgressBarUI() {
            protected Color getSelectionForeground() {
                return Color.BLACK;
            }

            protected Color getSelectionBackground() {
                return Color.BLACK;
            }
        };
        setUI(ui);
    }
    @Override
    public void updateUI() {
        setUI(getUI());
    }
}

In der Methode run() des Threads durchläuft eine Schleife die Anzeigewerte vom Maximum zum Minimum und setzt für jeden Wert die Vordergrundfarbe. Diese wird durch zwei if-Verzweigungen definiert, in denen die Abnahme und Zunahme der Farbanteile für die beiden Übergangsbereiche berechnet werden. Sie sind, wie auch die Farbwerte und der Berechnungsfaktor, an die eigenen Wünsche anpassbar. Wichtig ist, dass die Werte nicht den erlaubten Bereich von minimal 0 und maxima 255 unter- bzw. überschreiten. Der letzte Ausdruck im Konstruktor simuliert einen zeitintensiven Bearbeitungsvorgang, indem der Thread für kurze Zeit zum Pausieren veranlasst wird.