qt日常积累

张开发
2026/5/26 17:41:58 15 分钟阅读
qt日常积累
1.QlineEdit设置文本后如何使文本内容始终从左侧开始显示lineEdit-setText(这是一个示例); lineEdit-setCursorPosition(0); // 将光标移动到文本的开头lineEdit-setText(这是一个示例); lineEdit-home(false); // 移动光标到文本开头true会选中所有内容false不选中2.判断当前调试版本#ifdef QT_DEBUG // Debug version qDebug() This is a debug build.; #else // Release version qDebug() This is a release build.; #endif#ifdef QT_NO_DEBUG qDebug() This is a release build.; #else qDebug() This is a debug build.; #endif3. 设置窗口为独立窗口可以超出父控件范围childWidget-setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);4清空qtcreator设置删除该文件夹中内容 C:\Users\admin\AppData\Roaming\QtProject5.初始化列表顺序初始化列表的顺序最好和实际初始化顺序一致实际初始化先初始化父类在初始化子类qDebug“”不需要头文件6.生成随机数//生成随机数 QRandomGenerator::global()-generate(); //生成随机数 指定范围 QRandomGenerator::global()-bounded(100);7.引用放到定义中声明使用前向声明在.cpp文件中#include可以减少不必要的编译依赖如果头文件中有很多不必要的包含那么会导致.cpp文件编译时包含过多的内容增加编译时间。8. 程序避免重新打开单实例检测再次点击时激活已有窗口QSharedMemory sharedMemory(a.applicationName()); if(!sharedMemory.create(1,QSharedMemory::ReadOnly)){ QMessageBox::information(0,a.applicationName(),程序已经启动请勿重复打开.); }#include mainwindow.h #include QLocalServer #include QLocalSocket #include QApplication #include QSharedMemory #include QMessageBox int main(int argc, char *argv[]) { QApplication a(argc, argv); QSharedMemory shared_memory(app); if(!shared_memory.create(1)){ QLocalSocket socker; socker.connectToServer(app); if(socker.waitForConnected(500)){ socker.write(show); socker.flush(); // 等待写入信号若未写入成功弹出提示 if(!socker.waitForBytesWritten(300)){ QMessageBox::information(nullptr, u8提示, socker.errorString()); } } return 0; } QLocalServer server; server.removeServer(app); // 避免残留 server.listen(app); MainWindow w; w.show(); QObject::connect(server,QLocalServer::newConnection,[](){ QLocalSocket * client server.nextPendingConnection(); if(client-waitForReadyRead(500)){ QByteArray msg client-readAll(); if(msg show){ w.showNormal(); w.raise(); w.isActiveWindow(); } } client-deleteLater(); }); return a.exec(); }QLocalServer用于在同一台机器上的进程之间进行本地进程间通信 (IPC, Inter-Process Communication)。它相当于一个本地的“服务器”结合QLocalSocket可以实现基于本地套接字Local Socket的通信机制。简单来说它的作用类似于网络中的QTcpServer但只在本机范围内有效不经过网络栈效率更高。9. 继承关系QWidget QFrame QAbstracttScrollArea QAbstractItemView QListView QTreeView QTableView10. widgte设置属性this-setAttribute(Qt::WA_DeleteOnClose);this-setWindowFlag(Qt::FramelessWindowHint,true); //无边框this-setAttribute(Qt::WA_StyledBackground,true);//继承widget后样式表无效时this-setAttribute(Qt::WA_TranslucentBackground);11. widget跟随鼠标移动QPoint::manhantanlength()计算两点绝对横纵坐标之和QApplication::startDragDistance判断拖动操作的触发条件通常是10pxvoid Dialog::mousePressEvent(QMouseEvent *event) { //鼠标按键被按下 if(event-button() Qt::LeftButton){ m_lastPos event-pos(); // 记录固定距离 // event-pos() event-globalPosition().toPoint() - this-pos(); m_moving true; } Dialog::mousePressEvent(event); } void Dialog::mouseMoveEvent(QMouseEvent *event) { //鼠标按下左键移动 QPoint eventPos event-globalPosition().toPoint(); if (m_moving (event-buttons() Qt::LeftButton) (eventPos-m_lastPos-pos()).manhattanLength() QApplication::startDragDistance()) { move(eventPos - m_lastPos); } Dialog::mouseMoveEvent(event); } void Dialog::mouseReleaseEvent(QMouseEvent *event) { //鼠标按键被释放 m_moving false; }单精度4个字节双精度8个字节在大多数平台上如桌面系统qreal通常定义为double类型。在嵌入式设备上如某些 ARM 平台qreal可能被定义为float类型以提高性能和减少内存占用。12. qDeleteAllqDeleteAll删除了对象所占用的内存对象本身也随之被销毁。但容器中的指针仍然存在并指向已被释放的内存这些指针称为悬空指针Dangling Pointers。qDeleteAll(objectList); objectList.clear(); // 清空容器 qDeleteAll(objectList); for (auto ptr : objectList) { ptr nullptr; // 将指针置为 nullptr }13. 转义字符14. 判断是否全屏void MyWidget::toggleFullScreen() { if (isFullScreen()) { showNormal(); // 恢复到正常窗口模式 } else { showFullScreen(); // 显示为全屏模式 } }15. windowTitlethis-setWindowTitle(xxxx);//光标浮在图标上显示的文字16. 使用样式inventory_btn_freeze_r-setProperty(inventory,on); //设置属性和值 inventory_btn_freeze_r-setStyle(QApplication::style());//调用 //样式表中设置样式 QWidget[tempfreeze]#CabinetCabTopWidget{ background-color: #43bcd8; }17. lineedit限制输入QRegExpValidator * validator new QRegExpValidator(QRegExp(all_field_names.join(|)),this-lineEdit()); this-lineEdit()-setValidator(validator);18.重绘时不清除背景this-setAttribute(Qt::WA_OpaquePaintEvent, true);19. 分页控件中lineedit设置范围不生效使用QSpinBox来替代QLineEditseek_page_led_ new QSpinBox(); seek_page_led_-setButtonSymbols(QAbstractSpinBox::NoButtons); seek_page_led_-clear(); QLineEdit * spin_edit seek_page_led_-findChildQLineEdit*(); //不可以输入0开头的数字 connect(spin_edit, QLineEdit::textChanged, this,[](const QString text) { QString current_text spin_edit-text(); if (current_text.startsWith(0)) { current_text.remove(0, 1); spin_edit-setText(current_text); } }); //设置范围 spinbox会默认显示下限的数字输入0用正则过滤掉 seek_page_led_-setRange(0, total_table_page_);20. 前向声明和编译单元在 C 中一个编译单元Translation Unit指的是一个.cpp文件及其直接或间接包含的所有头文件。h文件引用头文件mywidget.h被多个.cpp文件包含每个.cpp都会解析QLabel增加编译时间。h文件前向声明QLabel只在mywidget.cpp解析不会影响其他.cpp减少全局编译时间。每个.cpp文件只包含一个.h文件并且.h只被这个.cpp文件包含那么两种方式的编译速度几乎没有区别。即使在这种情况下编译速度相近前向声明仍然更推荐原因是代码组织更清晰.h只声明接口不包含不必要的实现细节符合“最小依赖”原则。头文件变得更干净不会引入无关的 Qt 头文件。避免未来可能的扩展问题目前.h只被一个.cpp用但未来可能会被多个.cpp包含这时前向声明的优势就会体现。如果头文件#include QLabel而它被多个.cpp引用编译开销会成倍增加。采用前向声明可以在未来减少编译开销。减少不必要的#include防止循环依赖如果未来mywidget.h需要QLabel.h而QLabel.h也引用了mywidget.h可能导致循环依赖问题。采用前向声明可以降低这种风险。21 .设置按钮后点击后界面隐藏再点击一次取消隐藏connect(btn, QPushButton::clicked, this, []() {widget-setVisible(!widget-isVisible());});向上取整 int num (num y -1)/y 0还为0 x/y向下取整22. sql中limit和offsetsql中行数从1行开始limit限制多少行offset跳过N行从N1行开始23. model中data执行顺序data()执行了3次遍历每次遍历都执行每一行每一项的七个角色的赋值。int row index.row();int col index.column();qDebug() row: index.row() col: index.column() role: role ( QMetaEnum::fromTypeQt::ItemDataRole().valueToKey(role) );exec_sql_watcher_ new QFutureWatchervoid(); connect(exec_sql_watcher_, QFutureWatchervoid::finished, this, []() { updateScrollBarLimit(); exec_sql_watcher_-deleteLater(); exec_sql_watcher_ nullptr; }); exec_sql_watcher_-setFuture(QtConcurrent::run([]() { if (need_fetch_up) { int new_start_row qMax(0, current_min_row - fetch_size_); fetchRowsFromDbInternal(new_start_row, current_min_row - 1, true); // true: 上方 } else if (need_fetch_down) { int new_end_row current_max_row fetch_size_; fetchRowsFromDbInternal(current_max_row 1, new_end_row, false); // false: 下方 } })); QtConcurrent::run([]() { if (need_fetch_up) { int new_start_row qMax(0, current_min_row - fetch_size_); fetchRowsFromDbInternal(new_start_row, current_min_row - 1, true); // true: 上方 } else if (need_fetch_down) { int new_end_row current_max_row fetch_size_; fetchRowsFromDbInternal(current_max_row 1, new_end_row, false); // false: 下方 } QMetaObject::invokeMethod(this, []() { // emit dataChanged() 通知视图更新 updateScrollBarLimit(); }, Qt::QueuedConnection); });while (remove_num-- !cache_maps_.isEmpty()) { cache_maps_.remove(cache_maps_.lastKey()); } auto it cache_maps_.begin(); for (int index 0; index fetch_size_ it ! cache_maps_.end();index) { cache_maps_.erase(it); }void LazyTableModel::cleanupCache(int _keep_start_row, int _keep_end_row) const { for (auto it cache_maps_.begin(); it ! cache_maps_.end();) { int row it.key(); if (row _keep_start_row || row _keep_end_row) { it cache_maps_.erase(it); } else { it; } } }24. 设置QToolButtonQPushButton的图标及图标大小1、通过qproperty-iconSize来设置ICON的尺寸 2、通过qproperty-icon:来设置ICON QToolButton { qproperty-iconSize: 16px 16px; qproperty-icon:url(:/hover.png); } tool_btn-setIcon(QIcon(QString(:/icon/icon_%1_hover.png).arg(icon_name)));25. qt中get没有前缀set有前缀。信号自动关联 on_objectname_槽btn-setObjectName(btn);QMetaObject::connectSlotsByName(this); //自动关联Q_OBJECT宏必须分离声明和定义26 . comboxbox中设置当前项为空1.ui_-combo_ setCurrentIndex(-1)彻底清除当前选中项。 2.ui_-combo_-setEditable(true); // 设置为可编辑模式 ui_-combo_-setCurrentText();if (std::any_of(hide_field_list_.cbegin(), hide_field_list_.cend(), [](const QString hide) { return header_name.contains(hide);})) { continue; }27. lambda表达式[捕获列表](参数列表) - 返回类型 { // 函数体 } [a]按值捕获复制 [a]按引用捕获可以修改 []按值捕获所有使用到的外部变量 []按引用捕获所有使用到的外部变量 [this]捕获当前类实例指针用于成员函数中 默认值捕获的变量是只读的。如果你想修改使用引用捕获或 mutable lambda 表达式的返回类型 可以是 任意合法类型28. 使用枚举值表示最大值enum class emunType{ normal, invialide, } for(int i 0;iinvialide;i){}using list QListQString;typedef QListQString list;using 支持模板templatetypename Tusing sharedptr QSharedPointerT;28. qt源码位置C:\Qt\Qt5.14.2\5.14.2\Src\qtbase\src\widgets\kernel29.qt控件提升其实提升就是多继承的意思使得这个类拥有了多个类的成员和方法提升有个 全局包含 复选框打勾✔后ui_xxx.h 包含的时候就是 #include xxxxxx.h这样的话这个头文件就是相对工程根目录的路径了不打勾就是 #include xxxxx.h这个就是相对工程中的当前文件夹的路径了就可以用../../xx.h这样的访问方式30. 表格中模型更新ui各种model数据要在主线程中//构造函数中初始化一次display_sort_model_-setSourceModel(standard_source_model_);paging_control_table_-setModel(display_sort_model_);// 删除所有行 子线程中查询sql存储数据后在主线程中更新model数据standard_source_model_-removeRows(0, standard_source_model_-rowCount());//standard_source_model_-clear();setModel()会触发QTableView的完整重绘 造成闪烁31.Qt 的QSettings / ini 配置文件不写引号passwordwerwerw简洁通用必须写引号只有在值里面本身包含空格或特殊字符如、;、#时才需要QSettings 读取 INI 文件的原理QSettings 的 INI parser 是 Qt 内部实现的文本解析器以字节流方式读取文件按行解析[section]和keyvalue并不识别 BOM只把文件开头的字节当作普通字符UTF-8 BOM (0xEF 0xBB 0xBF)出现在文件开头Windows Qt 版本在某些版本下QTextStream读取文件时会自动识别 BOM 并跳过所以 Windows 上读取带 BOM 的 INI 文件通常不会报错Linux Qt 版本QSettings 的 INI parser 没有自动去掉 BOM会把0xEF 0xBB 0xBF当作非法字符导致第一个 section 或 key 解析失败QSettings 默认编码Windows 平台下QSettings 的IniFormat默认不是 UTF-8而是系统本地编码通常是 ANSI / GBK / CP1252Linux/macOS下默认是 UTF-8qt5qt5 QString username ([]{ QSettings s(config.ini, QSettings::IniFormat); s.setIniCodec(UTF-8); return s.value(General/username).toString(); })(); Qt 6 默认 UTF-8无需再调用 QString CASE_OR_TASK QSettings(:/file/pack_config.ini, QSettings::IniFormat) .value(General/username, 案件).toString();32.treewidget的setIndentation()默认值是20 像素。如果你的第一棵树有三层而第二棵树只有一层为了让内容对齐第三层你可以把第二棵树的缩进设置为40。treeWidget2-setIndentation(40); // 对齐三层树的最内层ui_-treeWidget2-setColumnWidth(i, columnWidth);//设置宽度ui_-treeWidget2-header()-setSectionResizeMode(0, QHeaderView::ResizeToContents);//这个视图的表头QHeaderView的第0 列设置成根据内容自动调整宽度。ui_-treeWidget2-header()-setSectionResizeMode(QHeaderView::ResizeToContents);//所有列都按内容自适应允许拖拽Interactive禁止拖拽Fixed/ResizeToContents/Stretch填满表格Stretch按内容自动适应ResizeToContents33. 设置进程优先级DWORD getPostgresPid(const QString dataDir) { QFile file(dataDir /data/postmaster.pid); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return 0; QTextStream in(file); QString pidStr in.readLine(); return pidStr.toUInt(); } void setPostgresHighPriority(DWORD pid) { if (pid 0) return; HANDLE hProcess OpenProcess(PROCESS_SET_INFORMATION, FALSE, pid); if (hProcess) { SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS); // 高优先级 CloseHandle(hProcess); } } cmd_process.start(QString(R(%1//bin//pg_ctl -D %1//data -l logfile -o -p %2 start)).arg(data_base_path).arg(new_db_port)); DWORD pgPid getPostgresPid(data_base_path); setPostgresHighPriority(pgPid);34 常用宏sql预处理#pragma region RegionName // 这里是代码块 #pragma endregion RegionName#ifdef QT_NO_DEBUG #endif #ifdef QT_DEBUG// 方式一exec(sql) —— 直接执行 query.exec(INSERT INTO users (id, name) VALUES (1001, Alice)); // 方式二prepare bind —— 可重复执行 query.prepare(INSERT INTO users (id, name) VALUES (:id, :name)); query.bindValue(:id, 1002); query.bindValue(:name, Bob); query.exec(); query.bindValue(:id, 1003); query.bindValue(:name, Charlie); query.exec();\bORDER\sBY\b\bword boundary匹配一个位置这个位置前后必须是“单词字符和非单词字符”的交界处。单词字符字母、数字、下划线[A-Za-z0-9_]非单词字符空格、标点、字符串开始/结束等\s的英文是whitespace character意思是「空白字符」。QString 的 left 从左往右mid从中间开始right从右往左35 PSQL数据库pg_ctl是PostgreSQL 自带的管理工具主要用于启动、停止、重启、重载配置pg_ctl会启动一个postgres 主进程主进程会自动派生多个子进程/后台进程所以在任务管理器里你会看到多个postgres.exe它们都属于同一个数据库服务实例PID英文全称为Process Identifiersql强制排序SELECT cntFROM (SELECT 1 AS ord, COUNT(id) AS cnt FROM software.ryda WHERE ajid%1 AND ztlx 1UNION ALLSELECT 2 AS ord, COUNT(id) AS cnt FROM software.ryda WHERE ajid%1 AND ztlx 2) tORDER BY ord;[, x]默认值捕获个别按引用[, x]默认引用捕获个别按值数据库中自增id默认从1而不是0开始sql中不可以执行二进制数据但是可以执行十六进制数据insert into tab;e(id,data) values(1,十六进制数据)36. mocQt 会自动扫描所有头文件.h / .hpp如果里面有Q_OBJECT就自动对它执行 moc。但默认情况下不会处理.cpp文件尤其是main.cpp。CONFIG moc的作用就是强制 qmake 对所有源文件包括 .cpp执行 moc 预处理。换句话说它让 qmake 把.cpp文件当作候选文件也会生成.moc文件。资源文件在运行时可能被编译到二进制中无实际文件系统路径37. QVariant判断(variant.isNull() || variant.isValid())38 . 关闭进程taskkill /F /IM 天玑图分析软件.exewmic process where Name天玑图分析软件.exe deleteQProcess cmd_process; cmd_process.start(taskkill, QStringList() /F /IM 天玑图分析软件.exe); if (!cmd_process.waitForFinished(3000)) { qWarning() taskkill 命令超时未响应; } qInfo() taskkill stdout: QString::fromLocal8Bit(cmd_process.readAllStandardOutput()); cmd_process.kill(); cmd_process.close();39. 转换时间QString date_string QDateTime::currentDateTime().toString(yyyyMMddhhmmss); 20251201154530 QString date_string QDateTime::currentDateTime().toString(yyyy-MM-dd hh:mm:ss); 2025-12-01 15:45:30其中mm和MM分别表示分钟、月份- 表示分隔符空格也可以用作分隔符40. QStringList的splitQStringList names find_operation_string.split(QRegularExpression([;]), Qt::SkipEmptyParts);QLineEdit设置正则表达式ui_-search_context_led_-setValidator(new QRegExpValidator(QRegExp((\\d;?){0,}))); ui_-search_context_led_-setValidator(new QRegExpValidator(QRegExp(^[\u4e00-\u9fa5a-zA-Z0-9][;]?([\u4e00-\u9fa5a-zA-Z0-9][;]?){0,}$))); ui_-search_context_led_-setValidator(new QRegExpValidator(QRegExp(^[\u4e00-\u9fa5a-zA-Z0-9][;]?([\u4e00-\u9fa5a-zA-Z0-9][;]?){0,}$)));41. QDiaolog关闭后删除对话框方式 1设置Qt::WA_DeleteOnClose属性最推荐AddWaitInquiryDialog *dialog new AddWaitInquiryDialog(record);方式 2手动delete简洁直接AddWaitInquiryDialog *dialog new AddWaitInquiryDialog(record); int result dialog-exec(); // 先接收exec的返回值 if (result QDialog::Accepted) { updateWaitInquiryTable(); } // 事件循环已完成手动删除对话框 delete dialog; dialog nullptr; // 避免野指针可选但推荐42. QString转换为QDateTime格式QDateTime begin_time QDateTime::fromString(ui_-begin_calender_time-toString(),yyyy-MM-dd hh:mm:ss); QDateTime end_time QDateTime::fromString(ui_-end_calender_time-toString(), yyyy-MM-dd hh:mm:ss); if (!begin_time.isValid() || !end_time.isValid()) { qDebug() Invalid date format. Expected: yyyy-MM-dd hh:mm:ss; } if (begin_time end_time) { return; }43. 键盘宏主键盘回车Key_Return、小键盘回车Key_Enter// 投递 setQuery 到主线程执行 QMetaObject::invokeMethod(sql_query_model, []() { sql_query_model-setQuery(query_result); // 主线程执行触发 modelReset }, Qt::QueuedConnection);QSortFilterProxyModel是 Qt 中用于对源模型如QStandardItemModel进行排序、过滤的代理模型核心调用逻辑排序的完整流程调用proxyModel-sort(col, order)手动触发或表头点击触发代理模型遍历源模型的所有数据项对每一对数据项调用lessThan()根据lessThan()的返回值结合order升序 / 降序确定数据项的最终展示顺序表格 / 视图刷新展示排序后的结果源模型数据无任何修改。44. QDialogQt 对话框的父窗口需在构造阶段绑定构造后调用setParent()仅修改父子关系不会自动更新窗口标志导致模态阻塞失效QDialog *dlg new QDialog(); // 无参构造 dlg-resize(500, 500); // 1. 构造后设置父对象必须后续修复逻辑 dlg-setParent(this); // 2. 核心修复重置窗口标志为对话框类型覆盖初始化的独立窗口标志 dlg-setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); dlg-setAttribute(Qt::WA_DeleteOnClose); // 关闭对话框时自动释放内存 // 3. 显式设置模态确保 exec() 阻塞 dlg-setModal(true); // 4. 内存管理exec() 场景下无需 WA_DeleteOnClose手动释放更安全 dlg-exec(); QApplication::activeWindow()setWindowModality(Qt::ApplicationModal)设置窗口模态级别作用是将目标窗口设置为应用级模态窗口45. pro文件设置config-debug_and_release的完整含义是从当前工程的编译配置中移除 “同时编译 debug 和 release 版本” 的选项。该路径中文件后缀已经添加了debug,添加后生成文件中删除debug和release文件夹45. Qt 程序中实现点击桌面任务栏图标时程序窗口能正常弹出显示再次点击则最小化到任务栏默认是此效果,setWindowFlags(Qt::FramelessWindowHint);后点击程序不会最小化setWindowFlags(Qt::Window|Qt::FramelessWindowHint |Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint|Qt::WindowMaximizeButtonHint); QDialog d; d.setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);Qt::FramelessWindowHint // 无边框 | Qt::WindowMinimizeButtonHint // 允许最小化 | Qt::WindowSystemMenuHint // 让系统识别为可交互窗口 | Qt::Window); // 基础窗口属性功能Qt5 必须写Qt6 必须写最小化按钮WindowMinimizeButtonHintWindowMinimizeButton最大化按钮WindowMaximizeButtonHintWindowMaximizeButton关闭按钮WindowCloseButtonHintWindowCloseButton如果最大化和最小化按钮不能用,重新设置最大最小尺寸setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint |Qt::WindowCloseButtonHint); setMinimumSize(0, 0); setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);46. 实现抽屉效果ToolBox可以实现,但是只能开一个,其它都会关闭;最好使用QScrollArea,其中放入QWdiget,按钮设置为QToolButton,隐藏或显示下方的QWdiget47. QPushbutton添加菜单ui-pushButton-setMenu(menu);QToolButton添加actionglobal_pos tool_btn-mapToGlobal(QPoint(0, tool_btn-height())); sort_order_menu_ new QMenu(this); sort_order_menu_-setAttribute(Qt::WA_DeleteOnClose); sort_order_menu_-addAction(升序); QAction *deleteAction sort_order_menu_-addAction(消除); /* 默认状态 */ QPushButton::menu-indicator { image: url(:/icons/arrow_down_normal.png); width: 16px; height: 16px; } /* 鼠标悬停在按钮上时 */ QPushButton:hover::menu-indicator { image: url(:/icons/arrow_down_hover.png); } /* 按钮按下时 */ QPushButton:pressed::menu-indicator { image: url(:/icons/arrow_down_pressed.png); }47 信号和槽重载时,QOverLoad参数类型明确指定信号和槽connect(commander, QOverload::of(Commander::go), soldier, QOverload::of(Soldier::fight)); connect(commander, QOverloadQString::of(Commander::go), soldier, QOverloadQString::of(Soldier::fight));写法来源适用 Qt 版本作用QOverloadQt 官方宏大写 QQt5 Qt6 都支持✅取重载函数地址qOverload早期辅助函数小写 q仅 Qt5 支持❌同上48. QMetaObject::invokeMethod因为在 Qt 中直接在不同线程中调用对象的方法是不安全的。invokeMethod可以确保方法的调用是在目标对象所在的线程上执行的从而避免线程安全性问题。方案用法优点缺点1. QMetaObject::invokeMethod直接调用对象函数最简单、万能、动态依赖字符串函数名2. 信号 槽Qt 官方推荐发信号 → 槽函数执行最安全、最标准、无耦合需要写信号槽3. QTimer::singleShot丢到目标线程执行简单不优雅、不正式4. moveToThread 异步函数把对象丢到线程直接调用结构清晰必须把对象移到线程必须用它的场景子线程更新主线程 UI最常用线程 A 调用线程 B 里对象的函数不想写信号槽想直接调用函数调用 private /protected 函数动态调用函数函数名是字符串QMetaObject::invokeMethod( obj, 函数名, Qt::QueuedConnection );49. 如何隐藏ui中的布局方案 1把布局放到一个QWidget里 → 隐藏这个 widget ✅最推荐方案 2遍历布局里的所有控件 → 全部隐藏for (int i 0; i layout-count(); i) { QWidget* w layout-itemAt(i)-widget(); if (w) w-hide(); // 隐藏控件 }50. 设置界面可拖放setAcceptDrops(true);void YourDialog::dragEnterEvent(QDragEnterEvent *event) { if (!event-mimeData()-hasUrls()) return; QListQUrl urls event-mimeData()-urls(); // 限制只能拖 1 个 if (urls.size() ! 1) return; // 获取文件路径 QString path urls.first().toLocalFile(); // 限制后缀必须是 .jatac if (path.endsWith(.jatac, Qt::CaseInsensitive)) // 不区分大小写 { event-acceptProposedAction(); } } // 松开后获取文件路径 void YourDialog::dropEvent(QDropEvent *event) { QString filePath event-mimeData()-urls().first().toLocalFile(); qDebug() 拖入的文件 filePath; }或者可以在类中为界面安装过滤事件,事件中可以对各种拖放等事件进行处理ui-genereate_drag_widget-installEventFilter(this);bool IntegrityCheck::eventFilter(QObject *watched, QEvent *event) { if (event-type() QEvent::DragEnter) { QDragEnterEvent *dragEvent static_castQDragEnterEvent*(event); if (dragEvent-mimeData()-hasUrls()) { bool hasOnlyFiles true; for (const QUrl url : dragEvent-mimeData()-urls()) { QFileInfo info(url.toLocalFile()); if (!info.isFile()) { hasOnlyFiles false; break; } } if (hasOnlyFiles) { dragEvent-setDropAction(Qt::MoveAction); dragEvent-accept(); } else { dragEvent-ignore(); // 含有文件夹禁止放置 } return true; } } else if (event-type() QEvent::Drop) { QDropEvent *dropEvent static_castQDropEvent*(event); if (dropEvent-mimeData()-hasUrls()) { QListQUrl urls dropEvent-mimeData()-urls(); QStringList files; for (const QUrl url : urls) { QString filePath url.toLocalFile(); if (!filePath.isEmpty()) { files filePath; } } generateHashProgress(files); return true; } } else if (event-type() QEvent::MouseButtonPress) { on_integrity_drag_btn_clicked(); return true; } return QWidget::eventFilter(watched, event); }if (event-type() QEvent::DragEnter || event-type() QEvent::Drop) { // 你自己处理拖放 return true; // ✅ 拦截不让控件自己处理 } return false; // ✅ 其他事件不管继续传递

更多文章