The UI development framework on the desktop side has been in a tepid state compared with the mature schemes on the mobile side and the Web side. In the wake of the pandemic, demand for desktop online education and video conferencing continues to emerge. The development framework under the traditional platform is difficult to meet the needs, and the directui-like framework can not be recognized by some enterprises because of the cross-platform, poor scalability, high threshold. The desktop Electron and Flutter frameworks often do not have the best solution due to individual requirements such as performance and native platform support.
Qt Quick can better solve the problems mentioned above. This article will introduce how to quickly build cross-platform business components on the desktop through Qt Quick from two aspects. First, we will talk about the advantages of Qt Quick on the desktop development, and then detail how to create a C++ extension plug-in for Qt Quick applications to use.
Qt Quick advantage
Cross-platform features
The Qt Quick Plugin mechanism addresses many of the requirements mentioned above. First, Qt is very cross-platform friendly, requiring only a few simple adaptations for a particular platform to use a single set of code to run on different terminals. The official title “One Framework. One Codebase. Any Platform” also highlights the cross-platform aspect of its work.
Easy to distribute component
A Qt Quick component written in Qt is easy to distribute, and its final export can be either source code or published as a binary folder containing packaging for the data model and UI base components.
UI components are highly reusable
Qt Quick makes it easy to create reusable components. Some basic components such as Google Material style controls are also available. Based on these basic components, we can extend different forms of UI components for external use without breaking the internal structure.
Front-end QML has a low learning threshold
Qt Quick is used to describe the front end of the QML language syntax is concise, very easy to understand, can be mixed with JavaScript to achieve almost every capability we can think of. And the new version of Qt Quick has further enhanced C++ and QML interaction, using simple scripts can achieve rich capabilities.
Suitable for encapsulating business modules
Thanks to Qt Quick’s model-View-delegate design, we can completely separate the encapsulation of business data and UI basic presentation capabilities, provide a complete data chain through the Model, and display data for different scenarios through the View and Delegate.
To create a complete application using the Qt Quick Plugin mechanism, you can do something like this:
Take audio and video scenes for example. No matter what form the upper application finally presents, the lower layer is fixed data, such as member and member state management, device list and device detection selection. What the user sees visually is nothing more than a video picture. Through encapsulation, we see a form like this:
For a design like MemberList, don’t give it a fixed visual style. Control with a globally predefined style sheet allows the UI to follow the user’s style changes. In a conference scenario it might be called “attendee”, in an online education scenario it might be called “student list”. This allows us to mix and match various types of business scenarios:
Build a Qt Quick C++ Plugin
A native Qt Quick application allows us to implement business functions directly based on their capabilities. As mentioned above, when different product lines need to use the same functional components or extend Qt Quick’s capabilities, We can use the [Qt Quick 2 Extension Plugin](http://Creating C++ Plugins for QML) to encapsulate these components. In a few simple steps, you can create your own Qt Quick plug-in.
Create the plug-in
First, create a Qt Quick 2 Extension project via Qt Creator. By default, a subclass of QQmlExtensionPlugin will be created to allow us to register our own custom modules for external use:
#include <QQmlExtensionPlugin>
class NEMeetingPlugin : public QQmlExtensionPlugin {
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char* uri) override;
};
Copy the code
Registering our custom types through this interface provides QML front-end use for introducing plug-ins:
void NEMeetingPlugin::registerTypes(const char* uri) { // @uri NEMeeting qmlRegisterType<NEMEngine>(uri, 1, 0, "NEMEngine"); qmlRegisterType<NEMAuthenticate>(uri, 1, 0, "NEMAuthenticate"); qmlRegisterType<NEMAccount>(uri, 1, 0, "NEMAccount"); / /... // Devices qmlRegisterType<NEMDevices>(uri, 1, 0, "NEMDevices"); qmlRegisterType<NEMDevicesModel>(uri, 1, 0, "NEMDeviceModel"); / /... // Schedules qmlRegisterType<NEMSchedule>(uri, 1, 0, "NEMSchedule"); qmlRegisterType<NEMScheduleModel>(uri, 1, 0, "NEMScheduleModel"); / /... // Meeting qmlRegisterType<NEMSession>(uri, 1, 0, "NEMSession"); qmlRegisterType<NEMMine>(uri, 1, 0, "NEMMine"); qmlRegisterType<NEMAudioController>(uri, 1, 0, "NEMAudioController"); / /... // Providers qmlRegisterType<NEMFrameProvider>(uri, 1, 0, "NEMFrameProvider"); / /... }Copy the code
Some of these components are front-end invisible components that create concrete instances as a front-end instantiable object, such as NEMEngine, which is the only engine for the entire component, and objects that inherit from QObject.
class NEMEngine : public QObject {}
Copy the code
Data-related encapsulations, however, need to be inherited from the QAbstract*Model. Using the device-specific data Model as an example, the following is an example code:
class NEMDevicesModel : public QAbstractListModel {
Q_OBJECT
public:
explicit NEMDevicesModel(QObject* parent = nullptr);
enum { DeviceName, DevicePath, DeviceProperty };
Q_PROPERTY(NEMDevices* deviceController READ deviceController WRITE setDeviceController NOTIFY deviceControllerChanged)
Q_PROPERTY(NEMDevices::DeviceType deviceType READ deviceType WRITE setDeviceType NOTIFY deviceTypeChanged)
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
NEMDevices* deviceController() const;
void setDeviceController(NEMDevices* deviceController);
NEMDevices::DeviceType deviceType() const;
void setDeviceType(const NEMDevices::DeviceType& deviceType);
Q_SIGNALS:
void deviceControllerChanged();
void deviceTypeChanged();
private:
NEMDevices* m_deviceController = nullptr;
NEMDevices::DeviceType m_deviceType = NEMDevices::DEVICE_TYPE_UNKNOWN;
};
Copy the code
The encapsulation of data model follows the principle of integrity, customizable and parameterization, and try not to mix detailed business requirements in the encapsulation process of components. Take NeRTC 2.0 SDK device enumeration sequence as an example, SDK provides two ways to enumerate devices.
- One is the SDK recommended device. When you have different devices, such as built-in device, external device, Bluetooth device, etc., the SDK will select the most suitable device to use as the first device.
- The other is the system default device, follow the system change to select devices to use.
Both scenarios require only one from the perspective of some business scenarios, but as a component that can be redeveloped, it should be possible to provide upper-level configuration for both, so the AutoSelectMode parameter is provided in the device-specific manager to provide external plug-in developers with control over which mode to use.
In addition to encapsulating data models, custom types, and so on, front-end components can also be provided to make it easier for developers to create applications using plug-ins. Using a container for video rendering as an example, here is a simple video rendering Delegate implemented with a NEMFrameProvider registered to the front end of C++.
Import QtQuick 2.0 import QtMultimedia 5.14 import NEMeeting 1.0 Rectangle {ID: root property bool Mirrored: false property alias frameProvider: frameProvider color: '#000000' VideoOutput { anchors.fill: parent source: frameProvider transform: Rotation { origin.x: root.width / 2 origin.y: root.height / 2 axis { x: 0; y: 1; z: 0 } angle: mirrored ? 180 : 0 } } NEMFrameProvider { id: frameProvider } }Copy the code
Through the project configuration, we let it export the plugins with the.qml UI files:
pluginfiles.files += \ imports/$$QML_IMPORT_NAME/qmldir \ imports/$$QML_IMPORT_NAME/components/NEMVideoOutput.qml .Copy the code
The introduction of the plugin
It is more convenient to use a created plug-in. Generally, plug-ins are distributed in the form of a folder after compilation. We only need to configure the plug-in we want to introduce and its path in the introduced function:
# Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = $$PWD/.. /binCopy the code
To use in QML, we first need to import the corresponding plug-in:
The import NEMeeting 1.0Copy the code
This allows you to use the types registered in the plugin:
/ / create instances NEMEngine engine {id: NEMEngine appKey: "092 dcd94d2c2566d1ed66061891 * * * * *"}Copy the code
To display the device list, simply create a list and specify the device data model that the plug-in registers.
ComboBox { Layout.fillWidth: true textRole: "deviceName" valueRole: "deviceId" currentIndex: {return nemDevices. CurrentPlayoutIndex} / / use c + + registered in the data model of the model: NEMDeviceModel {id: listModel deviceController: nemDevices deviceType: NEMDevices.DEVICE_TYPE_PLAYOUT } onActivated: { nemDevices.selectDevice(NEMDevices.DEVICE_TYPE_PLAYOUT, currentValue) } }Copy the code
When the device object type is created, we can use preset parameters to specify the device selection mode as SDK recommended mode.
NEMDevices {
id: nemDevices
engine: nemEngine
autoSelectMode: NEMDevices.RECOMMENDED_MODE
}
Copy the code
When the application is released, you just need to distribute the plugin directory and the application at the same time, and complete the packaging and distribution process without extra configuration.
conclusion
For the development and use of the Qt Quick 2 Extension Plugin, the official provides very detailed documentation. With this mechanism, we can not only create a development component that encapsulates the full functionality of an underlying capability SDK, but also allow the user to highly customize the interaction behavior. This is something that has been difficult or even impossible for previous desktop UI frameworks to do.
QML’s low barrier to entry also allows developers who have worked with front-end, C++, or some scripting language to quickly switch to Qt Quick. They don’t need to pay attention to the implementation details of a plug-in, just need to do some simple pieces of the components together to form a complete application. At the same time, this is also the direction that netease Yunxin team has been striving for. We use solutions and easy-to-use systems to enable audio, video, instant messaging and other technologies to be quickly and efficiently connected to corresponding services.
That’s all I have to share with you in this article. For more technical stuff about Qt Quick, please keep locking us in.
The authors introduce
Deng Jiajia, senior development engineer of netease Intelligent Enterprise Yunxin, is responsible for the pre-research and development of Netease Yunxin cross-platform NIM SDK and upper layer solutions, including online education, interactive live broadcasting, IM instant messaging and netease conference solutions built based on NIM SDK and NERTC SDK. Rich practical experience in Duilib, Qt Quick, CEF frameworks.
Live preview on May 20
Topic: MCtalk Live#3 JND sensing coding technology in narrowband hd
Target audience: students who are interested in live broadcasting and narrowband HD technology
Share content:
- Narrowband HD technology overview and industry common narrowband HD program introduction
- NE264 narrowband HD technology developed by netease
- JND sensing coding technology
Welcome to lock in the live broadcast room, register now
More technical dry goods, welcome to pay attention to [netease Smart enterprise technology +] wechat public number