vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 2

Tag 9

ActiveX-Steuerelemente

Auf dem heutigen Markt für Produkte der Anwendungsentwicklung gibt es Tausende vorgefertigter Komponenten, die man in eine Anwendung einbauen und damit die Funktionalität der Anwendung im Handumdrehen erweitern kann. Ursprünglich war es die Domäne der Visual Basic-Programmierer, jetzt aber kann man in nahezu jeder Programmiersprache - einschließlich Visual C++ - auf fertige ActiveX-Steuerelemente zurückgreifen. Heute lernen Sie, wie man ActiveX-Steuerelemente in Visual C++- Anwendungen einbaut und die vorhandene Funktionalität nutzt.

Insbesondere geht es heute um folgende Themen:

Was sind ActiveX-Steuerelemente?

Ein ActiveX-Steuerelement ist eine Softwarekomponente, die sich in die verschiedensten Programme einbauen läßt und die man wie einen nativen Teil des Programms verwenden kann. Das Konzept ist mit den Komponenten einer Stereoanlage vergleichbar. Wenn man ein neues Kassettendeck kauft, kann man es einfach mit der bereits vorhandenen Anlage verbinden und deren Funktionalität erweitern, ohne die bisherigen Funktionen zu beeinträchtigen. ActiveX-Steuerelemente bringen die gleichen Möglichkeiten der Zusammenarbeit von Komponenten in Softwareanwendungen.

ActiveX-Steuerelemente firmierten ursprünglich unter der Bezeichnung OLE 2.0. Die von Microsoft entwickelte Technologie OLE 2.0 diente dazu, zwei oder mehr Anwendungen zu kombinieren und wie eine einzige Anwendung erscheinen zu lassen (oder zumindest eine Umschaltung zwischen den verschiedenartigen Anwendungen innerhalb derselben Benutzeroberfläche zu erreichen). Dieser Gedanke war eine Erweiterung der ursprünglichen OLE-Technologie (OLE - Object Linking and Embedding, Objekte verknüpfen und einbetten), die es lediglich erlaubte, die mit verschiedenen Anwendungen erzeugten Dokumente zu einem Dokument zusammenzufassen. Beim Aufpolieren der OLE-Technologien für eine Arbeit in einer verteilten Umgebung (wie etwa dem Internet) hat sich Microsoft dafür entschieden, auch einen neuen Namen zu verwenden. Somit war ActiveX geboren.

ActiveX und die IDispatch-Schnittstelle

Die ActiveX-Technologie setzt auf der COM-Technologie von Microsoft auf (COM - Component Object Model) und stützt sich auf deren Oberfläche und das Interaktionsmodell, um die ActiveX-Steuerelemente nahtlos zu integrieren. Die COM-Technologie definiert, wie ActiveX-Objekte konstruiert sind und wie ihre Schnittstellen auszusehen haben. Die auf COM aufsetzende Schicht legt fest, welche Schnittstellen die verschiedenartigen Objekte unterstützen sollten und wie unterschiedliche Objekttypen miteinander in Wechselwirkung treten.

Die COM-Technologie von Microsoft definiert, wie Komponenten über die Schnittstellen miteinander interagieren können. Eine Schnittstelle verhält sich wie ein Funktionsaufruf an eine ActiveX-Komponente. COM legt dabei fest, wie dieser Funktionsaufruf aufgebaut sein muß, wie der Aufruf zu erfolgen hat und welche unterstützende Funktionalität den Funktionsaufruf begleiten muß.

Über Schnittstellen wie IUnknown, die in jedem COM-Objekt erforderlich sind, fragt man die Komponente ab, um herauszufinden, welche anderen Schnittstellen die Komponente bietet. Jede Schnittstelle unterstützt einen speziellen Satz von Funktionen - eine Schnittstelle behandelt etwa die visuelle Erscheinung des Steuerelements, eine andere steuert, wie die Erscheinung des Steuerelements mit der umgebenden Anwendung in Wechselwirkung tritt, eine weitere löst Ereignisse in der umgebenden Anwendung aus, usw.

Zu den Schlüsseltechnologien der ActiveX-Steuerelemente gehört die Automatisierung. Damit kann eine Anwendung, die in eine andere Anwendung eingebettet ist, sich selbst aktivieren, ihren Teil der Benutzeroberfläche oder des Dokuments steuern, Änderungen am Dokument vornehmen und sich dann wieder schließen, wenn der Benutzer zu einem anderen Teil der Anwendung geht, der nicht von der eingebetteten Anwendung gesteuert wird.

Diese Vorgänge laufen beispielsweise ab, wenn man ein Excel-Tabellenblatt in ein Word-Dokument einbettet. Ein Klick auf das Tabellenblatt aktiviert Excel. Das Tabellenblatt läßt sich dann mit Excel bearbeiten, selbst wenn man weiterhin in Word arbeitet. Sobald die Änderungen am Tabellenblatt abgeschlossen sind, schließt sich Excel automatisch, und man kann in Word weiterarbeiten.

Ein Schlüssel zur Arbeitsweise der Automatisierung ist eine spezielle Schnittstelle namens IDispatch (auch als Dispinterface bezeichnet). Die IDispatch-Schnittstelle besteht aus einem Zeiger auf eine Tabelle verfügbarer Methoden, die sich im ActiveX- Steuerelement oder der eingebetteten Anwendung ausführen lassen. Diesen Methoden sind ID-Nummern - sogenannte DISPIDs - zugeordnet, die ebenfalls in eine Tabelle geladen werden. In dieser Tabelle kann man dann nach der ID für eine bestimmte Methode nachschlagen. Nachdem man die DISPID für eine bestimmte Methode kennt, kann man diese Methode über die Methode Invoke der IDispatch-Schnittstelle aufrufen. Dabei übergibt man die DISPID, um die auszuführende Methode zu kennzeichnen. Abbildung 9.1 zeigt, wie die IDispatch-Schnittstelle die Methode Invoke verwendet, um Methoden im ActiveX-Objekt auszuführen.

