Cursor

Genauso wie bei den Icons gibt es auch beim Cursor System-Cursor und anwenderdefinierte Cursor. Und auch hier können anwenderdefinierte Cursor sowohl in einer Ressource als auch in einer externen Datei, einer  ICO-oder ANI-Datei, abgelegt sein. Standardmäßig besitzen Cursor eine Ausdehnung von 32x32 Pixel und sind monochrom. Seit WINDOWS95 können Cursor jedoch auch farbig oder sogar animiert sein.

Beachten Sie den Unterschied zwischen einem Cursor und dem in Kapitel Eingaben behandelten Caret. Der Cursor ist der Mauszeiger und das Caret die Schreibmarkierung in einem Editfeld.

Aber steigen wir auch hier gleich wieder in die Praxis ein.

Erzeugen Sie zunächst wieder ein SDI-Projekt und geben Sie diesem den Namen Cursor. Nachdem Sie das Projekt erstellt haben, gehen Sie wieder in die Ressourcen-Ansicht. Da vom Anwendungs-Assistenten standardmäßig keine Cursor-Ressource angelegt wird, müssen Sie sich eine Cursor-Ressource zunächst selbst erstellen. Klicken Sie dazu eine beliebige Ressource mit der rechten Maustaste an und wählen aus dem eingeblendeten Kontext-Menü den Eintrag Einfügen... aus. Sie erhalten darauf folgenden Dialog einblendet:

Neue Ressource erstellen

Selektieren Sie im Dialog den Eintrag Cursor und klicken dann den Button Neu an. Daraufhin wird eine neue, monochrome Cursor-Ressource mit der Standard-Auflösung 32x32 erzeugt. Wir wollen jedoch gleich einen farbigen Cursor erstellen. Klicken Sie dazu den Button neben dem Gerät-Auswahlfeld an und im eingeblendeten Dialog dann den Button Benutzerdefiniert.... Wählen Sie als Größe für den Cursor die Standard-Auflösung 32x32 und als Farbtiefe 16 Farben aus. Erstellen Sie anschließend mit dem Cursor-Editor einen eigenen, farbigen Cursor. Die Vorgehensweise dazu ist gleich wie bei der Erstellung eines Icons. Cursor können genauso wie Icons transparente und inverse Bereiche besitzen. Beachten Sie dies bitte bei der Erstellung des Cursors.

Cursor besitzen jedoch noch eine zusätzliche Eigenschaft zu Icons: sie haben einen sogenannten Hotspot. Der Hotspot ist der Punkt des Cursors, auf den WINDOWS sich bezieht um die Cursorposition zu bestimmen. Standardmäßig liegt dieser Hotspot auf der Cursor-Koordinate 0,0. Sie können diesen Hotspot jedoch durch anklicken des Hotspot-Buttons oberhalb des Editorfensters umsetzen.

Nach dem Sie Ihren Cursor erstellt haben, sollten Sie ihm noch eine aussagekräftigere ID als IDC_CURSOR1 geben. Klicken Sie dazu die ID mit der rechten Maustaste an und wählen Sie im Kontext-Menü den Eintrag Eigenschaften aus. Überschreiben Sie im dann eingeblendeten Dialog einfach die vorgegebene ID. Für das Beispiel verwenden Sie bitte die ID IDC_MYCUR.

Die IDs für Cursor sollten immer mit dem Präfix IDC_xxx beginnen

Damit haben Sie Ihren ersten Cursor erstellt. Bevor Sie den Cursor nun zur Anzeige bringen können, müssen sie diesen laden, genauso wie die in der vorherigen Lektion behandelten Icons. Hierbei muss nun unterschieden werden, ob Sie einen System-Cursor oder einen anwenderdefinierten Cursor laden wollen. Um einen der System-Cursor zu laden, rufen Sie die CWinApp Methode LoadStandardCursor(...) auf. Diese Methode erhält als Parameter die ID des zu ladenden Cursors laut nachfolgender Tabelle:

ID

Cursor

ID

Cursor

