Schiebe-/Drehregler und Scrollbars

Sehen wir uns in dieser Lektion ein paar weitere Controls an: den Schieberegler, das Drehfeld sowie die Bildlaufleiste. Doch auch hier wieder zunächst einmal der fertige Beispieldialog:

Der fertige Beispieldialog

Die drei Controls links oben im Dialog (Statusanzeige, Bildlaufleiste und Schieberegler) werden im Beispiel miteinander gekoppelt, d.h. sie laufen nachher immer synchron. Werden Änderungen an der Bildlaufleiste oder dem Schieberegler vorgenommen, so folgen die Anzeigen der beiden anderen Controls. Rechts von dieser 3er-Gruppe befindet sich ein Animation-Control. In einem Animation-Control können kleine AVI-Dateien, allerdings ohne Ton, wiedergegeben werden. Die Wiedergabe der AVI-Datei wird im Beispiel gestartet wenn der darunter befindliche Button angeklickt wird. Unten im Dialog ist nochmals eine Statusanzeige eingefügt. Diese Statusanzeige ist mit dem Drehfeld verbunden. Die aktuelle Einstellung des Drehfeldes wird im links davon stehenden Textfeld angezeigt.

Erstellen Sie für das Beispiel wieder eine dialogbasierende Anwendung und geben Sie ihr den Namen Slider. Nach dem der Anwendungs-Assistent seine Arbeit beendet hat, modifizieren Sie den vorgegebenen Dialog IDD_SLIDER_DIALOG. Fügen Sie die oben angegebenen Controls zum Dialog hinzu. Für die neuen Controls werden folgende Symbole im Toolbar des Dialogeditors verwendet:

Die neuen Controls

Belassen Sie alle Eigenschaften der Controls noch auf ihrem Vorgabewert. Passen Sie lediglich die Beschriftung der drei Gruppenfelder wie angegeben an.

Wie für allen anderen bisherigen Controls stellt die MFC auch für diese neuen Controls entsprechende C++ Klassen bereit. Wenn Sie diese Controls in Dialogen einsetzen, so benötigen Sie entweder entsprechende Membervariable oder Sie müssen mittels der Methode GetDlgItem(...) sich bei jedem Zugriff auf das Control ein entsprechendes temporäres Objekt erstellen.

Aber fangen wir jetzt mit dem einfachsten Control im Dialog an, der Statusanzeige (auch Progressbar genannt). Die Statusanzeige ist ein passives Control, d.h. der Anwender kann nicht direkt mit ihr arbeiten sondern sie dient nur zur Ausgabe. Für die Statusanzeige stellt die MFC die Klasse CProgressCtrl zu Verfügung. Statusanzeigen besitzen einen einstellbaren Anzeigebereich. Um den Anzeigebereich zu setzen wird die CProgressCtrl Methode SetRange32(...) aufgerufen. Sie erhält den unteren und oberen Grenzwert des Anzeigebereichs als Parameter. Standardmäßig besitzt eine Statusanzeige einen Anzeigebereich von 0 bis 100.

Es gibt noch eine weitere Methode SetRange(...) zum Festlegen des Anzeigebereichs. Obwohl die Parameter dieser Methode vom Typ short sind, und damit auch negative Werte annehmen können, ist die Statusanzeige bei Verwendung dieser Methode leider nicht in der Lage, negative Bereichsangaben bei der Anzeige darzustellen. Bei Verwendung von SetRange32(...) besteht diese Einschränkung nicht.

Um die Statusanzeige auf einen bestimmten Wert zu setzen, rufen Sie die Methode SetPos(...) auf. Liegt der hier angegebene Wert außerhalb des eingestellten Anzeigebereichs, so wird entweder überhaupt nicht dargestellt oder die Anzeige zeigt 'Vollausschlag'.

Passen wir die Statusanzeige links oben im Dialog nun an. Da sie an die beiden darunter liegenden Controls nachher gekoppelt wird, fügen Sie über den Klassen-Assistent zur Dialogklasse die zur Statusanzeige gehörende Membervariable m_CProgress1 (Typ CProgressCtrl) hinzu.

Membervariable für Statusanzeige

Anschließend kann die Statusanzeige in der Methode OnInitDialog(...) initialisiert werden.