Abbildung 9.1:
Die ActiveX-Schnittstelle IDispatch

ActiveX-Container und -Server

Um ein ActiveX-Objekt in ein anderes einzubetten, muß man das eingebettete Objekt als ActiveX-Server und das Objekt, das das erste Objekt enthält, als ActiveX-Container implementieren. Ein ActiveX-Objekt, das man in ein anderes einbetten kann, ist ein ActiveX-Server, ob es sich dabei nun um eine vollständige Anwendung oder nur ein kleines ActiveX-Steuerelement handelt. Jedes ActiveX-Objekt, das andere ActiveX- Objekte in sich aufnehmen kann, ist ein ActiveX-Container.

Verwechseln Sie nicht die Begriffe Container und Server mit dem Begriff Client in Abbildung 9.1. Der Client ist das Objekt, das die IDispatch- Schnittstelle des anderen Objekts aufruft. Wie Sie in Kürze sehen werden, rufen sowohl der Container als auch der Server die IDispatch-Schnittstellen des »Partners« auf und machen ihn damit zu ihrem Client.

Diese beiden Typen von ActiveX-Objekten schließen sich nicht gegenseitig aus. Ein ActiveX-Server kann auch ActiveX-Container sein. Ein Beispiel für dieses Konzept liefert der Internet Explorer von Microsoft. Der Internet Explorer ist als ActiveX-Server implementiert, der im Gerüst eines ActiveX-Containers (das ebenfalls Word, Excel, PowerPoint oder eine beliebige andere ActiveX-Server-Anwendung aufnehmen kann) läuft. Zur selben Zeit, da Internet Explorer als ActiveX-Server innerhalb der Browser- Umgebung läuft, kann er andere ActiveX-Steuerelemente enthalten.

ActiveX-Steuerelemente sind eine spezielle Instanz eines ActiveX-Servers. Manche ActiveX-Server sind ebenfalls Anwendungen, die eigenständig laufen können. ActiveX-Steuerelemente können nicht eigenständig laufen und müssen in einen ActiveX- Container eingebettet werden. Durch den Einsatz von ActiveX-Komponenten in Ihrer Visual C++-Anwendung machen Sie Ihre Anwendung automatisch zu einem ActiveX- Container.

Der größte Teil der Interaktion zwischen dem ActiveX-Container und einem ActiveX- Steuerelement findet über die IDispatch-Schnittstellen statt. Eine dieser IDispatch- Schnittstellen gehört zum Steuerelement und wird durch den Container verwendet, um Aufrufe der verschiedenen Methoden auszuführen, die das Steuerelement dem Container verfügbar macht.

Der Container stellt dem Steuerelement zwei IDispatch-Schnittstellen bereit. Das Steuerelement verwendet die erste dieser IDispatch-Schnittstellen, um Ereignisse in der Container-Anwendung auszulösen. Die zweite Schnittstelle dient dazu, die Eigenschaften des Steuerelements festzulegen, wie es Abbildung 9.2 darstellt. Die meisten Eigenschaften eines ActiveX-Steuerelements werden eigentlich vom Container bereitgestellt, aber durch das Steuerelement verwaltet. Wenn man eine Eigenschaft für das Steuerelement setzt, ruft der Container eine Methode im Steuerelement auf, um es anzuweisen, die Eigenschaften aus dem Container zu lesen. Größtenteils sind diese Abläufe für den Programmierer transparent, da Visual C++ eine Reihe von C++-Klassen um die Schnittstellen des ActiveX-Steuerelements aufbaut. Diese C++-Klassen legen Methoden frei. Genau über diese Methoden treten Sie in Wechselwirkung, und nicht durch direkte Aufrufe der IDispatch-Schnittstelle des Steuerelements.

Abbildung 9.2:
ActiveX-Container und Steuerelemente treten hauptsächlich über wenige IDispatch-Schnittstellen in Wechselwirkung.

Ein ActiveX-Steuerelement in das Projekt aufnehmen

Wenn man sich die Arbeitsweise von ActiveX-Steuerelementen ansieht, scheint es schwieriger zu sein als es in Wirklichkeit ist, Steuerelemente in Anwendungen einzubauen. Mit Visual C++ ist es schon einfach, ActiveX-Steuerelemente in eine Anwendung zu integrieren, und noch einfacher, sie zu verwenden. Bevor Sie ein ActiveX- Steuerelement in Ihre Anwendung aufnehmen, erzeugen Sie zunächst das Anwendungsgerüst, in das Sie ein ActiveX-Steuerelement einbauen:

1. Legen Sie mit dem MFC-Anwendungs-Assistenten ein neues Projekt namens ActiveX an.

2. Übernehmen Sie die Standardeinstellungen wie in den vergangenen Lektionen, lassen Sie aber im zweiten Dialogfeld des Assistenten das Kontrollkästchen für ActiveX-Steuerelemente eingeschaltet. Als Titel der Anwendung können Sie beispielsweise ActiveX-Steuerelemente eintragen.

