简体   繁体   English

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)

When writing a Qt application which doesn't use QML, and doesn't depend on new Qt 5 features, we can compile it with both Qt 4 and Qt 5 (except for the few source incompatibilities). 在编写不使用QML并且不依赖于新的Qt 5功能的Qt应用程序时,我们可以使用Qt 4和Qt 5编译它(除了少数源不兼容性)。

When we want to use a Qt 5 feature but want to fall back to an equivalent but less efficient Qt 4 solution, we can simply use an #if to check against the Qt version, eg to use the new QStringLiteral but falling back to QString::fromUtf8 when compiling with Qt 4. 当我们想要使用Qt 5功能但希望回归到同等但效率较低的Qt 4解决方案时,我们可以简单地使用#if来检查Qt版本,例如使用新的QStringLiteral但是回退到QString::fromUtf8当用Qt 4编译时从QString::fromUtf8

How can we do the same with QtQuick? 我们怎么能用QtQuick做同样的事情? Note that it's possible to use the QDeclarativeView with QtQuick 1.x in Qt 5, but that would not use the new scene graph from Qt 5. Only 1.x is supported in QDeclarativeView and only 2.x is supported in QQuickView , even if I don't use features introduced in Quick 2.0. 请注意,有可能使用QDeclarativeViewQtQuick 1.x使用Qt 5,但不会从Qt的使用新的场景图5.只有1.x支持在QDeclarativeView只有2.x在支持QQuickView ,即使我不使用Quick 2.0中引入的功能。

What I want is: 我想要的是:

  • When compiling with Qt 4, use QDeclarativeView and friends; 使用Qt 4进行编译时,请使用QDeclarativeView和朋友; in QML: import QtQuick 1.x 在QML中: import QtQuick 1.x
  • When compiling with Qt 5, use the new QQuickView and friends; 使用Qt 5进行编译时,请使用新的QQuickView和朋友; in QML: import QtQuick 2.x 在QML中: import QtQuick 2.x
  • Only have a single set of QML files, but not one for QtQuick 1.x and another for QtQuick 2.x 只有一组QML文件,但不是 QtQuick 1.xQtQuick 2.x另一组

Regarding the C++ part, this seems to be easy. 关于C ++部分,这似乎很容易。 In Qt 4 we can simply add: 在Qt 4中,我们可以简单地添加:

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

and then use QGuiApplication , QQuickView and so on in both Qt 4 and Qt 5. But when the QML file contains an import declarative for QtQuick , I can't add an #if to decide between 1.x and 2.x. 然后在Qt 4和Qt 5中使用QGuiApplicationQQuickView等。但是当QML文件包含QtQuick的导入声明时,我无法添加#if来决定1.x和2.x. Is there an official way to, let's say, add an alias to make QtQuick 1.x work in QQuickView (so it is actually parsed as QtQuick 2.0 )? 有没有官方的方法,比方说,添加别名QtQuick 1.xQQuickViewQQuickView (所以它实际上被解析为QtQuick 2.0 )?

What I did was replacing the string QtQuick xy in all QML files when deploying them. 我所做的是在部署它们时替换所有QML文件中的字符串QtQuick xy If you have a folder qml in your source tree, and want to have the same qml folder in your build tree, you can deploy the folder but replace the string to match the QtQuick version you want. 如果源树中有文件夹qml ,并且希望在构建树中具有相同的qml文件夹,则可以部署该文件夹,但替换字符串以匹配所需的QtQuick版本。

The following solution works on POSIX systems since it requires some command line tools; 以下解决方案适用于POSIX系统,因为它需要一些命令行工具; tested on Linux (Ubuntu). 在Linux(Ubuntu)上测试过。 Maybe someone with experience with the Windows command line can add a version for Windows. 也许具有Windows命令行经验的人可以为Windows添加版本。

Add in your .pro : (The following code assumes that from within the build folder, the source folder is reachable with ../src/ ; if this is not the case change the path where the *** comment is) 添加.pro :(以下代码假定在build文件夹中,源文件夹可以通过../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

In C++ ( main.cpp ) , you can then create a QQuickView which falls back to QDeclarativeView for Qt 4: 在C ++( main.cpp )中 ,您可以创建一个QQuickView ,它回QQuickView 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();
}

The QML file qml/main.qml opened by the code above can then look like this: 由上面的代码打开的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 from\nQtQuick 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()
    }
}

The QML file contains an import directive, which will select the proper QtQuick version (you can check this in your build folder). QML文件包含一个import指令,它将选择正确的QtQuick版本(您可以在build文件夹中查看)。 The string in the Text element gets replaced too, so you'll see the version easily in this demo. Text元素中的字符串也会被替换,因此您将在此演示中轻松查看该版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM