Das Beispiel zeigt wie ein eigenes Dock-Icon mit einer Badge eingerichtet werden kann.

Die Klasse java.awt.Taskbar stellt Methoden bereit, um ein selbst definiertes Dock-Icon zu laden. Es kann bei Bedarf auch mit einer Badge, einem kleinen roten Kreis für Anmerkungen, versehen werden.

Badge muss freigegeben werden

Im Beispiel wird ein kleines GUI erzeugt, das nur aus einem JFrame mit einem Button zum Beenden der Application besteht. Im Dock zeigt das Programm ein eigenes Icon, auf dem innerhalb einer Badge ein Countdown herunterzählt.
Es muss aber beachtet werden, dass die Badge nur bei Ausführen eines *.app-Bundles erscheint. Wird die Klasse selbst oder eine *.jar ausgeführt, kann zwar das Dock-Icon, nicht jedoch die Badge angezeigt werden. Zudem muss beim erstmaligen Aufruf der Anwendung das Anzeigen von Mitteilungen erlaubt werden. Die Application wird dadurch in den Systemeinstellungen unter Mitteilungen eingetragen.

Ein Dock-Icon mit Badge

Programmaufbau

Der Konstruktor dient zum Aufruf von init() [19]. In der Methode werden die Oberfläche und das Dock-Icon eingerichtet. Um dessen Anzeige mit seinem Zähler unabhängig und parallel zum Hauptfenster zu ermöglichen, muss dies nebenläufig erfolgen. Dies wird durch ein ExecutorService-Objekt gewährleistet, das einen Thread bereitstellt, in dem showDockIcon() aufgerufen wird [25]. Sobald sie nicht mehr benötigt werden, müssen die dafür benötigten Resourcen durch shutdown() wieder freigegeben werden [27].
Nicht jedes Betriebssystem stellt eine Taskbar bereit, sodass dies vorher durch die statische Methode Taskbar.isTaskbarSupported() abgefragt werden sollte [24].

import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.PopupMenu;
import java.awt.Taskbar;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class MacOSXDockIconMitBadge {

    private static final String ICON_PATH = "/img/icon512.png";

    public MacOSXDockIconMitBadge() {
        init();
    }

    private void init() {
        ExecutorService executor = Executors.newCachedThreadPool();
        if (Taskbar.isTaskbarSupported()) {
            executor.execute(() -> showDockIcon(15, false));
        }
        executor.shutdown();
        JButton butt = new JButton("Ende");
        butt.addActionListener(e -> System.exit(0));
        JFrame frame = new JFrame("Dock-Demo");
        frame.setLayout(new FlowLayout());
        frame.add(butt);
        frame.setSize(200, 80);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void showDockIcon(int number, boolean isFixed) {
        final Taskbar taskbar = Taskbar.getTaskbar();
        if (taskbar.isSupported(Taskbar.Feature.MENU)) {
            PopupMenu menu = new PopupMenu("Application");
            menu.add("Punkt 1");
            menu.add("Punkt 2");
            taskbar.setMenu(menu);
        }
        Image icon = loadImage(ICON_PATH);
        if ((icon != null) && taskbar.isSupported(Taskbar.Feature.ICON_IMAGE)) {
            taskbar.setIconImage(icon);
        }
        if (taskbar.isSupported(Taskbar.Feature.ICON_BADGE_TEXT)) {
            taskbar.setIconBadge(Integer.toString(number));
            if (!isFixed) {
                while (number > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    taskbar.setIconBadge(Integer.toString(--number));
                }
                taskbar.setIconBadge(null);
            }
        }
    }

    private Image loadImage(String imgPath) {
        Image img = null;
        try {
            img = ImageIO.read(getClass().getResource(imgPath));
        } catch (IOException e) {
            System.err.println("Dock-Icon kann nicht geladen werden!");
        }
        return img;
    }

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

Dock-Icon mit Kontextmenu

Ein Dock-Icon besitzt unter MacOS ein Kontextmenu. Es kann durch setMenu() der Klasse Taskbar erweitert werden [45]. Hierzu wird der Methode eine Instanz der Klasse PopupMenu als Parameter übergeben. Es enthält hier zwei Elemente, Punkt 1 und Punkt 2. Beide bleiben der Übersichtlichkeit halber funktionslos, können jedoch nach dem Start des Programms durch Rechtsklick auf das Dock-Icon bewundert werden.

Ein Dock-Icon mit Kontextmenu und Badge

Optionen mit Taskbar.Feature prüfen

Um zu prüfen, ob die Menufunktion überhaupt gegeben ist, wird die Methode isSupported() auf dem Taskbar-Objekt aufgerufen. Sie liefert einen boolschen Wert abhängig von der ihr als Parameter übergebenen Enum-Konstante vom Typ Taskbar.Feature [41]. Das Verfahren kann für eine Reihe an Taskbar-Prüfungen verwendet werden und wird im vorliegenden Beispiel noch fürs Testen der Möglichkeit zur Verwendung eines eigenen Taskbar-Icons [48] und einer Badge mit Text-Anzeige [51] herangezogen.
Das Setzen des Icons im Dock geschieht nach dem Laden der Icondatei durch Aufruf von setIconImage() auf dem Taskbar-Objekt [49].

Einrichten der Badge

Das Hinzufügen einer Badge zum Dock-Icon wird ab Zeile 51 demonstriert. Sie besteht aus einer kleinen roten Kreisfläche, die das Dock-Icon überlagert und innerhalb derer hier ein Countdown oder wahlweise auch ein statischer numerischer Wert angezeigt wird. Der Methode showDockIcon() werden hierzu zwei Argumente übergeben: Das erste ist der anzuzeigende int-Wert. Das zweite ist ein boolscher Wert, der reguliert, ob der übergebene numerische Wert statisch oder zum Countdown genutzt werden soll.
Ist der Parameter isFixed wie hier gezeigt false, wird der übergebene Startwert im Sekundenrhythmus heruntergezählt und die Badge mit dem jeweiligen Wert neu gesetzt [60]. Nach Beendigung des Countdowns wird die Badge duch Übergabe von null gelöscht [62].

Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.