3. Nachdem Sie das Anwendungsgerüst erstellt haben, entfernen Sie alle Steuerelemente aus dem Dialogfeld und fügen eine Schaltfläche hinzu.

4. Setzen Sie die ID der Schaltfläche auf IDC_EXIT und den Titel auf &Beenden.

5. Mit dem Klassen-Assistenten fügen Sie nun eine Funktion für das Ereignis BN_CLICKED der Schaltfläche hinzu.

6. In die eben erstellte Funktion tragen Sie den bereits aus vergangenen Lektionen bekannten Aufruf von OnOK ein, um die Anwendung schließen zu können.

Das Steuerelement registrieren

Bevor Sie ein ActiveX-Steuerelement in Ihr Dialogfeld aufnehmen, müssen Sie das Steuerelement sowohl bei Windows als auch bei Visual C++ registrieren. Die Registrierung für Windows kann auf zwei Wegen erfolgen. Der erste besteht darin, daß man die Installationsroutine, die zum ActiveX-Steuerelement gehört, ausführt. Wenn es keine Installationsroutine gibt, müssen Sie das Steuerelement manuell registrieren. Führen Sie in diesem Fall die folgenden Schritte aus:

1. Öffnen Sie die MS-DOS-Eingabeaufforderung.

2. Wechseln Sie in das Verzeichnis, wo sich das ActiveX-Steuerelement in Ihrem System befindet.

3. Führen Sie den Befehl regsvr32 aus. Geben Sie als Argument der Befehlszeile den Namen des ActiveX-Steuerelements an. Wenn Sie zum Beispiel ein Steuerelement namens MYCTL.OCX registrieren, das sich im Verzeichnis Windows\System befindet, führen Sie die folgenden Befehle an der MS-DOS-Eingabeaufforderung aus:

C:\WINDOWS>CD system
C:\WINDOWS\SYSTEM>regsvr32 MYCTL.OCX

Es empfiehlt sich, die zum Steuerelement gehörende Installationsroutine auszuführen, da die manuelle Registrierung das Steuerelement möglicherweise nicht für die Programmentwicklung aktiviert. Steuerelemente können für die Entwicklung und die Nutzung lizenziert sein. Wenn ein Steuerelement lediglich für die Nutzung lizenziert ist, können Sie es nicht in Ihren Visual C++-Anwendungen einsetzen. Dieser Mechanismus schützt Steuerelemententwickler, die ihre Produkte gegen eine entsprechende Gebühr an die Anwendungsentwickler verkaufen. Derartige Steuerelemente sind zwar auf dem jeweiligen System installiert, lassen sich aber nicht mit einer anderen Anwendung nutzen.

COM- und ActiveX-Objekte speichern eine Menge Informationen in der Registrierungsdatenbank von Windows. Wenn eine Anwendung auf ein ActiveX-Objekt zurückgreift, bezieht sich das Betriebssystem auf diese Informationen in der Windows-Registrierung und ermittelt, ob die Anwendung das Objekt in der angeforderten Weise verwenden darf. Mit dem Dienstprogramm regsvr32.exe werden zwar die meisten Informationen über das Steuerelement in die Systemregistrierung eingetragen, dennoch können zusätzliche Angaben in der Registrierung erforderlich sein, damit sich das Steuerelement in der vorgesehenen Weise nutzen läßt.

Nachdem Sie nun das gewünschte ActiveX-Steuerelement im Betriebssystem angemeldet haben, müssen Sie es noch bei Visual C++ registrieren und in Ihr Projekt einfügen. Führen Sie dazu folgende Schritte aus:

1. Wählen Sie Projekt / Dem Projekt hinzufügen / Komponenten und Steuerelemente aus dem Menü von Visual C++.

2. Im Dialogfeld Sammlung der Komponenten und Steuerelemente gehen Sie zum Ordner Registered ActiveX-Controls, wie es Abbildung 9.3 zeigt.

Abbildung 9.3:
Die ActiveX-Steuerelemente, die sich in das Projekt aufnehmen lassen

3. Markieren Sie das Steuerelement, das Sie registrieren wollen, beispielsweise das Steuerelement Microsoft FlexGrid Control, und klicken Sie auf die Schaltfläche Einfügen.

4. Klicken Sie im Meldungsfeld mit der Frage, ob Sie diese Komponente einfügen wollen, auf OK.

5. Im Dialogfeld Klassen bestätigen klicken Sie auf OK, um die angegebenen C++-Klassen hinzuzufügen (siehe Abbildung 9.4).

Abbildung 9.4:
Visual C++ gibt darüber Auskunft, welche Klassen in das Projekt eingebunden werden.

6. Klicken Sie im Dialogfeld Sammlung der Komponenten und Steuerelemente auf die Schaltfläche Schliessen, um die Aufnahme der Steuerelemente in Ihr Projekt fertigzustellen.

7. Das Steuerelement FlexGrid sollte nun in der Steuerelementpalette für Ihr Dialogfeld enthalten sein, wie es Abbildung 9.5 zeigt.

Abbildung 9.5:
Das ActiveX-Steuerelement FlexGrid wird in die Steuerelementpalette hinzugefügt und läßt sich in Dialogfeldern verwenden.

Im Arbeitsbereich sehen Sie auf der Registerkarte Klassen die vier Klassen, die Visual C++ in Ihr Projekt eingefügt hat. Wenn Sie die Klassenbäume erweitern, erscheinen die zahlreichen Methoden für diese Klassen. Visual C++ hat diese Klassen und Methoden nach einer Untersuchung des gerade hinzugefügten ActiveX-Steuerelements angelegt und Klassenmethoden erzeugt, um die jeweiligen Methoden der IDispatch- Schnittstelle des Steuerelements aufzurufen.

