COM App Beispiel (ActiveQt)
Das COM App Beispiel zeigt, wie man ActiveQt verwendet, um eine Qt-Anwendung zu entwickeln, die über COM automatisiert werden kann. Verschiedene QObject -basierte Klassen werden als COM-Objekte dargestellt, die mit der GUI der laufenden Qt-Anwendung kommunizieren. Die APIs dieser COM-Objekte wurden so gestaltet, dass sie den APIs von Standard-COM-Anwendungen, z.B. denen von Microsoft Office, ähneln.
class Application : public QObject { Q_OBJECT Q_CLASSINFO("ClassID", "{b50a71db-c4a7-4551-8d14-49983566afee}") Q_CLASSINFO("InterfaceID", "{4a427759-16ef-4ed8-be79-59ffe5789042}") Q_CLASSINFO("RegisterObject", "yes") Q_PROPERTY(DocumentList* documents READ documents) Q_PROPERTY(QString id READ id) Q_PROPERTY(bool visible READ isVisible WRITE setVisible) public: explicit Application(QObject *parent = nullptr); DocumentList *documents() const; QString id() const { return objectName(); } void setVisible(bool on); bool isVisible() const; QTabWidget *window() const { return m_ui.data(); } public slots: void quit(); private: QScopedPointer <DocumentList> m_docs; QScopedPointer <QTabWidget> m_ui; };
Die erste Klasse Application
repräsentiert das Anwendungsobjekt. Sie stellt schreibgeschützte Eigenschaften documents
und id
zur Verfügung, um Zugriff auf die Liste der Dokumente und einen Bezeichner zu erhalten. Eine Lese-/Schreibeigenschaft visible
steuert, ob die QTabWidget-basierte Benutzeroberfläche der Anwendung sichtbar sein soll, und ein Slot quit()
beendet die Anwendung.
Das RegisterObject-Attribut wird gesetzt, um sicherzustellen, dass Instanzen dieser Klasse in der COM-Running Object Table (ROT) registriert sind - dies ermöglicht COM-Clients, sich mit einem bereits instanziierten COM-Objekt zu verbinden.
class DocumentList : public QObject { Q_OBJECT Q_CLASSINFO("ClassID", "{496b761d-924b-4554-a18a-8f3704d2a9a6}") Q_CLASSINFO("InterfaceID", "{6c9e30e8-3ff6-4e6a-9edc-d219d074a148}") Q_PROPERTY(Application* application READ application) Q_PROPERTY(int count READ count) public: explicit DocumentList(Application *application); int count() const; Application *application() const; public slots: Document *addDocument(); Document *item(int index) const; private: QList<Document *> m_list; };
Die Klasse DocumentList
speichert eine Liste von Dokumenten. Sie stellt eine API zur Verfügung, um die Anzahl der Dokumente zu lesen, um auf jedes Dokument über den Index zuzugreifen und um ein neues Dokument zu erstellen. Die Eigenschaft application
gibt das Stammobjekt zurück.
class Document : public QObject { Q_OBJECT Q_CLASSINFO("ClassID", "{2b5775cd-72c2-43da-bc3b-b0e8d1e1c4f7}") Q_CLASSINFO("InterfaceID", "{2ce1761e-07a3-415c-bd11-0eab2c7283de}") Q_PROPERTY(Application *application READ application) Q_PROPERTY(QString title READ title WRITE setTitle) public: explicit Document(DocumentList *list); virtual ~Document(); Application *application() const; QString title() const; void setTitle(const QString &title); private: QScopedPointer <QWidget> m_page; };
Die Klasse Document
schließlich repräsentiert ein Dokument in der Anwendung. Jedes Dokument wird durch eine Seite im Registerkarten-Widget der Anwendung dargestellt und hat einen Titel, der über die API des Dokuments gelesen und geschrieben werden kann. Die Eigenschaft application
gibt wiederum das Stammobjekt zurück.
Document::Document(DocumentList *list) : QObject(list) { QTabWidget *tabs = list->application()->window(); m_page.reset(new QWidget(tabs)); m_page->setWindowTitle(tr("Unnamed")); tabs->addTab(m_page.data(), m_page->windowTitle()); m_page->show(); } Document::~Document() = default; Application *Document::application() const { return qobject_cast<DocumentList *>(parent())->application(); } QString Document::title() const { return m_page->windowTitle(); } void Document::setTitle(const QString &t) { m_page->setWindowTitle(t); QTabWidget *tabs = application()->window(); int index = tabs->indexOf(m_page.data()); tabs->setTabText(index, m_page->windowTitle()); }
Die Implementierung der Klasse Document
erstellt eine neue Seite für das Registerkarten-Widget und verwendet den Titel dieser Seite für die Eigenschaft title. Die Seite wird gelöscht, wenn das Dokument gelöscht wird.
DocumentList::DocumentList(Application *application) : QObject(application) { } Application *DocumentList::application() const { return qobject_cast<Application *>(parent()); } int DocumentList::count() const { return m_list.size(); } Document *DocumentList::item(int index) const { return m_list.value(index, nullptr); } Document *DocumentList::addDocument() { Document *document = new Document(this); m_list.append(document); return document; }
Die Implementierung von DocumentList
ist sehr einfach.
Application::Application(QObject *parent) : QObject(parent), m_ui(new QTabWidget), m_docs(new DocumentList(this)) { setObjectName(QStringLiteral("From QAxFactory")); } DocumentList *Application::documents() const { return m_docs.data(); } void Application::setVisible(bool on) { m_ui->setVisible(on); } bool Application::isVisible() const { return m_ui->isVisible(); } void Application::quit() { m_docs.reset(); m_ui.reset(); QTimer::singleShot(0 /*ms*/, qApp, &QCoreApplication::quit); } #include "main.moc"
Die Klasse Application
initialisiert die Benutzeroberfläche im Konstruktor und zeigt und verbirgt sie in der Implementierung von setVisible()
. Der Objektname (zugänglich über die Eigenschaft id
) wird auf "From
QAxFactory " gesetzt, um anzuzeigen, dass dieses COM-Objekt von COM erstellt wurde. Beachten Sie, dass es keinen Destruktor gibt, der QTabWidget löschen würde - dies geschieht stattdessen im Slot quit()
, bevor quit() durch einen Single-Shot-Timer aufgerufen wird, der notwendig ist, um sicherzustellen, dass der COM-Aufruf an den Slot vollständig ist.
QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}") QAXCLASS(Application) QAXTYPE(Document) QAXTYPE(DocumentList) QAXFACTORY_END()
Die Klassen werden vom Server mit Hilfe der QAxFactory Makros exportiert. Nur Application
Objekte können von außen instanziiert werden - die anderen APIs können erst nach dem Zugriff auf die entsprechenden Objekte über die Application
API verwendet werden.
int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setQuitOnLastWindowClosed(false); // started by COM - don't do anything if (QAxFactory::isServer()) return app.exec(); // started by user Application appobject; appobject.setObjectName(QStringLiteral("From Application")); QAxFactory::startServer(); QAxFactory::registerActiveObject(&appobject); appobject.window()->setMinimumSize(300, 100); appobject.setVisible(true); QObject::connect(&app, &QGuiApplication::lastWindowClosed, &appobject, &Application::quit); return app.exec(); }
Die main()-Einstiegsfunktion erstellt eine QApplication und tritt nur in die Ereignisschleife ein, wenn die Anwendung von COM gestartet wurde. Wurde die Anwendung vom Benutzer gestartet, wird das Objekt Application
erstellt und der Objektname auf "From Application" gesetzt. Dann wird der COM-Server gestartet, und das Anwendungsobjekt wird bei COM registriert. Es ist nun für COM-Clients über die clientspezifischen APIs zugänglich.
Das Beenden der Anwendung wird explizit gesteuert - wenn COM die Anwendung gestartet hat, muss der Client-Code quit() aufrufen; wenn der Benutzer die Anwendung gestartet hat, wird die Anwendung beendet, wenn das letzte Fenster geschlossen wurde.
Schließlich wird die Benutzeroberfläche sichtbar gemacht und die Ereignisschleife gestartet.
Eine einfache Visual Basic-Anwendung könnte nun auf diese Qt-Anwendung zugreifen. Starten Sie in VB ein neues "Standard Exe"-Projekt und fügen Sie einen Projektverweis auf die Typbibliothek comappLib hinzu. Erstellen Sie ein Formular mit einer Listbox "DocumentList", einem statischen Label "DocumentsCount" und einer Befehlsschaltfläche "NewDocument". Schließlich implementieren Sie den Code für das Formular wie folgt:
Private Application As comappLib.Application Private MyApp As Boolean Private Sub UpdateList() DocumentList.Clear DocumentsCount.Caption = Application.documents.Count For Index = 0 To Application.documents.Count - 1 DocumentList.AddItem (Application.documents.Item(Index).Title) Next End Sub Private Sub Form_Load() On Error GoTo CreateNew Set Application = GetObject(, "comapp.Application") MyApp = False GoTo Initialized CreateNew: On Error GoTo InitializeFailed Set Application = New Application Application.Visible = True MyApp = True Initialized: Caption = Application.id UpdateList InitializeFailed: End Sub Private Sub Form_Unload(Cancel As Integer) If MyApp Then Application.quit End If End Sub Private Sub NewDocument_Click() Application.documents.addDocument UpdateList End Sub
Um das Beispiel zu erstellen, müssen Sie zuerst die Bibliothek QAxServer erstellen. Führen Sie dann qmake
und Ihr Make-Tool in examples\activeqt\comapp
aus.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.