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
.
文件: