- 编程的过程中经常遇到需要将QString转成char *或者const char *的情况,在转换成QByteArray后调用.data()或者.constData()函数进行转换,这里需要注意的是,如果转换类型是const char *尽管用data()不会出错,会给你自动转换,但是还是不建议,因为深拷贝了一份,理论上增加了内存开销,如果字符串长度小还好,一旦很长,这个开销挺大,这是个好的编程习惯。
//查阅代码得知data函数有两个重载
inline char *QByteArray::data()
{ detach(); return d- >data(); }
inline const char *QByteArray::data() const
{ return d- >data(); }
inline const char *QByteArray::constData() const
{ return d- >data(); }
QByteArray data = "abc";
//深拷贝
char *d1 = data.data();
//深拷贝
const char *d2 = data.data();
//浅拷贝
const char *d3 = data.constData();
//深拷贝
test(data.data());
//浅拷贝
test(data.constData());
void test(const char *data)
{
}
//至于什么时候调用.data()会浅拷贝,酷码大佬说是当QByteArray被const修饰的时候
const QByteArray data;
//浅拷贝
const char *d = data.data();
//酷码大佬补充:自Qt 5.7版本以来,引入了qAsConst函数,专用于无脑转换。
//这个函数实现了C++17标准中的std::as_const()函数的功能,将一个非常量的左值转为常量的左值。
//增加qAsConst函数是为了Qt自己的非const 的容器能实现C++11标准的基于范围的循环。
//该函数主要用于qt容器在隐式共享中不被detach。
QString s = "abc";
//下面会深拷贝引起性能损失
for (QChar ch : s)
//不会深拷贝
for (QChar ch : qAsConst(s))
//下面也是浅拷贝,但是在编程时、在现实中,声明为const往往不容易做到。
const QString s;
for (QChar ch : s)
//总结:对Qt自己实现的容器如:QVector、QMap、 QHash、QLinkedList、QList等,如果一定要用基于for(var : container)范围的循环,则请用如下形式:
for (var : qAsConst(container))
- 新版的Qt6.5在ubuntu上编译运行程序后会提示 qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. ,无法正常弹出窗体程序,你需要主动安装xcb的相关库。sudo apt install libxcb*
- 有些场景下我们需要在 QApplication a(argc, argv); 前面执行一些处理,比如 QApplication::setAttribute 就必须在最前面执行,而很多时候这个设置的参数不能改写死,毕竟现场的环境千差万别,希望通过配置文件来配置,那么问题来了,读取配置文件一般需要指定路径才能正常读取到,如果是 ./ 这种,很可能未必是应用程序的当前路径,如果你是双击运行的程序,那肯定是应用程序的当前路径,不是双击运行那就是系统环境中的当前路径,意味着你开机启动或者用system、QProcess等方式在开机后调用启动的话,就未必正确了。为了保证这个路径的正确,必须从main函数的 argv 第一个值获取,通过查阅Qt自身代码中获取路径,也是从这个参数获取。
//程序最前面获取应用程序路径和名称
static void getCurrentInfo(char *argv[], QString &path, QString &name);
//程序最前面读取配置文件节点的值
static QString getIniValue(const QString &fileName, const QString &key);
static QString getIniValue(char *argv[], const QString &key, const QString &dir = QString());
void QtHelper::getCurrentInfo(char *argv[], QString &path, QString &name)
{
//必须用fromLocal8Bit保证中文路径正常
QString argv0 = QString::fromLocal8Bit(argv[0]);
QFileInfo file(argv0);
path = file.path();
name = file.baseName();
}
QString QtHelper::getIniValue(const QString &fileName, const QString &key)
{
QString value;
QFile file(fileName);
if (file.open(QFile::ReadOnly | QFile::Text)) {
while (!file.atEnd()) {
QString line = file.readLine();
if (line.startsWith(key)) {
line = line.replace("n", "");
line = line.trimmed();
value = line.split("=").last();
break;
}
}
}
return value;
}
QString QtHelper::getIniValue(char *argv[], const QString &key, const QString &dir)
{
QString path, name;
QtHelper::getCurrentInfo(argv, path, name);
QString fileName = QString("%1/%2%3.ini").arg(path).arg(dir).arg(name);
return getIniValue(fileName, key);
}
int main(int argc, char *argv[])
{
int openGLType = QtHelper::getIniValue(argv, "OpenGLType").toInt();
QtHelper::initOpenGL(openGLType);
QApplication a(argc, argv);
...
}
- 当我们对QTableView/QTreeView/QTableWidget/QTreeWidget某行选中后,会发现某些单元格设置的前景色被覆盖了,比如设置的红色,一旦选中就变成了白色,这肯定不是我们想要的,需要用自定义委托将其去掉。
class ItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit ItemDelegate(QObject *parent = 0);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#include "itemdelegate.h"
ItemDelegate::ItemDelegate(QObject *parent) : QItemDelegate(parent)
{
}
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem option2 = option;
QColor color = index.data(Qt::ForegroundRole).value< QColor >();
if (color.isValid() && color != option.palette.color(QPalette::WindowText)) {
option2.palette.setColor(QPalette::HighlightedText, color);
}
QItemDelegate::paint(painter, option2, index);
}
//对所有单元格设置该委托
ui- >tableWidget- >setItemDelegate(new ItemDelegate);
- 有些时候我们需要在项目文件比如pro/pri中识别当前Qt套件是否存在某个模块以及是否引入过某个模块,存在则引入,同时也希望代码中也能识别是否引入过某个模块比如sql模块,判断后再进行对应的处理。
//项目文件中判断
//如果当前套件中有multimedia模块则引入multimedia模块
qtHaveModule(multimedia) {QT += multimedia}
//在项目文件中已经通过 QT += multimedia 引入过模块
contains(QT, multimedia) {}
//代码文件判断
#ifdef QT_MULTIMEDIA_LIB
qDebug() < < "multimedia module is enabled";
#else
qDebug() < < "multimedia module is not enabled";
#endif
- 对MDI窗体区域设置背景颜色透明,会发现 QMdiArea{background:transparent;} 无效,哪怕是指定颜色 QMdiArea{background:#ff0000;} 或者 QMdiArea{background-color:#ff0000;} 都不行,这就很无语了,原来要用弱属性机制才行。QMdiArea{qproperty-background:transparent;}
- 当样式中启用了禁用样式 *:disabled{xxx} 的时候,会发现MDI子窗体无法拉伸了,这应该是Qt内部的BUG,怎么解决呢,只需要重新设置MDI这个类别的禁用样式的边框样式即可。QMdiSubWindow:disabled{border:8px solid rgba(0,0,0,0);}
- 用QProcess执行命令或者启动可执行文件,默认写法不支持带空格的路径,比如 Program Files ,需要在这个路径前后加上双引号才行,估计可能内部会用空格分割字符串导致解析失败。普通路径加上引号也能正常执行,所以为了确保以防万一,统一加上引号即可。
QString cmd = "c:/Program Files/a.exe";
//下面这个会执行失败
QProcess::startDetached(cmd);
//前后加上引号就可以正常执行
cmd = """ + cmd + """;
QProcess::startDetached(cmd);
- 在循环中取值,临时变量的定义尽量在循环外层定义,每次在循环里层定义会增加开销,特别是复杂类型比如QString(基础类型比如int/bool差别不大),循环次数越多,性能差别越大。
void MainWindow::on_pushButton_clicked()
{
QElapsedTimer timer;
timer.start();
QString s;
QString text = "abc";
for (int i = 0; i < 10000; ++i) {
s = text.at(0);
}
qDebug() < < "方式1" < < timer.nsecsElapsed();
}
void MainWindow::on_pushButton_2_clicked()
{
QElapsedTimer timer;
timer.start();
QString text = "abc";
for (int i = 0; i < 10000; ++i) {
QString s = text.at(0);
}
qDebug() < < "方式2" < < timer.nsecsElapsed();
}
//debug模式下方式1比方式2快6倍+
//release模式下方式1比方式2快30倍+
- Qt的属性机制非常强大,除了可以用来控制样式表,也可以很方便的用来传值,比如qml中的值传递,有时候我们写了一个通用类,希望这个类可以做很多事情,但是又希望其中有一些特殊变量存取值,一种办法是直接定义私有变量,提供get/set接口函数,还有一种偷懒的办法就是用属性setProperty/property,然Qt内部从元对象数据层面自己管理,这样不用在类中写对应的变量和get/set函数。但是肯定有性能损耗,性能上肯定比变量低,所以要看具体的实际需求,如果不是非常频繁的调用setProperty/property,通用性优先的话,那用属性机制会更方便。个人推荐方式三,继承通用类,在子类中增加set/get。
void MainWindow::on_pushButton_clicked()
{
QElapsedTimer timer;
timer.start();
for (int i = 0; i < 10000; ++i) {
Test *t = new Test;
//t- >setId(i);
//t- >setName("test");
t- >getName();
}
qDebug() < < "方式1" < < timer.nsecsElapsed();
}
void MainWindow::on_pushButton_2_clicked()
{
QElapsedTimer timer;
timer.start();
for (int i = 0; i < 10000; ++i) {
Test *t = new Test;
//t- >setProperty("id", i);
//t- >setProperty("name", "test");
t- >property("name").toString();
}
qDebug() < < "方式2" < < timer.nsecsElapsed();
}
//对比测试和具体的变量类型无关/int和QString类型产生的性能差别一样
//setProperty比setxxx方式性能差3倍+
//property比getxxx方式性能差1.3倍
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
内存
+关注
关注
8文章
3128浏览量
75365 -
编程
+关注
关注
88文章
3690浏览量
95395 -
函数
+关注
关注
3文章
4384浏览量
65138 -
char
+关注
关注
0文章
11浏览量
3830
发布评论请先 登录
相关推荐
热点推荐
windows下QT编程中_TCHAR与QString之间的转换
;utf16()#define TCHARToQString(x)QString::fromUtf16((x))#define TCHARToQStringN(x,y)QString::fromUtf16
发表于 03-21 11:22
如何将PowerPCB转成Protel的详细过程和软件
如何将PowerPCB转成Protel的详细过程第一步:用PowerPCB打开文件,选择“File”---“Export”导出,如图:导出格式Format选择PowerPCBV3.5的,然后
发表于 11-24 16:25
如何将PDF转成CAD
`现在很多设计图纸等操作者都需要对PDF格式得图纸进行二次编辑,但是PDF文件又不能直接进行编辑修改,那我们该如何操作呢,我们可以将PDF转成CAD文件然后再进行转换得操作,接下来就让小编来具体介绍
发表于 07-03 18:17
如何将Cadence的原理图和PCB转成PADS资料下载
电子发烧友网为你提供如何将Cadence的原理图和PCB转成PADS资料下载的电子资料下载,更有其他相关的电路图、源代码、课件教程、中文资料、英文资料、参考设计、用户指南、解决方案等资料,希望可以帮助到广大的电子工程师们。
发表于 04-19 08:54
?46次下载

数控直流稳压电源如何将交流电压转成直流电压?
数控直流稳压电源如何将交流电压转成直流电压? 数控直流稳压电源是一种将交流电压转换为直流电压的装置。在现代电子设备中,直流电压广泛应用,因为它在稳定性、可调性和可靠性方面具有优势。为了满足设备的要求
评论