BOOL CSliderDlg::OnInitDialog()
{
    ....
    // ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
    // Linke obere Statusanzeige initialisieren
    m_CProgress1.SetRange32(-100,100);
    m_CProgress1.SetPos(0);

    return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll....
}
Kommen Sie hier nicht in Versuchung die Statusanzeige aus der Methode InitInstance(...) des Anwendungsobjektes heraus zu initialisieren! Beim Aufruf der oben erwähnten Methoden SetRange32(...) und SetPos(...) muss das Control bereits existieren. Da der Dialog, und die in ihm enthaltenen Controls, aber erst mit dem Aufruf der CDialog Methode DoModal(...) erstellt werden, würde der Aufruf der Methoden einen Fehler innerhalb der MFC auslösen!

Passen wir nun noch den Stil der Statusanzeige etwas an. Standardmäßig werden Statusanzeigen mit einem unterbrochenem Balken angezeigt. Sie können jedoch auch Statusanzeigen erstellen, deren Balken durchgängig ausgefüllt ist, ja sogar Statusanzeigen, die vertikal verlaufen.

Um das Erscheinungsbild einer Statusanzeige anzupassen, öffnen Sie deren Eigenschaftsdialog. Wählen Sie dort den Tabulator Formate aus und dann die Eigenschaft Glatt. Im Dialogeditor wird die Statusanzeige daraufhin mit einem durchgängig ausgefüllten Balken dargestellt.

Eigenschaften einer Statusanzeige

Bei vielen kommerziellen Programmen enthält die Statusanzeige innerhalb des Balken noch einen zusätzlichen Text wie z.B. eine Prozentangabe. Wie Sie so etwas erreichen, das erfahren Sie bei den Tipps&Tricks zu diesem Kapitel.

Wenn Sie das Beispiel nun übersetzen und starten, so erhalten Sie eine bis zur Hälfte ausgefüllte Statusanzeige im Dialog dargestellt.

Sehen wir uns als nächstes den Schieberegler in dieser 3er-Gruppe an. Schieberegler werden durch die MFC Klasse CSliderCtrl repräsentiert. Sie verfügen ebenfalls über einen einstellbaren Anzeigebereich. Dieser Bereich wird mit der Methode SetRange(...) eingestellt.

Die Klasse CSliderCtrl besitzt leider keine Methode SetRange32(...). Aus diesem Grund kann ein Schieberegler nur positive Werte darstellen!

Das Einstellen der aktuellen Position erfolgt wieder mit einer gleichnamigen Methode SetPos(...) wie bei der Statusanzeige. Sie sehen, Schieberegler und Statusanzeigen haben vieles gemeinsam. Zusätzlich können Schieberegler noch einen Auswahlbereich darstellen, der über die entsprechende Eigenschaft Auswahl aktivieren des Schieberegler aktiviert wird.

Eigenschaften eines Schiebereglers

Dieser Auswahlbereich dient nur als optische Hervorhebung und hat sonst keinerlei weitere Funktionalität.

Auswahlbereich eines Schiebereglers

Der Auswahlbereich wird über die CSliderCtrl Methode SetSelection(...) gesetzt. Außerdem stehen für Schieberegler noch weitere Methoden zur Verfügung um z.B. den Abstand der Tickmarks (das sind die kleinen Striche) einzustellen oder auch die Schrittweite festzulegen.

Aber Schieberegler haben noch eine wesentliche Erweiterung gegenüber der vorherigen Statusanzeige: sie lassen sich durch den Anwender beeinflussen. Verändert der Anwender die Position eines Reglers, so sendet dieser eine Nachricht an sein übergeordnetes Fenster. Je nach dem, ob es sich um einen horizontalen Regler, wie im Beispiel, oder einen vertikalen Regler handelt, wird eine WM_HSCROLL bzw. WM_VSCROLL Nachricht versandt. Diese Nachrichten werden durch die MFC Nachrichtenbearbeiter OnHScroll(...) bzw. OnVScroll(...) verarbeitet. Im ersten Parameter der Nachrichtenbearbeiter steht die Ursache für das Auslösen dieser Nachricht. Für die Ursache sind eine Reihe von Konstanten definiert, die alle mit dem Präfix SB_xxx beginnen. Mehr dazu gleich bei der Behandlung der Bildlaufleiste da der Auslösegrund dort eine wesentliche Rolle spielt. Der nächste Parameter enthält die aktuelle Position des Reglers und der letzte Parameter ist ein Zeiger auf das Control, das die Nachricht WM_HSCROLL bzw WM_VSCROLL ausgelöst hat. Beachten Sie bitte, dass alle Regler, und auch die nachher noch aufgeführten Bildlaufleisten, innerhalb eines Dialogs die gleiche Nachricht versenden, so dass Sie im Nachrichtenbearbeiter in der Regel immer abfragen müssen, von welchem Control die Nachricht stammt. Hierzu es notwendig, die ID des Controls über dessen Methode GetDlgCtrlID(...) zu ermitteln.

