Qt——系统相关

前言:虽然Qt是跨平台的C++开发框架,但是Qt的很多能力都是操作系统提供的,这就说明程序是运行在操作系统上的,需要系统给我们提供支撑。


一.事件

1.概述

事件类似于信号槽,用户进行的各种操作,会产生事件,我们同样可以给事件关联上对应的处理函数(处理逻辑),当事件触发时,就能执行对应的代码。

实际上,信号槽是对事件的进一步封装,事件是信号槽的底层机制。

大多数情况下,我们都可以通过Qt内置的信号槽来实现代码逻辑,但是架不住在某些特定情况下,Qt内置的信号不能满足要求,此时就需要我们来通过重写事件处理函数的形式,来手动实现逻辑。

在 Qt 中使用一个对象来表示一个事件。所有的 Qt 事件均继承于抽象类 QEvent

常见事件属性如下:

鼠标事件 :鼠标左键、鼠标右键、鼠标滚轮,鼠标的移动,鼠标按键的按下和松开

键盘事件 :按键类型、按键按下、按键松开

定时器事件 :定时时间到达

进⼊离开事件: 鼠标的进⼊和离开

滚轮事件 :鼠标滚轮滚动

绘屏事件 :重绘屏幕的某些部分

显示隐藏事件 :窗口的显示和隐藏

移动事件: 窗口位置的变化

窗口事件: 是否为当前窗口

大小改变事件: 窗口大小改变

焦点事件: 键盘焦点移动

拖拽事件: 用鼠标进行拖拽


2.处理事件

让一段代码和某个事件关联起来,这样当事件触发时,就能执行对应的代码。

不同于信号槽通过connect完成关联,事件处理是通过重写对应的事件处理函数来实现的。

这里要用到**"多态"** 机制,创建子类,继承自Qt已有的父类,在子类中重写父类的事件处理函数,后续事件触发时,就会通过多态机制,执行子类中的函数。

值得注意的是,这里创建的子类,需要是对应的触发事件的控件,即想要哪个控件来触发事件,就创建对应的控件子类,在该子类中重写对应的函数

下面实现一下,当鼠标进入enterEvent()函数,离开leaveEvent()函数两个事件。

我们要实现鼠标进入、离开该标签 时,能够触发事件,由于上述两个函数的父类为QWidget ,所以只需要创建一个对应的子类,继承自QLabel父类,进而重写对应的两个函数

cpp 复制代码
void Label::enterEvent(QEvent* event)
{
    (void)event;
    qDebug() << "鼠标进入";
}

void Label::leaveEvent(QEvent* event)
{
    (void)event;
    qDebug() << "鼠标离开";
}

还有一点要注意的是,我们通过Qt designer创建的Label,默认的基类为QLabel:

所以我们自定义的子类是无法关联上该控件的,所以我们需要修改它的基类

右键点击控件,能够看到有一个"提升为":

填写我们自己创建的子类的类名及头文件 ,点击**"添加"** 、再点击**"提升"**,就可以修改其基类了。

结果如下:

通过qDebug可以在输出窗口打印对应的提示信息。


二.事件类型

下面分享一些常见的事件类型。


1.鼠标事件

void QWidget::mousePressEvent(QMouseEvent* event);//鼠标点击事件

void QWidget::mouseReleaseEvent(QMouseEvent* event);//鼠标释放事件

void QWidget::mouseDoubleClickEvent(QMouseEvent* event);//鼠标双击事件

void QWidget::mouseMoveEvent(QMouseEvent* event);//鼠标移动事件

void QWidget::wheelEvent(QWheelEvent* event);//鼠标滚轮滚动事件


2.键盘事件

void QWidget::keyPressEvent(QKeyEvent* event);//键盘按下事件

如果想要处理组合按键 事件,需要调用event对象中的modifiers()函数 ,获取用户按下的快捷键,随后与Qt::KeyboardModifier 中定义的处理键盘事件时对应的修改键进行比较:

Qt::NoModifier :无修改键

Qt::ShiftModifier :Shift 键

Qt::ControlModifier :Ctrl 键

Qt::AltModifier :Alt 键

