文章目录
前言
在Qt中,事件作为一个对象,继承自QEvent类,常见的有鼠标事件QMouseEvent、键盘事件QKeyEvent和定时器事件QTimerEvent等,本篇文章也主要讲解这三个事件。在讲之前,先看一下它们与QEvent的继承关系:
一、键盘事件QKeyEvent
在讲事件之前,先看一下事件的处理有哪些方法:
方法一:重新实现部件的paintEvent(),mousePressEvent()等事件处理函数。这是最常用也的一种方法,不过它只能用来处理特定部件的特定事件。例如前一章实现拖放操作,就是用的这种方法。
方法二:重新实现notify()函数。这个函数功能强大,提供了完全的控制,可以在事件过滤器得到事件之前就获得它们。但是,它一次只能处理一个事件。
方法三:向QApplication对象上安装事件过滤器。因为一个程序只有一个QApplication对象,所以这样实现的功能与使用notify()函数是相同的,优点是可以同时处理多个事件。
方法四:重新实现event()函数。QObject类的event()函数可以在事件到达默认的事件处理函数之前获得该事件。
方法五:在对象上安装事件过滤器。使用事件过滤器可以在一个界面类中同时处理不同子部件的不同事件。
在实际编程中,最常用的是方法一,其次是方法五。本篇文章讲的是方法一
键盘按下事件
void Widget::keyPressEvent(QKeyEvent *event) // 键盘按下事件
{
if(event->modifiers() == Qt::ControlModifier){ // 是否按下Ctrl键
if(event->key() == Qt::Key_M) // 是否按下M键
setWindowState(Qt::WindowMaximized); // 窗口最大化
}
else QWidget::keyPressEvent(event);
}
QKeyEvent的key()函数可以获取具体的按键,需要特别说明的是,回车键在这里是Qt::Key_Return;键盘上的一些修饰键,比如Ctrl和Shift等,这里需要使用QKeyEvent的modifiers()函数来获取它们
二、鼠标事件QMouseEvent
QMouseEvent类用来表示一个鼠标事件,当在窗口部件中按下鼠标或者移动鼠标指针时,都会产生鼠标事件。利用QMouseEvent类可以获知鼠标是哪个键按下了,还有鼠标指针的当前位置等信息。通常是重定义部件的鼠标事件处理函数来进行一些自定义的操作。
QWheelEvent类用来表示鼠标滚轮事件,在这个类中主要是获取滚轮移动的方向和距离。
1.鼠标按下事件:
void Widget::mousePressEvent(QMouseEvent *event) // 鼠标按下事件
{
if(event->button() == Qt::LeftButton){ // 如果是鼠标左键按下
QCursor cursor;
cursor.setShape(Qt::ClosedHandCursor);
QApplication::setOverrideCursor(cursor); // 使鼠标指针暂时改变形状
offset = event->globalPosition() - pos(); // 获取指针位置和窗口位置的差值
}
else if(event->button() == Qt::RightButton){ // 如果是鼠标右键按下
QCursor cursor(QPixmap("../mymouseevent/logo.png"));
QApplication::setOverrideCursor(cursor);// 使用自定义的图片作为鼠标指针
}
}
在鼠标按下事件处理函数中,先判断是哪个按键按下,如果是鼠标左键,那么就更改指针的形状,并且存储当前指针位置与窗口位置的差值。这里使用了globalPosition() 函数来获取鼠标指针的位置,这个位置是指针在桌面上的位置,因为窗口的位置就是指的它在桌面上的位置。另外,还可以使用QMouseEvent类的position()函数获取鼠标指针在窗口中的位置。如果是鼠标右键按下,那么就将指针显示为我们自己的图片。
2.鼠标移动事件
void Widget::mouseMoveEvent(QMouseEvent *event) // 鼠标移动事件
{
if(event->buttons() & Qt::LeftButton){ // 这里必须使用buttons()
QPointF temp;
temp = event->globalPosition() - offset;
move(temp.x(), temp.y());// 使用鼠标指针当前的位置减去差值,就得到了窗口应该移动的位置
}
}
在鼠标移动事件处理函数中,先判断是否是鼠标左键按下,如果是,那么就使用前面获取的差值来重新设置窗口的位置。因为在鼠标移动时,会检测所有按下的键,而这时使用QMouseEvent的button()函数无法获取哪个按键被按下,只能使用buttons()函数,所以这里使用buttons()和Qt::LeftButton进行按位与的方法来判断是否是鼠标左键按下。
3.鼠标释放事件
void Widget::mouseReleaseEvent(QMouseEvent *event) // 鼠标释放事件
{
QApplication::restoreOverrideCursor(); // 恢复鼠标指针形状
}
在鼠标释放函数中进行了恢复鼠标形状的操作,这里使用的restoreOverrideCursor()函数要和前面的setOverrideCursor()函数配合使用。
4.鼠标双击事件
void Widget::mouseDoubleClickEvent(QMouseEvent *event) // 鼠标双击事件
{
if(event->button() == Qt::LeftButton){ // 如果是鼠标左键按下
if(windowState() != Qt::WindowFullScreen) // 如果现在不是全屏
setWindowState(Qt::WindowFullScreen); // 将窗口设置为全屏
else setWindowState(Qt::WindowNoState); // 否则恢复以前的大小
}
}
在鼠标双击事件处理函数中使用setWidowState()函数来使窗口处于全屏状态或者恢复以前的大小。
5.滚轮事件
void Widget::wheelEvent(QWheelEvent *event) // 滚轮事件
{
if(event->angleDelta().y() > 0){ // 当滚轮远离使用者时
ui->textEdit->zoomIn(); // 进行放大
}else{ // 当滚轮向使用者方向旋转时
ui->textEdit->zoomOut(); // 进行缩小
}
}
在滚轮事件处理函数中,使用QWheelEvent类的angleDelta().y()函数获取了垂直滚轮移动的距离,每当滚轮旋转一下,默认是15度,这时delta()函数就会返回15*8即整数120。当滚轮向远离使用者的方向旋转时,返回正值;当向靠近使用者的方向旋转时,返回负值。这样便可以利用这个函数的返回值来判断滚轮的移动方向,从而进行编辑器中内容的放大或者缩小操作。
三、定时器事件QTimerEvent
QTimerEvent类用来描述一个定时器事件。对于一个QObject的子类,只需要使用
int QObject::startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer)
就可以开启一个定时器,函数的第一个参数interval用来设置触发定时器事件的间隔,单位是毫秒,第二个参数用来设置精度。该函数返回一个整型编号来代表这个定时器,可以使用QObject::killTimer(int id)来关闭指定的定时器。当定时器溢出时可以在timerEvent()函数中进行需要的操作
编程中更多的是使用QTimer类来实现一个定时器,它提供了更高层次的编程接口,比如可以使用信号和槽,还可以设置只运行一次的定时器。所以在以后的章节中,如果使用定时器,那么一般都是使用的QTimer类。
1.通过ID使用定时器
使用QTimerEvent的timerId()函数来获取定时器的编号,然后判断是哪一个定时器并分别进行不同的操作。
在构造函数中:
id1 = startTimer(1000); // 开启一个1秒定时器,返回其ID
id2 = startTimer(2000); // 开启一个2秒定时器,返回其ID
id3 = startTimer(3000); // 开启一个3秒定时器,返回其ID
下面是定时器事件函数的定义:
void Widget::timerEvent(QTimerEvent *event)
{
if (event->timerId() == id1) { // 判断是哪个定时器
qDebug() << "timer1";
}
else if (event->timerId() == id2) {
qDebug() << "timer2";
}
else {
qDebug() << "timer3";
}
}
2.通过信号和槽实现定时器
在构造函数中:
QTimer *timer = new QTimer(this); // 创建一个新的定时器
// 关联定时器的溢出信号到槽上
connect(timer, &QTimer::timeout, this, &Widget::timerUpdate);
timer->start(1000);
溢出处理:
void Widget::timerUpdate() // 定时器溢出处理
{
QTime time = QTime::currentTime(); // 获取当前时间
QString text = time.toString("hh:mm"); // 转换为字符串
if((time.second() % 2) == 0) text[2]=' '; // 每隔一秒就将“:”显示为空格
ui->lcdNumber->display(text);
}
这里在构造函数中开启了一个1秒的定时器,当它溢出时就会发射timeout()信号,这时就会执行我们的定时器溢出处理函数。在槽里我们获取了当前的时间,并且将它转换为可以显示的字符串。
参考书籍:Qt Creator快速入门(第四版)