解决 Qt 中资源文件、样式表、弹簧拉伸策略及文件操作问题的方法

日期: 2024-08-06 06:05:15|浏览: 476|编号: 59806

友情提醒:信息内容由网友发布,本站并不对内容真实性负责,请自鉴内容真实性。

QString content = "测试中文";
QString note = content.toUtf8().toPercentEncoding();

Qt 默认不支持大资源文件,比如添加字体文件,需要用 pro 文件来启用。

+=

在Qt中继承之后,样式表不起作用,解决方法有三种,强烈推荐方法1。

void Widget::paintEvent(QPaintEvent *)
{
    QStyleOption option;
    option.initFrom(this);
    QPainter painter(this);
    style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this);
}

有时候界面上加了一个弹簧,需要动态改变这个弹簧对应的拉伸策略,对应的方法是,很多人一开始会选择用set来找,但是怎么也找不到。

使用QFile时,不建议频繁打开文件进行写入然后关闭,比如你每隔5ms就输出一次日志,IO性能瓶颈就会很大,这种情况下建议先打开文件,不要关闭,等待合适的时机,比如析构时需要重新修改日志文件或者日期发生改变时再关闭文件。否则短时间内打开和关闭大量文件会造成很大的卡顿,文件越大卡顿越厉害。

很多网络应用中,需要自定义心跳包来维持连接,否则断电或者非法关闭程序,对方就无法识别,需要超时检测。但有些程序并没有提供心跳协议,这时候就需要开启系统级的保活功能,此方法适用于TCP连接。

int fd = tcpSocket->socketDescriptor();
int keepAlive = 1;      //开启keepalive属性,缺省值:0(关闭)
int keepIdle = 5;       //如果在5秒内没有任何数据交互,则进行探测,缺省值:7200(s)
int keepInterval = 2;   //探测时发探测包的时间间隔为2秒,缺省值:75(s)
int keepCount = 2;      //探测重试的次数,全部超时则认定连接失效,缺省值:9(次)
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

如果程序打包后弹出“此程序启动时无法找到或加载Qt”的提示,一般是因为插件目录没有打包或者打包错误。

强烈建议不要在tr中包含中文。虽然Qt新版本现在支持从中文到其他语言的翻译,但是很不规范,不知道谁教我的。tr的初衷是先包含英文,然后再翻译成中文等其他语言。现在很多初学者滥用tr,如果不需要翻译,就禁用tr。tr需要开销,Qt会默认认为需要翻译,会进行额外的特殊处理。

很多人分不清Qt和Qt的区别,经常会问Qt是什么版本,然后就拿个Qt版本来装。Qt是用Qt编写的一个集成开发环境IDE,像宇宙第一个就可以是msvc编译器(WIN对应的Qt集成安装环境自带的Qt就是msvc),也可以用mingw或者gcc编译,如果是自定义的控件插件,需要集成到Qt中,必须要保证插件的动态库、编译器和Qt版本以及对应文件(dll或者so文件)的位号要和Qt版本完全一致,否则基本没法集成。特别注意Qt集成环境安装包里的Qt版本和Qt的版本可能不完全一致,一定要擦亮眼睛仔细看,有些是一模一样的。

如果代码中有两处以上有相同的处理,建议写成单独的函数,尽量保持代码规范简洁,例如 if(a == 123) 应该写成 if (123 == a),值在前,例如 if (ok == true) 应该写成 if (ok),if (ok == false) 应该写成 if (!ok) 等等。

很多人问Qt嵌入式平台哪个好,这里统一回答一下(目前时间节点2018年):imx6+335x比较稳定,求性能高性能就用它,便宜就用全志H3,好玩就用树莓派,橙派。

对于大段注释的代码,建议使用#if 0 #endif 来包含代码块,而不是选中代码然后全部用双斜杠注释掉,下次再想打开这段代码时需要重新选中并取消。如果使用#if 0,只需要将0改为1即可,大大提高开发效率。