Noch ein Hinweis zur OnXScroll(...) Methode. Sie sollten am Ende der Methode immer die Basisklassen-Methode zusätzlich aufrufen, da sie unter Umständen die Nachricht an das Control weiterleitet.
Versuchen Sie einmal wieder selbst, den Regler in der OnInitDialog(...) Methode so zu konfigurieren, dass er einen Anzeigebereich von 0...200 besitzt, der Auswahlbereich von 50...150 geht und die Tickmarks einen Abstand von 25 Einheiten besitzen. Wie Sie den Abstand der Tickmarks einstellen, dass sollen Sie hier selbst mit Hilfe der Online-Hilfe herausbekommen.

Hinweis: Sie müssen selbstverständlich für den Regler wieder eine Membervariable vom Typ CSliderCtrl zur Dialogklasse hinzufügen. Geben Sie dieser Membervariable den Namen m_CSlider.

Lösung zur Konfiguration des Reglers

BOOL CSliderDlg::OnInitDialog()
{
    ....
    // Linke obere Statusanzeige initialisieren
    ....
    // Schieberegeler initialisieren
    m_CSlider.SetRange(0,200);
    m_CSlider.SetPos(100);
    m_CSlider.SetSelection(50,150);
    m_CSlider.SetTicFreq(25);
    return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll....
}

Haben Sie beim Definieren der Membervariable auch daran gedacht, dass diese vom Typ Control sein muss?

Ende der Lösung

Als nächstes wollen wir den Regler mit der Statusanzeige so koppeln, dass beide synchron laufen. Hierzu müssen wir die Nachricht WM_HSCROLL bearbeiten. Fügen Sie jetzt über die Klassenansicht (nicht über den Klassen-Assistent!) den Nachrichtenbearbeiter für diese WINDOWS-Nachricht hinzu. Erweitern Sie die eingefügte Methode wie folgt:

void CSliderDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen....
    // Falls Nachricht vom Schieberegler
    if (pScrollBar->GetDlgCtrlID()==IDC_SLIDER1)
        HandleSlider();   
    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

Falls die Nachricht von unserem Regler stammt (ID des Reglers ist IDC_SLIDER1) wird die Methode HandleSlider(...) aufgerufen. Diese Methode soll die Statusanzeige mit dem Regler synchronisieren. Dazu wird innerhalb der Methode zunächst die aktuelle Reglerposition ausgelesen und diese anschließend an die Statusanzeige übergeben.

Fügen Sie zur Dialogklasse jetzt die void Methode HandleSlider(...) hinzu. Die Methode benötigt keine weiteren Parameter. Erweitern Sie zum Schluss die Methode wie nachfolgend angegeben:

void CSliderDlg::HandleSlider()
{
    // Akt. Position des Schiebereglers auslesen
    int nActPos = m_CSlider.GetPos();
    // und Statusanzeige synchronisieren
    m_CProgress1.SetPos(nActPos-100);
}

Beachten Sie bitte, dass die Statusanzeige einen Bereich von -100...100 besitzt und der Regler dagegen einen Bereich von 0...200, da er keine negativen Daten verarbeiten kann.

Wenn Sie das Programm jetzt starten und den Regler bewegen, so wird die Statusanzeige diesem immer folgen.