Qt::MetaModifier :Meta键(在Windows上指Windows键,在macOS上指Command键)

Qt::KeypadModifier :使用键盘上的数字键盘进行输入时,Num Lock键处于打开状态

Qt::GroupSwitchModifier :用于在输入法组之间切换

例如获取Ctrl组合键,就需要进行如下判断:

event->modifiers() == Qt::ControlModifier


3.定时器事件

Qt 中在进行窗口程序的处理过程中,经常要周期性的执行某些操作,或者制作⼀些动画效果,使用定时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执行某⼀个任务。定时器在很多场景下都会使用到,如弹窗自动关闭之类的功能等。

QTimerEvent类 用来描述⼀个定时器事件 。在使用时需要通过 startTimer() 函数 来开启⼀个定时器,这个函数需要输入⼀个以毫秒为单位 的整数作为参数来表明设定的时间,它返回的整型值代表这个定时器 。当定时器溢出时(即定时时间到达)就可以在timerEvent() 函数中获取该定时器的编号来进行相关操作。

void QObject::timerEvent(QTimerEvent* event);//定时器事件


4.窗口事件

void QWidget::moveEvent(QMoveEvent* event);//窗口移动事件

void QWidget::resizeEvent(QResizeEvent* event);//窗口大小事件


三.Qt文件

文件操作是应用程序必不可少的部分。Qt 作为⼀个通用开发库,提供了跨平台的文件操作能力。 Qt提供了很多关于文件的类,通过这些类能够对文件系统进行操作,如文件读写、文件信息获取、文件复制或重命名等。

在 Qt 中,文件读写的类为 QFile 。QFile 的父类为 QFileDevice ,QFileDevice 提供了文件交互操作的底层功能。 QFileDevice 的父类是 QIODevice ,QIODevice 的父类为 QObject

QIODevice 是 Qt 中所有输入输出设备(input/output device,简称 I/O 设备)的基础类。


1.QFile

在 Qt 中,文件的读写主要是通过 QFile 类来实现。在 QFile 类中提供了⼀些用来读写文件的方法。对于文件的操作主要有:

读数据:QFile 中提供了多个方法用于读取文件内容;如 read()、readAll()、readLine()等。

写数据:QFile 中提供了多个方法用于往文件中写内容;如 write()、writeData()等。

关闭文件:文件使用结束后必须用函数 close() 关闭文件。

访问⼀个设备之前,需要使用 open() 函数打开该设备,而且必须指定正确的打开模式,QIODevice 中所有的打开模式由 QIODevice::OpenMode 枚举变量定义,其取值如下:

QIODevice::NotOpen :没有打开设备

QIODevice::ReadOnly :以只读方式打开设备

QIODevice::WriteOnly :以只写方式打开设备

QIODevice::ReadWrite :以读写方式打开设备

QIODevice::Append :以追加方式打开设备,数据将写到文件末尾

QIODevice::Truncate :每次打开文件后重写文件内容,原内容将被删除

QIODevice::Text :在读文件时,行尾终止符会被转换为 '\n';当写入文件时,行尾终止符会被转换为本地编码。如 Win32上为'\r\n';

QIODevice::Unbuffered :无缓冲形式打开文件,绕过设备中的任何缓冲区

QIODevice::NewOnly :文件存在则打开失败,不存在则创建文件

具体的文件操作方式如下:

1.根据文件路径,来创建一个QFile对象:

QFile file(path);

2.选择文件打开方式,打开文件,需要判断打开文件是否成功:

if(!(file.open(打开方式 )))

{}

3.读取/写入文件,可以使用QString对象来接收读取到的数据(前提为文本文件):

QString text = file.readAll();//读文件

const QString text = xxxx;//得到要写入的信息

file.write(text);//写文件

4.关闭文件

file.close();


2.文件和目录信息

QFileInfo 是 Qt 提供的⼀个用于获取文件和目录信息的类,如获取文件名、文件大小、文件修改日期等。QFileInfo类中提供了很多的方法,常用的有:

isDir() :检查该文件是否是目录;

isExecutable() :检查该文件是否是可执行文件;