IDC_ARROW IDC_SIZENESW
IDC_IBEAM IDC_SIZEWE
IDC_WAIT IDC_SIZENS
IDC_CROSS IDC_SIZEALL
IDC_UPARROW IDC_NO
IDC_SIZENWSE IDC_APPSTARTING
IDC_HELP IDC_HAND
(nur WINDOWS2000)

Als Returnwert liefert LoadStandardCursor(...) ein Handle HCURSOR auf den geladenen Cursor. Um den geladenen Cursor dann mit einem Fenster zu verbinden, wird die API-Funktion SetCursor(...) aufgerufen, die als Parameter das Handle des geladenen Cursors erhält.

Der Cursor gehört zu den sogenannten Fensterklassen-Attributen! Alle Fenster, die zu einer Fensterklasse gehören, besitzen immer den gleichen Cursor!

Doch das Setzen des Cursor über die Funktion SetCursor(...) alleine reicht leider noch nicht aus. Zusätzlich muss der Cursor noch in die Fensterklasse eingetragen werden. Dies erfolgt durch den Aufruf der bereits früher besprochenen API-Funktion SetClassLong(...). Als Index ist hierbei die Konstante GCL_HCURSOR anzugeben und im LONG-Parameter das Handle des Cursors.

Vergessen Sie einmal den Aufruf von SetClassLong(...), so wird zunächst der neue Cursor dargestellt. Sobald Sie aber die Maus bewegen, erhalten Sie wieder den alten Cursor angezeigt!

So, und auf geht's wieder. Jetzt sind Sie wieder dran.

Versuchen Sie einmal alle System-Cursor nacheinander darzustellen. Jedes Mal wenn die linke Maustaste gedrückt wird, soll ein anderer System-Cursor dargestellt werden. Überlegen Sie sich zuerst, in welcher Methode Sie den Cursor-Wechsel unterbringen.

Lösung zur Darstellung der System-Cursor

Der Cursor-Wechsel erfolgt (natürlich) in der Methode OnLButtonDown(...). Damit könnte diese Methode etwa wie folgt aussehen:

void CCursorView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen...
   
    // Aktueller Cursorindex
    static int nCurNum = 0;
    // System-Cursor
    static const char* ahSysCursor[] =
        {IDC_IBEAM, IDC_ARROW, IDC_WAIT, IDC_CROSS,
         IDC_UPARROW, IDC_SIZENWSE, IDC_SIZENESW, IDC_SIZEWE,
         IDC_SIZENS, IDC_SIZEALL, IDC_NO, IDC_APPSTARTING,
         IDC_HELP};
    // System-Cursor laden
    HCURSOR hCur = AfxGetApp()->LoadStandardCursor(ahSysCursor[nCurNum]);
    // und als Fensterklassen-Cursor eintragen
    ::SetCursor(hCur);
    ::SetClassLong(*this,GCL_HCURSOR,(LONG)hCur);
    // Cursorindex erhoehen
    nCurNum++;
    if (nCurNum == sizeof(ahSysCursor)/sizeof(char*))
        nCurNum = 0;
}

Zu Testzwecken können Sie auch einmal einen der beiden Aufrufe von SetCursor(...) bzw. SetClassLong(...) auskommentieren um die Wirkungsweise der Funktionen zu beobachten.

Ende der Lösung

So, als nächstes werden wir unseren eigenen, am Anfang der Lektion erstellen, Cursor sowie einen vorgegebenen animierten Cursor (abgelegt in einer externen ANI-Datei) darstellen. Um einen Cursor aus einer Ressource zu laden, rufen Sie die CWinApp Methode LoadCursor(...) auf, die als Parameter die ID des zu ladenden Cursors erhält. Als Returnwert erhalten Sie wieder das Cursor-Handle.

Es gibt noch eine weitere Methode LoadCursor(...), die als Parameter einen char-Zeiger besitzt. Diese Methode lädt eine Cursor-Ressource über einen Namen anstatt über eine ID. Der Cursor-Editor des Visual Studios erzeugt aber in der Regel immer eine ID, so dass Sie diese Methode relativ selten benötigen.

Soll ein Cursor aus einer externen Datei geladen werden, so verwenden Sie hierzu die API-Funktion LoadCursorFromFile(...).