Kommen wir nun zum letzten Element in dieser 3er-Gruppe, der Bildlaufleiste. Sie wird durch die MFC Klasse CScrollBar gekapselt. Diese Klasse verwendet zur Beeinflussung des Controls jedoch, wenigstens vom Namen her, andere Methoden als die beiden vorherigen Controls. Um den Bereich einer Bildlaufleiste zu setzen rufen Sie die Methode SetScrollRange(...) auf. Und damit es mal wieder nicht ganz zu einfach wird: der Anzeigebereich darf hier, wie bei der Statusanzeige, einen negativen Bereich besitzen. Außerdem besitzen Bildlaufleisten, im Gegensatz zu den vorherigen Controls, keinen Standardbereich, d.h. Sie müssen immer den Bereich explizit setzen. Um den Thumb, das ist das kleine Rechteck in der Bildlaufleiste, auf eine bestimmte Position zusetzen, dient die Methode SetScrollPos(...). Die aktuelle Position des Thumb erhalten Sie dementsprechend durch die Methode GetScrollPos(...) geliefert.

Werden nun Bildlaufleisten durch den Anwender verändert, so senden diese genauso wie Regler Nachrichten an die Anwendung. Unglücklicherweise verwenden Bildlaufleisten die gleichen Nachrichten wie Regler, d.h. eine horizontale Bildlaufleiste sendet ebenfalls eine WM_HSCROLL Nachricht und eine vertikale Bildlaufleiste eine WM_VSCROLL Nachricht. Haben Sie mehrere Bildlaufleisten und/oder Regler im Dialog, so müssen Sie innerhalb der Nachrichtenbearbeiter OnHScroll(...) bzw. OnVScroll(...) zuerst den Auslöser der Nachricht feststellen. Dies erfolgt durch den Aufruf der vorhin beschriebenen Methode GetDlgCtrlID(...). Und jetzt noch ein ganz wichtiger Hinweis, damit Sie sich wieder eine etwas länger dauernde Fehlersuche sparen können:

Während bei Regler das Einstellelement automatisch positioniert wird, müssen Sie bei Bildlaufleisten den Thumb immer selber positionieren. D.h. innerhalb des Nachrichtenbearbeiters OnHScroll(...) bzw. OnVScroll(...) werden Sie in der Regel die Methode SetScrollPos(...) aufrufen müssen. Vergessen Sie dies einmal, so springt der Thumb immer wieder auf seine Ausgangsposition wieder zurück.

Sehen wir uns (bevor wir das Beispiel erweitern) noch kurz den ersten Parameter nSBCode der OnXScroll(...) Methoden an. Dieser Parameter teilt der Anwendung mit, wie der Thumb verschoben wurde. Möglich sind hierbei die folgenden Werte:

Wert

Auslöser

durchzuführende Aktion

SB_LEFT Taste <POS1> Thumb ganz ans linke Ende schieben
SB_LINELEFT Bildlauf-Pfeil links oder Taste <CUR-HOCH> Thumb um eine Einheit nach links
SB_PAGELEFT klicken in Bildleiste links vom Thumb oder Taste <BIILD-HOCH> Thumb um mehrere Einheiten nach links
SB_RIGHT Taste <ENDE> Thumb ganz ans rechte Ende schieben
SB_LINERIGHT Bildlauf-Pfeil rechts oder Taste <CUR-RUNTER> Thumb um eine Einheit nach rechts schieben
SB_PAGERIGHT klicken in Bildleiste rechts vom Thumb oder Taste <BIILD-RUNTER> Thumb um mehrere Einheiten nach rechts
SB_THUMBTRACK Der Thumb wir im Augenblick gezogen. nPos enthält dann die aktuelle Position keine
SB_THUMBPOSITION Der gezogen Thumb wird losgelassen. nPos enthält die Endposition Thumb-Position auf nPos setzen

Bauen wir die Behandlung der Bildlaufleiste ins Beispiel ein. Die Bildlaufleiste soll wieder synchron zu den beiden anderen Controls laufen. Im Unterschied zum Regler soll jedoch die Position der Bildlaufleiste erst dann ausgewertet werden, wenn der Thumb nicht mehr gezogen wird, d.h. während der Thumb bewegt wird bleiben die anderen Controls unverändert.

