应用特性示例
展示具有各种功能(包括原生应用)的客户应用程序。
简介
本示例演示如何实现某些您可能在应用程序中需要的特定功能,例如
- 如何实现嵌套合成器
- 如何模拟崩溃并从中恢复
- 如何同时显示多个顶级窗口
- 如何使用原生运行时,不使用 QML
大多数这些功能仅在 多进程模式 中正确支持。
注意:本示例重点介绍应用(客户端)端。系统 UI(合成器/服务器)基于对 桌面系统 UI 示例 进行的一些修改。有关如何实现系统 UI 的更多详细信息,请参阅该示例。
嵌套合成器
嵌套合成器应用程序展示了如何在应用程序(Wayland 客户端)窗口内部实现一个 Wayland 合成器。合成器完全使用 QML 实现,并尽量减少使用。要在合成器中显示 Wayland 客户端,需要适当地设置 WAYLAND_DISPLAY
环境变量。
使用通过命令行设置的此环境变量启动客户
WAYLAND_DISPLAY=qtam-wayland-nested qmlscene client.qml -platform wayland
此命令仅在多进程模式下有效,因为嵌套合成器需要一个真实窗口作为其根元素。
嵌套合成器应用程序的 QML 代码如下
import QtQuick 2.11 import QtApplicationManager.Application 2.0 import QtWayland.Compositor 1.3 ApplicationManagerWindow { id: root color: "lightgrey" property ListModel shellSurfaces: ListModel {} Text { anchors.fill: parent anchors.margins: 8 font.pointSize: 14 wrapMode: Text.Wrap textFormat: Text.RichText text: "This Wayland<sup>*</sup> client window implements a Wayland compositor (nested compositor). " + "To display Wayland clients here, set:<br><br><b>WAYLAND_DISPLAY=qtam-wayland-nested</b>" + "<br><br>For instance:<br>WAYLAND_DISPLAY=qtam-wayland-nested qmlscene client.qml -platform wayland" + "<br><br><small>* in multi-process mode</small>" } WaylandCompositor { socketName: "qtam-wayland-nested" WaylandOutput { window: root sizeFollowsWindow: true } WlShell { onWlShellSurfaceCreated: shellSurfaces.append({shellSurface: shellSurface}); } XdgShellV6 { onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface}); } XdgShell { onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface}); } } Repeater { model: shellSurfaces ShellSurfaceItem { shellSurface: modelData onSurfaceDestroyed: shellSurfaces.remove(index) } } Component.onCompleted: console.info("Start a client application in the nested compositor for instance with:\n " + "WAYLAND_DISPLAY=qtam-wayland-nested QT_WAYLAND_DISABLE_WINDOWDECORATION=1 " + "QT_WAYLAND_SHELL_INTEGRATION=xdg-shell qmlscene client.qml -platform wayland"); }
崩溃模拟和恢复
此应用程序提供各种方法来强制应用程序崩溃,例如段错误。它利用一个用 C++ 实现的 QML 插件,以提供 Terminator
QML 类型来触发崩溃。然后应用程序管理器打印出崩溃的原因和相关信息,如回溯。系统 UI 实现了一种基本的崩溃恢复形式:重新启动应用程序。
此应用程序仅在多进程模式下工作。在单进程模式中,崩溃会影响整个程序(系统 UI)。
崩溃模拟和恢复应用程序的 QML 代码如下
import QtQuick 2.11 import QtApplicationManager.Application 2.0 import Terminator 2.0 ApplicationManagerWindow { id: root property var methods: ({ illegalMemory: "Illegal memory access", illegalMemoryInThread: "Illegal memory access in a thread", stackOverflow: "Force stack overflow", divideByZero: "Divide by zero", unhandledException: "Throw unhandled exception", abort: "Call abort", raise: "Raise signal 7", gracefully: "Exit gracefully" }) function accessIllegalMemory() { Terminator.accessIllegalMemory(); } Grid { columns: 2 Repeater { model: Object.keys(methods) Rectangle { width: root.width / 2 height: root.height / 4 border.width: 1 color: "lightgrey" Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.Wrap font.pointSize: 14 text: methods[modelData] } MouseArea { anchors.fill: parent onClicked: { switch (modelData) { case "illegalMemory": accessIllegalMemory(); break; case "illegalMemoryInThread": Terminator.accessIllegalMemoryInThread(); break; case "stackOverflow": Terminator.forceStackOverflow(); break; case "divideByZero": Terminator.divideByZero(); break; case "unhandledException": Terminator.throwUnhandledException(); break; case "abort": Terminator.abort(); break; case "raise": Terminator.raise(7); break; case "gracefully": Terminator.exitGracefully(); break; } } } } } } }
两个顶级窗口
此应用程序说明了如何通过将 QtObject 作为应用程序的根元素来显示多个顶级窗口。
两个顶级窗口应用程序的 QML 代码如下
import QtQuick 2.11 import QtApplicationManager.Application 2.0 QtObject { property var win1: ApplicationManagerWindow { color: "lightsteelblue" Rectangle { width: 80; height: 80; radius: 40 color: "orange" MouseArea { anchors.fill: parent drag.target: parent } } } property var win2: ApplicationManagerWindow { color: "transparent" Rectangle { id: rect anchors.fill: parent color: "orange" opacity: 0.4 } ApplicationManagerWindow { id: popup width: 300; height: 100 Rectangle { anchors.fill: parent border.width: 1 color: "orangered" } Text { anchors.centerIn: parent text: "Click to hide!" } MouseArea { anchors.fill: parent onClicked: popup.visible = false; } Component.onCompleted: setWindowProperty("type", "pop-up"); } } }
原生小部件
此应用程序基于 QWidget。与其他示例中的其他应用程序相比较,这些应用程序是 QML 应用程序,本程序使用原生运行时。因此,应用程序的入口点不是 main.qml
文件,而是一个可执行文件。这是一个基本的应用程序,仍然遵循此特定的系统 UI。目的是说明概念:系统 UI 需要一个表示正常窗口和弹出的窗口的 type
窗口属性。
此程序仅在多进程模式下工作,因为无法在单进程模式中启动应用程序进程。
原生小部件应用程序的 C++ 代码如下
#include <QApplication> #include <QPushButton> #include <QDialog> #include <QVBoxLayout> #include "launchermain.h" #include "logging.h" #include "dbusapplicationinterface.h" #include "dbusnotification.h" int main(int argc, char *argv[]) { QtAM::Logging::initialize(argc, argv); QtAM::Logging::setApplicationId("widgets"); QtAM::LauncherMain::initialize(); QApplication app(argc, argv); QtAM::LauncherMain launcher; launcher.registerWaylandExtensions(); launcher.loadConfiguration(); launcher.setupLogging(false, launcher.loggingRules(), QString(), launcher.useAMConsoleLogger()); launcher.setupDBusConnections(); QWidget window; QVBoxLayout layout(&window); // Popup using application manager window property QPushButton button1(QStringLiteral("Click to open/close a popup")); button1.setStyleSheet(QStringLiteral("QPushButton { background-color : limegreen; font-size: 36px; }")); layout.addWidget(&button1); QDialog *popup1 = new QDialog(&window); (new QPushButton(QStringLiteral("I'm a popup!"), popup1))->resize(340, 140); popup1->setStyleSheet(QStringLiteral("QPushButton { background-color : limegreen; color : white; font-size: 24px; }")); QObject::connect(&button1, &QPushButton::clicked, [&popup1, &launcher] () { popup1->setVisible(!popup1->isVisible()); launcher.setWindowProperty(popup1->windowHandle(), "type", QStringLiteral("pop-up")); }); // Notification QPushButton button2(QStringLiteral("Click to open a notification")); button2.setStyleSheet(QStringLiteral("QPushButton { background-color : darkgrey; font-size: 36px; }")); layout.addWidget(&button2); QtAM::DBusNotification *notification = QtAM::DBusNotification::create(&app); notification->setSummary(QStringLiteral("I'm a notification")); QObject::connect(&button2, &QPushButton::clicked, notification, &QtAM::DBusNotification::show); // Application interface for handling quit QtAM::DBusApplicationInterface iface(launcher.p2pDBusName(), launcher.notificationDBusName()); iface.initialize(); QObject::connect(&iface, &QtAM::DBusApplicationInterface::quit, [&iface] () { iface.acknowledgeQuit(); }); app.processEvents(); window.showNormal(); return app.exec(); }
代码结构
与其他纯粹基于QML的Qt应用程序管理器示例相比,本示例需要您显式构建。代码以这种方式结构化,结果的应用程序文件夹仅包含运行应用程序所需的工件。因此,您可以将这些应用程序打包并安装。
要构建包括其示例在内的Qt应用程序管理器,您需要向qmake
传递-config enable-examples
参数。了解更多详情,请参阅构建。
©2019 Luxoft Sweden AB. 本文档中包含的贡献是各自所有者的版权。本文档根据 Free Software Foundation 发布的 GNU自由文档许可协议版本1.3 的条款进行许可。Qt和相应标志是芬兰的Qt公司以及全球其他国家/地区的商标。所有其他商标均为各自所有者的财产。