Qt 的打包发布方式有很多种,Qt5 之后提供了打包工具(Linux 上和 Mac 上),可以很方便的打包应用。但是它不是万能的,有时候会打包一些不依赖的文件,有时候会忘记打包一些插件,尤其是使用 qml 的时候,无法识别第三方库,这样就相当于程序依赖了,需要自己去复制相应的库,终极方法是将你的可执行文件复制到 Qt 安装目录下的 bin 目录下,然后整个一起打包,再将不太可能依赖的组件一一删除,直到运行正常。

Qt中的动画使用底层的计时器来完成处理,比如针对一些指定的规则算法生成数据,然后对属性进行处理。

当绘制没有背景色,只有边框颜色的圆时,可以用360度圆弧代替,效果完全一样。

QRect rect(-radius, -radius, radius * 2, radius * 2);
//以下两种方法二选一,其实绘制360度的圆弧=绘制无背景的圆形
painter->drawArc(rect, 0360 * 16);
painter->drawEllipse(rect);

别把d指针想的很神秘,其实它只是类实现文件中定义的一个私有的类,用来存放局部变量而已,个人建议在做一些小项目的时候,没必要引入这个机制,会降低代码的可靠性,增加可读性和复杂度,新手接手项目之后会比较迷茫。

在绘图的时候很多人以为设置画笔就只能设置单调的颜色,其实QPen还可以设置画笔,灵活性增加了很多倍,比如设置了QPen的画笔之后就可以使用各种渐变色,比如用渐变色来绘制进度条、文字等,而不仅仅使用单一的颜色。

很多控件都有,比如//,有时候直接处理这些控件的时候发现不起作用,需要设置(),比如设置滚动条区域的背景透明,需要用->()->( "-color:;"); 而不是->("{-color:;}");

有时候如果设置了鼠标跟踪为true,而窗体上还有其他控件,当鼠标移到其他控件上时,父类的鼠标移动事件就无法识别,这种情况下就需要使用该事件,需要先设置(Qt::,true);

Qt封装的日期时间类功能非常强大,可以实现字符串与日期时间之间的转换,毫秒与日期时间之间的转换,以及1970年以来的秒数与日期时间之间的转换。

QDateTime dateTime;
QString dateTime_str = dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
//从字符串转换为毫秒(需完整的年月日时分秒)
datetime.fromString("2011-09-10 12:07:50:541""yyyy-MM-dd hh:mm:ss:zzz").toMSecsSinceEpoch();
//从字符串转换为秒(需完整的年月日时分秒)
datetime.fromString("2011-09-10 12:07:50:541""yyyy-MM-dd hh:mm:ss:zzz").toTime_t();
//从毫秒转换到年月日时分秒
datetime.fromMSecsSinceEpoch(1315193829218).toString("yyyy-MM-dd hh:mm:ss:zzz");
//从秒转换到年月日时分秒(若有zzz,则为000)
datetime.fromTime_t(1315193829).toString("yyyy-MM-dd hh:mm:ss[:zzz]");

我们在使用QList、Qt等链表或者数组的时候,如果只需要取回值,而不是赋值的话,强烈建议使用at()来取回值,而不要使用[]操作符。这本教材的原作者据说是Qt开发的核心成员,所以相当权威。至于使用at()和使用[]操作符的速度效率对比,网上一些网友也做过这样的对比。原文在书的第212页,里面是这样描述的:Qt对所有容器和许多其他类都使用了隐式共享。隐式共享的意思是Qt永远不会复制它不想修改的数据。为了确保隐式共享发挥最佳作用,可以养成两个新的编程习惯。 第一个习惯是在对(非常量)向量或列表进行只读访问时使用 at() 函数而不是 [] 运算符,因为 Qt 的容器类无法判断 [] 运算符是否会出现在赋值的左侧还是右侧,它会假设最坏情况并强制深度赋值,而 at() 函数不允许出现在赋值的左侧。