Fügen Sie zunächst zur Dialogklasse über den Klassen-Assistent die mit der Bildlaufleiste verbundene Membervariable m_CScroll (Typ CScrollBar) hinzu. Anschließend müssen in der OnInitDialog(...) Methode die Parameter der Bildlaufleiste festgelegt werden. Erweitern Sie hierfür die OnInitDialog(...) Methode wie folgt:
BOOL CSliderDlg::OnInitDialog()
{
    ....
    // Schieberegeler initialisieren
    ....
    // Bildlaufleiste initialisieren
    m_CScroll.SetScrollRange(-100,100);
    m_CScroll.SetScrollPos(0);
    return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll....
}

Starten Sie das Beispiel.

Nach dem Starten des Programms wird der Thumb in der Bildlaufleiste mittig positioniert. Wenn Sie nun Änderungen an der Bildlaufleiste vornehmen, so wird der Thumb danach immer wieder in diese Ausgangsposition zurückspringen. Dies liegt daran, dass Sie den Thumb, wie bereits erwähnt, immer selbst positionieren müssen.

Erweitern wir die Methode OnHScroll(...) um die Behandlung der Bildlaufleisten-Nachricht. Wird die Methode als Reaktion auf eine Veränderung der Bildlaufleiste aufgerufen, so soll die im Anschluss definierte Methode HandleScrollbar(...) aufgerufen werden.
void CSliderDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen ....
    if (pScrollBar->GetDlgCtrlID()==IDC_SLIDER1)
        HandleSlider();
    else
        if (pScrollBar->GetDlgCtrlID()==IDC_SCROLLBAR1)
            HandleScrollbar(nSBCode, nPos);
    CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

Fügen Sie anschließend die Methode HandleScrollbar(...) mit dem unten angegebenen Prototyping zur Bearbeitung der WM_HSCROLL Nachricht zur Dialogklasse hinzu. Erweitern Sie die Methode um folgenden, doch etwas umfangreicheren, Code:

void CSliderDlg::HandleScrollbar(UINT nSBCode, UINT nPos)
{

    int nScrollMin, nScrollMax, nActScrollPos;

    // Aktuelle Position des Thumbs auslesen
    nActScrollPos = m_CScroll.GetScrollPos();
    // Scrollbereich auslesen
    m_CScroll.GetScrollRange(&nScrollMin, &nScrollMax);
    // Scroll-Code auswerten
    switch(nSBCode)
    {
    case SB_LEFT:
        nActScrollPos = nScrollMin;
        break;
    case SB_LINELEFT:
        if (nActScrollPos != nScrollMin)
            nActScrollPos--;
        break;
    case SB_LINERIGHT:
        if (nActScrollPos != nScrollMax)
            nActScrollPos++;
        break;
    case SB_PAGELEFT:
        nActScrollPos -= 10;
        if (nActScrollPos < nScrollMin)
            nActScrollPos = nScrollMin;
        break;
    case SB_PAGERIGHT:
        nActScrollPos += 10;
        if (nActScrollPos > nScrollMax)
            nActScrollPos = nScrollMax;
        break;
    case SB_RIGHT:
        nActScrollPos = nScrollMax;
        break;
    case SB_THUMBPOSITION:
        nActScrollPos = nPos;
        break;
    case SB_THUMBTRACK:
        nActScrollPos = nPos;
        break;
    default:
        return;             
// nothing more to do!!
    }
    // Positions des Thumbs neu setzen
    m_CScroll.SetScrollPos(nActScrollPos);
    // Falls Thumb nicht gezogen wurde, Progressbar und
    // Slider synchronisieren
    if (nSBCode != SB_THUMBTRACK)
    {
        m_CProgress1.SetPos(nActScrollPos);
        m_CSlider.SetPos(nActScrollPos+100);
    }
}

Damit auch die Bildlaufleiste mit dem Regler synchron läuft, muss die Methode HandleSlider(...) zum Schluss etwas angepasst werden.

void CSliderDlg::HandleSlider()
{
    // Akt. Position des Schiebereglers auslesen
    int nActPos = m_CSlider.GetPos();
    // und Statusanzeige synchronisieren
    m_CProgress1.SetPos(nActPos-100);
    // und Bildlaufleiste auch noch
    m_CScroll.SetScrollPos(nActPos-100);
}

Starten Sie das Programm nun und die Controls in der 3er-Gruppe werden immer synchron laufen.