Wenn Sie mit älteren ActiveX-Steuerelementen in Ihren Visual C++-Anwendungen arbeiten, ist Visual C++ eventuell nicht in der Lage, die Klassen und Methoden zu erzeugen, um die Funktionalität des Steuerelements abzukapseln. Die Informationen im Steuerelement, die Visual C++ die notwendigen Angaben liefern, um diese Klassen und Methoden erstellen zu können, gehören zu den neueren Erweiterungen der ActiveX-Spezifikation. Letztendlich bringen ältere Steuerelemente diese Informationen nicht mit, wodurch sich ihr Einsatz mit Visual C++ schwieriger gestaltet.

Das Steuerelement in das Dialogfeld aufnehmen

Nachdem Sie nun das Steuerelement FlexGrid in Ihr Projekt eingebunden haben, können Sie es in Ihr Dialogfeld genau wie jedes andere Steuerelement aufnehmen. Legen Sie die Eigenschaften des Steuerelements gemäß Tabelle 9.1 fest.

Tabelle 9.1: Einstellungen der Steuerelementeigenschaften

Objekt

Eigenschaft

Einstellung

FlexGrid-Steuerelement

ID

Rows (Zeilen)

Cols (Spalten)

MergeCells

Format (Formatstring)

IDC_MSFGRID

20

4

2 - Zeilen beschränkt

<Gebiet |<Produkt |<Verkäufer |> Umsatz

(Leerzeichen je nach gewünschter Spaltenbreite hinzufügen.)

Nachdem Sie das Steuerelement in Ihr Dialogfeld aufgenommen haben, enthält das Eigenschaftsdialogfeld eine zusätzliche Registerkarte, die alle Eigenschaften des Steuerelements enthält (siehe Abbildung 9.6). Die Eigenschaften des Steuerelements können Sie über diese Registerkarte festlegen oder wie gewohnt über die anderen Registerkarten arbeiten.

Abbildung 9.6:
Die Registerkarte Eigenschaften eines ActiveX-Steuerelements enthält alle Eigenschaften des Steuerelements.

Wenn Sie alle Eigenschaften des Steuerelements eingestellt haben, fügen Sie eine Variable für das Steuerelement hinzu, damit Sie es per Code ansprechen können. Öffnen Sie dazu die Registerkarte Member-Variablen hinzufügen im Klassen-Assistenten. Da Sie eine Variable für ein Steuerelement hinzufügen, sind nur Variablen vom Typ Control verfügbar, so daß Sie nur den Variablennamen bereitstellen müssen. Benennen Sie die Variable für dieses Beispiel mit m_ctlFGrid.

ActiveX-Steuerelemente in einer Anwendung einsetzen

Nachdem Visual C++ alle Klassen generiert hat, um das ActiveX-Steuerelement zu verkapseln, können Sie wie bei jedem Standardsteuerelement die Methoden aufrufen und auf die Steuerelementereignisse reagieren. Als erstes verwenden Sie die Methoden des Steuerelements, um Informationen über das Steuerelement einzuholen und Daten innerhalb des Steuerelements zu modifizieren. Dann lernen Sie, wie man mit Visual C++ auf Steuerelementereignisse reagiert.

Mit dem Steuerelement in Wechselwirkung treten

Die heutige Beispielanwendung generiert eine Reihe von Produktumsätzen über fünf Verkaufsgebiete mit fünf Verkäufern. Man kann durch die Daten blättern, die nach Gebiet und Produkt sortiert sind, und vergleichen, wie jeder Verkäufer die einzelnen Produkte an den Mann gebracht hat.

Für dieses Projekt erstellen Sie ein Array mit Werten, die in die Zellen der Tabelle geladen werden. Die Anwendung sortiert dann die Tabelle in aufsteigender Reihenfolge und greift dabei auf die internen Sortierfähigkeiten des Steuerelements FlexGrid zurück.

Daten in das Steuerelement laden

Als erstes erstellen Sie eine Funktion, um Daten in das Steuerelement FlexGrid zu laden. Nehmen Sie in die Klasse CActiveXDlg eine neue Funktion auf. Dazu klicken Sie im Arbeitsbereich auf der Registerkarte Klassen mit der rechten Maustaste auf die Klasse CActiveXDlg und wählen den Befehl Member-Funktion hinzufügen aus dem Kontextmenü. Legen Sie den Funktionstyp als void, die Funktionsdeklaration mit LoadData und den Zugriff als Privat fest. Klicken Sie auf die Schaltfläche OK, und fügen Sie den Code aus Listing 9.1 in die Funktion ein.

Listing 9.1: Die Funktion LoadData

