The desktop UI development framework, compared with the mature solutions of mobile terminal and Web terminal, has been in a tepid state. With the outbreak of the storm, desktop online education, video conferencing and other demands continue to emerge. The traditional platform under the development framework is difficult to meet the needs, and the Directui-like framework because of cross-platform, poor scalability, high threshold problems and can not be recognized by some enterprises. The Electron and Flutter frameworks on the desktop often fail to provide 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 realize the desktop cross-platform business component construction through Qt Quick from two aspects. First, we talk about the advantages of Qt Quick on the desktop development, and then how to create a C++ extension plug-in for Qt Quick application to use.

Qt Quick advantage

Cross-platform features

The Qt Quick Plugin mechanism satisfies many of the requirements mentioned above. First of all, Qt is very cross-platform friendly, with only a few simple adaptations for a particular platform, you can use one 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 components

The Qt Quick component, written in Qt, is easily distributed and ultimately exported either in source code form or as a distributed binary folder containing the wraparound of the data model and the underlying components of the UI.

UI components are highly reusable

It is easy to create reusable components with Qt Quick, and some basic components such as Google Material style controls are also provided. 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 QML language with a concise syntax that is easy to understand and can be mixed with JavaScript to achieve almost any capability we can think of. And the new version of Qt Quick further enhances the interaction between C++ and QML, enabling rich capabilities with simple scripting.

Suitable for encapsulating business modules

Thanks to Qt Quick’s Model-View-Delegate design idea, we can completely separate the encapsulation of business data and basic UI display 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, you can do something like this:

Taking audio and video scenes for example, no matter what form the upper application finally presents, the bottom layer is some fixed data, such as member and member state management, device list and device detection selection, and the user can see nothing but the video screen visually. Through encapsulation, what we see is this form:

Similar to memberList design, do not set a fixed visual style to it, through the global predefined style sheet to control can let its UI change with the style of the user. In a meeting setting it might be called “meeting members,” and in an online education setting 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 functionality directly based on its capabilities, such as the scenarios mentioned above, when different product lines need to use the same functional components or need to extend Qt Quick capabilities. We can then use the Qt Quick 2 Extension Plugin to encapsulate these components. In a few simple steps, you can create your own Qt Quick plug-in.

Create the plug-in

Start by creating a Qt Quick 2 Extension Plugin project using Qt Creator. By default, a subclass derived from the QQMLExtensionPlugin is created in the base plug-in project, which allows 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;
};

Registering our custom types via this interface provides the introduction of the QML front end for use by the plug-in:

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"); / /... }

Some of these components are front-end invisible components. They will be created as a front-end instantiable object to create concrete instances. For example, NEMEngine is the only engine for the whole component and these objects will inherit from QObject.

class NEMEngine : public QObject {}

Data related encapsulation is different. They need to inherit from the QAbstract*Model. Take the device-related data Model for example, as shown in the following 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;
};

The data model is encapsulated in the principle of integrity, customization and parameterization, and the detailed business requirements should not be mixed in the process of component encapsulation as far as possible. For example, the NERTC 2.0 SDK device enumeration sequence 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 choose the most suitable one as the first device to use.
  • The other is the system default device, following the system changes to choose the device to use.

Only one of the two solutions is needed for some business scenarios, but as a secondary component, both should be able to provide upper configuration, 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, etc., it can also provide some front-end components for developers using plug-ins to create applications more quickly. As an example of a video rendering container, here is a Delegate to implement a simple video rendering using C++ registered to the front-end NEFrameProvider.

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 } }

With the project configuration, we made it export the plugin with these. QML UI files:

pluginfiles.files += \ imports/$$QML_IMPORT_NAME/qmldir \ imports/$$QML_IMPORT_NAME/components/NEMVideoOutput.qml .

The introduction of the plugin

It is more convenient to use a plug-in that has been created. Generally, plug-ins will be distributed in the form of a folder after compilation. We only need to configure the plug-in and path we want to introduce in the introduced function:

# Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = $$PWD/.. /bin

To use it in QML, we first need to import the corresponding plug-in:

The import NEMeeting 1.0

This allows you to use the types registered in the plugin:

/ / create instances NEMEngine engine {id: NEMEngine appKey: "092 dcd94d2c2566d1ed66061891 * * * * *"}

To present the device list, you simply create a list and specify the device data model that the plug-in has registered with.

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) } }

When creating the device object type, we can specify the device selection mode as SDK recommended nemdevices. RECOMMENDED_MODE by default:

NEMDevices {
    id: nemDevices
    engine: nemEngine
    autoSelectMode: NEMDevices.RECOMMENDED_MODE
}

When the application is released, you just need to distribute the plug-in directory with the application at the same time. No extra configuration is needed to complete the application packaging and publishing process.

conclusion

The Qt Quick 2 Extension Plugin is well documented for development and use. With this mechanism, we can not only create a development component that encapsulates the full functionality of an underlying capability SDK, but also allow users to highly customize the interaction behavior. This is something that has been difficult or even impossible with previous desktop UI development frameworks.

QML’s low barriers to entry also allow developers who have worked with front-end, C++, or some scripting languages to quickly switch to the Qt Quick development environment. They don’t need to worry about the implementation details of a plug-in, but simply put together a few components to make a complete application. At the same time, this is the direction that netease Yunxin team has been working hard 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 for this article, about Qt Quick more technical dry goods, also welcome to keep locking us.

The authors introduce

Deng Jiajia, senior development engineer of netease Intelligent Enterprise Yunxin, responsible for maintaining the pre-research and development of netease Yunxin cross-platform NIM SDK and upper-level solutions, including the maintenance of online education, interactive live broadcasting, IM IM and netease meeting solutions based on NIM SDK and NERTC SDK. Rich practical experience in Duilib, Qt Quick and CEF frameworks.

The trailer will be streamed online on May 20

Broadcast on demand has been closely related to daily life. What is the most important thing in this process? Lower broadcasting cost? Higher picture quality? This involves the narrowband high-definition technology, low bandwidth high-definition image quality cannot do without video coding.

The industry has a number of narrowband HD technology solutions, such as Taobao Live, Ali Nnarrowband HD, Tencent Speed HD, etc. NE264 is netease self-developed H264 encoder, has been successfully applied in video calling, live on-demand, bring lower delay, higher quality experience.

This sharing will reveal the mystery of narrowband HD technology and JND perceptual coding technology for you.

The topic of this issue: McTalk Live#3 Live on Demand Narrow Band HD JND Perception Coding Technology

Poke here, sign up

More technical dry goods, welcome to pay attention to “netease Intelligent Enterprise Technology +”