ZAARONBIN - 博客园

第六章 Qt之事件系统


​ 在Qt中,事件作为一个对象,继承自QEvent类。

image

6.1 Qt中的事件

事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。

  • Qt中使用一个对象来表示一个事件,继承自QEvent类。
  • 在Qt中,任何QObject子类实例都可以接收和处理事件。

6.1.1 事件的处理

事件处理的五中方法

  1. 重新实现部件的paintEvent()、mousePressEvent()等事件处理函数;只能用来处理特定部件的特定事件。(常用)
  2. 重新实现notify()函数。可以在事件过滤器得到事件之前获得事件。一次只能处理一个事件。
  3. 向QApplication对象上安装事件过滤器,实现的功能与notify()函数相同。同时可以处理多个事件。弊端:使用全局的事件过滤器减缓事件的传递
  4. 重新实现event()函数。QObject类的event()函数可以在事件到达默认的事件处理函数之前获得该事件。
  5. 在对象上安装事件过滤器。可以在一个界面类中同时处理不同子部件的不同事件。(常用)

6.1.2 事件的传递

应用程序运行时,一旦由事件发生,Qt便会构建一个相应的QEvent子类的对象来表示它,然后将它传递给相应的QObject对象或其子对象。

  • 事件是先传递给获得焦点的窗口部件
  • 如果焦点部件忽略掉该事件,那么这个事件会传递给这个部件的父部件
  • 事件的传递顺序为:过滤器-->焦点部件的event()函数-->焦点部件的事件处理函数-->如果焦点部件忽略该事件则传递给焦点部件的父部件的事件处理函数

6.2 鼠标事件和滚轮事件

QMouseEvent类用来表示一个鼠标事件,在窗口部件中按下鼠标或者移动鼠标指针时,都会产生鼠标事件。

  • QMouseEvent类可以获知鼠标的哪个键被按下、鼠标指针的当前位置
  • QWheelEvent类用来表示鼠标滚轮事件,滚轮移动的方向和距离
void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        QCursor cursor;
        cursor.setShape(Qt::ClosedHandCursor);
        QApplication::setOverrideCursor(cursor);    //使鼠标指针暂时改变形状
        offset = event->globalPos() - pos();    //获取指针位置和窗口位置的差值:前者为鼠标在桌面上的位置, 后者为在窗口中的位置
    }else if(event->button() == Qt::RightButton){
        QCursor cursor(QPixmap(":image/images/icon.jpg"));
        QApplication::setOverrideCursor(cursor);
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    QApplication::restoreOverrideCursor();  //恢复鼠标形状
}

void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        if(windowState() != Qt::WindowFullScreen)   //如果现在不是全屏
            setWindowState(Qt::WindowFullScreen);
        else
            setWindowState(Qt::WindowNoState);          //恢复以前的大小
    }
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton){
        QPoint temp;
        temp = event->globalPos()-offset;
        move(temp);
    }
}

void Widget::wheelEvent(QWheelEvent *event)
{
    if(event->delta() > 0)      //当滚轮远离使用者时delta()函数返回正值,否则返回负值
        textEdit->zoomIn();     //放大
    else
        textEdit->zoomOut();    //缩小
}

6.3 键盘事件

QKeyEvent类用来描述一个键盘事件,当键盘按键被按下或被释放时,键盘事件会被发送给拥有键盘输入焦点的部件。

  • QKeyEvent的key()函数可以获取具体的按键。Qt:Key关键字查看
  • 键盘上的修饰按键:Ctrl或Shift等,使用QKeyEvent的modifiers()函数获取。Qt:KeyboardModifier关键字查看
void Widget::keyPressEvent(QKeyEvent *event){
    if(event->key() == Qt::Key_Up){
        if(event->isAutoRepeat()) return ;			//利用该函数检查该键是否被重复按下,如果是则不做任何操作
        keyUp = true;
    }else if(event->key() == Qt::Key_Left){
        if(event->isAutoRepeat()) return;
        keyLeft = true;
    }
}

