目录
一、消息对话框 QMessageBox(掌握)
二、常用窗口类(掌握)
三、主窗口类 QMainWindow(重点)
四、parent参数(掌握)
五、窗口传参
5.1 成员函数/构造函数
5.2 信号槽传参
六、事件机制(掌握)
一、文件选择对话框 QFileDialog(熟悉)
二、文件信息类 QFileInfo
三、文件读写类 QFile(掌握)
四、UI与耗时操作(掌握)
五、多线程 QThread(掌握)
5.1 线程的基本使用
5.2 异步刷新
5.3 关闭线程
一、消息对话框 QMessageBox(掌握)
之前的编程更多的是使用QDebug进行信息的输出,但是QDebug是调试信息,这些信息用户不可见,如果想给用户一些通知信息,使用消息对话框十分合适。
预设了四种消息对话框:
这种预设好的QDialog派生类往往具有一个共同的特点:弹窗使用一个静态成员函数。
如果只是简单弹窗,四种预设窗口的参数是相同的,如下所示:
参数1:依赖的父窗口
参数2:标题
参数3:展示的信息
返回值:枚举,表示用户点击的按键,只对question有意义
二、常用窗口类(掌握)
常用的窗口类继承结构如下所示:
QWidget类除了可以表示所有组件类的基类外,也是所有窗口类的基类,当QWidget构造函数的parent参数没有传递时,表示一个窗口对象;如果传递了,则表示一个组件对象。但是由于QWidget的继承层次比较高,实际开发过程中很少使用它的对象作为窗口和组件。
QWidget的直接派生类不光有对话框窗口类QDialog,还有主窗口类QMainWindow。对于大多软件而言,主窗口只有一个,建议使用QMainWindow,因为QMainWindow包含了菜单栏、工具栏、状态栏等。而QDialog无法胜任功能很多的软件的主窗口。
QWidget类作为所有窗口类的基类,内部也规定了很多窗口类共用的一些函数和属性,例如:
- 设置窗口标题
void setWindowTitle(const QString &)
通过此函数设置windowTitle属性值,来更改窗口标题文字
- 设置窗口图标
void setWindowIcon(const QIcon & icon)
通过此函数设置窗口的icon属性,来更改窗口的图标
- 设置窗口标记
void setWindowFlags(Qt::WindowFlags type)
通过设置窗口标记的枚举值,让窗口达到某种视觉效果。
可以同时设定多个标记,如下所示。
setWindowFlags(Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint)
- 设置窗口状态
void QWidget::setWindowState(Qt::WindowStates windowState)
通过设置窗口状态的枚举值,让窗口达到某种显示状态。
三、主窗口类 QMainWindow(重点)
QMainWindow表示主窗口类,因为相比QDialog,它多出了很多部分。本节课程创建的项目主窗口为QMainWindow。
1. 菜单栏 QMenuBar
菜单栏中的每个选项是一个菜单类QMenu对象
,这些对象属于菜单栏。
每个菜单中可以触发的选项被称为“动作”,类名为QAction。每个QAction对象可以通过Designer下方的Action编辑器来设置属性值。
QAction的属性常用属性设定如下:
QAction的常用信号如下:
2. 工具栏 QToolBar
在Designer中,直接把Action编辑器中的QAction拖动到工具栏即可。
3. 中心组件 QWidget
中心组件相当于之前QDialog的内容,用于设计窗口中主要展示的内容。
4. 状态栏 QStatusBar
使用槽函数可以显示或清除状态栏信息。
void QStatusBar::showMessage(const QString & message, int timeout = 0) [slot]
展示信息
参数1:要展示的文字
参数2:显示的时长,参数为毫秒,默认值为持续显示
void QStatusBar::clearMessage() [slot]
清除信息
四、parent参数(掌握)
parent参数除了表示组件与窗口的之间从属关系外,parent参数还能有效地防止内存泄露。所有子组件和子窗口都会等待父窗口销毁时,一并销毁。
下面的例子,自定义一个Qt的窗口类,步骤如下:
1. 在Qt Creator中,选中项目名称,鼠标右键,点击“添加新文件”。
2. 在弹出的窗口中,按照下图所示进行操作。
3. 在弹出的窗口中,配置窗口的相关信息。
4. 在弹出的窗口中,填写类名,点击“下一步”。
5. 在项目管理页面,直接点击完成。可以看到项目中多了一个窗口类的相关文件。
五、窗口传参
5.1 成员函数/构造函数
【例子】有两个窗口(A启动B),在窗口A中转动QDial,窗口B中的另一个QDial跟随转动。
5.2 信号槽传参
【例子】有两个窗口(A启动B),在窗口B中转动QDial,窗口A中的另一个QDial跟随转动。
六、事件机制(掌握)
事件机制是Qt一个核心机制,一些操作可以层层传递,程序员可以在传递的任何一个环节中,捕捉到这个事件并进行处理,不同于信号槽的是,它的使用不需要建立连接。
下图是某事件,从操作系统内核到窗口类的传递过程。
常见的事件对应的处理函数有:
void QWidget::paintEvent(QPaintEvent * event) [virtual protected]
绘制事件函数
void QWidget::resizeEvent(QResizeEvent * event) [virtual protected]
大小改变
void QWidget::mousePressEvent(QMouseEvent * event) [virtual protected]
鼠标按压
void QWidget::mouseReleaseEvent(QMouseEvent * event) [virtual protected]
鼠标释放
void QWidget::mouseDoubleClickEvent(QMouseEvent * event) [virtual protected]
鼠标双击
void QWidget::mouseMoveEvent(QMouseEvent * event) [virtual protected]
鼠标移动
void QWidget::moveEvent(QMoveEvent * event) [virtual protected]
自身移动
void QWidget::keyPressEvent(QKeyEvent * event) [virtual protected]
按键按下
void QWidget::keyReleaseEvent(QKeyEvent * event) [virtual protected]
按键释放
void QWidget::focusInEvent(QFocusEvent * event) [virtual protected]
获取焦点
void QWidget::focusOutEvent(QFocusEvent * event) [virtual protected]
失去焦点
void QWidget::closeEvent(QCloseEvent * event) [virtual protected]
关闭
void QWidget::enterEvent(QEvent * event) [virtual protected]
鼠标进入
void QWidget::leaveEvent(QEvent * event) [virtual protected]
鼠标离开
事件函数的使用步骤如下所示:
1. 查阅文档,确定要使用的事件函数,如:
void QWidget::paintEvent(QPaintEvent * event) [virtual protected]
2. 在头文件中声明事件函数
3. 在源文件中定义(覆盖)事件函数。
4. 在事件函数的函数体中写当前事件触发后执行的逻辑。
一、文件选择对话框 QFileDialog(熟悉)
与QMessageBox一样,QFileDialog也继承自QDialog,表示一个文件读写的选择对话框,这类对话框往往都是通过静态成员函数打开,并且返回值是用户选择的内容。
QFileDialog的常用静态成员函数,如下所示。
函数功能:获取一个读/写的文件路径
参数1:parent参数
参数2:窗口标题
参数3:在哪个路径打开(默认值为工作目录)
参数4:文件类型过滤器
返回值:选中的文件路径,如果用户不选择,则返回“”
二、文件信息类 QFileInfo
获取某一个文件的信息,一个不存在的路径也能创建出对应的QFileInfo对象,但是这样的对象调用exists函数,返回值是false
/**
* @brief Dialog::printFileInfo 打印文件信息
* @param path 文件路径
* @param browser 显示的组件
*/
void Dialog::printFileInfo(QString path, QTextBrowser * browser)
{
// 创建文件信息类对象
QFileInfo info(path);
// 获得创建的日期
QString time = info.created().toString("yyyy-MM-dd hh:mm:ss");
browser->append(time);
if(info.isReadable())
browser->append("可读");
else
browser->append("不可读");
// 获取文件大小
qint64 size = info.size();
QString text;
text.setNum(size).append("字节");
browser->append(text);
}
三、文件读写类 QFile(掌握)
QFile类专用于文件的读写,其间接基类是QIODevice,QIODevice类是Qt中所有读写类的基类,内部规定了很多IO的相关基础框架。
QFile类用完即可释放,使用栈内存对象即可,因此也不需要parent参数的传递,构造函数只需要传递文件路径即可。
常用的函数如下:
bool QFile::open(OpenMode mode) [virtual]
以不同的模式打开文件,返回值是打开的结果。
virtual bool atEnd() const
判断是否读取到文件尾
QByteArray QIODevice::read(qint64 maxSize)
读取,参数为最大的字节数,返回值是读取好的字节数组对象
qint64 QIODevice::write(const QByteArray & byteArray)
写出,参数是写出的内容,返回值是实际写出的字节数,出错返回-1
四、UI与耗时操作(掌握)
在默认的情况,Qt只有一个线程,这个线程的主要作用是保证程序的正常执行(事件、信号槽、UI显示、UI交互等),被称为“主线程”或“UI线程”。
但是一些耗时操作(文件读写、网络通信等),如果主线程中执行耗时操作,会导致正常的UI相关操作被阻塞,程序UI出现卡顿、假死的情况。此时如果尝试关闭程序,关闭的命令也会被阻塞,操作系统发现某个程序关闭响应不及时执行,操作系统会弹出来引导用户是否强行关闭。
五、多线程 QThread(掌握)
5.1 线程的基本使用
QThread类是Qt中的线程类,常用函数如下:
void msleep(unsigned long msecs) [static]
让当前线程休眠一定的毫秒数
开启线程的步骤:
1. 在Qt Creator中,选中项目名称,鼠标右键,点击添加新文件。
2. 在弹出的窗口中,按照下图所示进行操作。
3. 依次按照下图所示输入类名、基类名、类型信息后,点击“下一步”。
4. 在项目管理界面,直接点击“完成”。可以看到在项目结构中多了线程类相关的文件。
5. QThread类中有一个void QThread::run() [virtual protected]函数,在自定义线程类中覆盖此函数。
6. 在run函数的函数体中,编写子线程要执行的代码。
7. 在主线程中创建子线程对象后,调用void QThread::start(Priority priority = InheritPriority) [slot]函数启动子线程,此时程序会出现两个执行的线程分支。
5.2 异步刷新
在实际的开发中,经常会遇见以下需求:
在子线程中执行耗时操作,在主线程中执行UI操作,但是主线程的UI操作需要根据子线程的执行情况进行刷新。
此时可以使用信号槽的方式进行线程通信。
需要注意的是,主线程不要执行耗时操作,子线程不要执行UI操作。
5.3 关闭线程
如果一个线程在运行的过程中被强行关闭会出现:
上面的情况说明,线程还咋运行突然被终止。我们应该保证线程先停止。
介绍两种停止线程的方式:
1. terminate
简单粗暴,但是是否即刻停止取决于调度。
2. interrupt
相对温和,内部通过标志位退出。
bool QThread::isInterruptionRequested() const
返回当前线程是否被请求终止。
需要注意的是,线程的run函数执行完也会自动停止。