如果是表单,需要让exec之后其他代码继续执行,请在表单exec之前添加一行代码,否则表单消息会被阻塞。

QDialog dialog;
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();

强烈建议使用 而不是安全删除Qt的对象类,因为它会选择在合适的时机释放,而 会立即释放,这很可能会导致错误和崩溃。如果要批量删除对象集合,可以使用,例如 (btns);

在控件中如果需要自定义列按钮、复选框、下拉框等显示方式,可以使用自定义委托来实现,如果需要禁用某一列,在自定义委托的重载函数中返回0即可。自定义委托对应的控件在进入编辑状态时出现,如果想让它一直出现,需要重载paint函数,使用或来绘制。

一旦熟悉了 ::style()、 、 等对应的方法,并结合属性,就可以玩转各种自定义委托,也可以直接用 paint 函数进行各种绘制操作。表格、树形列表、下拉框等绝对牛逼。如果 ::style()-> 第四个参数没有设置,绘制的控件不会应用样式表。

有了坐标,一切皆有可能,强烈建议在学习绘制自定义控件的时候,把.h头文件里面的所有函数都读一遍、试一遍、理解一遍,这里面包含了Qt所有内置的绘制接口,以及相应的所有参数,试一遍你会发现很多新奇的世界,这会在一定程度上激发你对绘画的兴趣,就像神笔马良一样,骑着马遨游在代码绘制的世界里。

在使用or的时候有时候会发现设置的控件不是居中显示而是默认左对齐,也不会自动拉伸填充,对于追求完美的程序员来说,这样不太好,有一个终极万能的解决办法就是把这个控件放在一个布局里,然后添加到item中,这样就完美解决了问题,而且多个控件可以组合生成复杂的控件。

//实例化进度条控件
QProgressBar *progress = new QProgressBar;
//增加widget+布局巧妙实现居中
QWidget *widget = new QWidget;
QHBoxLayout *layout = new QHBoxLayout;
layout->setSpacing(0);
layout->setMargin(0);
layout->addWidget(progress);
widget->setLayout(layout);
ui->tableWidget->setCellWidget(00, widget);

很多时候,需要在知道背景颜色的情况下,清晰地绘制文字,这时就需要计算相应的文字颜色。

//根据背景色自动计算合适的前景色
double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
QColor textColor = gray > 0.5 ? Qt::black : Qt::white;

启用或禁用列拖动。

#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
    ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
#endif

从 Qt4 切换到 Qt5 时,一些类方法已被废弃或过时。例如,如果您想在 Qt5 中启用 Qt4 方法,您可以在 pro 或 pri 文件中添加一行:+= =0

Qt对颜色的封装很完善,支持各种转换,比如rgb,hsb,cmy,hsl,分别对应toRgb,toHsv,toHsl,还支持透明度的设置,并且颜色值可以转换成16进制的形式进行显示。

QColor color(25500100);
qDebug() << color.name() << color.name(QColor::HexArgb);
//输出 #ff0000 #64ff0000

该类型极其强大,可以说是一个通用类型,在存储配置文件的时候,经常会用到它进行转换,它默认自带了 等 等 各种转换,但还是不够,比如有时候需要从 进行转换,但是没有提供函数,所以我们需要使用一个通用的方法。

if (variant.typeName() == "QColor") {
    QColor color = variant.value();
    QFont font = variant.value();
    QString nodeValue = color.name(QColor::HexArgb);
}

在Qt中,与const char *之间的转换,最好使用().c_str(),而不是().()。例如在中使用后者,中文字符串会不正确,但英文是正常的。

