• Qt开发经验小技巧合集


    一、开发经验总结

    1. 当编译发现大量错误的时候,从第一个看起,一个一个的解决,不要急着去看下一个错误,往往后面的错误都是由于前面的错误引起的,第一个解决后很可能都解决了。

    2. 定时器是个好东西,学会好使用它,有时候用QTimer::singleShot可以解决意想不到的问题。

    3. 打开creator,在构建套件的环境中增加MAKEFLAGS=-j8,可以不用每次设置多线程编译。珍爱时间和生命。新版的QtCreator已经默认就是j8。

    4. 如果你想顺利用QtCreator部署安卓程序,首先你要在AndroidStudio 里面配置成功,把坑全部趟平。

    5. 很多时候找到Qt对应封装的方法后,记得多看看该函数的重载,多个参数的,你会发现不一样的世界,有时候会恍然大悟,原来Qt已经帮我们封装好了。

    6. 可以在pro文件中写上标记版本号+ico图标(Qt5才支持)

    VERSION   	= 2018.7.25
    RC_ICONS    = main0.ico
    
    1. 管理员运行程序,限定在MSVC编译器。
    QMAKE_LFLAGS += /MANIFESTUAC:"level='requireAdministrator' uiAccess='false'" #以管理员运行
    QMAKE_LFLAGS += /SUBSYSTEM:WINDOWS,"5.01" #VS2013 在XP运行
    
    1. 运行文件附带调试输出窗口
      CONFIG += console pro

    2. 绘制平铺背景QPainter::drawTiledPixmap,绘制圆角矩形QPainter::drawRoundedRect(),而不是QPainter::drawRoundRect();

    3. 移除旧的样式

    //移除原有样式
    style()->unpolish(ui->btn);
    //重新设置新的该控件的样式。
    style()->polish(ui->btn);
    
    1. 获取类的属性
    const QMetaObject *metaobject = object->metaObject();
    int count = metaobject->propertyCount();
    for (int i = 0; i < count; ++i) {
        QMetaProperty metaproperty = metaobject->property(i);
        const char *name = metaproperty.name();
        QVariant value = object->property(name);
        qDebug() << name << value;
    }
    
    1. Qt内置图标封装在QStyle中,大概七十多个图标,可以直接拿来用。
      QStyle::SP_TitleBarMenuButton

    2. 根据操作系统位数判断加载

    win32 {
        contains(DEFINES, WIN64) { DESTDIR = $${PWD}/../../bin64
        } else { DESTDIR = $${PWD}/../../bin32 }
    }
    
    1. Qt5增强了很多安全性验证,如果出现setGeometry: Unable to set geometry,请将该控件的可见移到加入布局之后。

    2. 可以将控件A添加到布局,然后控件B设置该布局,这种灵活性大大提高了控件的组合度,比如可以在文本框左侧右侧增加一个搜索按钮,按钮设置图标即可。

    QPushButton *btn = new QPushButton;
    btn->resize(30, ui->lineEdit->height());
    QHBoxLayout *layout = new QHBoxLayout(ui->lineEdit);
    layout->setMargin(0);
    layout->addStretch();
    layout->addWidget(btn);
    
    1. 对QLCDNumber控件设置样式,需要将QLCDNumber的segmentstyle设置为flat。

    2. 巧妙的使用findChildren可以查找该控件下的所有子控件。findChild为查找单个。

    //查找指定类名objectName的控件
    QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
    //查找所有QPushButton
    QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>();
    //查找一级子控件,不然会一直遍历所有子控件
    QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
    
    1. 巧妙的使用inherits判断是否属于某种类。
    QTimer *timer = new QTimer;         // QTimer inherits QObject
    timer->inherits("QTimer");          // returns true
    timer->inherits("QObject");         // returns true
    timer->inherits("QAbstractButton"); // returns false
    
    1. 使用弱属性机制,可以存储临时的值用于传递判断。可以通过widget->dynamicPropertyNames()列出所有弱属性名称,然后通过widget->property("name")取出对应的弱属性的值。

    2. 在开发时, 无论是出于维护的便捷性, 还是节省内存资源的考虑, 都应该有一个 qss 文件来存放所有的样式表, 而不应该将 setStyleSheet 写的到处都是。如果是初学阶段或者测试阶段可以直接UI上右键设置样式表,正式项目还是建议统一到一个qss样式表文件比较好,统一管理。

    3. 如果出现Z-order assignment: is not a valid widget.错误提示,用记事本打开对应的ui文件,找到为空的地方,删除即可。

    4. 善于利用QComboBox的addItem的第二个参数设置用户数据,可以实现很多效果,使用itemData取出来。

    5. 如果用了webengine模块,发布程序的时候带上QtWebEngineProcess.exe+translations文件夹+resources文件夹。

    6. a.setAttribute(Qt::AA_NativeWindows);可以让每个控件都拥有独立的句柄。

    7. Qt+Android防止程序被关闭。

    #if defined(Q_OS_ANDROID)
    QAndroidService a(argc, argv);
    return a.exec()
    #else
    QApplication a(argc, argv);
    return a.exec();
    #endif
    
    1. 可以对整体的指示器设置样式,例如 ::down-arrow,::menu-indicator{} ::up-arrow:disabled,::up-arrow:off{}。

    2. 可以执行位置设置背景图片。

    QMainWindow > .QWidget {
        background-color: gainsboro;
        background-image: url(:/images/pagefold.png);
        background-position: top right;
        background-repeat: no-repeat
    }
    
    1. 嵌入式linux运行Qt程序 Qt4写法:./HelloQt -qws & Qt5写法:./HelloQt --platform xcb

    2. Qtcreator软件的配置文件存放在:C:UsersAdministratorAppDataRoamingQtProject,有时候如果发现出问题了,将这个文件夹删除后打开creator自动重新生成即可。

    3. QMediaPlayer依赖本地解码器,WIN上下载k-lite或者LAV Filters安装即可。

    4. 代码判断MSVC编译器版本。

    if (_MSC_VER == 1800)
    MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
    MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
    MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
    MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
    MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
    MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
    MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
    MSVC++ 7.0  _MSC_VER == 1300
    MSVC++ 6.0  _MSC_VER == 1200
    MSVC++ 5.0  _MSC_VER == 1100
    
    1. 在pro中判断不同平台:message($$QT_ARCH) contains(QT_ARCH,arm)。

    2. Qt最小化后恢复界面假死冻结,加上代码

    void showEvent(QShowEvent *e){
    setAttribute(Qt::WA_Mapped);
    QWidget::showEvent(e);
    }
    
    1. 获取标题栏高度:style()->pixelMetric(QStyle::PM_TitleBarHeight); PM_TitleBarHeight点进去你会发现新大陆。

    2. 设置高分屏属性以便支持2K4K等高分辨率,尤其是手机app。必须写在main函数的QApplication a(argc, argv);的前面。

    #if (QT_VERSION > QT_VERSION_CHECK(5,6,0))
        QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
    
    1. 如果运行程序出现 Fault tolerant heap shim applied to current process. This is usually due to previous crashes. 错误。
      办法:打开注册表,找到HKEY_LOCAL_MACHINESoftwareMicrosoftWindows NTCurrentVersionAppCompatFlagsLayers,选中Layers键值,从右侧列表中删除自己的那个程序路径即可。

    2. Qt内置了QFormLayout表单布局用于自动生成标签+输入框的组合的表单界面。

    3. qml播放视频在linux需要安装 sudo apt-get install libpulse-dev。

    4. 可以直接继承QSqlQueryModel实现自定义的QueryModel,比如某一列字体颜色,占位符,其他样式等,重写QVariant CustomSqlModel::data(const QModelIndex &index, int role) const。

    5. Qt5以后提供了类QScroller直接将控件滚动。

    ui->listWidget->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
    QScroller::grabGesture(ui->listWidget,QScroller::LeftMouseButtonGesture);
    
    1. 如果使用sqlite数据库不想产生数据库文件,可以创建内存数据库。
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    
    1. 清空数据表并重置自增ID,sql = truncate table table_name。

    2. Qtchart模块从Qt5.7开始自带,最低编译要求Qt5.4。在安装的时候记得勾选,默认不勾选。使用该模块需要引入命名空间。

    #include <QChartView>
    QT_CHARTS_USE_NAMESPACE
    class CustomChart : public QChartView
    
    1. QPushButton左对齐文字,需要设置样式表QPushButton{text-align:left;}

    2. QLabel有三种设置文本的方法,掌握好Qt的属性系统,举一反三,可以做出很多效果。

    ui->label->setStyleSheet("qproperty-text:hello;");
    ui->label->setProperty("text", "hello");
    ui->label->setText("hello");
    
    1. 巧妙的用QEventLoop开启事件循环,可以使得很多同步获取返回结果而不阻塞界面。QEventLoop内部新建了线程执行。
    QEventLoop loop;
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    
    1. 多种预定义变量 #if (defined webkit) || (defined webengine)。

    2. 新版的Qtcreator增强了语法检查,会弹出很多警告提示等,可以在插件列表中关闭clang打头的几个即可,Help》About Plugins。也可以设置代码检查级别,Tools》Options 》C++ 》Code Model。

    3. QSqlTableModel的rowCount方法,默认最大返回256,如果超过256,可以将表格拉到底部,会自动加载剩余的,每次最大加载256条数据,如果需要打印或者导出数据,记得最好采用sql语句去查询,而不是使用QSqlTableModel的rowCount方法。不然永远最大只会导出256条数据。
      如果数据量很小,也可以采用如下方法:

    //主动加载所有数据,不然获取到的行数<=256
    while(model->canFetchMore()) {
        model->fetchMore();
    }
    
    1. 如果需要指定无边框窗体,但是又需要保留操作系统的边框特性,可以自由拉伸边框,可以使用 setWindowFlags(Qt::CustomizeWindowHint);

    2. 在某些http post数据的时候,如果采用的是&字符串连接的数据发送,中文解析乱码的话,需要将中文进行URL转码。

    QString content = "测试中文";
    QString note = content.toUtf8().toPercentEncoding();
    
    1. Qt默认不支持大资源文件,比如添加了字体文件,需要pro文件开启。
      CONFIG += resources_big

    2. Qt中继承QWidget之后,样式表不起作用,解决办法有三个。强烈推荐方法一。
      方法一:设置属性 this->setAttribute(Qt::WA_StyledBackground, true);
      方法二:改成继承QFrame,因为QFrame自带paintEvent函数已做了实现,在使用样式表时会进行解析和绘制。
      方法三:重新实现QWidget的paintEvent函数时,使用QStylePainter绘制。

    void myclass::paintEvent(QPaintEvent *)
    {
        QStyleOption o;
        o.initFrom(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
    }
    
    1. 有时候在界面上加了弹簧,需要动态改变弹簧对应的拉伸策略,对应方法为changeSize,很多人会选择使用set开头去找,找不到的。

    2. 在使用QFile的过程中,不建议频繁的打开文件写入然后再关闭文件,比如间隔5ms输出日志,IO性能瓶颈很大,这种情况建议先打开文件不要关闭,等待合适的时机比如析构函数中或者日期变了需要重新变换日志文件的时候关闭文件。不然短时间内大量的打开关闭文件会很卡,文件越大越卡。

    3. 在很多网络应用程序,需要自定义心跳包来保持连接,不然断电或者非法关闭程序,对方识别不到,需要进行超时检测,但是有些程序没有提供心跳协议,此时需要启用系统层的保活程序,此方法适用于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));
    
    1. 如果程序打包好以后弹出提示 This application failed to start because it could not find or load the Qt platform plugin 一般都是因为platforms插件目录未打包或者打包错了的原因导致的。

    2. 非常不建议tr中包含中文,尽管现在的新版Qt支持中文到其他语言的翻译,但是很不规范,也不知道TMD是谁教的,tr的本意是包含英文,然后翻译到其他语言比如中文,现在大量的初学者滥用tr,如果没有翻译的需求,禁用tr,tr需要开销的,Qt默认会认为他需要翻译,会额外进行特殊处理。

    3. 很多人Qt和Qt Creator傻傻分不清楚,经常问Qt什么版本结果发一个Qt Creator的版本过来,Qt Creator是使用Qt编写的集成开发环境IDE,和宇宙第一的Visual Studio一样,他可以是msvc编译器的(WIN对应的Qt集成安装环境中自带的Qt Cerator是msvc的),也可以是mingw编译的,还可以是gcc的。如果是自定义控件插件,需要集成到Qt Creator中,必须保证该插件的动态库文件(dll或者so等文件)对应的编译器和Qt版本以及位数和Qt Creator的版本完全一致才行,否则基本不大可能集成进去。特别注意的是Qt集成环境安装包中的Qt版本和Qt Creator版本未必完全一致,必须擦亮眼睛看清楚,有些是完全一致的。

    4. 超过两处相同处理的代码,建议单独写成函数。代码尽量规范精简,比如 if(a == 123) 要写成 if (123 == a),值在前面,再比如 if (ok == true) 要写成 if (ok),if (ok == false) 要写成 if (!ok)等。

    5. 很多人问Qt嵌入式平台用哪个好,这里统一回答(当前时间节点2018年):imx6+335x比较稳定,性能高就用RK3288 RK3399,便宜的话就用全志H3,玩一玩可以用树莓派香橙派。

    6. 对于大段的注释代码,建议用 #if 0 #endif 将代码块包含起来,而不是将该段代码选中然后全部 // ,下次要打开这段代码的话,又需要重新选中一次取消,如果采用的是 #if 0则只要把0改成1即可,效率大大提升。

    7. Qt打包发布,有很多办法,Qt5以后提供了打包工具windeployqt(linux上为linuxdeployqt,mac上为macdeployqt)可以很方便的将应用程序打包,使用下来发现也不是万能的,有时候会多打包一些没有依赖的文件,有时候又会忘记打包一些插件尤其是用了qml的情况下,而且不能识别第三方库,比如程序依赖ffmpeg,则对应的库需要自行拷贝,终极大法就是将你的可执行文件复制到Qt安装目录下的bin目录,然后整个一起打包,挨个删除不大可能依赖的组件,直到删到正常运行为止。

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

    9. 在绘制无背景颜色只有边框颜色的圆形时候,可以用绘制360度的圆弧替代,效果完全一致。

    QRect rect(-radius, -radius, radius * 2, radius * 2);
    //以下两种方法二选一,其实绘制360度的圆弧=绘制无背景的圆形
    painter->drawArc(rect, 0, 360 * 16);
    painter->drawEllipse(rect);
    
    1. 不要把d指针看的很玄乎,其实就是在类的实现文件定义了一个私有类,用来存放局部变量,个人建议在做一些小项目时,没有太大必要引入这种机制,会降低代码可读性,增加复杂性,新手接受项目后会看的很懵逼。

    2. 很多人在绘制的时候,设置画笔以为就只可以设置个单调的颜色,其实QPen还可以设置brush,这样灵活性就提高不知道多少倍,比如设置QPen的brush以后,可以使用各种渐变,比如绘制渐变颜色的进度条和文字等,而不再是单调的一种颜色。

    3. 很多控件都带有viewport,比如QTextEdit/QTableWidget/QScrollArea,有时候对这些控件直接处理的时候发现不起作用,需要对其viewport()设置才行,比如设置滚动条区域背景透明,需要使用scrollArea->viewport()->setStyleSheet("background-color:transparent;");而不是scrollArea->setStyleSheet("QScrollArea{background-color:transparent;}");

    4. 有时候设置了鼠标跟踪setMouseTracking为真,如果该窗体上面还有其他控件,当鼠标移到其他控件上面的时候,父类的鼠标移动事件MouseMove识别不到了,此时需要用到HoverMove事件,需要先设置 setAttribute(Qt::WA_Hover, true);

    5. Qt封装的QDateTime日期时间类非常强大,可以字符串和日期时间相互转换,也可以毫秒数和日期时间相互转换,还可以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]");
    
    1. 在我们使用QList、QStringList、QByteArray等链表或者数组的过程中,如果只需要取值,而不是赋值,强烈建议使用 at() 取值而不是 [] 操作符,在官方书籍《C++ GUI Qt 4编程(第二版)》的书中有特别的强调说明,此教材的原作者据说是Qt开发的核心人员编写的,所以还是比较权威,至于使用 at() 与使用 [] 操作符速度效率的比较,网上也有网友做过此类对比。原文在书的212页,这样描述的:Qt对所有的容器和许多其他类都使用隐含共享,隐含共享是Qt对不希望修改的数据决不进行复制的保证,为了使隐含共享的作用发挥得最好,可以采用两个新的编程习惯。第一种习惯是对于一个(非常量的)向量或者列表进行只读存取时,使用 at() 函数而不用 [] 操作符,因为Qt的容器类不能辨别 [] 操作符是否将出现在一个赋值的左边还是右边,他假设最坏的情况出现并且强制执行深层赋值,而 at() 函数则不被允许出现在一个赋值的左边。

    2. 如果是dialog窗体,需要在exec以后还能让其他代码继续执行,请在dialog窗体exec前增加一行代码,否则会阻塞窗体消息。

    QDialog dialog;
    dialog.setWindowModality(Qt::WindowModal);
    dialog.exec();
    
    1. 安全的删除Qt的对象类,强烈建议使用deleteLater而不是delete,因为deleteLater会选择在合适的时机进行释放,而delete会立即释放,很可能会出错崩溃。如果要批量删除对象集合,可以用qDeleteAll,比如 qDeleteAll(btns);

    2. 在QTableView控件中,如果需要自定义的列按钮、复选框、下拉框等其他模式显示,可以采用自定义委托QItemDelegate来实现,如果需要禁用某列,则在自定义委托的重载createEditor函数返回0即可。自定义委托对应的控件在进入编辑状态的时候出现,如果想一直出现,则需要重载paint函数用drawPrimitive或者drawControl来绘制。

    3. 将 QApplication::style() 对应的drawPrimitive、drawControl、drawItemText、drawItemPixmap等几个方法用熟悉了,再结合QStyleOption属性,可以玩转各种自定义委托,还可以直接使用paint函数中的painter进行各种绘制,各种牛逼的表格、树状列表、下拉框等,绝对屌炸天。QApplication::style()->drawControl 的第4个参数如果不设置,则绘制出来的控件不会应用样式表。

    4. 心中有坐标,万物皆painter,强烈建议在学习自定义控件绘制的时候,将qpainter.h头文件中的函数全部看一遍、试一遍、理解一遍,这里边包含了所有Qt内置的绘制的接口,对应的参数都试一遍,你会发现很多新大陆,会大大激发你的绘制的兴趣,犹如神笔马良一般,策马崩腾遨游代码绘制的世界。

    5. 在使用setItemWidget或者setCellWidget的过程中,有时候会发现设置的控件没有居中显示而是默认的左对齐,而且不会自动拉伸填充,对于追求完美的程序员来说,这个可不大好看,有个终极通用办法就是,将这个控件放到一个widget的布局中,然后将widget添加到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(0, 0, widget);
    
    1. 很多时候需要在已知背景色的情况下,能够清晰的绘制文字,这个时候需要计算对应的文字颜色。
    //根据背景色自动计算合适的前景色
    double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
    QColor textColor = gray > 0.5 ? Qt::black : Qt::white;
    
    1. 对QTableView或者QTableWidget禁用列拖动。
    #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
    
    1. 从Qt4转到Qt5,有些类的方法已经废弃或者过时了,如果想要在Qt5中启用Qt4的方法,比如QHeadVew的setMovable,可以在你的pro或者pri文件中加上一行即可:DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0

    2. Qt中的QColor对颜色封装的很完美,支持各种转换,比如rgb、hsb、cmy、hsl,对应的是toRgb、toHsv、toCmyk、toHsl,还支持透明度设置,颜色值还能转成16进制格式显示。

    QColor color(255, 0, 0, 100);
    qDebug() << color.name() << color.name(QColor::HexArgb);
    //输出 #ff0000 #64ff0000
    
    1. QVariant类型异常的强大,可以说是万能的类型,在进行配置文件的存储的时候,经常会用到QVariant的转换,QVariant默认自带了toString、toFloat等各种转换,但是还是不够,比如有时候需要从QVariant转到QColor,而却没有提供toColor的函数,这个时候就要用到万能办法。
    if (variant.typeName() == "QColor") {
        QColor color = variant.value<QColor>();
        QFont font = variant.value<QFont>();
        QString nodeValue = color.name(QColor::HexArgb);
    }
    
    1. Qt中的QString和const char *之间转换,最好用toStdString().c_str()而不是toLocal8Bit().constData(),比如在setProperty中如果用后者,字符串中文就会不正确,英文正常。

    2. Qt的信号槽机制非常牛逼,也是Qt的独特的核心功能之一,有时候我们在很多窗体中传递信号来实现更新或者处理,如果窗体层级比较多,比如窗体A的父类是窗体B,窗体B的父类是窗体C,窗体C有个子窗体D,如果窗体A一个信号要传递给窗体D,问题来了,必须先经过窗体B中转到窗体C再到窗体D才行,这样的话各种信号关联信号的connect会非常多而且管理起来比较乱,可以考虑增加一个全局的单例类AppEvent,公共的信号放这里,然后窗体A对应信号绑定到AppEvent,窗体D绑定AppEvent的信号到对应的槽函数即可,干净清爽整洁。

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

    4. Qt中有个全局的焦点切换信号focusChanged,可以用它做自定义的输入法。Qt4中默认会安装输入法上下文,比如在main函数打印a.inputContext会显示值,这个默认安装的输入法上下文,会拦截两个牛逼的信号QEvent::RequestSoftwareInputPanel和QEvent::CloseSoftwareInputPanel,以至于就算你安装了全局的事件过滤器依然识别不到这两个信号,你只需要在main函数执行a.setInputContext(0)即可,意思是安装输入法上下文为空。

    5. 在Qt5.10以后,表格控件QTableWidget或者QTableView的默认最小列宽改成了15,以前的版本是0,所以在新版的qt中,如果设置表格的列宽过小,不会应用,取的是最小的列宽。所以如果要设置更小的列宽需要重新设置ui->tableView->horizontalHeader()->setMinimumSectionSize(0);

    6. Qt源码中内置了一些未公开的不能直接使用的黑科技,都藏在对应模块的private中,比如gui-private widgets-private等,比如zip文件解压类QZipReader、压缩类QZipWriter就在gui-private模块中,需要在pro中引入QT += gui-private才能使用。

    #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();
    
    1. 理论上串口和网络收发数据都是默认异步的,操作系统自动调度,完全不会卡住界面,网上那些说收发数据卡住界面主线程的都是扯几把蛋,真正的耗时是在运算以及运算后的处理,而不是收发数据,在一些小数据量运算处理的项目中,一般不建议动用线程去处理,线程需要调度开销的,不要什么东西都往线程里边扔,线程不是万能的。只有当真正需要将一些很耗时的操作比如编码解码等,才需要移到线程处理。

    2. 在构造函数中获取控件的宽高很可能是不正确的,需要在控件首次显示以后再获取才是正确的,控件是在首次显示以后才会设置好正确的宽高值,记住是在首次显示以后,而不是构造函数或者程序启动好以后,如果程序启动好以后有些容器控件比如QTabWidget中的没有显示的页面的控件,你去获取宽高很可能也是不正确的,万无一失的办法就是首次显示以后去获取。

    3. 数据库处理一般建议在主线程,如果非要在其他线程,务必记得打开数据库也要在那个线程,即在那个线程使用数据库就在那个线程打开,不能打开数据库在主线程,执行sql在子线程,很可能出问题。

    4. 新版的QTcpServer类在64位版本的Qt下很可能不会进入incomingConnection函数,那是因为Qt5对应的incomingConnection函数参数变了,由之前的int改成了qintptr,改成qintptr有个好处,在32位上自动是quint32而在64位上自动是quint64,如果在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
    
    1. 不要怀疑这部分被狗吃了,_中间部分待更新,会持续更新。也欢迎各位在文章底部留言加进去。

    2. Qt界的中文乱码问题,版本众多导致的如何选择安装包问题,如何打包发布程序的问题,堪称Qt界的三座大山!

    3. 在Qt的学习过程中,学会查看对应类的头文件是一个好习惯,如果在该类的头文件没有找到对应的函数,可以去他的父类中找找,实在不行还有爷爷类,肯定能找到的。通过头文件你会发现很多函数接口其实Qt已经帮我们封装好了,有空还可以阅读下他的实现代码。

    4. Qt安装目录下的Examples目录下的例子,看完学完,月薪20K起步。

    5. 崩溃的80%都是因为要么越界,要么未初始化,死扣这两点,80%的问题解决了。

    6. Qt一共有几百个版本,关于如何选择Qt版本的问题,我一般保留四个版本,为了兼容Qt4用4.8.7,最后的支持XP的版本5.7.0,最新的长期支持版本比如5.9.8,最高的新版本比如5.13.1。强烈不建议使用5.0到5.3之间的版本,太多BUG和坑,稳定性和兼容性相比于之后的版本相当差,能换就换,不能换睡服领导也要换。

    7. 终极秘籍:如果遇到问题搜索Qt方面找不到答案,试着将关键字用JAVA C# android打头,你会发现别有一番天地,其他人很可能做过!

    8. 最后一条:珍爱生命,远离编程。祝大家头发浓密,睡眠良好,情绪稳定,财富自由!

    二、推荐的Qt论坛+个人博客+网站

    名称 网址
    qtcn http://www.qtcn.org
    豆子的空间 https://www.devbean.net
    yafeilinux http://www.qter.org
    一去二三里 http://blog.csdn.net/liang19890820
    乌托邦2号 http://blog.csdn.net/taiyang1987912
    foruok http://blog.csdn.net/foruok
    jason http://blog.csdn.net/wsj18808050
    朝十晚八 http://www.cnblogs.com/swarmbees
    BIG_C_GOD http://blog.csdn.net/big_c_god
    公孙二狗 https://qtdebug.com/qtbook
    雨田哥 https://blog.csdn.net/ly305750665
    郑天佐 https://blog.csdn.net/zhengtianzuo06
    寒山-居士 https://blog.csdn.net/esonpo
    feiyangqingyun https://blog.csdn.net/feiyangqingyun
    前行中小猪 http://blog.csdn.net/goforwardtostep
    涛哥的知乎专栏 https://zhuanlan.zhihu.com/TaoQt
    Qt君 https://blog.csdn.net/nicai_xiaoqinxi
    Qt老外视频教程 http://space.bilibili.com/2592237/#!/index
    Qt维基补充文档 https://wiki.qt.io/Main
    Qt源码查看网站 https://code.woboq.org/qt5
    Qt官方下载地址 https://download.qt.io
    Qt国内镜像下载地址 https://mirrors.cloud.tencent.com/qt
    精美图表控件QWT http://qwt.sourceforge.net/
    精美图表控件QCustomPlot https://www.qcustomplot.com/

    三、其他

    1. Qt入门书籍推荐霍亚飞的《Qt Creator快速入门》,Qt进阶书籍推荐官方的《C++ GUI Qt4编程》,qml书籍推荐《Qt5编程入门》。
    2. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!
  • 相关阅读:
    7.13dfs例题:部分和
    7.12dfs例题:数独游戏
    1.2题解:如何找数组中唯一成对的那个数(位运算)
    左程云Java算法(1)
    SQL基本语句增删改查
    Python spyder Ipython console 连接失败问题
    VBA——Msgbox
    python 字符串
    Scrapy-selectors总结
    文字单行居中,多行居左/居右
  • 原文地址:https://www.cnblogs.com/feiyangqingyun/p/10962456.html
Copyright © 2020-2023  润新知