-
.pro文件:
1、本质Makefile文件 2、CONFIG配置选项:设置项目的配置信息和编译选项 3、-debug 构建debug版本可执行程序 4、-release 构建release版本可执行程序 5、debug and release 构建debug和release版本可执行程序 6、warn on 尽可能多的打印警告信息 7、warn off 不输出警告信息
-
软件开发流程
- 需求分析->功能分解->功能实现->功能测试(重构)->系统测试->发布
- 尽量将界面代码与功能代码分离开
- 尽量复用平台提供的组件
-
sender()函数,可以获取信号的发送者的指针
-
QT vs STL,有stl为什么qt要再实现一遍
- STL的标准只是接口标准,实现根据不同厂商而定
- 相同的全局函数
- 相同的算法类和数据结构类
- 相同的类成员函数
- qt字符串类优点
- 采用Unicode编码
- 使用隐式共享技术来节省内存和不必要的内存拷贝
- 跨平台使用时,不必考虑字符串的平台兼容性
-
对话框
- QDialog
- QDialog是qt中所有对话框的基类
- QDialog继承于qwidget是一种容器类型的组件
- QDialog不能作为子部件嵌入到其他容器中
- QDialog是定制了窗口样式的qwidget
- QDialog必须为顶层组件
- 通过QDialog::setModel函数可以设置混合特性的对话框,非模态对话框做模态对话框使用
- dialog->setAttribute(Qt::WA_DeleteOnClose);
- dialog->setModel(this);
- 通过QDialog::setModel函数可以设置混合特性的对话框,非模态对话框做模态对话框使用
- 模态对话框
- 阻塞式,无法与父窗口交互,QDialog::exec()
- 一般在栈上创建
- 返回值为交互结果
- void QDialog::done(int i)将i作为交互结果
- QDialog::Accepted成功
- QDialog::Rejected失败
- 当作为主窗口是不要再次调用a.exec()了
- 非模态对话框
- 非阻塞式,QDialog::show()
- 一般在堆上创建
- 需要指定dialog->setAttribute(Qt::WA_DeleteOnClose)属性
- 原因:在函数内的堆上创建后,关闭对话框不会释放资源
- 指定父类才可以保证显示在顶层
- 登录对话框(复用)
- 标准对话框
- QMessageBox
- QFileDialog
- QPrintDialog
- QColorDialog
- QFontDialog
- QInputDialog
- QProgressDialog
- QDialog
-
布局管理器
- QLayout是界面组件的定位策略
- QBoxLayout
- QgridLayout
- QFormLayout表单布局
- QStackLayout
- 组件大小一致,充满父组件的显示区
- 不能嵌套其他布局管理器(可以嵌套个qwidget里面再次布局)
- 能够自由切换需要显示的组件
- 设置比例系数:void setStretch(int index, int stretch)
- QLayout是界面组件的定位策略
-
文本编辑器
- construct
- initMenuBar
- initFileMenu
- initEditMenu
- initFormatMenu
- initViewMenu
- initHelpMeny
- initToolBar
- initFIleToolItem
- initEditToolItem
- initFormatToolItem
- initViewToolItem
- initStatusBar
- initMainEditor
- 使用QMap对保存时的后缀进行判断
- QplainText有对应的内部信号和槽函数设置拷贝剪切撤销等操作
- initMenuBar
- construct
-
软件开发流程
- 即兴模型
- 瀑布模型
- 增量模型
- 螺旋模型
- 敏捷模型
-
文件操作
-
QFile
- 支持文本文件和数据文件的读写
- QTextStream
- QDatastream
- 当数据流文件在不同版本的QT程序之间传递数据时,需要考虑版本问题
- void setVersion(QDataStream::Qt_4_7)
- int version()const
-
QFileInfo
-
QTemporaryFile
-
安全的创建一个全局唯一的临时文件
-
当对象销毁时对应的临时文件将被删除
-
临时文件的打开方式:QIODevice::ReadWrite
-
临时文件常用于大数据传递或者进程间通信
QTemporaryFile tempFile; if(tempFile.open()) { tempFile.write("zhang"); tempFile.close(); }
-
-
缓冲区
- 在线程间进行不同类型的传递
- 缓存外部设备中的数据返回
- 数据读取速度小于数据写入速度
QByteArray array; QBuffer buffer(&array); if(buffer.open(QIODevice::WriteOnly)) { QDataStream out(&buffer); out << "zhang"; buffer.close(); }
-
QDir
const char* PATH = "./dir"; QDir dir; if(!dir.exists(PATH)) { dir.mkdir(PATH); } if(dir.exists(PATH)) { dir.cd(PATH); QStringList list = dir.entryList(); for(int i=0; i< list.count(); i++) { } } //计算文件大小 unsigned int calculate_size(QString path) { QFileInfo info(path); unsigned int ret = 0; if(info.isFile()) { ret = info.size(); } else if(info.isDir()) { QDir dir(path); QFileInfoList list = dir.enteryInfoList(); for(int i = 0 i< list.count(); i++) { if( (list[i].fileName() != ".") && (list[i].fileName() != "..") { ret += calculate_size(list[i].absolateFilePath); } } } return ret; }
-
QFileSystemWather
- 能够监控特定目录和文件的状态
- 能够同时对多个目录和文件进行监控
- 当目录或者文件发生改变时触发信号
- 通过信号槽机制捕获信号
-
-
QMap & QHash
-
QMap
- QMap以升序顺序存储键值对
- 原型为class QMap<K, T>模板
- 根据key值进行了排序
- key类型必须重载了operator<
-
QHash
- QHash原型为class QHash<K, T>模板
- QHash中的键值对在内部无序排列
- QHash中的key类型必须重载operator==
- QHash中的key对象必须重载全局哈希函数qHash(),得到不同的id
-
比较
- 接口相同,可直接替换使用
- QHash查找速度明显低于QMap
- QHash占用的存储空间明显多于QMap
- QHash以任意方式存储数据
- QMap以key顺序存储元素
- QHash的key必须提供operator==()和qHash(key)函数
- QMap的key类型必须提供operator<()函数
-
Qt中的事件处理
-
处理顺序:事件过滤器->焦点部件的event()->焦点部件的具体事件处理函数->焦点部件忽略该事件后会传递到父组件的事件处理函数
-
QEvent
- QInputEvent
- QDropEvent
- QPaintEvent
- QCloseEvent
- QTimerEvent
-
QEvent* e
- e->accept();//表示事件已经被处理
- e->ignore();//表示忽略该事件,事件可能传递给父组件
- e->isAccepted();//判断当前是哪是否被处理
-
事件被组件对象处理后的消息有可能传递到其他父组件
-
eventFilter
-
拖拽事件
-
对应部件类中重写函数
void dragEnterEvent(QDragEnterEvent* e) { if(e->minmeData->hasUrls()) e->acceptProposeAction(); else e->ignore(); } void dropEvent(QDropEvent* e) { if(e->minmeData->hasUrls()) { QList<QUrl> list = e->mimeData()->urls(); qDebug() << list[0].toLocalFile(); } else e->ignore(); }
-
-
-
文本打印与光标定位
-
MVC架构:界面与界面内的数据分离技术
-
QPlainTextEdit本身只负责界面形态显示,内部通过QTextDocument对象存储文本数据
-
光标位置计算QTextCursor
QTextCusor c = mainEditor.textCursor();//获取当前光标 c.setPosition(1);//定位到下标为1的位置 c.setPosition(4, QTextCursor::KeepAnchor);//文本选择范围[1,4] mainEditor.setTextCursor(c);//设置光标信息到文本框
-
光标定位行列号算法没看懂!!!
-
-
自定义信号事件
-
QApplication类
-
阻塞型发送函数:
- bool sendEvent(QObject* receiver, QEvent* event);
- 函数内部调用的是QObject中的event()事件
- 同时支持栈事件对象和堆事件对象的发送
-
非阻塞型发送函数:
- void postEvent(QObject* receiver, QEvent* event);
- 发送成功后,将消息放入到消息队列中,并立即返回,将消息分发下去
- 只能发送堆事件,结束后有QT平台销毁
-
模拟键盘delete按下事件
void onEditDelete() { QKeyEvent keyPress(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier); QKeyEvent keyRelease(QEvent::KeyRelease, Qt::Key_Delete, Qt::NoModifier); //发送阻塞事件 QApplication::sendEvent(&mainEditor, &keyPress); QApplication::sendEvent(&mainEditot, &keyRelease); }
-
-
自定义事件类
- 必须继承自QEvent
- 必须拥有全局唯一的Type(自定义)值
- QEvent::User + value
- 程序中必须提供处理自定义事件对象的方法
- 将事件过滤器安装到目标对象,在eventFilter()函数中编写处理逻辑
- 或
- 重写event()函数,编写处理逻辑
- 使用情况
- 需要扩展一个已有组件类的功能
- 需要开发一个全新功能的组件类
- 需要向一个第三方的组件类发送消息
-
-
查找对话框设计,功能复用
-
替换对话框
-
Qt调色板
-
QPalette
- 激活颜色组(Active) 组件获得焦点使用的颜色方案
- 非激活颜色组(Inactive) 组件失去焦点使用的颜色方案
- 失效颜色组(Disabled) 组件处于不可用状态的颜色方案
- 使用
QPalette p =widget.palette(); p.setColor(QPalette::Active,QPalette::WindowText, Qt::blue); p.setColor(QPalette::Inactive, QPalette::WindowText, Qt::blue); widget.setPalette(p);
-
-
QDesktopServices::openUrl(QUrl(“path”));
-
命令行参数的应用
-
操作系统关联方式:文件双击运行,将文件路径作为命令行参数启动应用程序
mainWindow* w = MainWindow::NewInstance(); if(w != NULL) { if(argc > 1) { QFIleInfo info(argv[1]); if(info.exists()) { //打开文件 } } }
-
-
模型视图设计模式
-
思想:
- 将数据与现实分离
- 模型对外提供标准接口存取数据
- 视图自定义数据显示格式
- 模型中的数据都是以层次结构表示的
- 索引在需要是由模型创建
- 使用空索(虚拟父节点)引作为父节点表示顶层数据元素
-
必须为每一个数据提供独一无二的索引,视图通过索引访问模型中的具体数据
QFileSystemModel fsModel; //文件系统模型 QTreeView treeView; //属性显示视图 QString path = QDir::currentPath(); //要显示的目录 fsModel.seetRootPath(path); //从当前目录获取数据 treeView.setModel(&fsModel); //连接模型视图 treeView.setRootIndex(fsModel.index(path)); //设置属性视图的数据索引
-
类型
- 线性模型使用行列作为数据索引
- QModelIndex index = model->index(row, col);
- 非线性模型(树)
- 虚拟一个root节点,通过(index,parent)方式确定
- 三元组
- (row, col, parent)
- 线性模型使用行列作为数据索引
-
标准模型定义
QStandardItemModel model; QStandardItem* root = model.invisibleRootItem();//获取虚拟节点 QStandardItem* item1 = new QStandardItem(); QStandardItem* item2 = new QStandardItem(); item1->setData("aa", Qt::DisplayRole); item1->setData("bb", Qt::ToolTipRole); //角色定义 Qt::DisplayRole //作为直接可见的提示信息 Qt::DecorationRole //以图表方式显示 Qt::EditRole //可编辑的数据信息 Qt::ToolTipRole //悬浮框中的补充型提示信息 Qt::StatusTipRole //在状态中显示的提示性信息 Qt::WhatsThisRole //悬浮框中的详细帮助信息 Qt::SizeHintRole //数据大小信息 item2->setData("cc");//问题:必须设置角色属性否则无法显示,因为数据级别相同,无法区分 item2->setData("dd"); root->setChild(0, 0, item1); root->setChild(0, 1, item1); //不同视图显示的数据模型样式可能不同 tableView.setModel(&m_model); listView.setModel(&m_model); treeView.setModel(&m_model);
-
数据角色
- 模型中的数据在视图中的用途(显示方式)可能不同
- 模型必须为数据设置特定的属性
- 数据角色用于提示视图数据的作用
- 数据角色是不同视图以统一风格显示数据的标准
-
自定义模型类
- QStandardItemModel
- 能够以任意方式组织数据(线性,非线性)
- 数据组织的基本单位(QStandardItem)
- 每个数据项能够存储多个数据(数据角色)
- 每个数据项能够对数据状态进行控制
- 变体类型QVariant
- 用于封装的类型
- 能够表示大多数常见的值类型
- 每次只能保存单一类型的值
- 意义:能够设计 返回类型可变的函数
- 系统架构
- 数据显示层->数据组织层->数据表示层->数据层
- QStandardItemModel
-
视图 - 委托
- QStyleItemDeletgate
- 重写
- createEditor
- updateEditorGeometry
- setEditorData
- setModelData
- paint(可选)
- 重写
- 是视图中处理用户输入的部件
- 视图可以设置委托对象用于处理用户输入
- 委托能够提供编辑是需要的上下文环境
- 不同委托提供的编辑器类型不同(文本框,单选框)
- 编辑器从模型获取数据,并将编辑结果返回模型
- 委托也会负责部分数据的显示,如框体线
- paint负责数据绘制
- 自定义组件绘制
- 重写委托paint,处理数据显示方式
- 重写editorEvent,处理交互事件
- QStyleItemDeletgate
-
-
信号槽
- 信号只是一个特殊的成员函数声明
- 函数只能声明不能定义
- 函数返回值必须是void
- 信号必须使用signals关键字声明
- 函数的访问属性自动设置为protected
- 只能通过emit关键字触发信号
- 要求
- qt只能在头文件中声明
- 信号与槽的类型应完全相同
- 信号的参数个数可以多余槽的参数个数,多余的会被忽略
- 信号和槽的返回值必须是void
- 槽函数可以像普通函数一样调用
- 信号槽的访问属性对应connect和disconnect无效
- 意义
- 最大限度的弱化了类之间的耦合
- 在设计阶段可以减少不必要的接口类(抽象类)
- 在开发阶段,对象之间的交互使用信号槽动态绑定
- 信号只是一个特殊的成员函数声明
-
图形绘制
-
QPainter
- painter.setViewport();//设置视口,物理窗口的大小,即要显示窗口占总窗口的大小
- painter.setWindow();//设置窗口,逻辑坐标系大小,可以设置在指定视口范围内的坐标表示范围,即自定义坐标系
-
画图软件
-
图像
-
QImage
- 独立于具体硬件的图像类
- 针对IO访问设计
- 能够像素级访问
-
QPixmap
- 依赖具体硬件的图像类
- 针对屏幕设计,不可移植
-
灰度化
image = img.scaled(QSize(200, 200), Qt::KeepAspectRatio); for(int i=0; i<image.width(); i++) { for(int j = 0; j< image.height(); j++) { QRgb rgb = image.pixel(i, j); int r = QRed(rgb); int g = QGreen(rgb); int b = Qblue(rgb); int gray = (r + g + b) / 3; image.setPixel(i, j, QRgb(gray, gray, gray)); } }
-
屏幕截图
WId id = QApplication::desktop()->winId(); QPixmap pixmap = QPixmap::grabWindow(win); QImage image = pixmap.toImage(); image.save("image.png"); //grabWindow()用于对屏幕像素进行抓取 //grabWidget()用于对当前程序中的组件外观图像进行抓取
-
绘制文本
- QFontMettics获取字符串在指定字体下的宽高
- 通过改变字体大小产生字体由远到近的效果(动画效果)
- 在QPainter中可以自定义文字颜色、位置、字体、旋转
- QPainter可以将文字绘制与图片(水印效果)
-
-
-
进程&线程
-
程序&进程
- 源代码程序:文本文件,描述程序行为和功能
- 可执行程序:二进制文件,可以直接加载运行
-
进程
- 广义:程序关于某一个数据集合的一次运行活动
- 狭义:程序被加载早内存中执行后得到进程
-
程序和进程的区别
- 程序是硬盘中静态的文件,二进制文件
- 进程是内存中动态运行的实体,数据段,代码段,pc指针,等
- 一个程序可能对应多个进程,一个程序多次运行每个都是一个进程
- 一个进程可能包含多个程序,如:加载的其他动态库
-
当代操作系统中资源分配的单位的进程,CPU调度的基本单位是线程
-
QT多线程
- 不要使用terminate终止,会导致资源无法释放
- 方法:添加公有函数stop(),添加成员变量volatile bool m_toStop;使得run函数可以正常返回,且必须使用volatile关键字,每次从内存中取数据,不允许编译器做优化!!!
- 使用模式
- 无事件循环模式
- 耗时操作:文件复制,网络数据读取
- 开启事件循环模式
- 执行事务性操作:文件写入,数据库写入等
- 无事件循环模式
-
多线程同步
- QThread t; t.wait();
-
多线程互斥
-
生产者&消费者
-
QMutex
- lock();会判断当前锁是否空闲,必须调用unlock()解锁
- 锁在调用unlock()时是空闲状态,程序行为是未定义的
- 死锁
- 多个锁时,处理顺序不同,互相等待对方释放锁,可能会产生互锁
- 多个临界资源且临界资源不可抢占
- 线程需要多个临界资源才能执行
- 解决
- 对临界资源分配唯一ID,且对线程锁分配同样的ID,并且每个线程严格按照递增顺序请求资源
-
信号量QSemaphore
-
信号量是特殊的线程锁
-
信号量允许多个线程同时访问临界资源
-
QSemaphore内部维护一个整型值,每次使用acquire()减一,使用release()加一
QSemaphore sem(1); sem.acquire(); //do someting sem.release(); 等价于 QMutex mutex; mutex.lock(); //do something mutex.unlock();
-
-
-
-
银行家算法
- 将资金优先借给资金需求少的客户
- 应用场景
- 操作系统内核中的进程管理
- 数据库内核中的频繁事物管理
-
多线程信号槽
- 操作系统通过整型标识管理进程和线程
- 进程拥有全局唯一的ID值(PID)
- 线程拥有进程内的唯一ID值(TID)
- QThread
- QThread::currentThread();
- Qt::HANDLE currentThreadId();
- 线程拥有独立的栈空间用于函数调用
- 没有临界资源的函数可以无副作用的被多个线程调用
- QObject::moveToThread用于改变对象的线程依附性
- 线程中的事件循环
- 信号槽的机制需要事件循环的支持
- QThread类中提供了exec()函数(在run函数内部调用exec();)开始线程到的事件循环
- 调用了exec()开启了事件循环,run函数就不会返回,线程就没办法结束
- 解决:在线程启动后等待一定时间,thread.wait(1000)后,调用thread.quit()或者thread.exit(0)结束线程,(quit() == exit(0))
- 只有开启了事件循环,槽函数(线程内的)才能在信号发送后被调用(在依附的线程中被调用)
- 意义:
- 当信号和槽函数在不同线程时,可能产生临界资源的竞争问题
- 信号槽连接方式
- 立即调用:Qt::DirectConnection
- 异步调用:Qt::QueuedConnection
- 同步调用:Qt::BlockingQueuedConnection
- 默认连接:Qt::AutoConnection
- 单一连接:Qt::UniqueConnection
- 操作系统通过整型标识管理进程和线程
-
线程生命周期
-
准则
- 线程对象的生命周期 > 对应线程的生命周期
-
同步性线程设计
- 概念:
- 线程对象主动等待线程生命周期结束后才销毁
- 特点:
- 同时支持在栈和堆上创建线程对象
- 对象销毁时确保线程生命周期结束
- 使用方法:
- 在线程类的析构函数中调用wait()函数,等待线程结束再销毁线程
- 概念:
-
异步型线程设计
- 概念:
- 线程生命周期结束时通知销毁线程对象
- 特点:
- 只能在堆上创建线程对象
- 线程对象不能被外界主动销毁
- 使用场景:
- 线程生命周期不可控,需要长时间运行于后台
- 使用方法:
- 在run()函数中最后调用deleteLater()函数,会在线程结束后申请销毁调用run的对象
- 使用二阶构造,以保证在堆上创建对象,且不会主动调用析构函数销毁对象,以向qt平台发送的deleteLater()来申请销毁对象
- 概念:
-
线程创建方式
- 在类中定义一个槽函数void tmain();作为线程入口函数
- 在类中定义一个QThread成员对象m_thread;
- 改变当前对象的线程依附到m_thread
- 连接m_thread的start()到tmain();
-
多线程与界面组件通信
- 方式一:
- GUI只能在主线程操作,界面组件必须依赖于主线程
- 使用信号槽通信,连接必须采用异步连接方式
- 方式二:
- 自定义事件类用于描述界面更新细节
- 在主窗口类中冲写事件处理函数event()
- 使用postEvent函数(异步方式)发送自定义事件
- 方式一:
-
Qt问题:
- GUI系统的核心模型和机制是什么?
- 界面组件间的父子关系有什么意义?
- 信号槽的使用方式?
- 多线程和界面组件的关系是什么?
-
qt基础笔记
最新推荐文章于 2024-09-11 17:54:03 发布