fileName() :获得文件名;

completeBaseName() :获取完整的文件名;

suffix() :获取文件后缀名;

completeSuffix() :获取完整的文件后缀;

size() :获取文件大小;

isFile() :判断是否为文件;

fileTime() :获取文件创建时间、修改时间、最近访问时间等;


四.Qt多线程

在Qt中,多线程的处理⼀般是通过 QThread类 来实现。QThread 代表⼀个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据。QThread对象管理程序中的⼀个控制线程。

常用的方法如下:

run() :

线程的入口函数。

start() :

通过调用 run() 开始执行线程。操作系统将根据优先级参数调度线程。如果线程已经在运行,这个函数什么也不做。

currentThread() :

返回⼀个指向管理当前执行线程的 QThread的指针。

isRunning() :

如果线程正在运行则返回true;否则返回false。

sleep() / msleep() / usleep() :

使线程休眠,单位为秒 / 毫秒 / 微秒

wait() :

阻塞线程,直到满足以下任何⼀个条件:

  • 与此 QThread 对象关联的线程已经完成执行(即当它从run()返回时)。如果线程已经完成,这个函数将返回 true。如果线程尚未启动,它也返回 true。
  • 已经过了几毫秒。如果时间是 ULONG_MAX(默认值),那么等待永远不会超时(线程必须从run()返回)。如果等待超时,此函数将返回 false。
  • 这提供了与 POSIX pthread_join() 函数类似的功能。

terminate() :

终止线程的执行。线程可以立即终止,也可以不立即终止,这取决于操作系统的调度策略。在terminate() 之后使用 QThread::wait() 来确保。

finished() :

当线程结束时会发出该信号,可以通过该信号来实现线程的清理工作。


1.创建线程

创建线程的步骤:

  1. 自定义⼀个类,继承于 QThread,并且只有⼀个线程处理函数(和主线程不是同⼀个线程),这个线程处理函数主要就是重写父类中的 run() 函数。
  2. 线程处理函数里面写入需要执行的复杂数据处理;
  3. 启动线程不能直接调用 run() 函数,需要使用对象来调用start() 函数实现线程启动;
  4. 线程处理函数执行结束后可以定义⼀个信号来告诉主线程;
  5. 最后关闭线程。

线程函数内部不允许操作 UI 图形界面,⼀般做数据处理;只有主线程才可以操作UI界面。


2.线程安全

在Qt中,同样封装了对应的来维护线程的安全问题。

实现线程互斥和同步常用的类有:

  • 互斥锁:QMutex、QMutexLocker(智能锁)
  • 条件变量:QWaitCondition
  • 信号量:QSemaphore
  • 读写锁:QReadLocker、QWriteLocker、QReadWriteLock

Qt锁的使用方式与Linux一致。


相关推荐
橘子海全栈攻城狮24 分钟前
【源码+文档+调试讲解】“健康早知道”微信小程序
开发语言·servlet·微信小程序·小程序·notepad++
爱是小小的癌33 分钟前
Java-数据结构-顺序表(ArrayList)
java·开发语言·数据结构
我明天再来学Web渗透41 分钟前
【2024年-11月-9日-开源社区openEuler实践记录】OpenAMDC:开启智能边缘计算与系统管控的新征程
开发语言·人工智能·架构·开源·边缘计算·copilot·开源软件
egoist20231 小时前
数据结构之单链表(超详解)
c语言·开发语言·数据结构·笔记·学习·链表·gitee
小_太_阳1 小时前
Scala_【3】运算符
开发语言·scala·intellij-idea
xinghuitunan1 小时前
考试座位号(PTA)C语言
c语言·开发语言
程序边界1 小时前
AIGC赋能Java编程:智能工具引领效率、创新与理解的新纪元
java·开发语言·aigc
jk_1012 小时前
MATLAB中binopdf函数用法
开发语言·算法·matlab
木觞清2 小时前
Python 图像处理:生成美丽的书籍封面
开发语言·python
风_流沙2 小时前
parquet文件数据格式介绍以及python pandas对parquet常见操作
开发语言·python·pandas