void Widget::keyReleaseEvent(QKeyEvent *event){
    if(event->key() == Qt::Key_Up){
        if(event->isAutoRepeat()) return;
        keyUp   = false;
        if(move){
            move = false;
            return;
        }
        if(keyLeft){
            ui->pushButton->move(30,80);
            move = true;
        }else{
            ui->pushButton->move(120,80);
        }
    }else if(event->key() == Qt::Key_Left){
        if(event->isAutoRepeat()) return;
        keyLeft = false;
        if(move){
            move = false;
            return;
        }
        if(keyUp){
            ui->pushButton->move(30,80);
            move = true;
        }else{
            ui->pushButton->move(30,120);
        }
    }else if(event->key() == Qt::Key_Down){
        ui->pushButton->move(120,120);
    }
}


/*简单的移动操作*/
void Widget::keyPressEvent(QKeyEvent *event){
    if(event->key() == Qt::Key_Up)
    {
        ui->pushButton->move(ui->pushButton->x(), ui->pushButton->y()-1);
    }else if(event->key() == Qt::Key_Down){
        ui->pushButton->move(ui->pushButton->x(), ui->pushButton->y()+1);
    }else if(event->key() == Qt::Key_Right){
        ui->pushButton->move(ui->pushButton->x()+1, ui->pushButton->y());
    }else if(event->key() == Qt::Key_Left){
        ui->pushButton->move(ui->pushButton->x()-1, ui->pushButton->y());
    }
}

void Widget::keyReleaseEvent(QKeyEvent *event){
    Q_UNUSED(event);
}

6.4 定时器事件与随机数

QTimeEvent类用来描述一个定时器事件,对于一个QObject的子类,只需使用int QObject::stratTimer(int interval)函数开启定时器,其中输入参数为以ms为单位的整数,函数返回一个整型编号代表该定时器。当定时器溢出时可在该子类的处理函数timerEvent()中进行操作。

  • QTimerEvent()类定时器

  • QTimer类定时器。该类的定时器可以使用信号与槽,还可以设置定时器运行次数,比QTimerEvent更高级

    Qt中通过qrand()函数与qsrand()函数生成随机数。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    id1 = startTimer(1000);
    id2 = startTimer(1500);
    id3 = startTimer(2200);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::timerEvent(QTimerEvent *event)
{
    if(event->timerId() == id1){
        qDebug() << "Timer1";
    }
    else if(event->timerId() == id2){
        qDebug() <<"Timer2";
    }
    else{
        qDebug() << "Timer3";
    }
}
/*=========================================位置随机变化时钟效果======================================*/
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::timerUpdate);
    timer->start(1000);

    //在使用qrand()之前需使用qsrand()设置初值
   qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); //从当前时间到0:0:0所需要的秒数,由于当前时间的不断变化,qrand()的初值也在变化

    QTimer::singleShot(5000, this, &Widget::close);	//当定时器运行5s后调用close()函数关闭程序
}

Widget::~Widget()
{
    delete ui;
}

void Widget::timerUpdate()
{
    QTime time = QTime::currentTime();  //获取当前时间
    QString text = time.toString("hh:mm:ss");  //转换为字符串
    if(time.second() % 2 == 0) {
        text[2] = ' ';   //每隔一秒就将“:”显示为空
        text[5] = ' ';
    }
    ui->lcdNumber->setDigitCount(8);
    ui->lcdNumber->display(text);


    qDebug() << "qrand: "<<qrand();

    int rand = qrand() % 300;
    ui->lcdNumber->move(rand, rand);
}

6.5 事件过滤器与事件的发送

Qt中,事件过滤器是由两个函数组成的一种操作,都为QObject类中的函数。实现一个部件对其他部件的事件的监控。

  • installEventFilter()

  • eventFilter();依据事件传递的过程,如果需要事件在后续的处理函数中继续处理,则该函数输出false;否则,输出true;

  • QCoreApplication类提供了发送事件的功能

    • bool QCoreApplication::sengEvent(QObject* receiver, QEvent* event);

    • bool QCoreApplication::postEvent(QObject* receiver, QEvent* event, int ptiority = Qt::NormalEventPriority);

    • sengEvent postEvent
      立即处理 事件在等待调度队列中,下一次Qt主事件循环时处理
      事件发送完成后无法自动删除 可以自动删除
      需要在栈上创建QEvent对象 在堆上创建QEvent对象 (new)
QKeyEvent myEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
qApp->sendEvent(spinBox, &myEvent);             //qApp是QApplication的全局指针,每一个应用程序只允许有一个QApplication对象
posted @ 2021-03-29 10:33  BINBINBINZ  阅读(406)  评论(0)    收藏  举报