COM应用程序示例(ActiveQt)
COM应用程序示例显示了如何使用ActiveQt开发一个可以通过COM自动化的Qt应用程序。不同的基于QObject的类被暴露为COM对象,这些对象与正在运行的Qt应用程序的GUI进行通信。这些COM对象的API被设计得类似于标准COM应用程序的API;即来自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; };
第一个类Application
代表应用程序对象。它公开只读属性documents
和id
以获取文档列表和标识符的访问权限,一个可读写属性visible
控制应用程序基于QTabWidget的用户界面是否可见,一个槽quit()
终止应用程序。
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; };
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; };
最后,Document
类代表应用程序中的文档。每个文档由应用程序的选项卡控件中的一个页面表示,并通过文档的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() = 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()); }
Document
类实现的实现为选项卡控件创建一个新页面,并使用该页面的标题作为标题属性。当文档被删除时,页面也被删除。
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; }
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"
Application
类在构造函数中初始化用户界面,并在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宏从服务器导出的。只能从外部实例化Application
对象 - 其他API只能在通过Application
API访问相应对象之后使用。
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(); }
主入口函数main()创建了一个QApplication,如果应用程序是通过COM启动的,则直接进入事件循环。如果是由用户启动的应用程序,则创建一个Application
对象,并将对象名称设置为"From Application"。然后启动COM服务器,并将应用程序对象注册到COM。现在可以通过客户端特定的API被COM客户端访问。
应用程序的退出被明确定义 - 如果是由COM启动的应用程序,则客户端代码必须调用quit(); 如果是由用户启动的应用程序,则当最后一个窗口关闭时应用程序终止。
最后,用户界面变得可见,事件循环开始。
现在,一个简单的Visual Basic应用程序可以访问这个Qt应用程序。在VB中,启动一个新的"标准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) 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
要构建此示例,您必须首先构建QAxServer库。然后运行qmake
和examples\activeqt\comapp
中的您的构建工具。
© 2024 Qt公司。本文件中包含的文档贡献是各自所有者的版权。本文件提供的文档根据自由软件基金会发布的GNU Free Documentation License版本1.3的条款进行许可。Qt和相应的标志是芬兰以及/或世界其他国家的Qt公司的商标。所有其他商标均为各自所有者的财产。