Kommen wir jetzt zur Darstellung einer Animation innerhalb eines Dialogs. Sicher kennen Sie die kleine Animation mit der über einen Rechner kreisenden Lupe wenn Sie z.B. im Explorer nach Dateien suchen. Quasi als kleines Bonbon werden wir uns nun zunächst ansehen, wie Sie an diese Animation kommen und damit auch in ihren Anwendungen einsetzen können. Dazu gibt es verschiedene Wege, wir werden uns den einfachsten ansehen und die entsprechende AVI-Datei einfach aus der entsprechenden System-DLL extrahieren. Viele der Animationen liegen in der DLL SHELL32.DLL, die Sie im WINDOWS Systemverzeichnis finden. Ressourcen in EXE- und DLL-Dateien lassen sich mit dem Ressourcen-Editor öffnen. Wurde die Datei einmal geöffnet, können mittels des Ressourcen-Editors Ressourcen aus ihr extrahiert werden.

Schließen Sie nun (sicherheitshalber) das aktuelle Projekt; wir werden es später wieder öffnen. Anschließend kopieren Sie die Datei SHELL32.DLL aus dem WINDOWS Systemverzeichnis in ein temporäres Verzeichnis. Wählen Sie dann im Visual Studio das Menü Datei und dort den Menüpunkt Öffnen... aus. Wechseln Sie ins temporäre Verzeichnis. Stellen Sie im Öffnen-Dialog als Dateityp Ausführbare Dateien und in der Listbox Öffnen als den Typ Ressourcen ein. Öffnen Sie die kopierte Datei SHELL32.DLL.

Exportieren einer Ressource

Nach dem Laden der DLL werden Ihnen zunächst die vorhandenen Ressource-Typen angezeigt. Wir wollen uns eine AVI-Datei aus der Ressource 'ausleihen'. Öffnen Sie nun diesen Ressource-Typ und klicken dann die Ressource 152 mit der rechten Maustaste an. Im daraufhin eingeblendeten Kontextmenü wählen Sie den  Eintrag Exportieren... aus und speichern die AVI-Ressource jetzt in die Datei 152.avi ab. Beachten Sie bitte, dass im Export-Dialog als Dateierweiterung standardmäßig jedoch bin vorgegeben wird. Schließen Sie jetzt die DLL wieder. Zum Schluss kopieren Sie die extrahierte AVI-Datei in Ihr Arbeitsverzeichnis und löschen die Dateien im temporären Verzeichnis. So einfach geht's, wenn man es weiß.

Um jetzt AVI-Dateien (aber ohne Ton!) innerhalb eines Dialog wiederzugeben, wird im Dialog ein Animation-Control eingesetzt. Damit das Control von der Anwendung aus gesteuert werden kann, muss innerhalb des Dialogs wieder eine entsprechende Membervariable angelegt werden. Die MFC stellt zur Unterstützung von Animation-Controls die Klasse CAnimateCtrl zur Verfügung. Die Verknüpfung zwischen der darzustellenden AVI-Datei und dem Control erfolgt über die CAnimateCtrl Methode Open(...). Die Methode erhält als Parameter den Namen der nachher im Control abzuspielenden AVI-Datei. Als Returnwert liefert die Methode im Fehlerfall den Wert 0.

Sie sollten den Returnwert immer abfragen, da sich in einem Animation-Control nur AVI-Dateien ohne Tonspur abspielen lassen. Zudem müssen die AVI-Dateien noch in einer bestimmten Kodierung vorliegen.

Nach dem erfolgreichen Laden einer AVI-Datei kann diese dann anschließend mittels der CAnimateCtrl Methode Play(...) wiedergegeben werden. Sie können dieser Methode als Parameter einen Start- und Endframe sowie einen Wiederholungszähler mitgeben. Hierdurch lassen sich z.B. nur bestimmte Sequenzen innerhalb einer AVI-Datei wiedergeben. Den Abspielvorgang können Sie jederzeit mittels Stop(...) unterbrechen.

Erweitern wir jetzt unser Beispiel um die Darstellung der Animation.

Stellen Sie zunächst sicher, dass sich die im vorherigen Schritt extrahierte Datei 152.avi im aktuellen Arbeitsverzeichnis befindet. Öffnen Sie dann wieder das vorhin geschlossene Projekt Slider.

Und jetzt dürfen Sie wieder rann. Versuchen Sie einmal die AVI-Datei 152.avi im Animation-Control abzuspielen wenn der darunter liegende Button angeklickt wird. Geben Sie dem Button die ID IDC_SANIMATE und die Beschriftung Start.

