当前位置: 首页 > news >正文

公众号的微网站怎么做优惠券网站开发哪家好

公众号的微网站怎么做,优惠券网站开发哪家好,国家企业信用信息公示系统查询网,磁县邯郸网站建设目录 1概述1.1 什么是QT1.2 QT的发展史1.3 支持的平台1.4 QT版本1.5 下载与安装1.6 QT的优点1.7 成功案例 2 创建 Qt 项目2.1 使用向导创建2.2 .pro文件2.3 帮助文档(QTcreator自带的)2.4 QT应用程序介绍 3 创建第一个小程序3.1 按钮的创建3.1.1 设置主窗口标题的函数3.1.2 **固… 目录 1概述1.1 什么是QT1.2 QT的发展史1.3 支持的平台1.4 QT版本1.5 下载与安装1.6 QT的优点1.7 成功案例 2 创建 Qt 项目2.1 使用向导创建2.2 .pro文件2.3 帮助文档(QTcreator自带的)2.4 QT应用程序介绍 3 创建第一个小程序3.1 按钮的创建3.1.1 设置主窗口标题的函数3.1.2 **固定大小函数**3.1.3 创建按钮3.1.3.1 创建一个按钮3.1.3.2 创建第二个按钮3.1.3.3 移动函数3.1.3.4 创建第三个按钮3.1.3.5 重设大小 3.2 对象模型(对象树)3.3 Qt窗口坐标体系 4 信号和槽机制4.1 系统自带的信号和槽4.1.1 点击控件关闭窗口 4.2 自定义信号和槽4.2.1 无参的信号和槽4.2.2 带参数的信号和槽4.2.3 定义信号槽需要注意的事项 4.3 信号槽的拓展4.4 Qt4版本的信号槽写法4.5 lambda表达式 5 QMainWindow5.1 菜单栏5.1.1 添加菜单栏5.1.2 添加菜单5.1.3 在菜单里添加菜单项5.1.4 给菜单项添加快捷键5.1.5 给菜单项添加行为5.1.5 在菜单项之间添加分隔符 5.2 工具栏5.2.1 添加工具栏5.2.2 添加工具栏选项5.2.3 设置工具栏是否可浮动5.2.4 设置工具栏允许停靠的位置5.2.5 其他相关函数 5.3 状态栏5.3.1 创建状态栏5.3.2 添加标签5.3.3 其他相关函数 5.4 核心部件(中心部件)5.5 铆接部件5.6 资源文件5.6.1 添加资源文件5.6.2 使用资源 6 UI界面6.1 认识UI6.2 基本使用6.3 控件的使用 7 对话框QDialog7.1 基本概念7.2 标准对话框7.3 自定义消息框7.3.1 模态对话框7.3.2 非模态对话框 7.4 消息对话框7.4.1 显示严重错误对话框7.4.2 信息对话框7.4.3 提问对话框 7.5 字体对话框7.6 颜色对话框7.6.1 获取颜色函数7.6.2 输出对应三原色的值 7.7 标准文件对话框7.7.1 获取打开的文件名7.7.2 添加打开时显示的指定路径7.7.3 打开某路径下某类型文件7.7.4 设置多个类型文件同时显示 7.8 下拉列表框7.8.1 UI添加内容7.8.2 代码添加7.8.3 添加行为 8 布局管理器8.1 系统提供的布局控件8.2 利用widget做布局8.2.1 ui布局8.2.2 设计行为 9 容器container9.2 设计行为9.2.1 选中输出9.2.2 默认选择 10 常用控件10.1 QLabel控件使用10.1.1 显示文字(普通文本、html)10.1.2 显示图片10.1.3 显示动画 10.2 QLineEdit10.3 列表控件QListWidget10.4 树控件QTreeWidget10.4.1 ui添加10.4.2 代码添加10.4.3 添加行为 10.5 表格控件QLabelWidget10.5.1 ui添加10.5.2 代码添加10.5.3 添加行为 10.6 其他控件10.7 自定义控件10.7.1 创建自定义控件类10.7.2 使用自定义控件类10.7.3 添加动作10.7.4 设置对外接口 11 Qt消息机制和事件11.1 事件11.1.1 重写准备11.1.2 重写事件11.1.2.1 重写鼠标进入和离开事件11.1.2.2 重写鼠标按下和拖动事件11.1.2.3 重写获取鼠标哪个按键按下11.1.2.4 重写获取鼠标的坐标 11.2 事件分发器11.3 事件过滤器11.4 总结 12 定时器12.1 触发方式12.2 实现定时器12.2.1 定时器事件触发12.2.1.1 单个定时器12.2.2.2 同时启动多个定时器 12.2.2 定时器对象触发12.2.3 静态成员函数触发 13 绘图和绘图设备13.1 QPainter13.1.1 窗口加载背景13.1.2 update()重新加载13.1.3 绘制其他图案13.1.3.1 画线13.1.3.2 画矩形rect13.1.3.3 修改画笔颜色13.1.3.4 修改画笔样式13.1.3.5 画圆13.1.3.6 画椭圆13.1.3.7 画扇形 13.2 绘图设备13.2.1 QPixmap、QBitmap、QImage13.2.1.1 使用QBitmap绘图13.2.1.2 使用QImage绘图 13.2.2 QPicture 1概述 1.1 什么是QT Qt 是一个跨平台的 C图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面所需的所有功能。它是完全面向对象的很容易扩展并且允许真正的组件编程。 1.2 QT的发展史 1991年 Qt 最早由奇趣科技开发1996年 进入商业领域它也是目前流行的 Linux 桌面环境KDE 的基础2008年 奇趣科技被诺基亚公司收购Qt 称为诺基亚旗下的编程语言2012年 Qt 又被 Digia公司收购2014年4月 跨平台的集成开发环境Qt Crcator3.1.0发布同年5月20日配发了Qt5.3正式版至此Qt 实现了对 iOS、Android、WP 等各平台的全面支持 1.3 支持的平台 Windows - XP、Vista、Win7、Win8、Win2008、Winl0Uinux/X11 - Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX、FreeBSD、BSD/0S、和其他很多X11平台Macintosh - Mac OS XEmbedded- 有帧缓冲支持的嵌入式 Linux平台Windows CE 1.4 QT版本 Qt 按照不同的版本发行分为商业版和开源版 商业版 ​ 为商业软件提供开发他们提供传统商业软件发行版并且提供在商业有效期内的免费升级和技术支持服务 开源的 LGPL版本: ​ 为了开发自有而设计的开放源码软件它提供了和商业版本同样的功能在GNU 通用公共许可下它是免费的。 1.5 下载与安装 官网https://www.qt.io/download-open-source 1.6 QT的优点 跨平台几乎支持所有的平台接口简单容易上手学习 QT 框架对学习其他框架有参考意义。一定程度上简化了内存回收机制开发效率高能够快速的构建应用程序。有很好的社区氛围市场份额在缓慢上升。可以进行嵌入式开发面向对象 Qt 的良好封装机制使得 Qt 的模块化程度非常高可重用性较好对于用户开发来说 是非常方便的。QT提供了一种称为 signals/slots 的安全类型来替代 callback这使得 各个元件之间的协同工作变得十分简单。丰富的 APIQt 包括多达 250 个以上的 C 类还提供基于模板的 collections serialization file I/O devicedirectory management date/time 类。甚至还 包括正则表达式的处理功能,支持 2D/3D 图形渲染支持 OpenGL。 1.7 成功案例 Linux 桌面环境 KDEWPS Office 办公软件Skype 网络电话Google Earth 谷歌地图VLC 多媒体播放器VirtualBox 虚拟机软件… 2 创建 Qt 项目 2.1 使用向导创建 QMainWindow带菜单栏的窗口QWidget精简版窗口QDialog对话框 完成 crtlR创建 2.2 .pro文件 在使用 Qt 向导生成的应用程序.pro 文件格式如下 QT core gui //包含的模块 greaterThan(QT_MAJOR_VERSION, 4): QT widgets //大于 Qt4 版本 才包含 widget 模块低于包含在上面gui TARGET QtFirst //应用程序名 生成的.exe 程序名称 TEMPLATE app //模板类型 应用程序模板 SOURCES main.cpp\ //源文件mywidget.cpp HEADERS mywidget.h //头文件.pro 就是工程文件(project)它是 qmake 自动生成的用于生产 makefile 的配置文件。 .pro 文件的写法如下 注释 从“#”开始到这一行结束。 模板变量告诉 qmake 为这个应用程序生成哪种 makefile。下面是可供使用的 选择TEMPLATE app app -建立一个应用程序的 makefile。这是默认值所以如果模板没有被指定这个将被使用。 lib - 建立一个库的 makefile。 vcapp - 建立一个应用程序的 VisualStudio 项目文件。 vclib - 建立一个库的 VisualStudio 项目文件。 subdirs -这是一个特殊的模板它可以创建一个能够进入特定目录并且 为一个项目文件生成 makefile 并且为它调用make 的 makefile。 #指定生成的应用程序名 TARGET QtDemo #工程中包含的头文件 HEADERS include/painter.h #工程中包含的.ui 设计文件 FORMS forms/painter.ui #工程中包含的源文件 SOURCES sources/main.cpp sources #工程中包含的资源文件 RESOURCES qrc/painter.qrc greaterThan(QT_MAJOR_VERSION, 4): QT widgets 这条语句的含义是如果 QT_MAJOR_VERSION 大于 4(也就是当前使用的 Qt5 及更高版本)需要增加 widgets 模块。如果项目仅需支持 Qt5也可以直接 添加“QT widgets”一句。不过为了保持代码兼容最好还是按照 QtCreator 生成的语句编写。 #配置信息 CONFIG 用来告诉 qmake 关于应用程序的配置信息。 CONFIG c11 //使用 c11 的特性 。在这里使用“”是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“”那样替换已经指定的所有选项更安全。 2.3 帮助文档(QTcreator自带的) 例如QPushButton Public Functions //公共函数 Public Slots //公共槽函数Header: #include QPushButton //头文件 qmake: QT widgets //所在模块 Inherits: QAbstractButton //父类 Inherited By: QCommandLinkButton //子类2.4 QT应用程序介绍 首先对于main函数 #include widget.h #include QApplicationint main(int argc, char *argv[]) {//应用程序类初始化我们的应用程序QApplication a(argc, argv);//创建一个主窗口控件Widget w;//显示一个窗口hide隐藏窗口(窗口默认隐藏)w.show();//主事件循环带阻塞等待用户操作界面return a.exec(); }解释 Qt 系统提供的标准类名声明头文件没有.h 后缀 即系统头文件 Qt 一个类对应一个头文件类名就是头文件名 QApplication 应用程序类 管理图形用户界面应用程序的控制流和主要设置 是 Qt 的整个后台管理的命脉它包含主事件循环在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束 并且提供对话管理 对于任何一个使用 Qt 的图形用户界面应用程序都正好存在一个 QApplication 对象而不论这个应用程序在同一时间内是不是有 0、1、 2 或更多个窗口 a.exec() 程序主事件循环进入消息循环等待对用户输入进行响应。这里 main()把控制权转交给 QtQt 完成事件处理工作当应用程序退出的时候 exec()的值就会返回。 在 exec()中Qt 接受并处理用户和系统的事件并且把它们传递给适当的窗口部件 在实际设计界面时我们只需要在窗口控件的构造函数中设计即可而不在main函数中设计 3 创建第一个小程序 3.1 按钮的创建 首先我们知道窗口控件widget继承于QWidget 因此我们创建按钮时要在QWidget里寻找对应的函数 3.1.1 设置主窗口标题的函数 setWindowTitle(const QTstring )是在槽函数 同时这里也可以看到函数左边有个带凹槽的图标即说明是槽函数 this-setWindowTitle(The first window);运行 在输出为中文时显示可能为乱码将文件编码改为UTF-8即可 3.1.2 固定大小函数 void setFixedSize(const QSize s) void setFixedSize(int w, int h)有两个重载我们使用第二个指定宽高 this-setFixedSize(400,300);此时鼠标在边缘无法再拖动修改大小 3.1.3 创建按钮 使用QPushButton The QPushButton widget provides a command button. More...Header: #include QPushButton qmake: QT widgets Inherits: QAbstractButton Inherited By:QCommandLinkButton构造函数3个重载 QPushButton(const QIcon icon, const QString text, QWidget *parent nullptr) QPushButton(const QString text, QWidget *parent nullptr)//文本 //要放置在哪里即哪个窗口 QPushButton(QWidget *parent nullptr)3.1.3.1 创建一个按钮 包含头文件后我使用第二个 QPushButton *button new QPushButton(button1,this);new完后不需要手动 delete关闭后将会被父类结束所有窗口 3.1.3.2 创建第二个按钮 接下来创建button2 QPushButton *button new QPushButton(button1,this);QPushButton *button2 new QPushButton(button2,this);发现button1消失因为2个都是默认控件会自动显示到窗口的左上方 这时就需要将button2移动到其他地方 3.1.3.3 移动函数 经过查询是在QWidget类中才有move移动函数 void move(const QPoint ) void move(int x, int y)button2-move(200,150);3.1.3.4 创建第三个按钮 // button3QPushButton *button3 new QPushButton;button3-setParent(this); //设置父亲即将展示在哪个窗口button3-setText(button3);//设置文字button3-move(100,75); //移动位置上面代码中一个按钮其实就是一个 QPushButton 类下的对象如果只是创建出对象 是无法显示到窗口中的所以我们需要依赖一个父窗口也就是指定一个父亲利用 setParent 函数即可如果想设置按钮上显示的文字利用 setText移动按钮位置用 move 3.1.3.5 重设大小 // 重设大小this-resize(800,600);注意前面有setFixedSize则必须将其注释否则大小固定 3.2 对象模型(对象树) 在 Qt 中创建对象的时候会提供一个 Parent 对象指针下面来解释这个 parent到底是干什么的。 QObject 是以对象树的形式组织起来的。 当你创建一个 QObject 对象时会看到 QObject 的构造函数接收一个QObject 指针作为参数这个参数就是 parent也就是父对象指针。这相当于在创建 QOb.ject 对象时可以提供一个其父对象我们创建的这个 QObject 对象会自动添加到其父对象的 childrenO列表当父对象析构的时候这个列表中的所有对象也会被析构。(注意这里的父对象并不是继承意义上的父类。)这种机制在 GUI 程序设计中相当有用。例如一个按钮有一个QShortcut(快捷键) 对象作为其子对象。当我们删除按钮的时候这个快捷键理应被删除。这是合理的 QWidget 是能够在屏幕上显示的一切组件的父类。 QWidget 继承自 QObject因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此它会显示在父组件的坐标系统中被父组件的边界剪裁。例如当用户关闭一个对话框的时候应用程序将其删除那么我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此因为这些都是对话框的子组件。当然我们也可以自己删除子对象它们会自动从其父对象列表中删除,比如当我们删除了一个工具栏时其所在的主窗口会自动将该工具栏从其子对象列表中删除并且自动调整屏幕显示。 Qt 引入对象树的概念在一定程度上解决了内存问题 当一个 QObject 对象在堆上创建的时候Qt 会同时为其创建一个对象树不过对象树中对象的顺序是没有定义的。这意味着销毁这些对象的顺序也是未定义的。任何对象树中的 QObject 对象 delete 的时候如果这个对象有 parent,则自动将其从 parent 的 children0列表中删除;如果有孩子则自动delete 每一个孩子。Qt 保证没有 QObject 会被 delete 两次这是由析构顺序决定的。 如果 QObject 在栈上创建Qt 保持同样的行为。正常情况下这也不会发生什么问题。来看下下面的代码片段: {QWidget window;QPushButton quit(Quit, window); }作为父组件的 window 和作为子组件的 quit 都是 QObject 的子类(事实上它 们都是 QWidget 的子类而 QWidget 是 QObject 的子类)。这段代码是正确的 quit 的析构函数不会被调用两次因为标准 C要求局部对象的析构顺序应 该按照其创建顺序的相反过程。因此这段代码在超出作用域时会先调用 quit的析构函数将其从父对象 window 的子对象列表中删除然后才会再调用 window 的析构函数。 但是如果我们使用下面的代码 {QPushButton quit(Quit);QWidget window;quit.setParent(window); }情况又有所不同析构顺序就有了问题。我们看到在上面的代码中作为父对象的 window 会首先被析构因为它是最后一个创建的对象。在析构过程中它会调用子对象列表中每一个对象的析构函数也就是说quit 此时就被析构了。然后代码继续执行在 window 析构之后quit 也会被析构因为 quit 也是一个局部变量在超出作用域的时候当然也需要析构。但是这时候已经是第二次调用 quit 的析构函数了C 不允许调用两次析构函数因此程序崩溃了。 由此我们看到Qt 的对象树机制虽然帮助我们在一定程度上解决了内存问题但是也引入了一些值得注意的事情。这些细节在今后的开发过程中很可能时不时跳出来烦扰一下所以我们最好从开始就养成良好习惯在 Qt 中尽量在构造的时候就指定 parent 对象并且大胆在堆上创建 3.3 Qt窗口坐标体系 坐标体系 以左上角为原点(0,0)X 向右增加Y 向下增加 对于嵌套窗口其坐标是相对于父窗口来说的 4 信号和槽机制 概述 信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽实际就是观察者模式。当 某个事件发生之后比如按钮检测到自己被点击了一下它就会发出一个信号 (signal)。这种发出是没有目的的类似广播。如果有对象对这个信号感兴趣 它就会使用连接(connect)函数意思是将想要处理的信号和自己的一个函 数(称为槽(slot))绑定来处理这个信号。也就是说当信号发出时被连接的槽函数会自动被回调。这就类似观察者模式当发生了感兴趣的事件某一个操作就会被自动触发。 4.1 系统自带的信号和槽 4.1.1 点击控件关闭窗口 发起signal控件关闭窗口槽函数窗口this父类建立信号和槽函数的关系connect函数 void clicked(bool checked false) // 发出信号 bool close() //槽函数执行关闭动作 connect(sender, signal, receiver, slot); connect(信号发起者信号信号接收者行为函数);这里有小喇叭即信号 // 信号单击关闭connect(button2,QPushButton::clicked,this,QWidget::close);4.2 自定义信号和槽 使用 connect()可以让我们连接系统提供的信号和槽。但是Qt 的信号槽机制并不仅仅是使用系统提供的那部分还允许我们自己设计自己的信号和槽。 下面我们看看使用 Qt 的信号槽 首先创建新的工程然后创建学生类student和老师类teacher 右击工程点击Add new 创建 注意要继承QObject类否则没有槽函数可使用 class studnet : public QObject {Q_OBJECT public:explicit studnet(QObject *parent nullptr);signals:};注意 定义信号 在signals下方返回值类型为void只需声明不用实现可以有参数可以重载 定义槽函数 一般在public slots下方返回值类型为void需要声明和实现可以有参数可以重载 用户使用emit可以发出信号 4.2.1 无参的信号和槽 student.h里 public slots:void treat();student.cpp里 void student::treat() {qDebug()hello Tendl; }teacher.h里 signals: // 自定义信号函数void send();Widget::Widget(QWidget *parent): QWidget(parent) {this-resize(600,400);teacher *tea new teacher(this); //实例化一个老师student *stu new student(this); //实例化一个学生// 建立二者之间关系connect(tea,teacher::send,stu,student::treat);// 此时无法触发条件QPushButton *btn new QPushButton(Click,this);connect(btn,QPushButton::clicked,[](){// 单击后tea发出信号emit tea-send();}); }4.2.2 带参数的信号和槽 student.h里 public slots:void treat();void treat(QString foodname);student.cpp里 void student::treat(QString foodname) {qDebug()hello T:foodnameendl; }teacher.h里 signals: // 自定义信号函数void send();void send(QString foodname);widget #define n 0 //决定调用哪一块函数 Widget::Widget(QWidget *parent): QWidget(parent) {this-resize(600,400);teacher *tea new teacher(this); //实例化一个老师student *stu new student(this); //实例化一个学生// 建立二者之间关系//connect(tea,teacher::send,stu,student::treat);#if n // 重载调用无参的信号和槽void (teacher::*p1)() teacher::send;void (student::*p2)() student::treat;connect(tea,p1,stu,p2);QPushButton *btn new QPushButton(Click,this);connect(btn,QPushButton::clicked,[](){// 单击后tea发出信号emit tea-send();}); #else // 重载调用有参的信号和槽void (teacher::*p1)(QString foodname) teacher::send;void (student::*p2)(QString foodname) student::treat;connect(tea,p1,stu,p2);QPushButton *btn new QPushButton(Click,this);connect(btn,QPushButton::clicked,[](){// 单击后tea发出信号emit tea-send(joyce);}); #endif }4.2.3 定义信号槽需要注意的事项 发送者和接收者都需要是 QObject 的子类(当然槽函数是全局函数、Lambda表达式等无需接收者的时候除外)信号和槽函数返回值是 void信号只需要声明不需要实现槽函数需要声明也需要实现槽函数是普通的成员函数作为成员函数会受到 public、private、 protected 的影响使用 emit 在恰当的位置发送信号使用 connect()函数连接信号和槽。任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数信号槽要求信号和槽的参数一致所谓一致是参数类型一致。如果信号和槽的参数不一致允许的情况是槽函数的参数可以比信号的少 即便如此槽函数存在的那些参数的顺序也必须和信号的前面几个一致起 来。这是因为你可以在槽函数中选择忽略信号传来的数据(也就是槽函数 的参数比信号的少) 4.3 信号槽的拓展 一个信号可以和多个槽相连如果是这种情况这些槽会一个接一个的被调用但是它们的调用顺序是不确定的。多个信号可以连接到一个槽只要任意一个信号发出这个槽就会被调用一个信号可以连接到另外的一个信号当第一个信号发出时第二个信号被发出。除此之外这种信号-信号的形式和信号-槽的形式没有什么区别。槽可以被取消链接该情况并不经常出现因为当一个对象 delete 之后Qt 自动取消所有连接到这个对象上面的槽信号槽可以断开利用 disconnect 关键字是可以断开信号槽的使用 Lambda 表达式在使用 Qt 5 的时候能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。在连接信号和槽的时候槽函数可以使用 Lambda 表达式的方式进行处理 4.4 Qt4版本的信号槽写法 在Qt5中我们刚才是这么写信号槽 connect(tea,teacher::send,stu,student::treat)而在Qt4是这样 connect(tea,SIGNAL(send()),stu,SLOT(treat()))这里使用了 SIGNAL 和 SLOT 这两个宏将两个函数名转换成了字符串。注意到 connect()函数的 signal 和 slot 都是接受字符串一旦出现连接不成功的情 况Qt4 是没有编译错误的(因为一切都是字符串编译期是不检查字符串是否匹配)而是在运行时给出错误。这无疑会增加程序的不稳定性。 Qt5 在语法上完全兼容 Qt4而反之是不可以的 Qt5 因为不接收参数因此不能重载 例创建2个窗口第一个窗口有next按钮点击进入下一个L窗口下一个窗口有back按钮点击回到上一个窗口 首先新建LWidget窗口类 方法1 在widget.cpp中实现主窗口和2个按钮的创建 Widget::Widget(QWidget *parent): QWidget(parent) {this-resize(800,600);this-setWindowTitle(登陆界面);LWidget *win1new LWidget(); //创建第二个窗口{ // 创建按钮1并设置属性QPushButton *btn1 new QPushButton(this);btn1-move(400,300);btn1-setText(next);// 设置按钮1的作用connect(btn1,QPushButton::clicked,[](){this-hide();win1-show();});}{ // 创建按钮2并设置属性QPushButton *btn2 new QPushButton(win1);btn2-move(500,200);btn2-setText(back);// 设置按钮2的作用connect(btn2,QPushButton::clicked,[](){win1-hide();this-show();});} }在lwidget中设置第二个窗口的属性 LWidget::LWidget(QWidget *parent) : QWidget(parent) { // 设置第二个窗口的属性this-resize(800,600);this-setWindowTitle(确认界面); }方法2 先在lwidget.h中设置back信号然后在lwidget.cpp中设置窗口属性创建按钮2并创建按钮2的动作点击后发出back信号 lwidget.h signals:void back();lwidget.cpp LWidget::LWidget(QWidget *parent) : QWidget(parent) { // 设置第二个窗口的属性this-resize(800,600);this-setWindowTitle(确认界面);QPushButton *btn new QPushButton(back,this);btn-move(300,400);connect(btn,QPushButton::clicked,[](){ // 如有点击则发出back信号emit this-back();});在widget.cpp中实现主窗口和1个按钮的创建并检测第2个窗口的信号 Widget::Widget(QWidget *parent): QWidget(parent) {this-resize(800,600);this-setWindowTitle(登陆界面);LWidget *win1new LWidget(); //创建第二个窗口不在当前窗口上因此不加this{ // 创建按钮1并设置属性QPushButton *btn1 new QPushButton(this);btn1-move(400,300);btn1-setText(next);// 设置按钮1的作用connect(btn1,QPushButton::clicked,[](){this-hide();win1-show();});}// 检测第二个窗口的行为connect(win1,LWidget::back,[](){win1-hide();this-show();}); }4.5 lambda表达式 C11 中的Lambda 表达式用于定义并创建匿名的函数对象以简化编程工作。 首先看一下 Lambda表达式的基本构成 [函数对象参数](mutable) -返回值{函数体) [capture](parameters) mutable -return-type {statement }函数对象参数[]标识一个 Lambda 的开始这部分必须存在不能省略。函数对象参数 是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this)。 函数对象参数有以下形式 形式作用空没有使用任何函数对象参数函数体内可以使用 Lambda 所在作用范围内所有可见的局部变量(包括 Lambda 所在类的 this)并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)函数体内可以使用 Lambda 所在作用范围内所有可见的局部变量(包 括 Lambda 所在类的 this)并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)this函数体内可以使用 Lambda 所在类中的成员变量a将 a 按值进行传递。按值进行传递时函数体内不能修改传递进来的 a 的拷贝因为默认情况下函数是 const 的。要修改传递进来的 a 的拷 贝可以添加 mutable 修饰符a将 a 按引用进行传递ab将 a 按值进行传递b 按引用进行传递。ab除 a 和 b 按引用进行传递外其他参数都按值进行传递。ab除 a 和 b 按值进行传递外其他参数都按引用进行传递。 操作符重载函数参数 标识重载的()操作符的参数没有参数时这部分可以省略。参数可以通过 按值(如(a,b))和按引用(如(a,b))两种方式进行传递 可修改标示符 mutable 声明这部分可以省略。按值传递函数对象参数时加上 mutable 修饰符后可以修改按值传递进来的拷贝(注意是能修改拷贝而不是值本身) 函数返回值 -返回值类型标识函数返回值的类型当返回值为 void或者函数体中只 有一处 return 的地方(此时编译器可以自动推断出返回值类型)时这部 分可以省略 是函数体 {}标识函数的实现这部分不能省略但函数体可以为空 5 QMainWindow QMainWindow 是一个为用户提供主窗口程序的类包含一个菜单栏(menu bar)、 多个工具栏(tool bars)、多个锚接部件(dock widgets)、一个状态栏(status bar) 及一个中心部件(central widget)是许多应用程序的基础如文本编辑器图片编辑器等 5.1 菜单栏 Qt 并没有专门的菜单项类只是使用一个 QAction 类抽象出公共的动作。 当我们把 QAction 对象添加到菜单就显示成一个菜单项添加到工具栏 就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击 快捷键来激活这个动作。 创建工程 注意不要选择QWidget而是QMainWindow 5.1.1 添加菜单栏 一个主窗口最多只有一个菜单栏。位于主窗口顶部、主窗口标题栏下面。 如果这么写 MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {this-setWindowTitle(test);this-resize(600,400);// 创建一个菜单栏QMenuBar *menuBarnew QMenuBar(this); }菜单栏会被视为普通控件添加到主窗口的正文部分可以被move随便移动 所以我们需要将菜单栏单独列出添加到主窗口中 且由于是主窗口添加所以在主窗口QMainWindow中查找对应函数 //原函数 void QMainWindow::setMenuBar(QMenuBar *menuBar)//添加 // 将菜单栏添加到主窗口 this-setMenuBar(menuBar);5.1.2 添加菜单 同理在Qmenu里找对应函数 //原函数 QAction *addMenu(QMenu *menu) QMenu *addMenu(const QString title) QMenu *addMenu(const QIcon icon, const QString title)// 这里我使用第2个// 在菜单栏中添加菜单// 1、定义菜单QMenu *file new QMenu(文件,this);QMenu *edit new QMenu(编辑,this);QMenu *tool new QMenu(工具,this);QMenu *setting new QMenu(设置,this);QMenu *help new QMenu(帮助,this);// 2、将定义的菜单加入到菜单栏menuBar-addMenu(file);menuBar-addMenu(edit);menuBar-addMenu(tool);menuBar-addMenu(setting);menuBar-addMenu(help);5.1.3 在菜单里添加菜单项 在Qmenu里找对应函数 QAction *addAction(const QString text) QAction *addAction(const QIcon icon, const QString text) QAction *addAction(const QString text, const QObject *receiver, const char *member, const QKeySequence shortcut 0) QAction *addAction(const QIcon icon, const QString text, const QObject *receiver, const char *member, const QKeySequence shortcut 0) QAction *addAction(const QString text, Functor functor, const QKeySequence shortcut ...) QAction *addAction(const QString text, const QObject *context, Functor functor, const QKeySequence shortcut 0) QAction *addAction(const QIcon icon, const QString text, Functor functor, const QKeySequence shortcut ...) QAction *addAction(const QIcon icon, const QString text, const QObject *context, Functor functor, const QKeySequence shortcut 0)例 // 在菜单里添加菜单项// 1、定义菜单项QAction *newfile new QAction(新建,this);QAction *save new QAction(保存,this);QAction *option new QAction(选项,this);QAction *test new QAction(测试,this);QAction *dialog new QAction(对话,this);// 2、将定义的菜单项添加到菜单file-addAction(newfile);edit-addAction(save);tool-addAction(test);setting-addAction(option);help-addAction(dialog);5.1.4 给菜单项添加快捷键 在QAction里找对应函数 //原函数 void setShortcut(const QKeySequence shortcut) void setShortcutContext(Qt::ShortcutContext context) void setShortcutVisibleInContextMenu(bool show) void setShortcuts(const QListQKeySequence shortcuts) void setShortcuts(QKeySequence::StandardKey key)我们使用第一个 帮助里的例子 #include QKeySequence QKeySequence(QKeySequence::Print); QKeySequence(tr(CtrlP)); QKeySequence(tr(Ctrlp)); QKeySequence(Qt::CTRL Qt::Key_P);例 // 给菜单项里添加快捷键newfile-setShortcut(QKeySequence(Qt::CTRLQt::Key_N));save-setShortcut(QKeySequence(tr(Ctrls)));5.1.5 给菜单项添加行为 在QAction里找对应函数 //原函数发出信号 void triggered(bool checked false)例 // 给菜单项添加行为connect(newfile,QAction::triggered,[](){qDebug()新建文件endl;});5.1.5 在菜单项之间添加分隔符 file-addAction(recent);file-addSeparator(); // 在同一个菜单的相邻菜单项之间添加分隔符file-addAction(exit);5.2 工具栏 主窗口的工具栏上可以有多个工具条通常采用一个菜单对应一个工具条的的方 式也可根据需要进行工具条的划分 直接调用 QMainWindow 类的 addToolBar () 函数获取主窗口的工具条对象每增加一个工具条都需要调用一次该函数插入属于工具条的动作即在工具条上添加操作。通过 QToolBar 类的 addAction 函数添加工具条是一个可移动的窗口它的停靠区域由 QToolBar 的 allowAreas 决定 5.2.1 添加工具栏 头文件 #include QToolBar **创建工具栏原函数**在主窗口函数QMainWindow中查找 void addToolBar(Qt::ToolBarArea area, QToolBar *toolbar) void addToolBar(QToolBar *toolbar) QToolBar *addToolBar(const QString title)例 // 创建一个工具栏QToolBar *toolBar new QToolBar(this);// 将工具栏添加到主窗口中并默认出现在左侧this-addToolBar(Qt::LeftToolBarArea, toolBar); 上下左右及中间拖动会停靠到四周或悬浮中间 5.2.2 添加工具栏选项 在QToolBar中查找 原函数 QAction *addAction(const QString text) QAction *addAction(const QIcon icon, const QString text) QAction *addAction(const QString text, const QObject *receiver, const char *member) QAction *addAction(const QIcon icon, const QString text, const QObject *receiver, const char *member) QAction *addAction(const QString text, Functor functor) QAction *addAction(const QString text, const QObject *context, Functor functor) QAction *addAction(const QIcon icon, const QString text, Functor functor) QAction *addAction(const QIcon icon, const QString text, const QObject *context, Functor functor)将上面创建的几个菜单项添加到工具栏中 // 将菜单项添加到工具栏中toolBar-addAction(newfile);toolBar-addAction(save);toolBar-addSeparator();toolBar-addAction(test);toolBar-addAction(option);toolBar-addAction(recent);toolBar-addAction(exit);同时由于我们刚才有设置菜单项的动作因此点击对应的菜单项仍可以触发动作 5.2.3 设置工具栏是否可浮动 void setFloatable(bool floatable) //true可以浮动false不可浮动例 // 设置工具栏不可浮动toolBar-setFloatable(false);5.2.4 设置工具栏允许停靠的位置 包括: allowAreas停靠区域Qt::LeftToolBarArea停靠在左侧Qt::RightToolBarArea停靠在右侧Qt::TopToolBarArea停靠在顶部Qt::BottomToolBarArea停靠在底部Qt::AllToolBarAreas以上四个位置都可以停靠 使用 setAllowedAreas()函数指定停靠区域 原函数 void setAllowedAreas(Qt::ToolBarAreas areas)例 // 设置工具栏停靠的位置toolBar-setAllowedAreas(Qt::LeftToolBarArea |Qt::RightToolBarArea);注意由于默认是停靠上面因此当我们移动工具栏后将无法停靠在除设置外的其他位置 5.2.5 其他相关函数 使用 setMoveable()函数设定工具栏的可移动性 setMoveable(false) //工具条不可移动, 只能停靠在初始化的位置上5.3 状态栏 派生自 QWidget 类使用方法与 QWidget 类似QStatusBar 类常用成员函数状态栏也只能最多有一个 一般下面的是状态栏 头文件 #include QStatusBar 5.3.1 创建状态栏 void setStatusBar(QStatusBar *statusbar)例 // 创建一个状态栏QStatusBar *statusBar new QStatusBar(this);// 将状态栏添加到主窗口this-setStatusBar(statusBar);5.3.2 添加标签 头文件 #includeQLabel添加左右控件 void addPermanentWidget(QWidget *widget, int stretch 0) //添加右侧控件 void addWidget(QWidget *widget, int stretch 0) //添加左侧控件例通过控件添加到状态栏 // 创建2个标签lableQLabel *label1 new QLabel(左侧,this);QLabel *label2 new QLabel(右侧,this);// 将标签添加到状态栏statusBar-addWidget(label1);statusBar-addPermanentWidget(label2);5.3.3 其他相关函数 //添加小部件 void addWidget(QWidget * widget, int stretch 0) //插入小部件 int insertWidget(int index, QWidget * widget, int stretch 0) //删除小部件 void removeWidget(QWidget * widget)5.4 核心部件(中心部件) 中心显示的部件可以作为核心部件例如一个记事本文件可以利用 QTextEdit 做核心部件 void setCentralWidget(QWidget *widget)需要另一个部件 这里使用文本域QTextEdit 头文件 #includeQTextEdit例 // 创建一个核心部件// 创建一个文本域QTextEdit *text new QTextEdit(this);text-setText(如果阳光永远\n都炽热);//设置内容this-setCentralWidget(text);5.5 铆接部件 铆接部件 QDockWidget也称浮动窗口可以有多个分布在中心内容的四周 头文件 #include QDockWidget原函数在QMainWindow里 void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget) void addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget, Qt::Orientation orientation)铆接部件的区域 Qt::LeftDockWidgetArea Qt::RightDockWidgetArea Qt::TopDockWidgetArea Qt::BottomDockWidgetArea Qt::AllDockWidgetAreas Qt::NoDockWidgetArea例 // 创建一个铆接部件QDockWidget *DockWidget new QDockWidget(铆接部件,this);// 将铆接部件添加到主窗口this-addDockWidget(Qt::TopDockWidgetArea,DockWidget);// 设置允许铆接部件停靠的位置 上 下DockWidget-setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);5.6 资源文件 Qt 资源系统是一个跨平台的资源机制用于将程序运行时所需要的资源以二进 制的形式存储于可执行文件内部。 如果你的程序需要加载特定的资源图标、文本翻译等那么将其放置在资源文件中就再也不需要担心这些文件的丢失。 也就是说如果你将资源以资源文件形式存储它是会编译到可执行文件内部。 使用 Qt Creator 可以很方便地创建资源文件。 我们可以在工程上点右键选择 “添加新文件…”可以在 Qt 分类下找到“Qt 资源文件” 5.6.1 添加资源文件 将资源文件放入工程目录非必要 添加新文件 选择资源文件一直下一步就行 点击添加前缀并修改为/ 然后点击添加文件并选择所有要添加的资源必须先添加前缀 最后点击左下角的构建才算添加成功 如果后续想要继续添加右击资源并点击open in edit打开刚才的窗口继续编辑 5.6.2 使用资源 给菜单项添加图标: void setIcon(const QIcon icon) //添加图标 void setIconText(const QString text) //添加图标文本这里需要使用图片控件 头文件 #include QPixmap添加函数load bool load(const QString fileName, const char *format nullptr, Qt::ImageConversionFlags flags Qt::AutoColor)例 //给菜单项添加图标// 创建图片控件QPixmap pix;// 给图片控件添加资源图片// :资源的路径pix.load(:/logo/qq.png);// 将控件添加到菜单项newfile-setIcon(QIcon(pix));6 UI界面 6.1 认识UI 可以辅助用户设计文件 创建工程 6.2 基本使用 在右下角这里 geometry //可以修改窗口尺寸 minimumsize可 //以修改允许缩放到的最小尺寸windowTitle //可以修改窗口标题 windowIcon //可以修改窗口图标实现添加资源后 点击添加资源即可选择标题 窗口这里在这里输入内容回车即可自动添加菜单 点击某个菜单右侧会提示该处对象的代码最好修改名称否则不知道它代表哪个菜单 然后点击某一菜单点击输入并输入内容即可添加菜单项 填加分隔符即可添加分割符 点击某菜单项即可在右下角修改其图标方法同修改窗口 点击某菜单项即可在右下角设置快捷键双击右侧后在键盘上按下快捷键即可设置而非手动打字输入 6.3 控件的使用 由于UI已经给我们生成了各个控件因此我们不需要再生成控件只需要对其动作做出设定即可即设计控件的行为 回到主窗口文件mainWindow.cpp中在其构造函数中实现 添加菜单项newfile的行为 //通过UI指针成员访问UI文件上的控件而不需要再newconnect(ui-actionnew,QAction::triggered,[](){qDebug()new a file.endl;});7 对话框QDialog 7.1 基本概念 对话框是 GUI 程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。对话框通常会是一个顶层窗口出现在程序最上层用于实现短期任务或者简洁的用户交互。 Qt 中使用 QDialog 类实现对话框。就像主窗口一样我们通常会设计一个类继 承 QDialog。QDialog及其子类以及所有 Qt::Dialog 类型的类的对于其 parent 指针都有额外的解释如果 parent 为 NULL则该对话框会作为一个顶 层窗口否则则作为其父组件的子对话框此时其默认出现的位置是 parent 的中心。顶层窗口与非顶层窗口的区别在于顶层窗口在任务栏会有自己的位置而非顶层窗口则会共享其父组件的位置。 对话框分为模态对话框和非模态对话框。 模态对话框就是会阻塞同一应用程序中其它窗口的输入。 模态对话框很常见比如“打开文件”功能。你可以尝试一下记事本的打开 文件当打开文件对话框出现时我们是不能对除此对话框之外的窗口部分 进行操作的。非模态对话框例如查找对话框我们可以在显示着查找对话框的同时继续对记事本的内容进行编辑。 7.2 标准对话框 头文件 #includeQDialog所谓标准对话框是 Qt 内置的一系列对话框用于简化开发。事实上有很多对话框都是通用的比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同因此没有必要在每一个程序中都自己实现这么一个对话框。 Qt 的内置对话框大致分为以下几类 类型作用QColorDialog选择颜色QFileDialog选择文件或者目录QFontDialog选择字体QInputDialog允许用户输入一个值并将其值返回QMessageBox模态对话框用于显示信息、询问问题等QPageSetupDialog为打印机提供纸张相关的选项QPrintDialog打印机配置QPrintPreviewDialog打印预览QProgressDialog显示操作过程 7.3 自定义消息框 Qt 支持模态对话框和非模态对话框。 模态与非模态的实现 使用 QDialog::exec()实现应用程序级别的模态对话框使用 QDialog::open()实现窗口级别的模态对话框使用 QDialog::show()实现非模态对话框 7.3.1 模态对话框 Qt 有两种级别的模态对话框 **应用程序级别的模态**当该种模态的对话框出现时用户必须首先对对话框进行交互直到关 闭对话框然后才能访问程序中其他的窗口。**窗口级别的模态**该模态仅仅阻塞与对话框关联的窗口但是依然允许用户与程序中其它 窗口交互。窗口级别的模态尤其适用于多窗口模式。 一般默认是应用程序级别的模态 例将模态对话框连接菜单项copy #if n //使对话框运行模式为模态对话框connect(ui-actioncopy,QAction::triggered,[](){dlg-exec();qDebug()模态对话框endl;});7.3.2 非模态对话框 show()函数不会阻塞当前线程对话框会显示出来然后函数立即返回代码继续执行。注意dialog 是建立在栈上的show()函数返回MainWindow::open()函数结束dialog 超出作用域被析构因此对话框消失了我们将 dialog 改成堆上建立就没有这个问题 例非模态对话框连接菜单项paste #else //使对话框运行模式为非模态对话框connect(ui-actionpaste,QAction::triggered,[](){dlg-show();qDebug()非模态对话框endl;}); #endif7.4 消息对话框 QMessageBox 用于显示消息提示。我们一般会使用其提供的几个 static 函数 头文件 #includeQMessageBox显示关于对话框 void about(QWidget * parent, const QString title, const QString text) 这是一个最简单的对话框其标题是 title内容是 text父窗口是 parent。对话框只有一个 OK 按钮。 显示关于 Qt 对话框。该对话框用于显示有关 Qt 的信息。 void aboutQt(QWidget * parent, const QString title QString());警告对话框对话框提供一个黄色叹号图标。 StandardButton warning(QWidget * parent, const QString title, const QString text, StandardButtons buttons Ok, StandardButton defaultButton NoButton) 7.4.1 显示严重错误对话框 StandardButton critical(QWidget * parent, const QString title, const QString text, StandardButtons buttons Ok, StandardButton defaultButton NoButton);这个对话框将显示一个红色的错误符号。我们可以通过 buttons 参数指明 其 显 示 的 按 钮 。 默 认 情 况 下 只 有 一 个 Ok 按 钮 我 们 可 以 使 用 StandardButtons 类型指定多种按钮。 例先显示错误对话框再显示模态对话框 #if n //使对话框运行模式为模态对话框connect(ui-actioncopy,QAction::triggered,[](){QMessageBox::critical(this,error,there has been a huge error!);dlg-exec();qDebug()模态对话框endl;});7.4.2 信息对话框 提供一个普通信息图标 StandardButton information(QWidget * parent, const QString title, const QString text, StandardButtons buttons Ok, StandardButton defaultButton NoButton) 例同时显示非模态对话框和信息对话框 #else //使对话框运行模式为非模态对话框connect(ui-actionpaste,QAction::triggered,[](){dlg-show();qDebug()非模态对话框endl;QMessageBox::information(this,info,there is a vital information!);});7.4.3 提问对话框 提供一个问号 图标并且其显示的按钮是“是”和“否”。 StandardButton question(QWidget * parent, const QString title, const QString text, StandardButtons buttons StandardButtons( Yes | No ), StandardButton defaultButton NoButton)例 QMessageBox::question(this,ques,do u want to exit?);同时提问对话框的button可以修改 ConstantValueDescriptionOMessageBox::Ok0x00000400An “OK” button defined with the AcceptRole.OMessageBox::Open0x00002000An “Open” button defined with the AcceptRole.OMessageBox: :Save0x00000800An “Save” button defined with the AcceptRole.QMessageBox::Cancel0x00400000A “Cancel” button defined with the RejectRole.QMessageBox::Close0x00200000A Close button defined with the RejectRole.QMessageBox::Discard0x00800000A Discard or “Don’t Save” button, depending on the platformdefined with the DestructiveRole.OMessageBox: :Apply0x02000000An “Apply” button defined with the ApplyRoleOMessageBox: :Reset0x04000000A “Reset” button defined with the ResetRole.QMessageBox::RestoreDefaults0x08000000A “Restore” Defaults button defined with the ResetRole.OMessageBox::Help0x01000000A “Help” button defined with the HelpRole.QMessageBox: : SaveA110x00001000A “Save All” button defined with the AcceptRole.OMessageBox: :Yes0x00004000A “Yes” button defined with the YesRole.QMessageBox::YesToA110x00008000A “Yes to All” button defined with the YesRole.OMessageBox::No0x00010000A “No” button defined with the NoRole.QMessageBox::NoToA1]0x00020000A “No to All” button defined with the NoRole.QMessageBox: :Abort0x00040000An “Abort” button defined with the RejectRole.OMessageBox: :Retry0x00080000A “Retry” button defined with the AcceptRoleOMessageBox::Ignore0x00100000An “Ignore” button defined with the AcceptRole.OMessageBox: :NoButton0x00000000An invalid button. 例修改button为save和cancel QMessageBox::question(this,ques,tdo u want to exit?,QMessageBox::Save | QMessageBox::Cancel);注意button默认是左边的有点蓝色 例将默认修改为右边的cancel QMessageBox::question(this,ques,tdo u want to exit?,QMessageBox::Save | QMessageBox::Cancel,QMessageBox::Cancel);同时可以为选项添加行为 QMessageBox::StandardButton ret ;ret QMessageBox::question(this,ques,tdo u want to exit?,QMessageBox::Save | QMessageBox::Cancel,QMessageBox::Cancel);if (ret QMessageBox::Save)qDebug()保存数据endl;else if(ret QMessageBox::Cancel)qDebug()取消!endl;7.5 字体对话框 头文件 #include QFontDialog 原函数 //获得字体 QFont getFont(bool *ok, const QFont initial, QWidget *parent nullptr, const QString title QString(), QFontDialog::FontDialogOptions options FontDialogOptions()) QFont getFont(bool *ok, QWidget *parent nullptr)例 bool yes;QFontDialog::getFont(yes,QFont(宋体),this);其他函数 QString family() const //查看字体类型 int pointSize() const //查看字体大小例 bool yes;QFont font;font QFontDialog::getFont(yes,QFont(宋体),this);if(yes){qDebug()字体为:font.family()大小为:font.pointSize()endl;}然后点击OK 7.6 颜色对话框 头文件 #include QColorDialog 7.6.1 获取颜色函数 QColor getColor(const QColor initial Qt::white, QWidget *parent nullptr, const QString title QString(), QColorDialog::ColorDialogOptions options ColorDialogOptions())例显示颜色对话框 QColorDialog::getColor();7.6.2 输出对应三原色的值 QColor color;color QColorDialog::getColor();qDebug()red:color.red(),green:color.green(),blue:color.blue()endl;或 7.7 标准文件对话框 QFileDialog也就是文件对话框。在本节中我们将尝试编写一个简单的文本文件编辑器我们将使用 QFileDialog 来打开一个文本文件并将修改过的文件保存到硬盘。 头文件 #include QFileDialog7.7.1 获取打开的文件名 QString getOpenFileName(QWidget *parent nullptr, const QString caption QString(), const QString dir QString(), const QString filter QString(), QString *selectedFilter nullptr, QFileDialog::Options options Options())QStringList getOpenFileNames(QWidget *parent nullptr, const QString caption QString(), const QString dir QString(), const Q String filter QString(), QString *selectedFilter nullptr, QFileDialog::Options options Options())不过注意它的所有参数都是可选的因此在一定程度上说这个函数也是简单的。这六个参数分别是 **parent父窗口**Qt 的标准对话框提供静态函数用于返回一个模态对话框caption对话框标题dir对话框打开时的默认目录 “.” 代表程序运行目录“/” 代表当前盘符的根目录特指 Windows 平台Linux 平台当然就是根目录这个参数也可以是平台相关的比如“C:\”等 **filter过滤器**我们使用文件对话框可以浏览很多类型的文件但是很多时候我们仅希望打开特定类型的文件。比如文本编辑器希望打开文本文件图片浏览器希望打开图片文件。过滤器就是用于过滤特定的后缀名。如果我们使用“ImageFiles(*.jpg*.png)”则只能显示后缀名是 jpg 或者 png 的文件。如果需要多个过滤器使用“;;”分割比如“JPEG Files(*.jpg);;PNGFiles(*.png)”selectedFilter默认选择的过滤器options对话框的一些参数设定比如只显示文件夹等等它的取值是 enum QFileDialog::Option每个选项可以使用 | 运算组合起来。 QFileDialog::getOpenFileName()返回值是选择的文件路径。我们将其赋值给filename。通过判断 filename 是否为空可以确定用户是否选择了某一文件。只有当用户选择了一个文件时我们才执行下面的操作 在 saveFile()中使用的 QFileDialog::getSaveFileName()也是类似的。使用这 种静态函数在 Windows、Mac OS 上面都是直接调用本地对话框但是 Linux 上 则是 QFileDialog 自己的模拟。这暗示了如果你不使用这些静态函数而是直 接使用 QFileDialog 进行设置那么得到的对话框很可能与系统对话框的外观不 一致。这一点是需要注意的 例随便打开个文件 QString filename;filename QFileDialog::getOpenFileName();qDebug()filenameendl;成功显示 7.7.2 添加打开时显示的指定路径 QString filename;filename QFileDialog::getOpenFileName(this,file,C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\03\\logo);//注意要用双斜线\\qDebug()filenameendl;则会自动打开该路径 7.7.3 打开某路径下某类型文件 创建3个txt后缀文件 修改代码 QString filename;filename QFileDialog::getOpenFileName(this,file,C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\03\\logo,(*.txt));qDebug()filenameendl; // 类型7.7.4 设置多个类型文件同时显示 QString filename;filename QFileDialog::getOpenFileName(this,file,C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\03\\logo,(*.txt *.png));qDebug()filenameendl; // 不同类型中加空格7.8 下拉列表框 拖入下拉列表框Combo box 7.8.1 UI添加内容 同样的双击可以添加内容 7.8.2 代码添加 头文件 #include QComboBox 添加项目函数 void addItem(const QString text, const QVariant userData QVariant()) void addItem(const QIcon icon, const QString text, const QVariant userData QVariant()) void addItems(const QStringList texts) //链表只能是string这里我使用第三个 //给下拉列表框添加选项QStringList list;list梅赛德斯帕拉梅拉科尼赛克;ui-comboBox-addItems(list);打开默认是第一个元素我们修改默认索引 函数 void setCurrentIndex(int index)ui-comboBox-setCurrentIndex(2);//设置默认索引7.8.3 添加行为 信号 void currentIndexChanged(const QString text) void currentIndexChanged(int index)//重载 void currentTextChanged(const QString text)例 //添加行为void ( QComboBox::*p )(int) QComboBox::currentIndexChanged; // 返回值 作用域 希望他的类型connect(ui-comboBox,p,[](int index){qDebug()indexendl; // 下标qDebug()ui-comboBox-currentIndex()endl; //也是下标qDebug()ui-comboBox-currentText()endl; //文本});注意信号发生重载要用函数指针匹配 8 布局管理器 所谓 GUI 界面归根结底就是一堆组件的叠加。我们创建一个窗口把按钮 放上面把图标放上面这样就成了一个界面。在放置时组件的位置尤其重要。 我们必须要指定组件放在哪里以便窗口能够按照我们需要的方式进行渲染。这就涉及到组件定位的机制。 Qt 提供了两种组件定位机制绝对定位和布局定位。 **绝对定位**一种最原始的定位方法给出这个组件的坐标和长宽值。 这样Qt 就知道该把组件放在哪里以及如何设置组件的大小。但是这样做带来的一个问题是如果用户改变了窗口大小比如点击最大化按钮或者使 用鼠标拖动窗口边缘采用绝对定位的组件是不会有任何响应的。这也很自然因为你并没有告诉 Qt在窗口变化时组件是否要更新自己以及如何 更新。或者还有更简单的方法禁止用户改变窗口大小。但这总不是长远之计。**布局定位**你只要把组件放入某一种布局布局由专门的布局管理器进行管理。当需要调整大小或者位置的时候Qt 使用对应的布局管理器进行调整。 布局定位完美的解决了使用绝对定位的缺陷。 Qt 提供的布局中以下三种是我们最常用的 QHBoxLayout按照水平方向从左到右布局QVBoxLayout按照竖直方向从上到下布局QGridLayout在一个网格中进行布局类似于 HTML 的 table 8.1 系统提供的布局控件 分别是垂直布局、水平布局、栅格布局表单布局 同时这里有水平布局、垂直布局和栅格布局 这 4 个为系统给我们提供的布局的控件但是使用起来不是非常的灵活这里不再详细介绍。 8.2 利用widget做布局 8.2.1 ui布局 接下来设计一个登录窗口 直接拖动过去即可并输入内容 运行 比较丑接下来优化 将水平弹簧分别放在用户名、密码两侧以及下面的三处 然后选中一整行点击上面的水平布局将其重新划分下面同理 然后随便点击空白处再点击上面的垂直布局 重新分布后运行 随着我们拖动边缘它的布局仍然规整 点击某一弹簧后可以设置其宽高 如果要解除布局可以点击空白处或某一控件再点击上面的打破布局 接下来双击输入框并修改名字以方便我们识别与使用 同理我们把登录和注册账号按钮也制定一下 完成后运行我们输入用户名和密码会发现密码可以被看到 因此需要修改密码输入框的模式 双击密码框右下角在echoMode里选择password 8.2.2 设计行为 获取user和passwd 点击登录获取用户名和密码 QString text() const因此我们需要QString类型的字段接收 //点击登录获取用户名和密码connect(ui-pushButton_login,QPushButton::clicked,[](){QString username ui-lineEdit_user-text(); // 获取用户名QString passwd ui-lineEdit_passwd-text(); // 获取密码qDebug()用户名为:username\t密码为:passwdendl;9 容器container 拖动Radio Button按钮并输入内容创建4个按钮 一次性只能从4个选择一个 接下来我们使用Group Box组拖动出2个组并将2组年龄和性别加入注意button需要先放在外面否则会压住 此时可以选择2组 双击修改一下各个组件的名字方便后面识别与使用 9.2 设计行为 9.2.1 选中输出 选中male则输出男 //选中则输出对应的内容connect(ui-radioButton_male,QRadioButton::clicked,[](){qDebug()男endl;});9.2.2 默认选择 打开程序时默认的选择 void setChecked(bool)//默认选择ui-radioButton_female-setChecked(true);10 常用控件 Qt 为我们应用程序界面开发提供的一系列的控件所有控件的使用方法我们都可以通过帮助文档获取 10.1 QLabel控件使用 10.1.1 显示文字(普通文本、html) 通过 QLabel 类的 setText 函数设置显示的内容: void setText(const QString )可以显示普通文本字符串 QLable *label new QLable; label-setText(“Hello, World!”);可以显示 HTML 格式的字符串 比如显示一个链接: QLabel * label new QLabel(this); label -setText(Hello, World); label -setText(h1a href\https://www.baidu.com\百度一下/a/h1); label -setOpenExternalLinks(true);其中 setOpenExternalLinks()函数是用来设置用户点击链接之后是否自动 打开链接如果参数指定为 true 则会自动打开 例 创建工程并拖入label QString text() const //获取文本函数//添加文本ui-label-setText(babe hello);qDebug()ui-label-text()endl;10.1.2 显示图片 可以使用 QLabel 的成员函数 setPixmap 设置图片 头文件 #include QPixmap void setPixmap(const QPixmap ) 首先添加资源然后拖动一个新的label_2进入画布 定义 QPixmap 对象 QPixmap pixmap; 然后pixmap加载图片 bool load(const QString fileName, const char *format nullptr, Qt::ImageConversionFlags flags Qt::AutoColor)pixmap.load(:/logo/anime.png);最后将图片设置到 label_2中 void setPixmap(const QPixmap )ui-label_2-setPixmap(pixmap);10.1.3 显示动画 先创建新项目并拖入label和button 头文件 #include QMovie 首先定义 QMovied 对象并初始化: QMovie *movie new QMovie(:/game.gif);使用 QLabel 的成员函数 setMovie 加载动画可以播放 gif 格式的文件 movie-start(); 将动画设置到 QLabel 中 void setMovie(QMovie * movie)例ui-label-setMovie(movie);播放加载的动画 绑定按钮 signal bool jumpToNextFrame() //跳到下一个动画 void setPaused(bool paused) //暂停 void setSpeed(int percentSpeed) //设置速度 void start() //开始 void stop() //停止例//开始播放connect(ui-pushButton,QPushButton::clicked,[](){movie-start();});//停止播放connect(ui-pushButton_2,QPushButton::clicked,[](){movie-stop();});//开始播放connect(ui-pushButton_3,QPushButton::clicked,[](){movie-setPaused(1);});运行 10.2 QLineEdit Qt 提供的单行文本编辑框。 设置/获取内容 获取编辑框内容使用 text函数声明如下 QString text() const 设置编辑框内容 void setText(const QString )设置显示模式 使用 QLineEdit 类的 setEchoMode () 函数设置文本的显示模式函数声明: void setEchoMode(EchoMode mode) EchoMode 是一个枚举类型,一共定义了四种显示模式: **QLineEdit::Normal 模式显示方式**按照输入的内容显示。**QLineEdit::NoEcho 不显示任何内容**此模式下无法看到用户的输入。**QLineEdit::Password 密码模式**输入的字符会根据平台转换为特殊字符。QLineEdit::PasswordEchoOnEdit 编辑时显示字符否则显示字符作为密码。 另外我们再使用 QLineEdit 显示文本的时候希望在左侧留出一段空白的区域 那么就可以使用 QLineEdit 给我们提供的 setTextMargins 函数 void setTextMargins(int left, int top, int right, int bottom)用此函数可以指定显示的文本与输入框上下左右边界的间隔的像素数。 10.3 列表控件QListWidget 这里接着容器9.2.2的部分 注意不要选错 头文件 #include QListWidget #include QListWidgetItem拖动进主窗口注意拖进去了后面才有listwidget否则没有 添加项目函数 void addItem(const QString label) void addItem(QListWidgetItem *item) void addItems(const QStringList labels)例使用第二个函数 //添加列表控件:方法2QListWidgetItem *item new QListWidgetItem(多远都要在一起);ui-listWidget-addItem(item);例使用第三个函数链表list //添加列表控件:方法3QStringList list; // 使用链表list就让我独自守着回忆如果阳光永远都炽热如果彩虹不会掉颜色;ui-listWidget-addItems(list);扩展点击项目输出内容 这里使用 void itemClicked(QListWidgetItem *item)例参数保持一致 //点击项目输出内容connect(ui-listWidget,QListWidget::itemClicked,[](QListWidgetItem *item){qDebug()item-text()endl;});10.4 树控件QTreeWidget 10.4.1 ui添加 拖入树控件tree widget 双击树控件最上面 双击列以修改内容下面±可以增加或减少列 点击项目可以双击列下面的位置以输入内容 紫色可以设置子项目 运行 这种方法好处是操作方便简单缺点是运行起来后无法再修改 因此需要使用代码添加 10.4.2 代码添加 创建新项目先把树控件拖入主窗口 头文件 #include QTreeWidget 添加头信息函数 void setHeaderItem(QTreeWidgetItem *item) void setHeaderLabel(const QString label) //只能1个 void setHeaderLabels(const QStringList labels) // 多个这里使用第三个 //设置树控件头信息//创建链表以存入各个头信息QStringList list;list语言介绍;ui-treeWidget-setHeaderLabels(list);接下来添加顶层控件 原函数 void addTopLevelItem(QTreeWidgetItem *item) //单个 void addTopLevelItems(const QListQTreeWidgetItem * items) //多个由于我们等下会对顶层控件操作因此使用第一个逐个添加 而他需要QTreeWidgetItem类型的参数 QTreeWidgetItem(const QTreeWidgetItem other) QTreeWidgetItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding, int type Type) QTreeWidgetItem(QTreeWidgetItem *parent, const QStringList strings, int type Type) QTreeWidgetItem(QTreeWidgetItem *parent, int type Type) QTreeWidgetItem(QTreeWidget *parent, QTreeWidgetItem *preceding, int type Type) QTreeWidgetItem(QTreeWidget *parent, const QStringList strings, int type Type) QTreeWidgetItem(QTreeWidget *parent, int type Type) QTreeWidgetItem(const QStringList strings, int type Type) QTreeWidgetItem(int type Type)我们使用匿名函数对象注意只能写一个内容 //添加顶层控件QTreeWidgetItem *item1 new QTreeWidgetItem(QStringList()Chinese);ui-treeWidget-addTopLevelItem(item1);QTreeWidgetItem *item2 new QTreeWidgetItem(QStringList()mandarin普通话);ui-treeWidget-addTopLevelItem(item1);QTreeWidgetItem *item3 new QTreeWidgetItem(QStringList()English);ui-treeWidget-addTopLevelItem(item1);接下来添加顶层控件的子控件 来自于QTreeWidgetItem void addChild(QTreeWidgetItem *child) void addChildren(const QListQTreeWidgetItem * children)//添加子控件//方法1:先创建再传入QTreeWidgetItem *child1 new QTreeWidgetItem(QStringList()简体中文(简体));item1-addChild(child1);//方法2:创建时直接作为参数传入item1-addChild(new QTreeWidgetItem(QStringList()繁体中文(繁体)));item3-addChild(new QTreeWidgetItem(QStringList()英式英语(英式)));item3-addChild(new QTreeWidgetItem(QStringList()美式英语(美式)));10.4.3 添加行为 当点击某个项目时我们为其添加输出内容的行为 信号 void itemClicked(QTreeWidgetItem *item, int column) //单击信号 void itemDoubleClicked(QTreeWidgetItem *item, int column) //双击信号注意这里参数column相当于一个数组代表第列子空控件代表第列的子控件 输出内容 QString text(int column) const//添加行为connect(ui-treeWidget,QTreeWidget::itemClicked,[](QTreeWidgetItem *item, int column){qDebug()item-text(column)endl;});去掉双引号以utf8格式输出 //添加行为connect(ui-treeWidget,QTreeWidget::itemClicked,[](QTreeWidgetItem *item, int column){qDebug()item-text(column).toUtf8().data()endl;});10.5 表格控件QLabelWidget 10.5.1 ui添加 拖入表格控件table widget 也可以双击空白处添加内容 运行 紫色项目 运行 10.5.2 代码添加 重新创建工程拖出一个表格控件 头文件 #include QTableWidget设置列/行数函数 void setColumnCount(int columns) void setRowCount(int rows)//设置3列ui-tableWidget-setColumnCount(3);//设置4行ui-tableWidget-setRowCount(4);设置水平/垂直表头信息函数 void setHorizontalHeaderItem(int column, QTableWidgetItem *item) void setHorizontalHeaderLabels(const QStringList labels)void setVerticalHeaderItem(int row, QTableWidgetItem *item) void setVerticalHeaderLabels(const QStringList labels)例 //添加表头信息ui-tableWidget-setHorizontalHeaderLabels(QStringList()国家语言介绍);为表格添加项目 函数 void setItem(int row, int column, QTableWidgetItem *item)//行 列 item首先向表中添加控件有2中方式 按列添加 即一列一列添加创建一列的数据再循环将这一列的0行数据1行数据2行数据…添加进去 例 //向表中添加控件//创建一列控件QStringList country;countryChinaUSAJapanUK;QStringList language;languageChineseEnglishJapaneseEnglish;QStringList introduce;introducegoodniceshitnice;//将控件按列添加进去for(int i0;i4;i){ui-tableWidget-setItem(i,0,new QTableWidgetItem(country[i]));ui-tableWidget-setItem(i,1,new QTableWidgetItem(language[i]));ui-tableWidget-setItem(i,2,new QTableWidgetItem(introduce[i]));}按行添加 即一行数据一行数据添加原理相同不再演示 10.5.3 添加行为 点击表格中的某个数据将其内容输出来自于QTableWidget 发出信号函数 void cellActivated(int row, int column) void cellChanged(int row, int column) void cellClicked(int row, int column) void cellDoubleClicked(int row, int column) void cellEntered(int row, int column) void cellPressed(int row, int column) void currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn) void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous) void itemActivated(QTableWidgetItem *item) void itemChanged(QTableWidgetItem *item) void itemClicked(QTableWidgetItem *item) void itemDoubleClicked(QTableWidgetItem *item) void itemEntered(QTableWidgetItem *item) void itemPressed(QTableWidgetItem *item) void itemSelectionChanged()1、这里我们使用单击信号itemClicked 例 //添加动作connect(ui-tableWidget,QTableWidget::itemClicked,[](QTableWidgetItem *item){qDebug()item-text()endl;});2、使用cellClicked信号以返回行列 connect(ui-tableWidget,QTableWidget::cellClicked,[](int row,int col){qDebug()row:rowcolcolendl;});10.6 其他控件 Qt 中控件的使用方法可参考 Qt 提供的帮助文档 10.7 自定义控件 在搭建 Qt 窗口界面的时候在一个项目中很多窗口或者是窗口中的某个模块会被经常性的重复使用。一般遇到这种情况我们都会将这个窗口或者模块拿出来做成一个独立的窗口类以备以后重复使用。 10.7.1 创建自定义控件类 创建新工程右击添加新文件选择QT设计师界面类 下面选择widget即可 随便取个名 mywidget就是我们自己创建的ui文件 双击进入我们创建的ui文件添加常用控件 这里我拖入spin box和水平进度条控件 布局后 然后到其他ui里准备使用我们的自定义控件 10.7.2 使用自定义控件类 打开其他ui先拖入一个widget 在widget里存放控件 右击widget控件选择提升 输入我们的自定义控件类 点击添加和提升 此时它属于我们的自定义控件类 运行 10.7.3 添加动作 1、设置spinbox改变导致slider滑动 spinbox 头文件 #include QSpinBox发出信号 void textChanged(const QString text) void valueChanged(int i) void valueChanged(const QString text) // 重载需要用函数指针匹配slider 头文件 #include QSlider 父的槽函数 void setValue(int)在构造函数实现且ui属于mywidget所以要在mywidget.cpp中实现 //重载valueChangedvoid (QSpinBox:: *p)(int) QSpinBox::valueChanged;//设置spinbox改变导致slider滑动connect(ui-spinBox,p,ui-horizontalSlider,QSlider::setValue);2、设置滑动slider导致spinbox改变 spinbox 槽函数 void setValue(int val)slider 发出信号 void valueChanged(int value)//设置滑动slider导致spinbox改变connect(ui-horizontalSlider,QSlider::valueChanged,ui-spinBox,QSpinBox::setValue);10.7.4 设置对外接口 在主窗口中设置2个按钮setHalf、getValue 不过由于这两个ui分别是不同的文件无法直接调用 因此需要在自定义控件里设置对外接口 首先在mywidget.h的public中声明对外接口 public:explicit MyWidget(QWidget *parent nullptr);~MyWidget();//提供setHalf接口void mysetHalf(int value);//提供getValue接口int mygetValue(void);然后在mywidget.cpp中实现 void MyWidget::mysetHalf(int value) {ui-horizontalSlider-setValue(value); }int MyWidget::mygetValue() {return ui-horizontalSlider-value(); }最后在widget.cpp中调用 //调用2个接口connect(ui-button_setHalf,QPushButton::clicked,[](){ui-widget-mysetHalf(50);});connect(ui-button_getValue,QPushButton::clicked,[](){qDebug()ui-widget-mygetValue()endl;});11 Qt消息机制和事件 11.1 事件 事件event是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、 敲下键盘或者是窗口需要重新绘制的时候都会发出一个相应的事件。一些事件在对用户操作做出响应时发出如键盘事件等另一些事件则是由系统自动发 出如计时器事件。 在前面我们也曾经简单提到Qt 程序需要在 main()函数创建一个 QApplication 对象然后调用它的 exec()函数。这个函数就是开始 Qt 的主事件循环。在执行 exec()函数之后程序将进入事件循环来监听应用程序的事件。当事件发生时 Qt 将创建一个事件对象。Qt 中所有事件类都继承于 QEvent。在事件对象创建完毕后Qt 将这个事件对象传递给 QObject 的 event()函数。event()函数并不直接处理事件而是按照事件对象的类型分派给特定的事件处理函数event handler关于这一点会在后边详细说明。 在所有组件的父类 QWidget 中定义了很多事件处理的回调函数如 virtual void keyPressEvent(QKeyEvent *event) virtual void keyReleaseEvent(QKeyEvent *event) virtual void leaveEvent(QEvent *event) //鼠标离开事件 virtual void mouseDoubleClickEvent(QMouseEvent *event) virtual void mouseMoveEvent(QMouseEvent *event) virtual void mousePressEvent(QMouseEvent *event) virtual void mouseReleaseEvent(QMouseEvent *event) virtual void enterEvent(QEvent *event) //鼠标进入事件这些函数都是 virtual 的所以我们必须在子类中重新实现这些函数。 11.1.1 重写准备 例重写label控件的事件如上面的几个事件 创建工程添加label并对label添加边框 注意label属于系统QLbel类无法修改因此如果重写QLabel事件需要在自定义label控件中实现事件的重写即自定义一个类令其继承于该类 所以需要在工程里新建一个类 添加名称mylabel后父类这里没有QLabel类因此我们先写QWidget 修改mylabel.h文件中的QWidget为QLabel #include QLabelclass mylabel : public QLabel {Q_OBJECT public:explicit mylabel(QWidget *parent nullptr);signals:};这时我们制定的类mylabel继承于QLabel这样我们才可以在mylabel中重写QLabel的事件 修改mylabel.cpp文件内容 mylabel::mylabel(QWidget *parent) : QLabel(parent) {}注意此时label属于QLabel而不是我们需要的mylabel 因此需要将label的类型提升成mylabel这样label的控件才能使用mylabel重写的事件 添加内容后添加并提升即可 提升成功 总结如果想重写某个类的事件一般情况下需要自定义一个类继承于该控件的类型然后将控件的类提升成自定义的类这样我们就可以在自定义类中重写控件类型事件函数 11.1.2 重写事件 QLabel的一些事件 virtual void keyPressEvent(QKeyEvent *ev) override //键盘事件 virtual void mouseMoveEvent(QMouseEvent *ev) override //鼠标移动事件 virtual void mousePressEvent(QMouseEvent *ev) override//鼠标按压事件 virtual void mouseReleaseEvent(QMouseEvent *ev) override //鼠标释放事件 virtual void paintEvent(QPaintEvent *) override //绘画事件QWidget的一些事件 11.1.2.1 重写鼠标进入和离开事件 virtual void leaveEvent(QEvent *event) //鼠标离开事件 virtual void enterEvent(QEvent *event) //鼠标进入事件在mylabel.h中声明这两个事件 virtual void leaveEvent(QEvent *event); //鼠标离开事件virtual void enterEvent(QEvent *event); //鼠标进入事件在mylabel.cpp中实现这两个事件 void mylabel::leaveEvent(QEvent *event) {qDebug()mouseLeaveendl; }void mylabel::enterEvent(QEvent *event) {qDebug()mouseEnterendl; }11.1.2.2 重写鼠标按下和拖动事件 virtual void mouseMoveEvent(QMouseEvent *ev) override //鼠标移动事件 virtual void mousePressEvent(QMouseEvent *ev) override//鼠标按压事件在mylabel.h中声明这两个事件 virtual void mouseMoveEvent(QMouseEvent *ev) override; //鼠标移动事件virtual void mousePressEvent(QMouseEvent *ev) override;//鼠标按压事件在mylabel.cpp中实现这两个事件 void mylabel::mouseMoveEvent(QMouseEvent *ev) {qDebug()鼠标移动endl; }void mylabel::mousePressEvent(QMouseEvent *ev) {qDebug()mousePressendl; }11.1.2.3 重写获取鼠标哪个按键按下 查看QMouseEvent类 头文件 #include QMouseEvent公共函数 //判断是鼠标哪个按键 Qt::MouseButton button() const Qt::MouseButtons buttons() const而Qt::MouseButton里 例 void mylabel::mousePressEvent(QMouseEvent *ev) {if(ev-button() Qt::LeftButton)qDebug()左键按下endl;else if(ev-button() Qt::RightButton)qDebug()右键按下endl; }11.1.2.4 重写获取鼠标的坐标 //全局坐标 int globalX() const int globalY() const//局部坐标 int x() const int y() const例 void mylabel::mouseMoveEvent(QMouseEvent *ev) {//默认情况鼠标按下才可移动qDebug()鼠标移动 xev-x()yev-y()endl; }void mylabel::mousePressEvent(QMouseEvent *ev) {if(ev-button() Qt::LeftButton)qDebug()左键按下 xev-x()yev-y()endl;else if(ev-button() Qt::RightButton)qDebug()右键按下 xev-x()yev-y()endl; }不过默认情况下只有按下才会触发移动函数 设置鼠标跟踪函数 在QWidget公共函数里只需在mylabel的构造函数中设置 void setMouseTracking(bool enable)在mylabel.cpp中加入 mylabel::mylabel(QWidget *parent) : QLabel(parent) {this-setMouseTracking(true); }此时不需要按下鼠标就能显示坐标 11.2 事件分发器 事件对象创建完毕后Qt 将这个事件对象传递给 QObject 的 event()函数。 event()函数并不直接处理事件而是将这些事件对象按照它们不同的类型分发给不同的事件处理器event handler。 如上所述event()函数主要用于事件的分发 因此如果希望在事件分发之前做一些操作可以重写这个 event()函数这个函数有一个 QEvent 对象作为参数也就是需要转发的事件对象。函数返回值是 bool 类型 如果传入的事件已被识别并且处理则需要返回 true否则返回 false。 如果返回值是 true那么 Qt 会认为这个事件已经处理完毕不会再将这个事件发送给其它对象而是会继续处理事件队列中的下一事件。 在 event()函数中调用事件对象的 accept()和 ignore()函数是没有作用的不会影响到事件的传播。 我们处理过自己感兴趣的事件之后可以直接返回 true表示我们已经对此事件进行了处理对于其它我们不关心的事件则需要调用父类的event()函数继续转发否则这个组件就只能处理我们定义的事件 //QLabel virtual bool event(QEvent *e) override//QEvent Public Types enum Type { None, ActionAdded, ActionChanged, ActionRemoved, ActivationChange, …, MaxUser }点击 例在事件分发器中处理鼠标按压事件 先将原来的没有重写事件分发器的鼠标按压事件加以处理以区分 void mylabel::mousePressEvent(QMouseEvent *ev) {if(ev-button() Qt::LeftButton)qDebug()mousePressEvent左键按下 xev-x()yev-y()endl;else if(ev-button() Qt::RightButton)qDebug()mousePressEvent右键按下 xev-x()yev-y()endl; }mylabel.h中声明重写事件分发器 virtual bool event(QEvent *e) override;在mylabel.cpp中实现 bool mylabel::event(QEvent *e) {//只关心mouseButtonPress事件if(e-type() QEvent::MouseButtonPress){qDebug()事件分发器鼠标按下endl;return true;}//其他事件调用父类QLabel的event处理return QLabel::event(e); }分发器里加入获取x,y坐标 注意Event中没有对应的函数在QMouseEvent中有因此我们在分发器运行后将其类型转化为QMouseEvent if(e-type() QEvent::MouseButtonPress){qDebug()事件分发器鼠标按下endl;QMouseEvent *ev static_castQMouseEvent *(e);qDebug()x ev-x()y ev-y()endl;return 0;}11.3 事件过滤器 有时候对象需要查看、甚至要拦截发送到另外对象的事件。例如对话框可能想要拦截按键事件不让别的组件接收到或者要修改回车键的默认处理。 通过前面的章节我们已经知道Qt 创建了 QEvent 事件对象之后会调用 QObject 的 event()函数处理事件的分发。显然我们可以在 event()函数中实现拦截的操作。由于 event()函数是 protected 的因此需要继承已有类。 如果组件很多就需要重写很多个 event()函数。这当然相当麻烦更不用说重 写 event()函数还得小心一堆问题。好在 Qt 提供了另外一种机制来达到这一目 的事件过滤器。 步骤 加载事件过滤器重写事件过滤器 QObject 有一个 eventFilter()函数用于建立事件过滤器。函数原型如下 Public Functions virtual bool eventFilter(QObject *watched, QEvent *event) //重写事件过滤器// 事件触发的控件 控件产生的具体事件(鼠标按下、移动等) void installEventFilter(QObject *filterObj) //加载事件过滤器这个函数正如其名字显示的那样是一个“事件过滤器”。所谓事件过滤器可以理解成一种过滤代码。事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型就进行我们自己的处理如果不是就继续转发。这个函数返回一个 bool 类型如果将参数 event 过滤出来不想让它继续转发 就返回 true否则返回 false。事件过滤器的调用时间是目标对象也就是参数里面的 watched 对象接收到事件对象之前。也就是说如果你在事件过滤器中停止了某个事件那么watched 对象以及以后所有的事件过滤器根本不会知道这么一个事件。 例 首先在mylabel.cpp的构造函数中加载事件过滤器 mylabel::mylabel(QWidget *parent) : QLabel(parent) {this-setMouseTracking(true);//鼠标跟踪//加载事件过滤器this-installEventFilter(this); }然后重写事件过滤器在mylabel.h中声明 事件过滤器函数 //声明事件过滤器virtual bool eventFilter(QObject *watched, QEvent *event);在mylabel.cpp中实现 事件过滤器函数 //重写事件过滤器 bool mylabel::eventFilter(QObject *watched, QEvent *event) {if(watched this){if(event-type() QEvent::MouseButtonPress){qDebug()事件过滤器鼠标按下endl;QMouseEvent *ev static_castQMouseEvent *(event);qDebug()x ev-x()y ev-y()endl;return 1;}}// 其他控件和事件全部交给父类处理return QLabel::eventFilter(watched,event); }注意 事件过滤器的强大之处在于我们可以为整个应用程序添加一个事件过滤器。 installEventFilter() 函 数 是 QObject 的 函 数 QApplication 或 者 QCoreApplication 对象都是 QObject 的子类因此我们可以向 QApplication 或者 QCoreApplication 添加事件过滤器。 这种全局的事件过滤器将会在所有其它特性对象的事件过滤器之前调用。尽管很强大但这种行为会严重降低整个 应用程序的事件分发效率。因此除非是不得不使用的情况否则的话尽量不使用。事件过滤器和被安装过滤器的组件必须在同一线程否则过滤器将不起作用。 另外如果在安装过滤器之后这两个组件到了不同的线程那么只有等到二者重新回到同一线程的时候过滤器才会有效 11.4 总结 Qt 的事件是整个 Qt 框架的核心机制之一也比较复杂。说它复杂更多是因为它涉及到的函数众多而处理方法也很多有时候让人难以选择。现在我们简单总结一下 Qt 中的事件机制。 Qt 中有很多种事件鼠标事件、键盘事件、大小改变的事件、位置移动的事件 等等。如何处理这些事件实际有两种选择 所有事件对应一个事件处理函数在这个事件处理函数中用一个很大的分支 语句进行选择其代表作就是 win32 API LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam在这个函数中我们需要使用 switch 语句选择 message 参数的类型进行处理典型代码是 switch(message) {case WM_PAINT:// ...break;case WM_DESTROY:// ...break;... }每一种事件对应一个事件处理函数。Qt 就是使用的这么一种机制 mouseEvent() keyPressEvent() … Qt 具有这么多种事件处理函数肯定有一个地方对其进行分发否则Qt 怎么知道哪一种事件调用哪一个事件处理函数呢这个分发的函数就是 event()显然当 QMouseEvent 产生之后event()函数将其分发给 mouseEvent()事件处理器进行处理。 而event()函数会有两个问题 event()函数是一个 protected 的函数这意味着我们要想重写 event() 必须继承一个已有的类。试想我的程序根本不想要鼠标事件程序中所有 组件都不允许处理鼠标事件是不是我得继承所有组件一一重写其 event() 函数protected 函数带来的另外一个问题是如果我基于第三方库进行开 发而对方没有提供源代码只有一个链接库其它都是封装好的。我怎么 去继承这种库中的组件呢event()函数的确有一定的控制不过有时候我的需求更严格一些我希望那些组件根本看不到这种事件。event()函数虽然可以拦截但其实也是接收到了QMouseEvent 对象。我连让它收都收不到。这样做的好处是模拟一种系统根本没有那个事件的效果所以其它组件根本不会收到这个事件也就无需修改自己的事件处理函数。这种需求怎么办呢 这两个问题是 event()函数无法处理的。于是Qt 提供了另外一种解决方案 事件过滤器。 事件过滤器给我们一种能力让我们能够完全移除某种事件。事件过滤器可以安装到任意 QObject 类型上面并且可以安装多个。如果要实现全局的事件过滤器则可以安装到 QApplication 或者 QCoreApplication 上面。这里需要注意的是如果使用 installEventFilter()函数给一个对象安装事件过滤器那么该事件过滤器只对该对象有效只有这个对象的事件需要先传递给事件过滤器的 eventFilter() 函数进行过滤 其它对象不受影响。如果给QApplication 对象安装事件过滤器那么该过滤器对程序中的每一个对象都有效任何对象的事件都是先传给 eventFilter()函数。 事件过滤器可以解决刚刚我们提出的 event()函数的两点不足 首先事件过滤器不是 protected 的因此我们可以向任何 QObject 子类 安装事件过滤器其次事件过滤器在目标对象接收到事件之前进行处理如果我们将事件过 滤掉目标对象根本不会见到这个事件。 事实上还有一种方法我们没有介绍。Qt 事件的调用最终都会追溯到QCoreApplication::notify() 函 数 因此最大的控制权实际上是重写QCoreApplication::notify()。这个函数的声明是 virtual bool QCoreApplication::notify ( QObject * receiver, QEvent * event );该函数会将 event 发送给 receiver也就是调用 receiver-event(event)其返回值就是来自 receiver 的事件处理器。注意这个函数为任意线程的任意对象的任意事件调用因此它不存在事件过滤器的线程的问题。不过我们并不推荐这么做因为notify()函数只有一个而事件过滤器要灵活得多。 现在我们可以总结一下 Qt 的事件处理实际上是有五个层次 重写 paintEvent()、mousePressEvent()等事件处理函数。这是最普通、最简单的形式同时功能也最简单。重写 event()函数。event()函数是所有对象的事件入口QObject 和 QWidget 中的实现默认是把事件传递给特定的事件处理函数。在特定对象上面安装事件过滤器。该过滤器仅过滤该对象接收到的事件。在 QCoreApplication::instance()上面安装事件过滤器。该过滤器将过滤所 有对象的所有事件因此和 notify()函数一样强大但是它更灵活因为可以安装多个过滤器。全局的事件过滤器可以看到 disabled 组件上面发出的鼠标事件。全局过滤器有一个问题只能用在主线程。重写 QCoreApplication::notify()函数。这是最强大的和全局事件过滤器 一样提供完全控制并且不受线程的限制。但是全局范围内只能有一个被使用因为 QCoreApplication 是单例的 12 定时器 12.1 触发方式 定时器事件触发定时器对象(信号)触发静态成员函数触发 定时器事件函数 QTimer ClassReimplemented Protected Functions virtual void timerEvent(QTimerEvent *e) override启动计时器函数 QObjectPublic Functions int startTimer(int interval, Qt::TimerType timerType Qt::CoarseTimer) int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType Qt::CoarseTimer)注意这里返回值是int类型是定时器的ID即一个进程可以有多个计时器 12.2 实现定时器 12.2.1 定时器事件触发 12.2.1.1 单个定时器 创建工程 先在widget.h中声明定时器事件 //声明定时器事件virtual void timerEvent(QTimerEvent *e) override;然后在widget.cpp中实现 //重写定时器事件 void Widget::timerEvent(QTimerEvent *e) {static int time 0;ui-label-setText(QString::number(time)); }然后在widget.cpp的构造函数中启动定时器事件 Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui-setupUi(this);//启动定时器事件this-startTimer(1000); //1000ms }12.2.2.2 同时启动多个定时器 返回定时器ID函数 QTimerEvent ClassPublic Functions int QTimerEvent::timerId() const创建工程在UI里拖出2个label 由于不同定时器有不同的ID因此我们先在widget.h创建两个ID以存放定时器ID private:Ui::Widget *ui;//定时器idint id1;int id2;在widget.h中声明定时器事件 //声明定时器事件virtual void timerEvent(QTimerEvent *e) override;在widget.c中重写 先开启2个定时器 //开始2个定时器this-id1 this-startTimer(1000);this-id2 this-startTimer(2000);然后实现 //实现定时器事件 void Widget::timerEvent(QTimerEvent *e) {static int num1 0 ;static int num2 0;//使用timerID函数if(e-timerId() id1)ui-label-setText(QString::number(num1));else if (e-timerId() id2)ui-label_2-setText(QString::number(num2)); }12.2.2 定时器对象触发 头文件 #includeQTimer先向UI中再拖入一个label和2个button_start/button_stop QTimer ClassPublic Slots void start() void start(int msec) void stop()Signals void timeout()先在构造函数中创建一个定时器对象 // 计时器对象创建QTimer *time new QTimer(this);然后给定时器添加行为超时记录时间 // 给定时器添加行为:超时记录时间connect(time,QTimer::timeout,[](){static int num 0 ;ui-label_3-setText(QString::number(num));});最后给2个button添加行为点击start与stop //启动定时器connect(ui-button_start,QPushButton::clicked,[](){time-start(1000);});//暂停定时器connect(ui-button_stop,QPushButton::clicked,[](){time-stop();});12.2.3 静态成员函数触发 通过singleShot实现延时功能做完即结束而非重复循环某事件 先向UI中再拖入一个label_4 在构造函数中实现 由于是静态成员函数所以可以通过类名称访问 //静态成员函数触发QTimer::singleShot(3000,[](){ui-label_4-setText(Hello,my pricess.);});13 绘图和绘图设备 13.1 QPainter Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制。整个绘图系统基于 QPainterQPainterDevice 和 QPaintEngine 三个类。 QPainter画笔用来执行绘制的操作QPaintDevice画图设备一个二维空间的抽象这个二维空间允许 QPainter 在其上面进行绘制也就是 QPainter 工作的空间QPaintEngine画图引擎提供了画笔QPainter在不同的设备上进行绘制的统一的接口。 QPaintEngine 类应用于 QPainter 和 QPaintDevice 之间通常对开发人员是透明的。除非你需要自定义一个设备否则你是不需要关心 QPaintEngine 这个类的。我们可以把 QPainter 理解成画笔把 QPaintDevice 理解成使用画笔的地方 比如纸张、屏幕等而对于纸张、屏幕而言肯定要使用不同的画笔绘制为了统一使用一种画笔我们设计了 QPaintEngine 类这个类让不同的纸张、屏幕都能使用一种画笔 下图给出了这三个类之间的层次结构 即使用 QPainter 在 QPainterDevice 上进行绘制它们之间使用 QPaintEngine 进行通讯也就是翻译 QPainter 的指令。 注意如果在主窗口上绘画必须在绘画事件(paintEvent)中完成绘图 [virtual protected] void QWidget::paintEvent(QPaintEvent *event)头文件 #include QPaintEvent #include QPainter绘画事件调用的时机 窗口加载update() 绘图函数 QPainter ClassPublic Functions // Arc弧 void drawArc(const QRectF rectangle, int startAngle, int spanAngle) void drawArc(const QRect rectangle, int startAngle, int spanAngle) void drawArc(int x, int y, int width, int height, int startAngle, int spanAngle)//chord弦 void drawChord(const QRectF rectangle, int startAngle, int spanAngle) void drawChord(int x, int y, int width, int height, int startAngle, int spanAngle) void drawChord(const QRect rectangle, int startAngle, int spanAngle)//ConvexPolygon凸多边形 void drawConvexPolygon(const QPointF *points, int pointCount) void drawConvexPolygon(const QPolygonF polygon) void drawConvexPolygon(const QPoint *points, int pointCount) void drawConvexPolygon(const QPolygon polygon)//Ellipse椭圆 void drawEllipse(const QRectF rectangle) void drawEllipse(const QRect rectangle) void drawEllipse(int x, int y, int width, int height) void drawEllipse(const QPointF center, qreal rx, qreal ry) void drawEllipse(const QPoint center, int rx, int ry)//GlyphRun字形运行 void drawGlyphRun(const QPointF position, const QGlyphRun glyphs)//图像 void drawImage(const QRectF target, const QImage image, const QRectF source, Qt::ImageConversionFlags flags Qt::AutoColor) void drawImage(const QRect target, const QImage image, const QRect source, Qt::ImageConversionFlags flags Qt::AutoColor) void drawImage(const QPointF point, const QImage image, const QRectF source, Qt::ImageConversionFlags flags ...) void drawImage(const QPoint point, const QImage image, const QRect source, Qt::ImageConversionFlags flags ...) void drawImage(const QRectF rectangle, const QImage image) void drawImage(const QRect rectangle, const QImage image) void drawImage(const QPointF point, const QImage image) void drawImage(const QPoint point, const QImage image) void drawImage(int x, int y, const QImage image, int sx 0, int sy 0, int sw -1, int sh -1, Qt::ImageConversionFlags flags Qt::AutoColor)//单条线 void drawLine(const QLineF line) void drawLine(const QLine line) void drawLine(int x1, int y1, int x2, int y2) void drawLine(const QPoint p1, const QPoint p2) void drawLine(const QPointF p1, const QPointF p2)//线 void drawLines(const QLineF *lines, int lineCount) void drawLines(const QVectorQLineF lines) void drawLines(const QPointF *pointPairs, int lineCount) void drawLines(const QVectorQPointF pointPairs) void drawLines(const QLine *lines, int lineCount) void drawLines(const QVectorQLine lines) void drawLines(const QPoint *pointPairs, int lineCount) void drawLines(const QVectorQPoint pointPairs)//路径 void drawPath(const QPainterPath path)//图片 void drawPicture(const QPointF point, const QPicture picture) void drawPicture(int x, int y, const QPicture picture) void drawPicture(const QPoint point, const QPicture picture)//饼图圆 void drawPie(const QRectF rectangle, int startAngle, int spanAngle) void drawPie(int x, int y, int width, int height, int startAngle, int spanAngle) void drawPie(const QRect rectangle, int startAngle, int spanAngle)//像素图 void drawPixmap(const QRectF target, const QPixmap pixmap, const QRectF source) void drawPixmap(const QRect target, const QPixmap pixmap, const QRect source) void drawPixmap(int x, int y, int w, int h, const QPixmap pixmap, int sx, int sy, int sw, int sh) void drawPixmap(int x, int y, const QPixmap pixmap, int sx, int sy, int sw, int sh) void drawPixmap(const QPointF point, const QPixmap pixmap, const QRectF source) void drawPixmap(const QPoint point, const QPixmap pixmap, const QRect source) void drawPixmap(const QPointF point, const QPixmap pixmap) void drawPixmap(const QPoint point, const QPixmap pixmap) void drawPixmap(int x, int y, const QPixmap pixmap) void drawPixmap(const QRect rectangle, const QPixmap pixmap) void drawPixmap(int x, int y, int width, int height, const QPixmap pixmap) void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap pixmap, QPainter::PixmapFragmentHints hints PixmapFragmentHints())//点 void drawPoint(const QPointF position) void drawPoint(const QPoint position) void drawPoint(int x, int y) void drawPoints(const QPointF *points, int pointCount) void drawPoints(const QPolygonF points) void drawPoints(const QPoint *points, int pointCount) void drawPoints(const QPolygon points) void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule Qt::OddEvenFill)//Polygon多边形 void drawPolygon(const QPolygonF points, Qt::FillRule fillRule Qt::OddEvenFill) void drawPolygon(const QPoint *points, int pointCount, Qt::FillRule fillRule Qt::OddEvenFill) void drawPolygon(const QPolygon points, Qt::FillRule fillRule Qt::OddEvenFill)//Polyline折线 void drawPolyline(const QPointF *points, int pointCount) void drawPolyline(const QPolygonF points) void drawPolyline(const QPoint *points, int pointCount) void drawPolyline(const QPolygon points)//Rect矩形 void drawRect(const QRectF rectangle) void drawRect(int x, int y, int width, int height) void drawRect(const QRect rectangle) void drawRects(const QRectF *rectangles, int rectCount) void drawRects(const QVectorQRectF rectangles) void drawRects(const QRect *rectangles, int rectCount) void drawRects(const QVectorQRect rectangles)//圆角矩形 void drawRoundedRect(const QRectF rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode Qt::AbsoluteSize) void drawRoundedRect(int x, int y, int w, int h, qreal xRadius, qreal yRadius, Qt::SizeMode mode ...) void drawRoundedRect(const QRect rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode ...)//静态文本 void drawStaticText(const QPointF topLeftPosition, const QStaticText staticText) void drawStaticText(const QPoint topLeftPosition, const QStaticText staticText) void drawStaticText(int left, int top, const QStaticText staticText)//文本 void drawText(const QRectF rectangle, int flags, const QString text, QRectF *boundingRect nullptr) void drawText(const QPointF position, const QString text) void drawText(const QPoint position, const QString text) void drawText(int x, int y, const QString text) void drawText(const QRect rectangle, int flags, const QString text, QRect *boundingRect nullptr) void drawText(int x, int y, int width, int height, int flags, const QString text, QRect *boundingRect nullptr) void drawText(const QRectF rectangle, const QString text, const QTextOption option QTextOption())//TiledPixmap平铺像素图 void drawTiledPixmap(const QRectF rectangle, const QPixmap pixmap, const QPointF position QPointF()) void drawTiledPixmap(int x, int y, int width, int height, const QPixmap pixmap, int sx 0, int sy 0) void drawTiledPixmap(const QRect rectangle, const QPixmap pixmap, const QPoint position ...)设置画笔函数 QPainter ClassPublic Functions void setPen(const QPen pen) void setPen(const QColor color) //颜色 void setPen(Qt::PenStyle style) //样式13.1.1 窗口加载背景 例画一个背景图 创建工程首先在widget.h声明绘图事件 //声明绘图事件virtual void paintEvent(QPaintEvent *event);添加资源图片 在widget.cpp实现绘图事件 定义画笔painter QPainter *painter new QPainter(this);使用pixmap加载资源图片并修改图片大小 //定义图片控件QPixmap pix;pix.load(:/benz.jpg);//修改图片大小pix.scaled(this-size());修改大小函数 QPixmap ClassPublic Functions QPixmap scaled(const QSize size, Qt::AspectRatioMode aspectRatioMode Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode Qt::FastTransformation) const QPixmap scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode Qt::FastTransformation) const画笔在主窗口绘画 //画笔在主窗口绘画painter-drawPixmap(0,0,this-width(),this-height(),pix);13.1.2 update()重新加载 新建工程 头文件 #includeQPainter #includeQPixmap首先在widget.h声明绘图事件 //声明绘图事件virtual void paintEvent(QPaintEvent *event);添加资源图片 在widget.cpp实现绘图事件 定义画笔painter QPainter *painter new QPainter(this);使用pixmap加载资源图片并修改图片大小 //定义图片控件QPixmap pix;pix.load(:/benz.jpg);//修改图片大小pix.scaled(this-size());画笔在主窗口绘画 //画笔在主窗口绘画painter-drawPixmap(0,0,this-width()*0.75,this-height()*0.75,pix); //注意高和长都缩小到原来的0.75倍下面添加一个button 修改button位置到中间的下方 首先我们要知道窗口和按钮的宽高 this-width();this-height(); //窗口的宽高 ui-pushButton-width();ui-pushButton-height(); //按钮的宽高 计算图 //修改button位置到中间的下方ui-pushButton-move((this-width()-ui-pushButton-width())*0.5,\this-height()-ui-pushButton-height());添加button的动作使其被点击时图片向右移动10单位更新显示移动后的图片 修改painter函数 static int x 0 ;//静态成员不会被释放如果是普通的每次使用都是0//画笔在主窗口绘画painter-drawPixmap(x,0,this-width()*0.85,this-height()*0.85,pix);if(x this-width())//超出窗口宽度x0;x10;为button按钮添加动作点击更新图片 connect(ui-pushButton,QPushButton::clicked,[](){//按下按钮update重新绘图this-update();});13.1.3 绘制其他图案 新建工程首先在widget.h声明绘图事件 //声明绘图事件virtual void paintEvent(QPaintEvent *event);在widget.cpp实现绘图事件 定义画笔painter QPainter *painter new QPainter(this);13.1.3.1 画线 //画线函数painter-drawLine(0,0,400,400);13.1.3.2 画矩形rect void drawRect(int x, int y, int width, int height)//画矩形rectanglepainter-drawRect(0,0,300,300);13.1.3.3 修改画笔颜色 //修改画笔颜色painter-setPen(Qt::red);painter-drawRect(100,100,300,300);//改完再画一次13.1.3.4 修改画笔样式 //修改画笔样式painter-setPen(Qt::DashLine);painter-drawRect(200,200,200,200);不过只能设置颜色或样式无法同时设置 13.1.3.5 画圆 void drawEllipse(int x, int y, int width, int height)//画圆painter-drawEllipse(300,300,300,300);13.1.3.6 画椭圆 void drawEllipse(int x, int y, int width, int height)//画椭圆painter-drawEllipse(200,200,300,150);13.1.3.7 画扇形 void drawPie(int x, int y, int width, int height, int startAngle, int spanAngle) //画扇形painter-setPen(Qt::red);painter-drawPie(200,200,400,400,0,2000);13.2 绘图设备 绘图设备是指继承 QPaintDevice 的子类。Qt 一共提供了四个这样的类分别 是 QPixmap、QBitmap、QImage 和 QPicture。其中 QPixmap专门为图像在屏幕上的显示做了优化QBitmapQPixmap 的一个子类它的色深限定为 1可以使用 QPixmap 的 isQBitmap()函数来确定这个 QPixmap 是不是一个 QBitmap。QImage专门为图像的像素级访问做了优化。QPicture则可以记录和重现 QPainter 的各条命令 13.2.1 QPixmap、QBitmap、QImage QPixmap 继承了 QPaintDevice因此你可以使用 QPainter 直接在上面绘制图 形。QPixmap 也可以接受一个字符串作为一个文件的路径来显示这个文件比如你想在程序之中打开 png、jpeg 之类的文件就可以使用 QPixmap。使用 QPainter 的 drawPixmap()函数可以把这个文件绘制到一个 QLabel、QPushButton 或者其他的设备上面。QPixmap 是针对屏幕进行特殊优化的因此它与实际的底层显示设备息息相关。注意这里说的显示设备并不是硬件而是操作系统提供的原 生的绘图引擎。所以在不同的操作系统平台下QPixmap 的显示可能会有所差别。 QBitmap 继承自 QPixmap因此具有 QPixmap 的所有特性提供单色图像。QBitmap 的色深始终为 1。色深这个概念来自计算机图形学是指用于表现颜色的二进制 的位数。我们知道计算机里面的数据都是使用二进制表示的。为了表示一种颜 色我们也会使用二进制。比如我们要表示 8 种颜色需要用 3 个二进制位这 时我们就说色深是 3。因此所谓色深为 1也就是使用 1 个二进制位表示颜色。 1 个位只有两种状态0 和 1因此它所表示的颜色就有两种黑和白。所以说 QBitmap 实际上是只有黑白两色的图像数据。 由于 QBitmap 色深小因此只占用很少的存储空间所以适合做光标文件和笔刷 下面我们来看同一个图像文件在 QPixmap 和 QBitmap 下的不同表现 void PaintWidget::paintEvent(QPaintEvent *) {QPixmap pixmap(:/Image/butterfly.png);QPixmap pixmap1(:/Image/butterfly1.png);QBitmap bitmap(:/Image/butterfly.png);QBitmap bitmap1(:/Image/butterfly1.png);QPainter painter(this);painter.drawPixmap(0, 0, pixmap);painter.drawPixmap(200, 0, pixmap1);painter.drawPixmap(0, 130, bitmap);painter.drawPixmap(200, 130, bitmap1); }这里我们给出了两张 png 图片。butterfly1.png 是没有透明色的纯白背景而 butterfly.png 是具有透明色的背景。我们分别使用 QPixmap 和 QBitmap 来加载它们。注意看它们的区别白色的背景在 QBitmap 中消失了而透明色在 QBitmap 中转换成了黑色其他颜色则是使用点的疏密程度来体现的。 QPixmap 使用底层平台的绘制系统进行绘制无法提供像素级别的操作而 QImage 则是使用独立于硬件的绘制系统实际上是自己绘制自己因此提供了像素级别的操作并且能够在不同系统之上提供一个一致的显示形式。 QImage 与 QPixmap 的区别 QPixmap 主要是用于绘图针对屏幕显示而最佳化设计QImage 主要是为图 像 I/O、图片访问和像素修改而设计的QPixmap 依赖于所在的平台的绘图引擎故例如反锯齿等一些效果在不同的 平台上可能会有不同的显示效果QImage 使用 Qt 自身的绘图引擎可在不 同平台上具有相同的显示效果由于 QImage 是独立于硬件的也是一种 QPaintDevice因此我们可以在另 一个线程中对其进行绘制而不需要在 GUI 线程中处理使用这一方式可以 很大幅度提高 UI 响应速度。QImage 可通过 setPixpel()和pixel()等方法直接存取指定的像素。 QImage 与 QPixmap 之间的转换: QImage 转 QPixmap 使用 QPixmap 的静态成员函数: fromImage() QPixmap fromImage(const QImage image, Qt::ImageConversionFlags flags Qt::AutoColor) QPixmap 转 QImage: 使用 QPixmap 类的成员函数: toImage() QImage toImage() const13.2.1.1 使用QBitmap绘图 在widget.cpp构造函数中 //定义一个绘图设备QBitmapQBitmap bit(800,800);定义画笔 //定义画笔QPainter painter(bit);painter.drawEllipse(QPoint(400,400),bit.width()/3,bit.height()/3);保存图片至某目录 //保存图片bit.save(C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\11_painter\\bit01.png);运行后不是显示到屏幕上而是保存在文件里打开文件 13.2.1.2 使用QImage绘图 在widget.cpp构造函数中 //定义一个绘图设备QImage并加载图片提前添加资源QImage img;img.load(:/benz_2.jpg);定义画笔 //定义画笔QPainter painter2(img);painter2.drawEllipse(QPoint(800,800),bit.width()/2,bit.height()/2);保存图片至某目录 //保存图片img.save(C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\11_painter\\img_01.png);运行后不是显示到屏幕上而是保存到文件里打开文件 注意观察可以看到圆的边缘 接下来我们根据QImage像素级别的操作的特性更改图片RBG颜色 在加载完图片后 //定义一个绘图设备QImageQImage img;img.load(:/benz_2.jpg); //由于圆心在(400,400)这里我将颜色起点设为(450450)以便观察for(int i450;i600;i){for(int j450;j600;j){int val qRgb(233,0,0);img.setPixel(i,j,val);}}运行 13.2.2 QPicture 可以记录和重现 QPainter 命令的绘图设备。 QPicture 将 QPainter 的命令序列化到一个 IO 设备保存为一个平台独立的文件格式。这种格式有时候会是“元文件(meta- files)”。Qt 的这种格式是二进制的不同于某些本地的元文件Qt 的 pictures 文件没有内容上的限制只要是能够被 QPainter 绘制的元素不论是字体还是 pixmap或者是变换 都可以保存进一个 picture 中。 QPicture 是平台无关的因此它可以使用在多种设备之上比如 svg、pdf、ps、 打印机或者屏幕。回忆下我们这里所说的 QPaintDevice实际上是说可以有 QPainter 绘制的对象。QPicture 使用系统的分辨率并且可以调整 QPainter 来消除不同设备之间的显示差异。 如果我们要记录下 QPainter 的命令首先要使用 QPainter::begin()函数将 QPicture 实例作为参数传递进去以便告诉系统开始记录记录完毕后使用 QPainter::end()命令终止。 例 在widget.cpp构造函数中 //定义一个绘图设备QPictureQPicture pic;//定义画笔QPainter painter3;记录绘图指令 //记录绘图指令painter3.begin(pic); //开始指令painter3.drawEllipse(100,100,100,100);//画图painter3.end(); //结束指令保存图片至某目录 //保存指令pic.save(C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\11_painter\\pic01.cmd);运行后将把指令保存到文件里 接下来重现绘图指令到主窗口在绘图事件完成 void Widget::paintEvent(QPaintEvent *event) { //重现画图指令://创建绘图设备QPicture pic;QPainter painter(this);//绘图设备pic加载绘图指令pic.load(C:\\Users\\HUIO\\Desktop\\Me\\QT\\00\\11_painter\\pic01.cmd);//画笔根据绘图指令绘图painter.drawPicture(10,10,pic); }
http://www.zqtcl.cn/news/235865/

