草庐IT

与 Qt 4 (QtQuick 1.x) 和 Qt 5 (QtQuick 2.x) 兼容的 C++/QML 项目

coder 2024-02-05 原文

当编写不使用 QML 且不依赖于新的 Qt 5 功能的 Qt 应用程序时,我们可以同时使用 Qt 4 和 Qt 5 对其进行编译(除了少数源代码不兼容)。

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

我们怎样才能用 QtQuick 做同样的事情?请注意,可以使用 QDeclarativeViewQtQuick 1.x在 Qt 5 中,但这不会使用 Qt 5 中的新场景图。只有 1.xQDeclarativeView 中得到支持并且只有 2.xQQuickView 中得到支持,即使我不使用 Quick 2.0 中引入的功能。

我想要的是:

  • 使用 Qt 4 编译时,使用 QDeclarativeView和 friend ;在 QML 中:import QtQuick 1.x
  • 使用 Qt 5 编译时,使用新的 QQuickView和 friend ;在 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;

然后使用 QGuiApplication , QQuickView在 Qt 4 和 Qt 5 中依此类推。但是当 QML 文件包含 QtQuick 的导入声明时, 我无法添加 #if在 1.x 和 2.x 之间做出决定。比方说,有没有一种官方方法可以添加一个别名 来生成QtQuick 1.x?在 QQuickView 工作(所以它实际上被解析为 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,它回落到 QDeclarativeView对于 Qt 4:

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

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

关于与 Qt 4 (QtQuick 1.x) 和 Qt 5 (QtQuick 2.x) 兼容的 C++/QML 项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21412257/

有关与 Qt 4 (QtQuick 1.x) 和 Qt 5 (QtQuick 2.x) 兼容的 C++/QML 项目的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  4. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  5. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  6. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 如何在 Ruby 字符串中插入项目符号字符? - 2

    我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195

随机推荐