Lösung zur Anzeige der Animation

Fügen Sie über den Klassen-Assistent die zum Animation-Control gehörende Membervariable m_CAnimate (Typ CAnimateCtrl) hinzu. Anschließend verbinden Sie die AVI-Datei 152.avi in der OnInitDialog(...) Methode mit dem Control.

BOOL CSliderDlg::OnInitDialog()
{
....
    // Schieberegeler initialisieren
    ....
    // Animation-Control initialisieren
    BOOL bRetCode = m_CAnimate.Open("152.avi");
    ASSERT (bRetCode);
    return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll ....
}

Zum Schluss fehlt nur das Abspielen der geladenen AVI-Datei. Dazu wird über den Klassen-Assistenten der Nachrichtenbearbeiter für die BN_CLICKED Nachricht des Buttons IDC_SANIMATE zum Dialog hinzugefügt und dessen Code wie folgt erweitert:

void CSliderDlg::OnSanimate()
{
    // TODO: Code für die Behandlungsroutine der Steuerelement-....
    m_CAnimate.Play(0,-1,1);
}

Ende der Lösung

Starten Sie das Programm dann.

Nach dem Starten des Programms wird im Animation-Control der erste Frame der AVI-Datei angezeigt. Das AVI wird standardmäßig oben links im Control platziert. Was im Augenblick vielleicht noch etwas störend wirkt ist die Hintergrundfarbe der AVI-Datei. Dies wollen wir nun über die Eigenschaften des Animation-Controls korrigieren.

Setzen Sie dazu einfach, wie unten angegeben, im Eigenschaftsdialog des Animation-Controls die Eigenschaften Zentriert und Transparent.

Eigenschaften des Animate-Controls

Wenn Sie nun das Programm starten, so wird der farbige Hintergrund ausgeblendet und die AVI-Datei mittig im Control positioniert.

Damit beenden wir die Behandlung des Animation-Controls und kommen zur letzten Gruppe in Dialog. Diese Gruppe besteht ebenfalls aus drei Controls: einer Statusanzeige, einem Textfeld und einem Drehfeld. Richten wir unser Augenmerk zunächst auf das Drehfeld. Das Drehfeld, oft auch als Spin-Button bezeichnet, wird hauptsächlich dann eingesetzt, wenn nummerische Werte eingestellt werden sollen. Das Drehfeld selbst besteht nur aus den beiden Pfeilen. In der Praxis ist dem Drehfeld aber meistens ein Text- oder Editfeld zugeordnet um den aktuellen Wert des Drehfeldes darzustellen. Dieses zugeordnete Feld wird auch als Buddy-Control bezeichnet. Mehr dazu gleich. Wird ein Drehfeld in einem Dialog (oder Fenster) verwendet, so wird in der Regel in der entsprechenden Klasse ein mit ihm verbundenes Objekt der Klasse CSpinButtonCtrl instantiiert. Und auch Drehfelder besitzen einen Bereich, in dem die Werte durchlaufen werden. Dieser Bereich wird mit der Methode SetRange32(...), jetzt jedoch der Klasse CSpinButtonCtrl zugehörig, einstellt. Die Parameter der Methode entsprechen denen der gleichnamigen Methode der Klasse CProgressBar (siehe weiter oben).

Obwohl Drehfelder standardmäßig den Bereich 0 bis 100 besitzen sollten Sie trotzdem immer die Methode SetRange32(...) aufrufen. Ohne den Aufruf dieser Methode wird über den oberen Pfeil-Button der Wert des Drehfeldes dekrementiert und über den unteren Button inkrementiert. Wird die Methode SetRange32(...) aufgerufen, so dreht sich dieses Verhalten um, d.h. über den oberen Pfeil-Button wird dann der Wert inkrementiert und über den unteren dekrementiert.

Um die Position (Wert) eines Drehfeldes zu setzen oder auszulesen, werden auch hier die Methoden SetPos(...) und GetPos(...) aufgerufen.

Aber sehen wir uns noch einige der Eigenschaften des Drehfeldes an.

Eigenschaften des Drehfeldes

