如果想把Qt4.x上面开发的软件在Qt5上面正常运行,如果什么都不做的话估计会出现各做各样的错误,笔者也是经历过这种迷茫痛,后面才发现官方已有系统发文一一提及到诸多迁移会遇到的问题以及解决办法。附上官网地址,以供参考http://qt-project.org/wiki/Transition_from_Qt_4.x_to_Qt5
为了提高开发者的开发效率,我对这个文档大致做一个翻译,也算为大家提供中文版的解决方案吧,如有异议,请参考原文。
- QtWidgets 是一个独立的模块
例如,编译出现如下错误
error: QMainWindow: No such file or directory
error: QToolButton: No such file or directory
error: QWidget: No such file or directory
解决方法:
在工程的 *.pro文件中添加下面内容:
QT += widgets
同时把头文件
#include <QtGui>
更改为
#include <QtWidgets>
这样代码就可以正常运行了,不过有时候需要添加更详细的头文件,例如
#include <QtWidgets/QtoolButton>
2.QtWebKitWidgets也是一个独立的模块
例如,编译的时候出现如下错误:
error: invalid use of incomplete type 'class QWebFrame'
error: forward declaration of 'class QWebFrame'
解决方法:
在工程的 *.pro 文件中添加:
QT += webkitwidgets
备注:当已经有QT += webkitwidgets ,就不需要添加 QT += widgets
同时把工程文件里面添加的所有
#include <QtWebKit>
更改为
#include <QtWebKitWidgets>
3.QPrinter 不起作用
如果你已经添加了如下两行
#include <QPrinter>
#include <QPrintDialog>
在工程的 *.pro 文件中添加:
QT += printsupport
如果还是不能工作,把添加的
#include <QPrinter>
#include <QprintDialog>
更改为
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
4.没有toAscii() 和 fromAscii()方法
把
fromAscii()
toAscii()
替换成
fromLatin1()
toLatin1()
例如,在 Qt 4 上的代码
QByteArray configfileti = TMP_Config.toAscii();
更改成
QByteArray configfileti = TMP_Config.toLatin1();
5.去掉了QCoreApplication::UnicodeUTF8
因为Qt5都是采用 UnicodeUTF8的编码方式,所以 UnicodeUTF8这个枚举类型就显得有点多此一举了,所以删掉了所有的关于QCoreApplication::UnicodeUTF8参数的传递。
例如:
Href_Gui->setWindowTitle(QApplication::translate("Href_Gui", "Url / www", 0, QApplication::UnicodeUTF8));
label->setText(QApplication::translate("Href_Gui", "Text:", 0, QApplication::UnicodeUTF8));
label_2->setText(QApplication::translate("Href_Gui", "Url:", 0, QApplication::UnicodeUTF8));
label_3->setText(QApplication::translate("Href_Gui", "Target / Name:", 0, QApplication::UnicodeUTF8));
更改为:
Href_Gui->setWindowTitle(QApplication::translate("Href_Gui", "Url / www", 0));
label->setText(QApplication::translate("Href_Gui", "Text:", 0));
label_2->setText(QApplication::translate("Href_Gui", "Url:", 0));
label_3->setText(QApplication::translate("Href_Gui", "Target / Name:", 0));
6.去掉了QWorkspace类
在Qt4.3中,这个类就已经被 QMdiArea类替换掉了,在Qt5中把QWorkspace类正式删除掉了。QMdiArea类和QWorkspace类有类似的API接口,只是需要更改下一些方法,信号和槽的接口名字即可。
替换
#include <QWorkspace>
为
#include <QMdiArea>
7.QDrag类问题
应用的拖拽功能或许需要一些微调,例如
QDrag *drag = new QDrag(event->widget());
在 Qt 5 会有如下错误
error: no matching function for call to 'QDrag::QDrag(QWidget*)'
加上如下头文件或许可以解决如上错误
#include <QWidget>
8.删掉了qFindChildren
如果遇到如下错误
error: 'qFindChildren' was not declared in this scope
解决办法
用findChildren 方法替代qFindChildren ,需要注意的是,调用方法的方式略有改变。参考如下例子:
toString(const QObject* obj, int indentLevel) const {
[...]
/* Query over QObjects */
if (m_children) {
QList<QObject*> childlist = qFindChildren<QObject*>(obj, QString());
[...]
把上述例子中的如下代码
QList<QObject*> childlist = qFindChildren<QObject*>(obj, QString());
替换成如下代码
QList<QObject*> childlist = obj->findChildren<QObject*>(QString());
9.删掉了qVariantValue
编译时报如下错误
error: 'qVariantValue' was not declared in this scope
这个函数等同于QVariant::value(value)。因此可以把如下代码
QTime t = qVariantValue<QTime>(val);
更改为
QTime t = val.value<QTime>();
This QTime enclosed in the angled brackets lets the compiler know what QVariant will return. However, if the variable is not a QVariable the type enclosed in the angled brackets should not be used(doing so will result in a vague compile time error). So given that m_color is of type QColor you will rewrite
s.setValue("color/favorite", qVariantValue<QColor>(m_color));
to
s.setValue("color/favorite", m_color.value());
10.删除了qVariantCanConvert
替换
Q_ASSERT(qVariantCanConvert<QString>(variant));
Q_ASSERT(qVariantCanConvert<QSize>(variant));
Q_ASSERT(qVariantCanConvert<QFont>(fontVariant));
为
Q_ASSERT(variant.canConvert(QMetaType::QString));
Q_ASSERT(variant.canConvert(QMetaType::QSize));
Q_ASSERT(fontVariant.canConvert(QMetaType::QFont));
11.删掉了Qt::escape
error: 'escape' is not a member of 'Qt'
So you would change the following block:
if (result == QString())
result = Qt::escape(val.toString());
else
result = Qt::escape(result);
return result;
to
if (result == QString())
result = QString(val.toString()).toHtmlEscaped();
else
result = QString(result).toHtmlEscaped();
return result;
12.删掉了QDesktopServices::storageLocation
error: 'storageLocation' is not a member of 'QDesktopServices'
error: 'DataLocation' is not a member of 'QDesktopServices'
用 QStandardPaths::StandardLocation代替,把如下
QString path = s.value("db.path", QDesktopServices::storageLocation(QDesktopServices::DataLocation)).toString();
替换为
QString path = s.value("db.path", QStandardPaths::standardLocations(QStandardPaths::DataLocation)).toString();
13.删掉了CONFIG+=qtestlib
If you have the above line in your project file the compiler will warn you in the compile window, nonetheless the code will still run as usual:
如果在工程文件中有上面这一行,编译器将在编译窗口中产生警告:
Project WARNING: CONFIG+=qtestlib is deprecated. Use QT+=testlib instead.
14.QWeakPointer quirks
A code block like
quint64 decodedPointer = line.toULongLong();
MetaData* md = reinterpret_cast<MetaData*>(decodedPointer);
QWeakPointer<MetaData> wp(md);
results in
error: no matching function for call to 'QWeakPointer<MetaData>::QWeakPointer(MetaData*&)'
To fix this add to the project file:
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
15.QtConcurrent Library is Missing?
C:\Qt\Qt5.0.2\5.0.2\mingw47_32\include\QtConcurrent\qtconcurrentthreadengine.h:133: error: undefined reference to `_imp___ZN12QtConcurrent16ThreadEngineBaseD2Ev'
In Qt 4, QtConcurrent was part of QtCore, so there was no need to include specific headers. This is no longer the case with Qt 5. If your source code have lines like
m_current = QtConcurrent::blockingMappedReduced(slices, functor, stitchReduce, QtConcurrent::UnorderedReduce );
You will need to include the header:
#include <QtConcurrent/QtConcurrent>
and add the following line to your project file:
LIBS += -lQt5Concurrent
16.Fixing #include<> Headers
A Perl script “fixqt4headers.pl” exists in qtbase/bin/. that should be run on source code using Qt that corrects the #include<> directives for Qt components to also consider the module name.
17.Plugin loading
The Q_EXPORT_PLUGIN,Q_EXPORT_PLUGIN2 macros have been deprecated in favor of the new Q_PLUGIN_METADATA macro. The advantage of the new system is that it allows Qt to query the metadata for the plugin without actually dlopen’ing it. This greatly improves performance and reliability of the plugin system.
The new Q_PLUGIN_METADATA macro is included next to the Q_OBJECT macro in the QObject derived class that is returned when loading the plugin. It contains the plugins IID and a filename pointing to a json file containing the metadata for the plugin. The json file is compiled into the plugin and does not need to be installed.
An example on how to change your plugins can be found by looking at the patch that changes the Gif p_w_picpath format plugin, see http://qt.gitorious.org/qt/qtbase/commit/963b4c1647299fd023ddbe7c4a25ac404e303c5d .
18.Deploying to systems without C++11
When Qt is built from source code on a system with C++11 installed, the Qt libraries/frameworks are linked against the system’s C++11 library (libc++). This means that the Qt libraries/frameworks are not deployable to systems without C++11 installed (such as out-of-the-box Mac OS X 10.6). To be able to deploy to systems that only support the older C++ standard (libstdc++), build Qt from source code with the -no-c++11 configure option.
19.QTimer is no longer accurate to the millisecond by default
QTimer has now 3 accuracy types, with a new default behaviour:
The new default type is Qt::CoarseTimer which, to reduce power/CPU consumption, allow 5% difference between requested time and actual one, and even allow the timer to fire before the requested time.
The former one is Qt::PreciseTimer (to the millisecond, never before the requested time).
A third one is Qt::VeryCoarseTimer and allow a 1 second difference
20.QUrl addQueryItem moved to QUrlQuery
If you have:
QUrl url;
// ...
url.addQueryItem(key, value);
You will want to change it to
QUrl url;
QUrlQuery urlQuery;
// ...
urlQuery.addQueryItem(key, value);
url.setUrlQuery(urlQuery);
21.QAbstractItemModel changes
void reset()
void setRoleNames(const QHash<int, QByteArray> & roleNames)
both have changed and are now protected.
See Compatibility Members for QAbstractItemModel [qt-project.org]
Recommended Reading
C++ API Changes [qt-project.org]
The porting guide [qt-project.org]
Porting Desktop Applications from Qt 4 to Qt 5 [blog.ics.com]
Porting from Qt 4 to Qt 5 [kdab.com]
Automated porting from Qt 4 to Qt 5 [kdab.com]
Categories:
Developing_Qt
Developing_with_Qt