相关文章:

  • 有哪些网站的搜索引擎网站设计需要需要用
  • 网站建设有哪些需求徐州百度运营中心
  • 怎么做电脑网站后台杭州网站制作公司排名
  • 济南手机网站定制价格wordpress前端登陆 投稿
  • 建设企业网站的原因网站开发项目经验和教训
  • 京东网站的建设与发展现状分析手机与pc网站同步模板
  • 枣阳网站建设吧yw最新域名备案查询
  • 西安知名网站建设公司什么网站可以分享wordpress
  • ugc网站开发2022恢复线下教学通知
  • 网站界面尺寸珠海网站建设制作哪家专业
  • 上海闸北城市建设有限公司网站想学设计没有基础怎么办
  • 免费微网站哪个好用在线网页代理浏览免费
  • 广州建设专业网站寻找做项目的网站
  • 湛江网站建设方案服务卖wordpress主题
  • 扬州做网站的网络公司wordpress设置登录背景图片
  • 有哪些好的网站建设移动网站建设解决方案
  • 江苏网站建设公司排名高校门户网站建设问题
  • 网站怎么加关键词视频网站程序
  • 建设网站需要的人员及资金建设一个网站的具体流程
  • 北京长空建设有限公司网站网站开发制作培训学校
  • 哪些网站可以免费做推广呢o2o营销模式
  • 注册网站的流程南京今天的最新消息
  • 做网站的没有进项票怎么办张家口市一建公司官网
  • 建设网站的本质智慧团建手机版
  • 嘉兴网站建设有前途吗沈阳男科医院排名10强名单公布
  • 手机网站变灰17种新型商业模式
  • 图书网站开发需求文档模板做网站现在用什么语言
  • 创建网站主题在哪里接单赚钱平台
  • 企业做网站的流程权威发布新闻的含义
  • 国外大型购物网站桂林视频网站制作