1: void CActiveXDlg::LoadData()
2: {
3: int liCount; // Zeilenzähler für Tabelle
4: CString lsAmount; // Umsatz
5:
6: // Zufallszahlengenerator initialisieren
7: srand((unsigned)time(NULL));
8: // Array im Steuerelement erzeugen
9: for (liCount = m_ctlFGrid.GetFixedRows();
10: liCount < m_ctlFGrid.GetRows(); liCount++)
11: {
12: // Werte für erste Spalte (Gebiet) generieren
13: m_ctlFGrid.SetTextArray(GenID(liCount, 0), RandomStringValue(0));
14: // Werte für zweite Spalte (Produkt) generieren
15: m_ctlFGrid.SetTextArray(GenID(liCount, 1), RandomStringValue(1));
16: // Werte für dritte Spalte (Verkäufer) generieren
17: m_ctlFGrid.SetTextArray(GenID(liCount, 2), RandomStringValue(2));
18: // Werte für vierte Spalte (Umsatz) generieren
19: lsAmount.Format("%5d.00", rand());
20: // Vierte Spalte füllen
21: m_ctlFGrid.SetTextArray(GenID(liCount, 3), lsAmount);
22: }
23:
24: // Aufeinanderfolgende, zusammengehörige Zeilen in diesen Spalten Âvereinigen
25: m_ctlFGrid.SetMergeCol(0, TRUE);
26: m_ctlFGrid.SetMergeCol(1, TRUE);
27: m_ctlFGrid.SetMergeCol(2, TRUE);
28:
29: // Tabelle sortieren
30: DoSort();
31: }

Diese Funktion initialisiert zuerst den Zufallszahlengenerator. Als nächstes durchläuft sie eine Schleife über alle Zeilen des Steuerelements und schreibt Daten in die einzelnen Zellen. Die Gesamtzahl der Zeilen im Steuerelement ermitteln Sie durch Aufruf der Methode GetRows, die Anzahl der Kopfzeilen durch Aufruf der Methode GetFixedRows . Über die Methode SetTextArray lassen sich Daten in das Steuerelement einfügen. Die Methode SetTextArray übernimmt die Zellen-ID als erstes Argument und den Zelleninhalt als zweites. Beide Argumente generieren Sie über Funktionen, die Sie in Kürze erstellen.

Nachdem die Daten in den Tabellenzellen eingetragen sind, rufen Sie die Methode SetMergeCol auf, um dem Steuerelement mitzuteilen, daß es die Zellen in den ersten drei Spalten zusammenfassen kann, falls angrenzende Zeilen den gleichen Wert enthalten. Schließlich sortieren Sie das Steuerelement mit einer weiteren Funktion, die noch zu erstellen ist.

Die ID einer Zelle berechnen

Die Zellen im Steuerelement FlexGrid sind fortlaufend von links nach rechts und von oben nach unten numeriert. Im Beispiel hat das Steuerelement in der ersten Zeile, die die Überschriften enthält (und die bereits ausgefüllt sind), die Zellen 0 bis 3, die zweite Reihe die Zellen 4 bis 7 usw. Die ID einer Zelle läßt sich demnach berechnen, indem man die Anzahl der Spalten mit der aktuellen Zeilennummer multipliziert und dazu die Spaltennummer addiert. Besteht das Steuerelement zum Beispiel aus vier Spalten, und die Zelle liegt in der dritten Spalte und vierten Zeile, berechnet sich die Zellen-ID zu (4 * 3) + 2 = 14. (Beachten Sie dabei, daß die Zählung der Spalten und Zeilen mit 0 beginnt. Die Nummer der dritten Spalte ist demnach 2 und die Nummer der vierten Zeile gleich 3.)

Nachdem Sie nun wissen, wie man die Zellen-ID berechnet, implementieren Sie diese Formel in einer Funktion. Fügen Sie eine neue Funktion in die Klasse CActiveXDlg nach der gleichen Methode wie die Funktion LoadData hinzu. Für die Funktion legen Sie als Typ int und als Deklaration GenID(int m_iRow, int m_iCol) fest. In die Funktion schreiben Sie den Code gemäß Listing 9.2.

Listing 9.2: Die Funktion GenID

1: int CActiveXDlg::GenID(int m_iRow, int m_iCol)
2: {
3: // Anzahl der Spalten ermitteln
4: int liCols = m_ctlFGrid.GetCols();
5:
6: // ID auf Basis der Spaltenzahl, der aktuellen Spalte
7: // und der aktuellen Zeile berechnen
8: return (m_iCol + liCols * m_iRow);
9: }

Zufallsdaten erzeugen

Die ersten drei Spalten der Tabelle wollen wir in der Beispielanwendung mit zufälligen Daten füllen. In der ersten Spalte sollen die Namen der Gebiete stehen. Die zweite Spalte erhält die Namen der Produkte, und die dritte Spalte führt die Verkäufer auf. In einer switch-Anweisung bestimmt man die Spalte, für die Daten zu generieren sind. Im entsprechenden case-Zweig generiert man dann eine zufällige Zahl, unterzieht diese einer Modulo-Division und wertet das Ergebnis in einer weiteren switch-Anweisung aus, so daß man unter einer begrenzten Menge von Datenstrings wählen kann.

Um diese Funktionalität zu implementieren, nehmen Sie in die Klasse CActiveXDlg eine weitere Funktion auf. Für den Typ legen Sie CString und als Deklaration RandomStringValue(int m_iColumn) fest. In die Funktion übernehmen Sie den Code aus Listing 9.3

Listing 9.3: Die Funktion RandomStringValue

