总结参考了以下链接:
知识点总结
琐碎知识点总结
01 — 10
1)qt不能跨线程操作Ui界面,如在Qt子线程操作主线程下的UI控件,会发生无法预知的界面显示异常甚至崩溃。
2)定时器不能跨线程调用。
3)如果控件被设置为固定尺寸,则布局里的stretch属性(控制布局里控件的伸缩大小)就不能对布局里控件的大小进行自由伸缩,但会留出足够的伸缩空间给控件伸缩。
4)Qt中的布局函数setStretch,setSpacing,setMargin这三个函数的区别:
- setStretch(int index, int stretch);//用于设置布局中的部件的拉伸因子,index表示布局中的部件索引,stretch表示拉伸因子;
- setSpacing(int spacing);//用于设置布局中的部件之间的间距,spacing表示部件之间的间距大小,以像素为单位;
- setMargin(int margin);//用于设置布局边缘与布局内部部件之间的边距,margin表示边距的大小,以像素为单位。
5)QTabWidget与QTabBar:QTabBar=每一个标签tab,QTabWidget=每一个标签tab+插入的QWidget。
6)QSlider(滑动条)、QScrollBar(滚动条)、QProgressBar(进度条)区别:滑动条(QSlider)主要是选择数值范围的,滚动条(QScrollBar)主要用于滚动视图内容的,进度条主要是用于显示任务进度的。
7)QScrollBar(滚动条)与QScrollArea(滚动区域)区别:QScrollBar(滚动条)是一个单独的滚动条组件,QScrollArea(滚动区域)是一个容器组件用于在一个矩形区域内显示并滚动内容,并且QScrollArea会自动根据内容的大小以及可见区域的大小提供滚动条。当内容的尺寸大于可见区域时,QScrollArea会显示相应的滚动条,以便用户可以滚动内容并查看超出可见区域的部分。
8)QStringList和QList的区别:
- QStringList是Qt提供的专门存储字符串的容器类,其底层实现是基于QString的链表结构。使用QStringList时,可以直接进行字符串的操作和处理,例如追加、删除、查找等。
- QList是模板类QList的一个特化版本,用于存储QString类型的元素。使用QList时,需要通过QList提供的成员函数来进行字符串的操作和处理,如append、remove、indexOf等。
- 一般来说,如果需要处理字符串列表并进行一些特定的操作,使用QStringList会更为方便。如果需要通用的动态数组容器,并且元素为QString类型,可以选择使用QList。
9)QFileInfoList与QList两者是等价的,QFileInfoList 实际上是 QList 的别名,它们都表示一个包含 QFileInfo 对象的列表,QFileInfoList是用于获得指定目录下所有文件/文件夹的基本信息。
10)当前日期的格式化获取:调用QDate的静态函数currentDate,使用如下:QDate::currentDate().toString(“yyyy-MM-dd”)。
11 — 20
11)字符串类型:C—>char* C++—>std::String、char* Qt—QString、QByteArray。
12)QByteArray类可以将其看成c语言char*的升级版。我们可以在调用该类构造函数的时候申请一块动态内存,用来存放要处理的字符串数据,而QString也是封装了字符串,但是内部的编码是utf8,utf8属于Unicode字符集,它固定使用多个字节(window为2字节,linux为3字节)来表示一个字符,这样可以将世界上几乎所有语言的常用字符收录其中。
13)append和prepend属于Qt风格,push_back和push_front属于C++风格。
14)QByteArray QString::toutf8() const是QString类的成员函数,可以将其utf8格式的QByteArray,这是最常用的QString转换程QByteArray的方法,也最好用这个,不建议用下面的toLocal8bit()函数。
15)QString QString::fromUtf8(const QByteArray &str)是QString类的静态函数,可以将QByteArray 转换为QString 。
16)QString QString::fromLocal8Bit(const QByteArray &str)是QString类的静态函数,可以将本地编码的QByteArray 转换为QString,一般windows系统的本地编码格式是ANSI码(也叫本地编码页编码),MSVC默认的就是ANSI格式。
17)QByteArray QString::toLocal8Bit() const是QString类的成员函数,可以将QString类对象转换为本地编码的QByteArray对象。
18)QString类做不到一步转换到char*,只有先通过QString调用QString的成员函数toutf8转换到QByteArray,再调用QByteArray的成员函数data才能转换程char*,最好分两步转换,如果直接一步到位的转换,可能会出现意想不到的转换结果。
19)QString与QByteArray类的区别:1)同样的字符串串对象,其length有可能是不一样的,QString算的length是字符长度,一个汉字字符或其他特殊字符都算1个,而QByteArray算的是字符串占用的字节数,一个汉字占3个字节,一个英文占1个字节,1个特殊字符占1个;2)QByteArray就是对char*的浅层次包装,QString是内部做了深层次包装,重新对其做了utf8编码。
20)QCoreApplication用于非GUI的应用程序(不需要依赖QtGui库),QApplication用于包含GUI的应用程序(需要用到QtGui库),QApplication继承了QGuiApplication类,而QGuiApplication继承了QCoreApplication类,而QCoreApplication又继承QObject的,而QObject就是QT中最基本的基类,也就是QT的根基。
21 — 30
21)内存地址从左往右(低地址——>高地址) 字节从左往右(最高有效位——>最低有效位) 。
22)富文本:又称呼为格式化文本,具有风格、排版等信息,如颜色、式样(黑体、斜体等)、字体尺寸、特性(如超链接)等。
23)QBrush类是 Qt 框架中用于绘制图形对象的画刷类。它用于确定图形对象(如矩形或椭圆)的填充样式和颜色。
24)QSS设置常用:border: width style color;font: style weight size family。
25)QTableView和QTableWidget主要的区别:
- 数据模型:QTableView使用QAbstractItemModel作为数据模型,而QTableWidget使用QTableWidgetItem列表来管理数据。
- 灵活性:由于使用了自定义的数据模型,QTableView更加灵活。你可以根据需要实现自己的数据模型,并将其与QTableView关联,以便处理更复杂的数据结构和操作。而对于简单的表格显示,QTableWidget提供了一个简单的接口。
- 单元格编辑:在QTableWidget中,可以直接在单元格内编辑内容。而在QTableView中,默认情况下不能直接编辑单元格内容,需要通过委托(Delegate)来实现编辑功能。
- 布局管理:对于布局管理方面,QTableWidget具有内置的行列布局管理器,并且可以很容易地添加、删除和调整大小。而在QTableView中,你需要手动设置布局管理器,并进行更多的自定义布局操作。
- 总体而言,如果你需要更高度定制化、灵活性较强以及处理大量数据时,请选择使用 QTableView。如果你只是需要简单地展示和编辑少量数据,并且不需要太多定制化操作,则可以选择 QTableWidget。
26)QStringLiteral是Qt框架提供的一个宏,用于创建静态的QString对象。它在编译时对字符串进行优化,避免了运行时的字符串拷贝操作,提高了性能。
27)QFile用于读取和写入文件的操作,QFileInfo用于获取文件和目录的信息,而QDir用于管理目录的操作。
28)Qt灰度图像的format格式:QImage::Format_Indexed8。
29)".“表示当前目录,而”…"表示父级目录或者说是上级目录。这两个目录是在每个目录中都存在的默认目录。当我们想要获取目录中的实际子目录和文件列表时,通常希望忽略这两个特殊目录。QDir类使用QDir类来遍历某个目录中所有目录和文件时,会调用枚举类型QDir::NoDotAndDotDot来过滤这两个目录。
30)QDir::entryInfoList函数且过滤器是QDir::Dirs返回的QFileInfoList(说明都是当前目录下的子目录),每一个FileInfo调用absoluteFilePath函数,返回的是当前目录下的一个子目录路径(此时子目录可以看成是一个文件),调用absolutePath函数返回的是当前目录路径,调用fileName函数是当前目录下的一个子目录名称。
31)$$PWD是一种特殊的变量,用来表示当前工作目录的路径。它是Qt预定义的一种变量,在.pro文件或.qmake文件中使用。
32)跨线程通过信号槽机制传输QImage图像时,信号函数的参数必须是QImage图像的深拷贝。
33)在Qt的UI界面设计中,当你在设计界面中拖动一个QHBoxLayout(例如使用Qt Designer)时,它会自动生成一个QHBoxLayoutWidget对象。QHBoxLayoutWidget是一个特殊的QWidget子类,用于容纳QHBoxLayout布局。它提供了一个可视化的容器,使得在设计时可以直观地看到布局的效果。
34)在Qt中的MainWindow类的构造函数里调用mapToGlobal函数返回的坐标不是全局(屏幕)坐标的原因:窗口可能还没有完全创建和显示,因此得到的结果可能不准确。
35)QLabel设置文本的3种方法:
//常规办法
ui->label->setText("日历");
//取巧办法
ui->label->setProperty("text","日历");
//属性方法
ui->label->setStyleSheet("qproperty-text:日历;");
36)获取类的属性方法:
//获取类的属性
const QMetaObject* tempMetaObject = ui->label->metaObject();
int count = tempMetaObject->propertyCount();
for (int i = 0; i < count; ++i) {
QMetaProperty metaproperty = tempMetaObject->property(i);
const char *name = metaproperty.name();
QVariant value = ui->label->property(name);
qDebug() << name << value;//类 属性名称 属性值
}
37)Qt内置图标封装在QStyle中,大概七十多个图标,可以直接拿来用。
SP_TitleBarMenuButton,
SP_TitleBarMinButton,
SP_TitleBarMaxButton,
SP_TitleBarCloseButton,
SP_MessageBoxInformation,
SP_MessageBoxWarning,
SP_MessageBoxCritical,
SP_MessageBoxQuestion,
...
//下面这样取出来使用就行
QPixmap pixmap = this->style()->standardPixmap(QStyle::SP_TitleBarMenuButton);
ui->label->setPixmap(pixmap);
38)巧妙的使用 findChildren 可以查找该控件下的所有子控件。 findChild 为查找单个。
//查找指定类名objectName的控件
QList<QWidget *> widgets = fatherWidget.findChildren<QWidget *>("widgetname");
//查找所有QPushButton
QList<QPushButton *> allPButtons = fatherWidget.findChildren<QPushButton *>();
//查找一级子控件,不然会一直遍历所有子控件
QList<QPushButton *> childButtons = fatherWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
39)巧妙的使用inherits判断是否属于某种类。
QTimer *timer = new QTimer; // QTimer inherits QObject
timer->inherits("QTimer"); // returns true
timer->inherits("QObject"); // returns true
timer->inherits("QAbstractButton"); // returns false
40)Qt内置了QFormLayout表单布局用于自动生成标签+输入框的组合的表单界面,设置布局用的很少,一般用的最多的是横向布局、垂直布局、表格布局。
41 — 50
41)Qt中继承QWidget之后,样式表不起作用,解决办法有三个。强烈推荐方法一。
方法一:设置属性 this->setAttribute(Qt::WA_StyledBackground, true);
方法二:改成继承QFrame,因为QFrame自带paintEvent函数已做了实现,在使用样式表时会进行解析和绘制。
方法三:重新实现QWidget的paintEvent函数时,使用QStylePainter绘制。
void Widget::paintEvent(QPaintEvent *)
{
QStyleOption option;
option.initFrom(this);
QPainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this);
}
42)有时候在界面上加了弹簧,需要动态改变弹簧对应的拉伸策略,对应方法为changeSize,很多人会选择使用set开头去找,找不到的。并且qt中的弹簧控件必须要在布局中配合使用,这是因为弹簧控件的主要作用是调整布局中控件之间的空间,使布局更加合理和灵活。
43)在使用QFile的过程中,不建议频繁的打开文件写入然后再关闭文件,比如间隔5ms输出日志,IO性能瓶颈很大,这种情况建议先打开文件不要关闭,等待合适的时机比如析构函数中或者日期变了需要重新变换日志文件的时候关闭文件。不然短时间内大量的打开关闭文件会很卡,文件越大越卡。
44)非常不建议tr中包含中文,尽管现在的新版Qt支持中文到其他语言的翻译,但是很不规范,也不知道TMD是谁教的,tr的本意是包含英文,然后翻译到其他语言比如中文,现在大量的初学者滥用tr,如果没有翻译的需求,禁用tr,tr需要开销的,Qt默认会认为他需要翻译,会额外进行特殊处理。
45)对于大段的注释代码,建议用 #if 0 #endif 将代码块包含起来,而不是将该段代码选中然后全部双斜杠注释,下次要打开这段代码的话,又需要重新选中一次取消,如果采用的是 #if 0则只要把0改成1即可,开发效率提升很多。
46)Qt打包发布,有很多办法,Qt5以后提供了打包工具windeployqt(linux上为linuxdeployqt,mac上为macdeployqt)可以很方便的将应用程序打包,使用下来发现也不是万能的,有时候会多打包一些没有依赖的文件,有时候又会忘记打包一些插件尤其是用了qml的情况下,而且不能识别第三方库,比如程序依赖ffmpeg,则对应的库需要自行拷贝,终极大法就是将你的可执行文件复制到Qt安装目录下的bin目录,然后整个一起打包,挨个删除不大可能依赖的组件,直到删到正常运行为止。
47)很多人在绘制的时候,设置画笔以为就只可以设置个单调的颜色,其实QPen还可以设置brush,这样灵活性就提高不知道多少倍,比如设置QPen的brush以后,可以使用各种渐变,比如绘制渐变颜色的进度条和文字等,而不再是单调的一种颜色。
48)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]");
49)在我们使用QList、QStringList、QByteArray等链表或者数组的过程中,如果只需要取值,而不是赋值,强烈建议使用 at() 取值而不是 [] 操作符,在官方书籍《C++ GUI Qt 4编程(第二版)》的书中有特别的强调说明,此教材的原作者据说是Qt开发的核心人员编写的,所以还是比较权威,至于使用 at() 与使用 [] 操作符速度效率的比较,网上也有网友做过此类对比。原文在书的212页,这样描述的:Qt对所有的容器和许多其他类都使用隐含共享,隐含共享是Qt对不希望修改的数据决不进行复制的保证,为了使隐含共享的作用发挥得最好,可以采用两个新的编程习惯。第一种习惯是对于一个(非常量的)向量或者列表进行只读存取时,使用 at() 函数而不用 [] 操作符,因为Qt的容器类不能辨别 [] 操作符是否将出现在一个赋值的左边还是右边,他假设最坏的情况出现并且强制执行深层赋值,而 at() 函数则不被允许出现在一个赋值的左边。
50)如果是dialog窗体,需要在exec以后还能让其他代码继续执行,请在dialog窗体exec前增加一行代码,否则会阻塞窗体消息。
QDialog dialog;
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
51 — 60
51)安全的删除Qt的对象类,强烈建议使用deleteLater而不是delete,因为deleteLater会选择在合适的时机进行释放,而delete会立即释放,很可能会出错崩溃。如果要批量删除对象集合,可以用qDeleteAll,比如 qDeleteAll(btns);
52)在QTableView控件中,如果需要自定义的列按钮、复选框、下拉框等其他模式显示,可以采用自定义委托QItemDelegate来实现,如果需要禁用某列,则在自定义委托的重载createEditor函数返回0即可。自定义委托对应的控件在进入编辑状态的时候出现,如果想一直出现,则需要重载paint函数用drawPrimitive或者drawControl来绘制。
53)将 QApplication::style() 对应的drawPrimitive、drawControl、drawItemText、drawItemPixmap等几个方法用熟悉了,再结合QStyleOption属性,可以玩转各种自定义委托,还可以直接使用paint函数中的painter进行各种绘制,各种牛逼的表格、树状列表、下拉框等,绝对屌炸天。QApplication::style()->drawControl 的第4个参数如果不设置,则绘制出来的控件不会应用样式表。这个有空研究一下????
54)心中有坐标,万物皆painter,强烈建议在学习自定义控件绘制的时候,将qpainter.h头文件中的函数全部看一遍、试一遍、理解一遍,这里边包含了所有Qt内置的绘制的接口,对应的参数都试一遍,你会发现很多新大陆,会一定程度上激发你的绘制的兴趣,犹如神笔马良一般,策马崩腾遨游代码绘制的世界。
55)在使用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);
56)很多时候需要在已知背景色的情况下,能够清晰的绘制文字,这个时候需要计算对应的文字颜色。
//根据背景色自动计算合适的前景色
double gray = (0.299 * color.red()