Und weiter geht's mit dem Beispiel. Unser eigener Cursor sowie der animierte Cursor aus der Datei 99Templates\globle.ani soll immer dann anzeigt werden, wenn die rechte Maustaste gedrückt wird, wobei bei jedem Drücken der rechten Maustaste zwischen den beiden Cursor umgeschaltet werden soll. Kopieren Sie sich nun den animierten Cursor zuerst in Ihr Arbeitsverzeichnis. Anschließen fügen Sie der Klasse CCursorView die Methode OnRButtonDown(...) hinzu sowie die beiden Membervariablen m_hCur1 und m_hCur2, beide vom Typ HCURSOR. Die beiden Membervariablen dienen zur Aufnahme der entsprechenden Cursor-Handle. Die Cursor selbst sollen selbstverständlich nur einmal geladen werden. Dies erfolgt wiederum in der Methode OnInitialUpdate(...). Fügen Sie diese Methode ebenfalls zur Klasse hinzu. Modifizieren Sie den Code der beiden neuen Methoden wie folgt:
void CCursorView::OnInitialUpdate()
{
    CView::OnInitialUpdate();
   
    // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
    // Cursor aus Ressource sowie aus Datei laden
    m_hCur1 = AfxGetApp()->LoadCursor(IDC_MYCUR);
    m_hCur2 = (HCURSOR)::LoadCursorFromFile("globe.ani");
    // Geladenen Cursor nun setzen
    ::SetCursor(m_hCur1);
    // Sehr wichtig, sonst wird Cursor sofort wieder zurueckgesetzt!
    ::SetClassLong(*this,GCL_HCURSOR,(LONG)m_hCur1);
}

void CCursorView::OnRButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen...
   
    // Cursor umsetzen
    if (::GetClassLong(*this,GCL_HCURSOR) == (DWORD)m_hCur2)
    {
        ::SetClassLong(*this,GCL_HCURSOR,(LONG)m_hCur1);
        ::SetCursor(m_hCur1);
    }
    else
    {
        ::SetClassLong(*this,GCL_HCURSOR,(LONG)m_hCur2);
        ::SetCursor(m_hCur2);
    }
}

Übersetzen und starten Sie das Programm nun. Welchen Cursor erhalten Sie?

Nun, vermutlich werden Sie zunächst überhaupt keinen Cursor sehen. Erst durch drücken der linken Maustaste sehen Sie nacheinander die verschiedenen System-Cursor. Was passiert hier? Erinnern Sie sich noch an den Anfang der Lektion? Dort haben wir einen anwenderdefinierten farbigen Cursor erstellt. Der leere Standard-Cursor (schwarz/weiß) unter dieser ID ist jedoch immer noch vorhanden. Und genau dieser Cursor wird in unserem Programm geladen. Um den farbigen Cursor zu laden, müssen Sie zuerst den Standard-Cursor entfernen.

Entfernen Sie den Standard-Cursor wie folgt: Wählen Sie zunächst den eigenen Cursor in der Ressource-Ansicht aus. Im Auswahlfeld Gerät selektieren Sie dann den Cursor Monochrom (32.x32). Anschließend öffnen Sie das Menü Bild und wählen dort den Menüpunkt Geräteabbild löschen aus. Der Standard-Cursor wird aus der Ressource entfernt und es bleibt nur noch der eigene farbige Cursor übrig.

Übersetzen Sie das Programm erneut und Sie werden die gewünschten Cursor anzeigt bekommen.

Das fertige Beispiel finden Sie unter 07Ressourcen\Cursor.

Damit beenden wir die Einführung in die Cursor-Ressource und sehen uns in der nächsten Lektion die String-Ressource an. Bei den Tipps&Tricks zu diesem Kapitel erfahren Sie dann noch, wie Sie einen Cursor durch die Anwendung zeichnen lassen können.



Copyright © 2004

Senden Sie Emails mit Fragen oder Kommentaren zu dieser Website an: mailto:info@cpp-tutor.de
 Wolfgang Schröder, Lerchenweg 23, D-72805 Lichtenstein. Tel: +49 7129 6470