1: CString CActiveXDlg::RandomStringValue(int m_iColumn)
2: {
3: CString lsStr; // Rückgabestring
4: int liCase; // Zufallszahl als ID
5:
6: // Für welche Spalte werden Daten generiert?
7: switch (m_iColumn)
8: {
9: case 0: // Die erste Spalte (Gebiet)
10: // Zufallszahl zwischen 0 und 4 erzeugen
11: liCase = (rand() % 5);
12: // Welcher Wert wurde erzeugt?
13: switch (liCase)
14: {
15: case 0:
16: // 0 - Gebiet Nordwest
17: lsStr = "Nordwest";
18: break;
19: case 1:
20: // 1 - Gebiet Südwest
21: lsStr = "Südwest";
22: break;
23: case 2:
24: // 2 - Gebiet Mitte
25: lsStr = "Mitte";
26: break;
27: case 3:
28: // 3 - Gebiet Nordost
29: lsStr = "Nordost";
30: break;
31: default:
32: // 4 - Gebiet Südost
33: lsStr = "Südost";
34: break;
35: }
36: break;
37: case 1: // Die zweite Spalte (Produkt)
38: // Zufallszahl zwischen 0 und 4 erzeugen
39: liCase = (rand() % 5);
40: // Welcher Wert wurde erzeugt?
41: switch (liCase)
42: {
43: case 0:
44: // 0 - Dusch zu zweit
45: lsStr = "Dusch zu zweit";
46: break;
47: case 1:
48: // 1 - April Spezial-Dragees
49: lsStr = "April Spezial-Dragees";
50: break;
51: case 2:
52: // 2 - Nachelle No. 6
53: lsStr = "Nachelle No. 6";
54: break;
55: case 3:
56: // 3 - Eau-De-Vie
57: lsStr = "Eau-De-Vie";
58: break;
59: default:
60: // 4 - Haut&Haar
61: lsStr = "Haut&Haar";
62: break;
63: }
64: break;
65: case 2: // Die dritte Spalte (Verkäufer)
66: // Zufallszahl zwischen 0 und 3 erzeugen
67: liCase = (rand() % 4);
68: // Welcher Wert wurde erzeugt?
69: switch (liCase)
70: {
71: case 0:
72: // 0 - Samson
73: lsStr = "Samson";
74: break;
75: case 1:
76: // 1 - Harry
77: lsStr = "Harry";
78: break;
79: case 2:
80: // 2 - Susi
81: lsStr = "Susi";
82: break;
83: default:
84: // 3 - Linda
85: lsStr = "Linda";
86: break;
87: }
88: break;
89: }
90: // Generierten String zurückgeben
91: return lsStr;
92: }

Das Steuerelement sortieren

Um die Tabelle des Steuerelements FlexGrid zu sortieren, muß man alle Spalten auswählen und dann die Sortierung mit aufsteigend festlegen. Um diese Funktionalität zu implementieren, fügen Sie in die Klasse CActiveXDlg eine weitere Funktion ein. Legen Sie den Typ als void und die Definition mit DoSort fest. In die Funktion übernehmen Sie den Code aus Listing 9.4.

Listing 9.4: Die Funktion DoSort

1: void CActiveXDlg::DoSort()
2: {
3: // Aktuelle Spalte auf 0 setzen
4: m_ctlFGrid.SetCol(0);
5: // Spaltenauswahl für alle Spalten festlegen
6: m_ctlFGrid.SetColSel((m_ctlFGrid.GetCols() - 1));
7: // Aufsteigend sortieren
8: m_ctlFGrid.SetSort(1);
9: }

Die Funktion DoSort setzt die aktuelle Spalte mit Hilfe der Methode SetCol auf die erste Spalte (d.h. Spalte 0). Als nächstes markiert sie mit der Methode SetColSel alle Spalten von der ersten bis zur letzten, so daß alle Spalten im Steuerelement ausgewählt sind. Schließlich ruft die Funktion die Methode SetSort auf, um das Steuerelement anzuweisen, die Spalten in aufsteigender Reihenfolge zu sortieren. Die Sortierreihenfolge wird durch Übergabe einer 1 an die Methode festgelegt.

Die Funktionalität zum Füllen des Steuerelements mit Daten ist damit vollständig realisiert. In der Funktion OnInitDialog ist nun noch die Funktion LoadData aufzurufen, um die Daten zu laden, bevor das Steuerelement für den Benutzer sichtbar ist. Bearbeiten Sie dazu die Funktion OnInitDialog gemäß Listing 9.5.

Listing 9.5: Die Funktion OnInitDialog

1: BOOL CActiveXDlg::OnInitDialog()
2: {
3: CDialog::OnInitDialog();
4: .
5: .
6: .
7: // ZU ERLEDIGEN: Hier zusätzliche Initialisierung einfügen
8:
9: ///////////////////////
10: // EIGENER CODE, ANFANG
11: ///////////////////////
12:
13: // Daten in Grid-Steuerelement laden
14: LoadData();
15:
16: ///////////////////////
17: // EIGENER CODE, ENDE
18: ///////////////////////
19:
20: return TRUE; // Geben Sie TRUE zurück, außer ein Steuerelement soll den ÂFokus erhalten
21: }

Wenn Sie die Anwendung in der jetzigen Entwicklungsphase kompilieren und ausführen, werden die Daten geladen und sortiert, wie es Abbildung 9.7 zeigt.

Abbildung 9.7:
FlexGrid mit Daten gefüllt

Auf Steuerelementereignisse reagieren

Das Steuerelement FlexGrid reagiert momentan noch nicht auf Eingaben, die Sie vielleicht in die Tabelle aufnehmen möchten. Wenn Sie auf eine der Zellen klicken und versuchen, den Wert zu ändern, passiert überhaupt nichts. Es ist also ein Steuerelementereignis hinzuzufügen, um die Eingabe zu behandeln. ActiveX-Steuerelemente machen verschiedene Ereignisse für die Nutzung in Visual C++-Anwendungen verfügbar. Mit dem Klassen-Assistenten können Sie sich die verfügbaren Ereignisse ansehen und bestimmen, welche Ereignisse für die gewünschte Funktionalität erforderlich sind und welche man ignorieren kann. Die meisten ActiveX-Steuerelemente verbinden mit den verfügbaren Ereignissen keine Standardfunktionalität, sondern erwarten, daß der Programmierer dem Steuerelement sagt, was bei welchem Ereignis zu tun ist.

