ZhangJie Software Development Engineer

Qt开发笔记

2021-10-30
ZhangJie

本文记录平时使用Qt开发时的一些经验总结。

开发环境

  • Qt5.2.0 + vs2010
vs2010
qt-windows-opensource-5.2.0-msvc2010_opengl-x86-offline.exe
qt-vs-addin-1.2.2-opensource.exe
  • Qt5.9.9 + vs2015
vs2015
qt-vsaddin-msvc2015-2.5.1.vsix
qt-opensource-windows-x86-5.9.9.exe

开发笔记

防止Qt进程重复启动

int main(int argc, char* argv[]) {
    
    QApplication a(argc, argv);

    QSharedMemory singleton(a.applicationName());
    if (!singleton.create(1))
    {
        QMessageBox::warning(NULL, "Waring", "Program already running!");
        return false;
    }

    return a.exec();
}

QMessageBox定时自动关闭

QMessageBox* warnBox = new QMessageBox(QMessageBox::Warning, "Waring", "Program already running!");
warnBox->setAttribute(Qt::WA_DeleteOnClose);
// 1s后自动关闭
QTimer::singleShot(1000, warnBox, SLOT(accept()));
warnBox->exec();

Qt设置生成的exe文件图标

1.创建.rc文件
在Qt中,设置窗口图标可以使用setWindowIcon函数来实现,但仅仅只设置了当前窗口的图标,如果需要对编译后生成的exe文件设置图标,这个时候就需要添加一个.rc文件。

新建一个文本文件,并将后缀改为.rc,这里命名为app.rc。

2.编辑.rc文件
此时有一个需要设置为exe文件图标的app_icon.ico图标文件,使用文本编辑器例如Notepad++打开app.rc,在app.rc中输入如下文本并保存。

IDI_ICON1 ICON DISCARDABLE "app_icon.ico"

3.添加.rc文件
在Qt应用工程文件中,使用RC_FILE添加.rc文件。

RC_FILE += app.rc

然后编译生成exe文件后,可以查看到exe文件已有图标。

Cannot open include file: ‘GLES2/gl2.h’: No such file or directory

C/C++ -> General -> Additional Include Directories中添加:

$(QTDIR)\include\QtANGLE

©无法显示: warning C4566: 由通用字符名称“\u00A9”表示的字符不能在当前代码页(936)中表示出来

// ©1988-2022 XXX有限公司 版权所有
QLabel *titleLabel = new QLabel(QString(L'\u00A9') + QStringLiteral("1988-2022 XXX有限公司 版权所有"), this);

win7下VS2015+Qt5.9.9编译出错

C:\Users\Administrator\AppData\Local\QtMsBuild\qt_vars.targets(246,5): error : 此编译的源文件可以在以下位置找到:“C:\Users\Administrator\AppData\Local\Temp\88bf35cb-38ce-41c4-a691-27d54fc325ed.txt”

编译Qt工程出现报错,并不是Qt没装好,很可能是.net frmework版本太低,需要4.7以上的才支持高版本的Qt。

查看Microsoft .NET Framework版本:VS2015 -> Help -> About Microsoft Visual Studio

应用程序无法正常启动0xc000007b

windeployqt.exe .\xxx.exe -> 找到同级目录中的vcredist_x86.exe安装

对界面进行操作后,有时界面会退出最前显示,隐藏到其他程序窗口后,如何解决?

activateWindow();
setWindowState((windowState() &~Qt::WindowMinimized) | Qt::WindowActive);

本机运行托盘图标正常,拷贝到别的机器,托盘图标不显示了。

解决措施:拷贝QT安装目录中的imageformats整个文件夹到exe所在目录。

Qt plugin路径问题

QString pluginsPath = "./plugins";
QString platformsRelPath = "platforms";
QString imageformatsRelPath = "imageformats";

QString platformsPath = QDir(pluginsPath).absoluteFilePath(platformsRelPath);
QString imageformatsPath = QDir(pluginsPath).absoluteFilePath(imageformatsRelPath);

QStringList pathes = QApplication::libraryPaths();
pathes << pluginsPath;
pathes << platformsPath;
pathes << imageformatsPath;
QApplication::setLibraryPaths(pathes);

Qt无法解析的外部符号”public:virtual struct QMetaObjectconst*__thiscallWidget::metaObject”

.vcxproj

"<ClInclude Include=" -> "<QtMoc Include="

Qt5加载ocx控件

  • 运行”C:\Program Files (x86)\Windows Kits\8.1\bin\x86\oleview.exe”,打开自己的.ocx文件(确保位置正确,可以先注册一下),找到uuid。

  • 根据.ocx中的uuid生成对应的.h和.cpp文件

PS D:\ProgramFiles\Qt\Qt5.9.9\5.9.9\msvc2015\bin> .\dumpcpp.exe "{21104E34-B72C-4A0D-B1E9-7DA3BC169199}"
PS D:\ProgramFiles\Qt\Qt5.9.9\5.9.9\msvc2015\bin>
  • VS2015 -> Qt project Settings -> Qt Modules 中添加 axcontainer

QChart

  • setUseOpenGL可以加速绘制,但是会导致界面闪烁的问题。

QSS样式

QSS中最常用的当属ID选择器了,用#号区分:

QLabel#thisIsLabel {
    color: red;
}

用了ID选择器以后,将只会有这个ID对应的控件会产生样式效果。拿这个ID怎么来的呢?一般通过setObjectName指定的,像对这个QLabel进行设置,就必须在代码中加上:

thisIsLabel->setObjectName("thisIsLabel");

属性选择器有些时候也会有妙用,比如当你的一个控件需要因为一个属性的改变而希望样式改变的时候,就需要用到属性选择器。 []内部的就是选择的属性,属性名和value都需要通过setProperty这个函数实现。

QLabel#thisIsLabel[enable=true] {
    color: red;
}

QLabel#thisIsLabel[enable=false] {
    color: blue;
}
  • 示例
// qss
QWidget#Widget_a {
    background-color:rgb(25,25,112);
}

QLabel[parent="Widget_b"] {
    font: bold;
    color: #00BFFF;
    font-family: "Microsoft YaHei";
    font-size: 22px;
}

// Widget_a.cpp
setObjectName("Widget_a");

// Widget_b.cpp
ui.label->setProperty("parent", "Widget_b");

Qt国际化

  • 添加环境变量
D:\ProgramFiles\Qt\Qt5.9.9\5.9.9\msvc2015\bin
D:\ProgramFiles\Microsoft Visual Studio 14.0\VC\bin
  • VS2015 -> Qt VS Tools -> Create New Translation File

例如分别创建中英文文件:

xx_zh.ts xx_en.ts

  • xx.pro文件中添加
TRANSLATIONS += Resources/qm/xx_en.ts \
    Resources/qm/xx_zh.ts
  • 更新.ts文件
lupdate xx.pro

// 更新.ts文件,并删除旧字符串
lupdate xx.pro -no-obsolete
  • Linguist同时打开xx_zh.ts、xx_en.ts进行翻译

  • 生成.qm文件

lrelease xx.pro
  • 程序中加载.qm文件
QTranslator translator;
std::string translationFile = getTranslationFilename();
if (isFileExist(translationFile)) {
    translator.load(str2qstr(translationFile));
}
else {
    int lan = getSdmLanguage();
    if (Language_en == lan) {
        translator.load(":/qm/xx_en");
    }
    else {
        translator.load(":/qm/xx_zh");
    }
}
a.installTranslator(&translator);

QPushButton

QPushButton按下后状态显示网格, 如何取消?

border-radius: none;

QTableView

QTableView常见设置

// 设置整行选中
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);

// 设置不可编辑
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);

// 取消选中后的虚线框
tableView->setFocusPolicy(Qt::NoFocus);

// 点击某一行,默认情况表头会加粗,下行代码取消加粗
tableView->horizontalHeader()->setHighlightSections(false);

QTableView单元格字符串较长时多行显示

tableView->horizontalHeader()->resizeSection(0, 80);
tableView->horizontalHeader()->resizeSection(1, 200);
tableView->horizontalHeader()->resizeSection(2, 200);
tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
tableView->horizontalHeader()->resizeSection(4, 200);

// 显示不下则多行显示
tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

模态对话框、非模态对话框、半模态对话框

  • 模态对话框,会阻塞当前主界面及其他窗体,后续代码必须等到当前窗体关闭后方可执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("模态对话框"));
// 以模态方法显示对话框
pDialog->exec();
// 关闭模态对话框后,才会继续执行下面的代码
qDebug() << __FUNCTION__ << "模态对话框";
  • 非模态对话框,不会阻塞当前主界面及其他窗体,不影响后续代码立即执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("非模态对话框"));
// 以非模态方法显示对话框
pDialog->show();
// 无需关闭弹出对话框,下面的代码会立即运行
qDebug() << __FUNCTION__ << "非模态对话框";
  • 半模态对话框,会阻塞当前主界面及其他窗体,同时不影响后续代码立即执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("半模态对话框"));
// 以半模态方法显示对话框
pDialog->open();
// 无需关闭弹出对话框,下面的代码会立即运行
qDebug() << __FUNCTION__ <<"半模态对话框";

QStandardItemModel使用效率优化

大量插入数据非常低效:

auto item = new QStandardItem(pOneVar->m_bolName.c_str());
item->setTextAlignment(Qt::AlignCenter);
item->setData(itemData);
m_modelBoolVar->insertRow(line_no++, item);

优化:

m_modelBoolVar->setRowCount(rowCnt);

m_modelBoolVar->setData(m_modelBoolVar->index(line_no, 0), pOneVar->m_bolName.c_str(), Qt::DisplayRole);

auto item = m_modelBoolVar->item(line_no, 0);
item->setTextAlignment(Qt::AlignCenter);
item->setData(itemData);

进制转换

// 位数不足,前面补0

int x = 15;

// 15 -> 0x0F
QString("0x%1").arg(x, 2, 16, QLatin1Char('0'));

// 15 -> 00001111
QString("%1").arg(x, 8, 2, QLatin1Char('0'));

常用控件用法

QComboBox

  • QComboBox区分大小写
QCompleter sensitive;
sensitive.setCaseSensitivity(Qt::CaseSensitive);
m_ui.comboBox_keyWordSearch->setCompleter(&sensitive);

下一篇 Linux学习笔记

Comments

Content