Wie bereits vorher erwähnt besteht ein Drehfeld nur aus den Pfeil-Buttons. Um die aktuelle Position (Wert) des Drehfeldes auszugeben, wird in der Regel ein Text- oder Editfeld eingesetzt. Dieses Feld muss in der Tab-Reihenfolge unmittelbar vor dem Drehfeld stehen. Wird nun die Eigenschaft Auto Buddy und Buddy-Ganzzahl setzen gesetzt, so wird die aktuelle Position in diesem Feld ausgegeben, ohne dass Sie dafür eine Zeile Code schreiben müssen. Über die Eigenschaft Umbruch kann zusätzlich noch eingestellt werden, ob der der Wert beim Überschreiten einer der Bereichsgrenze ans anderen 'Ende' springt.

Die nicht in der Online-Hilfe aufgeführte Eigenschaft Hot Track verändert die Farbe der Pfeiltasten wenn der Cursor über ihnen positioniert wird.

Soweit zur generellen Handhabung des Drehfeldes. Fehlt uns nur noch die 'nachrichtendienstliche' Bearbeitung des Controls. Drehfelder senden ebenfalls WM_HSCROLL bzw. WM_VSCROLL Nachrichten (abhängig von der eingestellten Ausrichtung, siehe Bild oben) wenn ihre Position (Wert) verändert wird. Wie diese Nachrichten zu behandeln sind haben Sie in dieser Lektion bereits erfahren. Da im Beispiel ein Drehfeld mit vertikalen Pfeilen eingesetzt wird, empfängt der Dialog entsprechende WM_VSCROLL Nachrichten.

Im Beispiel soll der über das Drehfeld eingestellte Wert in dem rechts von ihm befindlichen Textfeld ausgegeben und zusätzlich in der darüber liegenden Statusanzeige angezeigt werden. Erweitern wir dazu das Beispiel ein letztes Mal.

Passen wir zuerst den Dialog an. Stellen Sie die Eigenschaften des Drehfeldes wie oben angegeben ein. Damit wird dem Drehfeld automatisch ein Feld zur Anzeige der aktuellen Position zugeordnet. Um das Feld zur Ausgabe des Wertes zu bestimmen, muss dieses in der Tab-Reihenfolge unmittelbar vor dem Drehfeld stehen. Dabei ist es nicht relevant, ob die Tabstopp Eigenschaft des Feldes gesetzt ist oder nicht, wichtig ist alleine die Tab-Reihenfolge (siehe nachfolgendes Bild).

Tab-Reihenfolge des Dialogs

Als nächstes fügen Sie über den Klassen-Assistenten die mit der Statusanzeige verbundene Membervariable m_CProgress2 (Typ CProgressCtrl) und die mit dem Drehfeld verbundene Membervariable m_CSpin (Typ CSpinButtonCtrl) hinzu. Initialisieren die Controls in der Methode OnInitDialog(...) wie folgt:

BOOL CSliderDlg::OnInitDialog()
{
    // Animation-Control initialisieren
    BOOL bRetCode =
m_CAnimate.Open("152.avi");
    ASSERT(bRetCode);
    // Spin-Button und 2. Statusanzeige initialisieren
    m_CSpin.SetRange(0, 100);
    m_CSpin.SetPos(25);
    m_CProgress2.SetRange(0,100);
    m_CProgress2.SetPos(25);

    return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll ....
}

Bleibt jetzt nur noch die Kopplung des Drehfeldes mit der Statusanzeige übrig. Dazu muss der Nachrichtenbearbeiter OnVScroll(...) zum Dialog hinzugefügt werden. Die Vorgehensweise hierzu ist die gleiche wie weiter oben beim Hinzufügen der OnHScroll(...) Methode. Nachdem Sie die OnVScroll(...) Methode hinzugefügt haben, passen Sie deren Code noch wie folgt an:

void CSliderDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen ....
    m_CProgress2.SetPos(nPos);
    CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}

Wenn Sie das Programm starten, so wird die aktuelle Position des Drehfeldes im links davon befindlichen Textfeld und in der Statusanzeige ausgegeben.

Das fertige Beispiel finden Sie auch 08Dialoge.

Damit ist dieses Kapitel im Prinzip beendet. Zum Schluss können Sie sich nun noch einige Tipps&Tricks zum Thema Dialoge ansehen.



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