C /QML项目与QT 4(Qtquick 1.x)和QT 5(Qtquick 2.x)兼容

C++/QML project compatible with both Qt 4 (QtQuick 1.x) and Qt 5 (QtQuick 2.x)

本文关键字:Qtquick QT 兼容 QML 项目      更新时间:2023-10-16

编写不使用QML的QT应用程序时,并且不依赖于新的QT 5功能,我们可以使用QT 4和QT 5进行编译(除了几个来源不相容)。

当我们想使用QT 5功能,但要落回等效但效率较低的QT 4解决方案时,我们可以简单地使用#if来检查QT版本,例如使用新的QStringLiteral,但使用QT 4进行编译时掉回QString::fromUtf8

我们如何使用Qtquick做同样的事情?请注意,可以在QT 5中使用QDeclarativeViewQtQuick 1.x一起使用CC_4,但是在QDeclarativeView中仅支持1.x的新场景图。在Quick 2.0中。

我想要的是:

  • 使用QT 4编译时,请使用QDeclarativeView和朋友;在QML中:import QtQuick 1.x
  • 使用QT 5编译时,请使用新的QQuickView和朋友;在QML中:import QtQuick 2.x
  • 只有一组QML文件,但是不是一个用于QtQuick 1.x,另一组用于QtQuick 2.x

关于C 部分,这似乎很容易。在QT 4中,我们可以简单地添加:

#include <QApplication>
#include <QDeclarativeView>
#include <QDeclarativeEngine>
typedef QApplication QGuiApplication;
typedef QDeclarativeView QQuickView;

然后在QT 4和QT 5中使用QGuiApplicationQQuickView等。但是,当QML文件包含QtQuick的导入声明时,我无法添加#if来决定1.x和2.x。是否有一种官方方法可以说,添加一个别名使QtQuick 1.xQQuickView中起作用(因此实际上将其解析为QtQuick 2.0)?

我所做的是在部署它们时在所有QML文件中替换字符串QtQuick x.y。如果您的源树中有一个文件夹qml,并且想要在构建树中具有相同的qml文件夹,则可以部署该文件夹,但要替换字符串以匹配所需的Qtquick版本。

以下解决方案在POSIX系统上起作用,因为它需要一些命令行工具。在Linux(Ubuntu)上测试。也许有Windows命令行经验的人可以为Windows添加一个版本。

添加您的 .pro(以下代码假设从构建文件夹中,使用../src/可以触发源文件夹;如果不是这种情况,则会更改***注释的路径)

// Define QT5 macro for use in C++, and select the correct module for QML:
greaterThan(QT_MAJOR_VERSION, 4) {
    DEFINES += QT5
    QT += quick
} else {
    QT += declarative
}
// Define qmake variables for QtQuick version, and if you want, QtQuick Controls:
equals(QT_MAJOR_VERSION, 4) {
    equals(QT_MINOR_VERSION, 7) {
        QT_QUICK_VERSION = 1.0
    }
    equals(QT_MINOR_VERSION, 8) {
        QT_QUICK_VERSION = 1.1
    }
}
equals(QT_MAJOR_VERSION, 5) {
    QT_QUICK_VERSION = 2.$${QT_MINOR_VERSION}
    equals(QT_MINOR_VERSION, 1): QT_QUICKCONTROLS_VERSION = 1.0
    equals(QT_MINOR_VERSION, 2): QT_QUICKCONTROLS_VERSION = 1.1
    equals(QT_MINOR_VERSION, 3): QT_QUICKCONTROLS_VERSION = 1.2
}
// Add a pre-build step which copies your qml folder
QtQuickVersion.target = FORCE
QtQuickVersion.commands = "rm -rf qml/;"
QtQuickVersion.commands += "cp -r ../src/qml/ .;"  // <-- *** Here is the source path
!isEmpty(QT_QUICK_VERSION) {
    QtQuickVersion.commands += "grep -rl 'QtQuick [0-9]\.[0-9]' qml/ | xargs -r sed -i 's/QtQuick [0-9]\.[0-9]/QtQuick $${QT_QUICK_VERSION}/g';"
}
!isEmpty(QT_QUICKCONTROLS_VERSION) {
    QtQuickVersion.commands += "grep -rl 'QtQuick.Controls [0-9]\.[0-9]' qml/ | xargs -r sed -i 's/QtQuick.Controls [0-9]\.[0-9]/QtQuick.Controls $${QT_QUICKCONTROLS_VERSION}/g';"
}
// Give the Makefile target *any* name which will *not* be created
// as a file, so the step is always executed
PRE_TARGETDEPS += FORCE
QMAKE_EXTRA_TARGETS += QtQuickVersion

在C (main.cpp中,您可以创建一个QQuickView,该CC_30落在QT 4:

QDeclarativeView
#ifdef QT5
#include <QGuiApplication>
#include <QQuickView>
#include <QQmlEngine>
#else
#include <QApplication>
#include <QDeclarativeView>
#include <QDeclarativeEngine>
typedef QApplication QGuiApplication;
typedef QDeclarativeView QQuickView;
// The following is the official fallback for QStringLiteral,
// see qstring.h in Qt 5 after #ifndef QStringLiteral */
#define QStringLiteral(str) QString::fromUtf8("" str "", sizeof(str) - 1)
#endif

int main(int argc, char *argv[])
{
    QGuiApplication a(argc, argv);
    // (add qmlRegisterType etc.)
    // Open the QML view with the main QML document:
    QQuickView view;
    view.setSource(QUrl::fromLocalFile(QStringLiteral("qml/main.qml")));
    view.show();
    // Needed for "Qt.quit()" within QML:
    QObject::connect(view.engine(), SIGNAL(quit()), &a, SLOT(quit()));
    // I normally use this sizing behavior:
    view.setResizeMode(QQuickView::SizeRootObjectToView);
    return a.exec();
}

QML文件qml/main.qml 由上面的代码打开,然后看起来像这样:

// This import will replaced with the largest supported QtQuick version:
import QtQuick 1.0
Rectangle {
    width: 450
    height: 200
    Text {
        anchors.centerIn: parent
        horizontalAlignment: Text.AlignHCenter
        font.pointSize: Math.min(parent.width / 10, parent.height / 5)
        // This text will also be replaced to show the correct QtQuick version:
        text: "Hello fromnQtQuick 1.0!"
        // Some fancy animations...
        SequentialAnimation on scale {
            running: true; loops: Animation.Infinite
            NumberAnimation { from: 1; to: .6; easing.type: Easing.InOutQuad; duration: 600 }
            NumberAnimation { from: .6; to: 1; easing.type: Easing.InOutQuad; duration: 600 }
        }
        SequentialAnimation on rotation {
            running: true; loops: Animation.Infinite
            NumberAnimation { from: -10; to: 10; easing.type: Easing.InOutQuad; duration: 2000 }
            NumberAnimation { from: 10; to: -10; easing.type: Easing.InOutQuad; duration: 2000 }
        }
    }
    MouseArea {
        anchors.fill: parent
        onClicked: Qt.quit()
    }
}

QML文件包含一个导入指令,该指令将选择适当的Qtquick版本(您可以在构建文件夹中检查此版本)。Text元素中的字符串也被替换,因此您将在此演示中轻松看到版本。