Qt 的信号槽机制非常强大,也是 Qt 独有的核心功能之一。有时我们会在很多窗口中传递信号,实现更新或者处理。如果窗口层级很多,比如窗口 A 的父类是 Form B,Form B 的父类是 Form C,Form C 有一个子 Form D。如果要从 Form A 传递信号给 Form D,那么问题就来了,必须先经过 Form B 才能到 Form D。这样一来,与信号相关的信号就会很多,管理起来比较混乱。可以考虑增加一个全局的单例类,把公共的信号放在这里,然后在 Form A 中绑定相应的信号即可。只需将 Form D 的信号绑定到相应的槽函数上,就干净整洁了。

右键菜单默认是英文的,如果想显示中文,只需要加载.qm文件即可。Qt程序中可以安装多个翻译文件,不会冲突。

Qt中有一个全局焦点切换信号,可以通过该信号来自定义输入法,Qt4中默认安装了输入法上下文,比如在main函数中打印a的时候,会显示该值,这个默认安装的输入法上下文会拦截两个很厉害的信号::Panel和::nel,所以就算你安装了全局事件过滤器,还是无法识别这两个信号,只需要在main函数中执行a.(0)即可,安装的输入法上下文为空。

在Qt5.10之后,表格控件默认的最小列宽还是改为了15。之前的版本是0。因此在新版本的Qt中,如果表格的列宽设置得太小,将不会应用,而会使用最小的列宽。所以如果想设置更小的列宽,需要重新设置ui->->()->e(0);

Qt源码中内置了一些未公开的黑科技,并不能直接使用,都隐藏在相应的模块中,如gui--等,例如zip文件解压类、压缩类都在gui-模块中,需要在pro QT+=gui-中引入才可以使用。

#include "QtGui/private/qzipreader_p.h"
#include "QtGui/private/qzipwriter_p.h"

QZipReader reader(dirPath);
QString path("");
//解压文件夹到当前目录
reader.extractAll(path);
//文件夹名称
QZipReader::FileInfo fileInfo = reader.entryInfoAt(0);
//解压文件
QFile file(filePath);
file.open(QIODevice::WriteOnly);
file.write(reader.fileData(QString::fromLocal8Bit("%1").arg(filePath)));
file.close();
reader.close();

QZipWriter *writer = new QZipWriter(dirPath);
//添加文件夹
writer->addDirectory(unCompress);
//添加文件
QFile file(filePath);
file.open(QIODevice::ReadOnly);
writer->addFile(data, file.readAll());
file.close();
writer->close();

理论上来说串口和网络数据收发默认都是异步的,操作系统自动调度,所以界面根本不会卡,那些说收发数据会阻塞界面主线程的说法都是在胡说,真正耗时是在计算以及计算后处理,而不是发送接收数据,在一些数据量计算处理不大的项目里,一般不建议用线程来处理,线程需要调度开销,不要把所有的事情都扔到线程里,线程不是万能的,只有真正需要一些编码解码等耗时操作的时候,才需要把它们挪到线程里处理。

很有可能是构造函数中获取到的控件宽高是不正确的,你需要在控件第一次显示之后再去获取,控件第一次显示之后就会设置正确的宽高值,记住一定要在第一次显示之后才去获取,而不是在构造函数或者程序启动之后,如果程序启动之后还有一些容器控件,比如不显示的页面的控件,很有可能你会获取到错误的宽高,万无一失的方法就是在第一次显示之后再去获取。

一般建议在主线程中处理数据库,如果一定要在其他线程中使用,一定要在该线程中打开数据库,也就是使用时就在该线程中打开数据库,不能在主线程中打开数据库,在子线程中执行SQL,这样很可能会出错。

新版本的类在64位版本的Qt下可能进不去函数,这是因为Qt5对应的函数参数由之前的int变成了。改变有个好处就是在32位上自动是int,在64位上自动是yes。如果你在Qt5中继续把参数写成int,在32位上不会有问题,但在64位上就会有问题。所以为了兼容Qt4和Qt5,一定要按照不同的参数来写。

#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
    void incomingConnection(qintptr handle);
#else
    void incomingConnection(int handle);
#endif

