继续讲一些Qt开发中的技巧操作:
1.新版随机数
Qt中有自己的随机数取值方法,Qt5.10以前使用qsrand方法, Qt5.10以后提供了新的类 QRandomGenerator QRandomGenerator64 管理随机数,使用更方便,尤其是取某个区间的随机数。
//早期处理办法 先初始化随机数种子然后取随机数
qsrand(QTime::currentTime().msec());
//取 0-10 之间的随机数
qrand() % 10;
//取 0-1 之间的浮点数
qrand() / double(RAND_MAX);
//新版处理办法 支持5.10以后的所有版本包括qt6
QRandomGenerator::global()->bounded(10); //生成一个0和10之间的整数
QRandomGenerator::global()->bounded(10.123); //生成一个0和10.123之间的浮点数
QRandomGenerator::global()->bounded(10, 15); //生成一个10和15之间的整数
//兼容qt4-qt6及以后所有版本的方法 就是用标准c++的随机数函数
srand(QTime::currentTime().msec());
rand() % 10;
rand() / double(RAND_MAX);
//通用公式 a是起始值,n是整数的范围
int value = a + rand() % n;
//(min, max)的随机数
int value = min + 1 + (rand() % (max - min - 1));
//(min, max]的随机数
int value = min + 1 + (rand() % (max - min + 0));
//[min, max)的随机数
int value = min + 0 + (rand() % (max - min + 0));
//[min, max]的随机数
int value = min + 0 + (rand() % (max - min + 1));
2.模拟鼠标移动
Qt的UI界面在resize以后有个BUG,悬停样式没有取消掉,就是说界面变化后,还停留在鼠标悬停的状态,需要主动模拟鼠标动一下。这种方式可以用在一些界面刷新后,状态未变动的问题。
void frmMain::on_btnMenu_clicked()
{
......
//有个BUG,当按钮操作界面变化后,悬停样式没有取消掉,需要主动模拟鼠标动一下
QEvent event(QEvent::Leave);
QApplication::sendEvent(ui->btnMenu_Max, &event);
}
3.QTextEdit卡死问题
Qt的文本控件比如QTextEdit默认加载大文本比如10MB的文本,很容易卡死甚至崩溃,那是因为默认undoRedoEnabled这个属性开启了,只要屏蔽掉就好很多。这个属性是用于开启undo撤消和redo重做的。关掉这个属性,就会释放出一些预留的空间,QTextEdit自然也就不那么卡了。
可以用代码关闭
ui->textEdit->setUndoRedoEnabled(false);
也可以在设计器里边关闭
4.函数返回值
如果你的函数声明和定义时设置了返回值,那么一定要确保函数退出时return对应的返回值。有部分编译器在没有返回值的情况下也能正常编译通过,不会给你报错,但是运行的时候会出问题,甚至崩溃。我就不慎踩了好几次这个坑,函数里边忘了return,编译不报错,结果,一调用到这个函数立马崩溃。
你可以试试这样:
int MainWindow::testFun()
{
int nRet = 0;
//return nRet;
}
一段简单测试代码,专门去掉返回值,你会发现widows上编译报错,Linux上编译不报错。
5.参数结构化
有时候我们定义一些函数时,设定的参数很多,后期可能还会修改和增加,一旦要修改增删,那么源头修改以后,关联信号槽的地方也要修改,参数类型和位置必须保持完全一致,对应槽函数处理胡总和调用方也要修改等,改动的工作量非常大而且极不友好。这时候,我们可以考虑将这些参数做成一个结构体或者类,这样非常容易增加其他的参数,而且不用修改信号槽关联和信号槽函数定义等,比如学生姓名、年龄,性别等信息表作为参数传输,最佳方案就是将这些参数合在一个结构体或者类中,做一个数据类型来传输。
//"StudentInfo"结构体包含学生各项信息
bool showStudentData(const int& nIndex, const StudentInfo& studentInfo)
{
ui->labelName.setText(studentInfo.name);
ui->labelSix.setText(studentInfo.six);
ui->labelAge.setText(studentInfo.age);
}
6.选项卡控件
QTabWidget选项卡控件,生成的tabbar选项卡宽度是按照文本自动设置的,文本越长选项卡的宽度越大,很多时候,我们需要的是一样的宽度或者等分填充。
//方法1:字符串空格填充
ui->tabWidget->addTab(httpClient1, "测 试");
ui->tabWidget->addTab(httpClient1, "人员管理");
ui->tabWidget->addTab(httpClient1, "系统设置");
//方法2:识别尺寸改变事件自动设置最小宽度
void MainWindow::resizeEvent(QResizeEvent *e)
{
int count = ui->tabWidget->tabBar()->count();
int width = this->width() - 30;
QString qss = QString("QTabBar::tab{min-width:%1px;}").arg(width / count);
this->setStyleSheet(qss);
}
//方法3:设置全局样式,不同选项卡个数的设置不同的宽度
QStringList list;
list << QString("QTabWidget[tabCount=\"2\"]>QTabBar::tab{minwidth:%1px;}").arg(100);
list << QString("QTabWidget[tabCount=\"3\"]>QTabBar::tab{minwidth:%1px;}").arg(70);
qApp->setStyleSheet(list.join(""));
//设置了tabCount弱属性自动去找对应的宽度设置
ui->tabWidget->setProperty("tabCount", 2);
ui->tabWidget->setProperty("tabCount", 3);
//方法4:强烈推荐-》使用内置的方法 setExpanding setDocumentMode 两个属性都必须设置
//Qt4的tabBar()是propected的,所以建议还是通过样式表设置
ui->tabWidget->tabBar()->setDocumentMode(true);
ui->tabWidget->tabBar()->setExpanding(true);
//样式表一步到位不用每个都单独设置
QString("QTabBar{qproperty-usesScrollButtons:false;qpropertydocumentMode:true;qproperty-expanding:true;}");
7.窗体属性
Qt提供了N种窗体属性比如无边框属性FramelessWindowHint、不在任务栏显示属性Tool等,有时候我们需要对窗口的属性进行动态设置,比如增加一个属性或者移除一个属性,Qt5.9以前需要拿到原有的窗体属性做运算,Qt5.9以后可以用新的方法。
//增加一个无边框属性
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
//移除无边框属性
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
//下面是5.9以后新增的方法
//增加一个无边框属性到窗体属性链表
setWindowFlag(Qt::FramelessWindowHint, true);
//从窗体属性链表中移除无边框属性
setWindowFlag(Qt::FramelessWindowHint, false);
窗体属性的各个属性很多,可以都试试他们呈现出什么样子。