In der Beispielanwendung fügen wir zwei Steuerelementereignisse hinzu, um das Klikken und die Bewegung der Maus aufzufangen. Wenn der Benutzer auf einen Spaltenkopf klickt und ihn an eine andere Position zieht, soll sich die Anordnung der Spalten entsprechend ändern. Um diese Funktionalität zu implementieren, sind zwei Steuerelementereignisse aufzufangen, wenn die Maustaste gedrückt und wenn sie wieder losgelassen wird. Für das erste Ereignis müssen Sie prüfen, ob der Benutzer einen Spaltenkopf angeklickt hat. Wenn ja, ist die ausgewählte Spalte gemeint. Beim zweiten Ereignis ist die ausgewählte Spalte zu der Spalte zu verschieben, auf der die Maustaste losgelassen wurde.

Um diese Funktionalität zu erreichen, erzeugen Sie eine neue Klassenvariable, in der Sie die Nummer der angeklickten Spalte zwischen zwei Ereignissen verwalten. Fügen Sie in die Klasse CActiveXDlg eine neue Variable ein, genauso wie Sie weiter oben die Funktionen hinzugefügt haben. Legen Sie den Variablentyp als int, den Namen als m_iMouseCol und den Zugriff als Privat fest.

Die ausgewählte Spalte auffangen

Um das Klickereignis für das Steuerelement abzufangen, führen Sie die folgenden Schritte aus:

1. Fügen Sie mit dem Klassen-Assistenten eine Funktion zur Behandlung der Nachricht MouseDown für das Objekt IDC_MSFGRID hinzu.

2. In die Funktion übernehmen Sie den Code aus Listing 9.6.

Listing 9.6: Die Funktion OnMouseDownMsfgrid

1: void CActiveXDlg::OnMouseDownMsfgrid(short Button, short Shift, long x, long y)
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement-Benachrichtigung Âhier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Hat Benutzer auf eine Datenzeile und nicht die
10: // Kopfzeile geklickt?
11: if (m_ctlFGrid.GetMouseRow() != 0)
12: {
13: // Wenn ja, dann Spaltenvariable auf 0 setzen
14: // und beenden
15: m_iMouseCol = 0;
16: return;
17: }
18: // Angeklickte Spalte sichern
19: m_iMouseCol = m_ctlFGrid.GetMouseCol();
20:
21: ///////////////////////
22: // EIGENER CODE, ENDE
23: ///////////////////////
24: }

Die Funktion prüft mit der Methode GetMouseRow die angeklickte Zeile. Wenn es sich nicht um die erste Zeile handelt, tragen Sie eine 0 in die Spaltenvariable ein und verlassen die Funktion. Andernfalls wird durch Aufruf der Methode GetMouseCol die angeklickte Spalte ermittelt. Die zurückgegebene Spaltennummer kommt in die Variable m_iMouseCol, die Sie gerade in die Klasse aufgenommen haben.

Spalte zum Zielort verschieben

Nachdem Sie nun die Nummer der ausgewählten Spalte ermittelt haben, müssen Sie die Spalte ermitteln, wo der Benutzer die Maustaste losläßt. Um das Ereignis beim Loslassen der Maus für das Steuerelement aufzufangen, führen Sie die folgenden Schritte aus:

1. Fügen Sie mit dem Klassen-Assistenten eine Funktion für die Nachricht MouseUp des Objekts IDC_MSFGRID hinzu.

2. Schreiben Sie in die Funktion den Code aus Listing 9.7.

Listing 9.7: Die Funktion OnMouseUpMsfgrid

1: void CActiveXDlg::OnMouseUpMsfgrid(short Button, short Shift, long x, long y)
2: {
3: // TODO: Code für die Behandlungsroutine der Steuerelement- ÂBenachrichtigung hier einfügen
4:
5: ///////////////////////
6: // EIGENER CODE, ANFANG
7: ///////////////////////
8:
9: // Wenn gewählte Spalte gleich erste Spalte,
10: // dann ist nichts zu tun.
11: if (m_iMouseCol == 0)
12: return;
13: // Neuzeichnen des Steuerelements abschalten
14: m_ctlFGrid.SetRedraw(FALSE);
15: // Gewählte Spaltenposition ändern
16: m_ctlFGrid.SetColPosition(m_iMouseCol, m_ctlFGrid.GetMouseCol());
17: // Tabelle neu sortieren
18: DoSort();
19: // Neuzeichnen wieder einschalten
20: m_ctlFGrid.SetRedraw(TRUE);
21:
22: ///////////////////////
23: // EIGENER CODE, ENDE
24: ///////////////////////
25: }

Die Funktion prüft zuerst, ob eine ausgewählte Spalte zu verschieben ist. Wenn nicht, wird die Funktion ohne weitere Aktionen verlassen. Ist eine Spalte markiert, schaltet die Funktion das Neuzeichnen des Steuerelements mit der Methode SetRedraw ab, damit die Verschiebung für den Benutzer nicht sichtbar ist. Als nächstes verschiebt die Funktion mit der Methode SetColPosition die ausgewählte Spalte zu der Spalte, wo der Benutzer die Maustaste losgelassen hat. Anschließend erfolgt der Aufruf der Funktion DoSort, um die Tabelle neu zu sortieren. Schließlich wird das Neuzeichnen wieder aktiviert, um das Steuerelement zu aktualisieren und dem Benutzer die verschobene Spalte anzuzeigen. Wenn Sie die Anwendung kompilieren und ausführen, sollten Sie nun in der Lage sein, die Spalten per Drag & Drop der Spaltenköpfe zu verschieben, wie es Abbildung 9.8 zeigt.