Qt支持所有的界面控件,比如自动关联 (参数)信号槽,比如某个按钮的点击信号d(),然后直接实现槽函数即可。

因为使用了控件,在有些电脑上,驱动可能太低,导致画面失真或者各种奇怪的问题,比如鼠标右键无效,需要在主函数里开启软件渲染等。

#if (QT_VERSION > QT_VERSION_CHECK(5,4,0))
    //下面两种方法都可以,Qt默认采用的是AA_UseDesktopOpenGL
    QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
    //QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
#endif
    QApplication a(argc, argv);

解决全屏+控件组合使用时右键菜单无法弹出的另一种方法,需要将其上移一个像素

QRect rect = qApp->desktop()->geometry();
rect.setY(-1);
rect.setHeight(rect.height());
this->setGeometry(rect);

有很多内置方法非常有用,比如准确获取鼠标按下时滑块的值。

QStyle::sliderValueFromPosition(minimum(), maximum(), event->x(), width());

使用QFile读写文件时,建议使用文件流来读写文件。速度快很多,基本上会有30%的提升。文件越大,性能差异越大。

//从文件加载英文属性与中文属性对照表
QFile file(":/propertyname.txt");
if (file.open(QFile::ReadOnly)) {
    //QTextStream方法读取速度至少快百分之30
#if 0
    while(!file.atEnd()) {
        QString line = file.readLine();
        appendName(line);
    }
#else
    QTextStream in(&file);
    while (!in.atEnd()) {
        QString line = in.readLine();
        appendName(line);
    }
#endif
    file.close();
}

用QFile.()读取QSS文件默认格式是ANSI,不支持UTF8,如果你在 中打开qss文件,编辑并保存,很可能加载qss后没有任何效果。

void frmMain::initStyle()
{
    //加载样式表
    QString qss;
    //QFile file(":/qss/psblack.css");
    //QFile file(":/qss/flatwhite.css");
    QFile file(":/qss/lightblue.css");
    if (file.open(QFile::ReadOnly)) {
#if 1
        //用QTextStream读取样式文件不用区分文件编码 带bom也行
        QStringList list;
        QTextStream in(&file);
        //in.setCodec("utf-8");
        while (!in.atEnd()) {
            QString line;
            in >> line;
            list << line;
        }

        qss = list.join("\n");
#else
        //用readAll读取默认支持的是ANSI格式,如果不小心用creator打开编辑过了很可能打不开
        qss = QLatin1String(file.readAll());
#endif
        QString paletteColor = qss.mid(20, 7);
        qApp->setPalette(QPalette(QColor(paletteColor)));
        qApp->setStyleSheet(qss);
        file.close();
    }
}

内置了很多转换函数,比如转换成数据,但是转换打印的时候会发现精度降低了,只剩下三位了,其实原始数据还是有完整精度的,只是打印的时候优化成了三位,如果要保证完整精度,可以调用ion函数来设置精度的位数。

QString s1, s2;
s1 = "666.5567124";
s2.setNum(888.5632123'f'7);
qDebug() << qSetRealNumberPrecision(10) << s1.toDouble() << s2.toDouble();

在解析数据的时候会发现总是多了一个节点内容,内容为空,如果需要跳过就加一行代码。

while (it.hasNext()) {
    it.next();    
    if (it.flags() & QScriptValue::SkipInEnumeration)      
       continue;     
    qDebug() << it.name();
}

这是最糟糕的映射方式。它通常只用于简单且不频繁的映射。建议经常绘制。双缓冲是默认设置。在高级点使用绘制以利用 GPU。

如果需要在尺寸改变时不重绘窗体,只需设置属性this->(Qt::, true);这样可以避免重新绘制已经显示的区域。

默认情况下,程序获取焦点后会有一个虚拟边框,如果嫌麻烦,可以通过设置style:(“*{:0px;}”);去

提醒:请联系我时一定说明是从101箱包皮具网上看到的!