继续讲一些Qt开发中的技巧操作:
1.字符串去除空格
我们经常会遇到字符串重去除空格的情况,对于QString去除空格,有多种场景,可能需要去除左侧、右侧、所有等位置的空格;
//字符串去空格 -1=移除左侧空格 0=移除所有空格 1=移除右侧空格 2=移除首尾空格 3=首尾清除中
间留一个空格
QString QtHelperData::trimmed(const QString &text, int type)
{
QString temp = text;
QString pattern;
if (type == -1) {
pattern = "^ +\\s*";
} else if (type == 0) {
pattern = "\\s";
//temp.replace(" ", "");
} else if (type == 1) {
pattern = "\\s* +$";
} else if (type == 2) {
temp = temp.trimmed();
} else if (type == 3) {
temp = temp.simplified();
}
//调用正则表达式移除空格
if (!pattern.isEmpty()) {
#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
temp.remove(QRegularExpression(pattern));
#else
temp.remove(QRegExp(pattern));
#endif
}
return temp;
}
2.跨网段搜索不生效
Qt的网络库支持udp广播搜索和组播搜索,其中组播搜索可以跨网段搜索,有时候你会发现失灵,此时你可以尝试把本地的虚拟机的网卡禁用试试,估计就好了。还有就是在本地开启了代理啥的,先关掉试试。近期在使用tcpsocket连接的时候,发现在Qt4和Qt5中正常的程序,到了Qt6中就不行了,报错提示 The proxy type is invalid for this operation ,原来是本地设置了代理导致的,可能在Qt6以前会默认跳过去不处理;
//也可以通过代码设置跳过代理
#include <QNetworkProxy>
QNetworkProxyFactory::setUseSystemConfiguration(false);
//下面这样每次设置也可以
tcpSocket->setProxy(QNetworkProxy::NoProxy);
//从5.8开始socket默认代理类型是DefaultProxy而不是NoProxy,不知道为啥
3.设置图片显示失败问题
在Qt中设置图片有时候会发现不成功,很可能是因为文件的拓展名不正确导致的,比如jpg的图片拓展名是png,bmp的图片拓展名改成了jpg,QImage、QPixmap传入文件路径加载图片,是通过拓展名去调用对应的图片解析算法,比较傻,但是速度快,不用经过分析具体内部是何种图片格式。如果想要不管拓展名都能保证加载成功,则必须读取图片文件数据加载的方式处理。
//可以是资源文件中的图片也可以是本地文件
QString fileName = ":/test.png";
//此方式按照拓展名来区分具体格式不准确
//如果拓展名不正确就无法加载成功
ui->label->setPixmap(QPixmap(fileName));
//通过直接读取图片数据加载保证成功
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
//通过 QImage 处理
QImage img;
img.loadFromData(data);
//下面这种方式也行
//QImage img = QImage::fromData(data);
ui->label->setPixmap(QPixmap::fromImage(img));
//通过 QPixmap 处理
QPixmap pix;
pix.loadFromData(data);
ui->label->setPixmap(pix);
4.表格视图的批量删除
在对表格数据模型操作的时候,经常遇到一种场景就是,删除某条记录后,希望重新选中某一行。QTableView、QTableWidget本身就支持多选全选等操作,比如批量删除可以多选。
//拿到表格数据模型
QAbstractItemModel *model = ui->tableView->model();
//主动定位到第三行
ui->tableView->setCurrentIndex(model->index(3, 0));
//主动定位到最后一行
ui->tableView->setCurrentIndex(model->index(model->rowCount() - 1, 0));
//设置选择模式支持多选,其他几个枚举值自行查阅文档。
ui->tableView->setSelectionMode(QAbstractItemView::MultiSelection);
//选择全部
ui->tableView->selectAll();
//取消所有选中
ui->tableView->clearSelection();
//选中行,注意如果该行选中则执行后取消选中,如此往复。这个设计很巧妙。
ui->tableView->selectRow(row);
//选中列,注意如果该列选中则执行后取消选中,如此往复。这个设计很巧妙。
ui->tableView->selectColumn(column);
//获取选中行的内容
QItemSelectionModel *selections = ui->tableView->selectionModel();
QModelIndexList selected = selections->selectedIndexes();
foreach (QModelIndex index, selected) {
qDebug() << index.row() << index.column() << index.data();
}
5.主动判断字串编码
在读取文本文件的时候,有时候会发现读取出来的中文乱码,这个时候就需要识别文件编码格式,然后主动设置对应的编码去读取就不会乱码。
//检查文件编码 0=ANSI 1=UTF-16LE 2=UTF-16BE 3=UTF-8 4=UTF-8BOM
int DataCsv::findCode(const QString &fileName)
{
//假定默认编码utf8
int code = 3;
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
//读取3字节用于判断
QByteArray buffer = file.read(3);
quint8 b1 = buffer.at(0);
quint8 b2 = buffer.at(1);
quint8 b3 = buffer.at(2);
if (b1 == 0xFF && b2 == 0xFE) {
code = 1;
} else if (b1 == 0xFE && b2 == 0xFF) {
code = 2;
} else if (b1 == 0xEF && b2 == 0xBB && b3 == 0xBF) {
code = 4;
} else {
//尝试用utf8转换,如果可用字符数大于0,则表示是ansi编码
QTextCodec::ConverterState state;
QTextCodec *codec = QTextCodec::codecForName("utf-8");
codec->toUnicode(buffer.constData(), buffer.size(), &state);
if (state.invalidChars > 0) {
code = 0;
}
}
file.close();
}
return code;
}
6.开启向前查询的属性
在连接远程数据库进行查询数据的时候,有时候会发现很慢,尤其是表数据量越多越慢,本地的话同等数据量快很多,可以尝试开启只前进属性,query.setForwardOnly(true);这样的话只会缓存一次的数据,极大提高远程数据库的查询效率,据说可以提高几十倍百倍的速度。当然,前提是对查询的数据,只有向前取数据的需求,如果还要往后取数据或者在数据模型QSqlQueryModel中使用,则不能开启此属性。原因在每次利用QSqlQuery获取下一条记录时,若不开启isForwardOnly属性(很遗憾默认就是不开启),则每次都开辟新的内存空间,来存储已经访问及未访问的记录,这样,每次都会浪费好多存储空间。
7.画家类载入html来绘制
Qt中的painter绘制非常灵活强大,接口丰富,但是对于很多初学者来说还是有一定的难度,尤其是各种奇奇怪怪的复杂格式,而这些格式通过引入html却能很好描述,比如控制行间距、字符间距等,此时可以用QTextDocument传入html格式内容交给QPainter绘制,非常完美、简单、强大,包括一些数学公式啥的。就是说,Qt提供一个画板,实际的绘制样式通过html完成,Qt对这个html进行解析从而展示。
void Form::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QTextDocument doc;
doc.setHtml(html);
//设置文本宽度
doc.setTextWidth(200);
//指定绘制区域
doc.drawContents(&painter, QRect(0, 0, 200, 70));
}