Wie kann ein eigener Cursor definiert werden?

Die Erstellung eines mit Hilfe einer kleinen Bilddatei selbstgestalteten Cursors ist einfacher als vielleicht gedacht. Allerdings kann dieser Cursor mit den Standardeinstellungen nicht applikationsweit verwendet werden, sondern ist an eine Komponente gebunden. Soll dies geändert werden, so muss das GlassPane des Frames sichtbar gesetzt werden.

Das Beispiel definiert einen JFrame, der im oberen Bereich eine JCheckBox und im unteren Bereich zur Demonstration des Cursor-Verhaltens ein leeres JTextField enthält. Mit der Checkbox wird das GlassPane des Frames sichtbar, bzw. unsichtbar geschaltet.

Ein GlassPane muss man sich als durchsichtige Schicht oberhalb des ContentPane einer Heavy-Weight-Komponente (JApplet, JFrame, JDialog und JWindow) vorstellen, die in der Lage ist, Darstellungen über bestehenden Komponenten vorzunehmen oder auch Ereignisse abzufangen. Sie ist standardmäßig unsichtbar. Schaltet man sie sichtbar, ändert sich an der Erscheinung der Programmoberfläche zunächst einmal gar nichts. Allerdings wird beim Wechsel des Cursors dessen Standardverhalten geändert: Ein Cursor wird immer an eine Komponente gebunden. Ist er z.B. an den Frame gebunden, so gilt diese Bindung zunächst nicht für Komponenten, die eigene Cursor definieren, wie z.B. Textkomponenten. Sie stellen nach wie vor den ihnen als Standard zugewiesen Text-Cursor dar. Wird das GlassPane sichtbar gesetzt, so behält der Cursor auch über diesen Komponenten die gewünschte neue Erscheinung. Die Funktionalitäten bleiben gleichzeitig erhalten. Im Beispiel wird dies durch Sichtar- und Unsichtbarsetzen des GlassPane mit der Checkbox demonstriert.

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class EigenerCursor {

    public EigenerCursor() {

        final JFrame frame = new JFrame("Eigener Cursor");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JTextField(), BorderLayout.SOUTH);
        JCheckBox cb = new JCheckBox("GlassPane-Sichtbarkeit");
        frame.add(cb, BorderLayout.NORTH);
        cb.addChangeListener(new ChangeListener(){
            public void stateChanged(ChangeEvent e) {
                frame.getGlassPane().setVisible(((JCheckBox)e.getSource()).isSelected());
            }});
        frame.setSize(300, 300);

        try {
            URL url = getClass().getClassLoader().getResource("img/redCursor.png"); 
            BufferedImage img = ImageIO.read(url);
            Point hotSpot = new Point(0, 0);
            Cursor cursor = Toolkit.getDefaultToolkit().createCustomCursor(img,
                    hotSpot, "red Cursor");
            frame.setCursor(cursor);
        } catch (IOException e) {
            e.printStackTrace();
        }
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new EigenerCursor();
    }
}

Die Erstellung eines benutzerdefinerten Cursors erfolgt folgendermaßen: Zunächst muss ein kleines Icon als *.png-, *.gif- oder *.jpg-Datei erstellt und in einem Verzeichnis innerhalb des Classpath abgelegt werden. Im Quelltext wird daraufhin zur Demonstration ein JFrame deklariert, auf den in der Folge der Cursor registriert wird.
Der ClassLoader generiert einen URL aus dem relativ zum Aufruf gefundenen Pfad. Mit seiner Hilfe liest ein ImageIO-Objekt die Bilddatei aus und erzeugt ein BufferedImage.
Innerhalb der Fläche dieser Bilddatei muss nun ein sog. Hotspot definiert werden. Das ist jener Punkt, der die Aktivität des Cursors übernimmt, sozusagen der 'klickempfindliche' Punkt. Durch die Methode createCustomCursor() des DefaultToolkit kann nun der Cursor erzeugt werden. Als Parameter müssen das BufferdImage, der Hotspot, und ein frei wählbarer Name des Cursors als String übergeben werden. Dem JFrame wird nun das fertige Cursor-Objekt übergeben.
Da das Auslesen der Bilddatei scheitern kann, muss zumindest dieser Teil durch einen try-catch-Block oder eine entsprechende throws-Anweisung gekapselt werden.

GlassPane sichtbar GlassPane unsichtbar