Abbildung 9.8:
FlexGrid mit neu angeordneten Spalten

Zusammenfassung

Heute haben Sie gelernt, wie man ActiveX-Steuerelemente in Visual C++-Anwendungen einsetzt, um in einfacher Weise die Funktionalität der Anwendung zu erweitern. Zuerst wurde die grundsätzliche Arbeitsweise von ActiveX-Steuerelementen erläutert und gezeigt, wie sie mit der Container-Anwendung in Wechselwirkung treten. Weiterhin haben Sie gelernt, wie man ein ActiveX-Steuerelement in das Entwicklungsprojekt einbindet, so daß man das Steuerelement in der Anwendung nutzen kann. Es wurde dargestellt, wie Visual C++ verschiedene C++-Klassen erzeugt, um die hinzugefügten ActiveX-Steuerelemente abzukapseln, und wie man mit dem Steuerelement über die freigelegten Methoden dieser generierten C++-Klassen interagiert. Schließlich ging es darum, wie man Ereignisse auffängt, die das ActiveX-Steuerelement auslöst, so daß man in der Anwendung auf die Ereignisse reagieren kann.

Fragen und Antworten

Frage:
Wie kann ich ermitteln, welche Methoden verfügbar sind, wenn ich mit einem ActiveX-Steuerelement arbeite?

Antwort:
Untersuchen Sie die C++-Klassen, die Visual C++ erstellt, um das Steuerelement abzukapseln. Dadurch erhalten Sie einen Überblick über die verfügbare Funktionalität. Wenn Sie die Dokumentation zum Steuerelement besitzen, können Sie sie mit den C++-Klassen vergleichen, um herauszufinden, welche Klassenmethode welche Methode des Steuerelements aufruft. Untersuchen Sie auch die Liste der Ereignisse für das Steuerelement im Klassen-Assistenten. Hieraus können Sie ersehen, welche Ereignisse für das Steuerelement verfügbar sind.

Frage:
Wie kann ich die auf meinem Computer für andere Anwendungen installierten ActiveX-Steuerelemente in meinen Visual C++-Anwendungen nutzen?

Antwort:
Das hängt davon ab, wie die Steuerelemente lizenziert sind und welche Anwendung die Steuerelemente installiert hat. Wurden die Steuerelemente durch ein anderes Entwicklungswerkzeug installiert, besitzen Sie wahrscheinlich auch die Entwicklungslizenz für das Steuerelement. In diesem Fall sollten Sie es in Ihren Visual C++-Anwendungen einsetzen können. Wenn die Steuerelemente von einer Endbenutzer-Anwendung installiert wurden, wie zum Beispiel Word oder Quicken, werden Sie wahrscheinlich nur über die Laufzeitlizenz für das Steuerelement verfügen. Wenn Sie diese Steuerelemente in eigenen Anwendungen einsetzen möchten, müssen Sie sich mit dem Hersteller des Steuerelements in Verbindung setzen, um eine Entwicklungslizenz für das Steuerelement zu erwerben.

Frage:
Da mir das Steuerelement FlexGrid nicht erlaubt, Daten direkt in das Steuerelement einzugeben, wie kann ich dann meinen Benutzern die Möglichkeit bieten, Daten in das Steuerelement genau wie in ein Tabellenblatt einzugeben?

Antwort:
Um diese Funktionalität für das Steuerelement FlexGrid zu implementieren, müssen Sie ein unverankertes Eingabefeld in Ihrem Fenster bereitstellen. Im Code ermitteln Sie, welche Zelle der Benutzer bearbeiten möchte, und setzen dann das Eingabefeld vor diese Zelle. Durch diese Anordnung erhält der Benutzer das Gefühl, als würde er die Daten direkt in die Zelle eintragen. Bei einer anderen Lösung könnte man ein zusätzliches Feld zur Dateneingabe außerhalb der Tabelle vorsehen, das etwa wie die Bearbeitungsleiste in Excel funktioniert. Hier gibt der Benutzer seine Daten ein. Man kann die Zellen, durch die der Benutzer navigiert, hervorheben, um ihm eine Rückmeldung für seine Aktionen zu bieten.

Workshop

Kontrollfragen

1. Wie ruft der ActiveX-Container die Methoden in einem ActiveX-Steuerelement auf?

2. Wie löst ein ActiveX-Steuerelement Ereignisse in der Container-Anwendung aus?

3. Welche Option im Anwendungs-Assistenten muß aktiviert sein, damit ActiveX- Steuerelemente in einer Visual C++-Anwendung wie gewünscht funktionieren?

4. Wie erleichtert Visual C++ die Arbeit mit ActiveX-Steuerelementen?

5. Warum kann es schwierig sein, in Visual C++ mit älteren ActiveX-Steuerelementen zu arbeiten?

Übung

Modifizieren Sie die Anwendung, so daß der Benutzer auf einen Spaltenkopf doppelklicken kann, um die Spalte als erste Spalte der Tabelle anzuordnen.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


Ein Imprint des Markt&Technik Buch- und Software-Verlag GmbH.
Elektronische Fassung des Titels: Visual C++ 6 in 21 Tagen, ISBN: 3-8272-2035-1