The COM App example shows how to use ActiveQt to develop a Qt application that can be automated via COM. Different QObject based classes are exposed as COM objects that communicate with the GUI of the running Qt application. The APIs of those COM objects has been designed to resemble the APIs of standard COM applications; i.e. those from Microsoft Office.
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; };
第 1 個類
應用程序
錶示應用程序對象。它暴露隻讀特性
documents
and
id
以訪問文檔列錶和標識符。讀/寫特性
visible
控製是否
QTabWidget
基應用程序的用戶界麵應該可見,和槽
quit()
終止應用程序。
The RegisterObject 屬性的設置是為確保在 COM ROT (運行對象錶) 中注冊此類的實例 - 這允許 COM 客戶端連接到已實例化的 COM 對象。
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; };
The
DocumentList
類存儲文檔的列錶。它提供讀取文檔數、按索引訪問各文檔及創建新文檔的 API。
application
特性返迴根對象。
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; };
The
Document
類錶示最終應用程序文檔。各文檔由應用程序選項卡 Widget 中的頁麵錶示,且擁有的標題透過文檔 API 可讀寫。
application
特性再次返迴根對象。
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() { } 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()); }
實現為
Document
類為選項卡 Widget 創建新頁麵,並將該頁麵標題用於 title 特性。會刪除頁麵當刪除文檔時。
DocumentList::DocumentList(Application *application) : QObject(application) { } Application *DocumentList::application() const { return qobject_cast<Application *>(parent()); } int DocumentList::count() const { return m_list.count(); } 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; }
The
DocumentList
實現很簡單。
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"
The
應用程序
類在構造函數中初始化用戶界麵,並展示和隱藏它在實現
setVisible()
。對象名稱 (可訪問透過
id
特性) 被設為
"From
QAxFactory
" 以指示此 COM 對象已由 COM 所創建。注意,沒有析構函數會刪除
QTabWidget
- 代替履行這的是在
quit()
槽,先於調用
quit()
透過單發計時器,確保完成 COM 槽的調用是必要的。
QAXFACTORY_BEGIN("{edd3e836-f537-4c6f-be7d-6014c155cc7a}", "{b7da3de8-83bb-4bbe-9ab7-99a05819e201}") QAXCLASS(Application) QAXTYPE(Document) QAXTYPE(DocumentList) QAXFACTORY_END()
類的導齣是從服務器使用
QAxFactory
宏。僅
應用程序
對象可以從外部實例化 - 纔可以使用其它 API 後於訪問各個對象縱觀
應用程序
API.
int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 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(); }
main() 入口點函數創建
QApplication
,且僅僅進入事件循環若應用程序已由 COM 所啓動。若應用程序已由用戶所啓動,則
應用程序
對象被創建且對象名稱被設為 From Application。然後啓動 COM 服務器,並采用 COM 注冊應用程序對象。現在,透過特定客戶端 API 可訪問 COM 客戶端。
應用程序的退齣是明確控製的 - 若 COM 啓動瞭應用程序,則客戶端代碼必須調用 quit();若用戶啓動瞭應用程序,則終止應用程序當關閉最後窗口時。
最後,使用戶界麵可見,並啓動事件循環。
簡單的 Visual Basic 應用程序現在可以訪問此 Qt 應用程序。以 VB,啓動新 Standard Exe 工程並嚮 comappLib 類型庫添加工程引用。創建具有 DocumentList 列錶框、DocumentsCount 靜態標簽及 NewDocument 命令按鈕的錶單。最後,為錶單實現像這樣的代碼:
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) 下一 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
要構建範例必須先構建
QAxServer
庫。然後運行
qmake
和 make 工具在
examples\activeqt\comapp
.
文件: