QT-事件处理

事件模型

事件处理

virtual void 

keyPressEvent(QKeyEvent *event)

virtual void 

keyReleaseEvent(QKeyEvent *event)

virtual void 

mouseDoubleClickEvent(QMouseEvent *event)

virtual void 

mouseMoveEvent(QMouseEvent *event)

virtual void 

mousePressEvent(QMouseEvent *event)

virtual void 

mouseReleaseEvent(QMouseEvent *event)

virtual void 

moveEvent(QMoveEvent *event)

virtual void 

paintEvent(QPaintEvent *event)

virtual void 

resizeEvent(QResizeEvent *event)

virtual void 

wheelEvent(QWheelEvent *event)

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    startTimer(1000);//1秒
}

Widget::~Widget()
{

}

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QMouseEvent>
#include <QKeyEvent>
#include <QWheelEvent>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

    void mousePressEvent(QMouseEvent *event)
    {
        qDebug()<<"pressssss: "<<event->pos();//鼠标按下

    }

    void mouseMoveEvent(QMouseEvent *event)
    {
        qDebug()<<"moving!"<<event->pos();//鼠标移动
    }

    void keyPressEvent(QKeyEvent *event)
    {
        qDebug()<<"key: "<<event->key();//键盘按下
    }

    void wheelEvent(QWheelEvent *event)
    {
        qDebug()<<"wheel: "<<event->delta();//鼠标滚轮
    }

    void timerEvent(QTimerEvent *event)
    {
        qDebug()<<"timer!";//定时器
    }
};

#endif // WIDGET_H

绘图事件

virtual void paintEvent(QPaintEvent *event)
{ 
    if(isDrawing)  {  
	 tempPix = pix;       //双缓冲     
	QPainter pp(&tempPix);  
	painter.drawPixmap(0,0,tempPix);  
    }  
    else {  
	QPainter pp(&pix);  
	painter.drawPixmap(0,0,pix);  
    }  
}

paintEvent类是一个处理绘图事件的类,它是Qt中的一个事件类。paintEvent类的作用是在窗口上绘制图形或者图片。一般情况下,我们需要继承QWidget或者其子类,并重写其paintEvent()函数,来实现自定义的绘图操作。

在重写paintEvent()函数时,我们可以通过调用 QPainter 类的成员函数进行绘图操作,例如绘制线条、矩形、圆形等。paintEvent类还提供了一些与绘图相关的函数,例如设置画笔和画刷的属性、设置字体等。

paintEvent类是一个重要的类,它可以实现自定义的绘图需求。通过重写paintEvent()函数,我们可以在窗口上进行各种绘图操作,例如绘制图表、绘制动画等。同时,paintEvent类还可以处理其他与绘图相关的事件,例如鼠标点击事件、鼠标移动事件等。

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QPainter>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);//QWidget是Widget类的父类,parent是一个QWidget类型的指针,默认值为0(即空指针)
    ~Widget();
    void paintEvent(QPaintEvent *event)
    {
        qDebug()<<"ppppppp";

        QPainter p(this);

        p.translate(this->width()/2, this->height()/2);
        p.drawEllipse(QPoint(0, 0), 100, 100);
        //      p.drawLine(0, 0, 50, 50);
        p.rotate(i++*10);//p 中的元素按照每次递增10度的角度进行旋转
        p.drawLine(0, 0, 50, 50);
    }

    void timerEvent(QTimerEvent *event)
    {
        update();//时间事件触发后,update触发paintEvent事件
    }

private:
    int i;
};
//在这段代码中,parent是一个指向父QWidget的指针,用于指定Widget的父窗口。QWidget是Widget类的父类,因此Widget继承了QWidget的属性和方法。

//QPaintEvent是一个事件类,当窗口需要重绘时,会发送一个QPaintEvent对象给窗口,从而触发paintEvent函数。在paintEvent函数中,可以使用QPainter类进行绘图操作。
    
//  QPainter类是用于进行绘图的类,可以在指定的绘图设备上绘制各种形状、线条、图像等。在这段代码中,使用QPainter对象p绘制一个椭圆和一条旋转的直线。
    
//QWidget类是Qt中所有窗口的基类,提供了窗口的基本功能和特性。QPainter类是QWidget类的一个成员,用于在窗口上进行绘图操作。
//在上述代码中,paintEvent第一次事件是由QWidget的父类QMainWindow的构造函数触发的。当QMainWindow被创建时,它会自动调用paintEvent函数来绘制窗口的初始状态。
#endif // WIDGET_H
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    i = 0;
    startTimer(1000);//每1s出发一次timer事件
}

Widget::~Widget()
{

}

 双缓冲绘图

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMouseEvent>
#include <QPainter>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

    void mousePressEvent(QMouseEvent *event)
    {
        startp = event->pos();//鼠标点击的位置为起点
    }

    void mouseReleaseEvent(QMouseEvent *event)
    {
        saveit = true;//左键释放的时候设置标志
        update();
    }

    void mouseMoveEvent(QMouseEvent *event)
    {
        endp = event->pos();//移动的位置为终点
        update();//触发paintEvent事件
    }

    void paintEvent(QPaintEvent *event)
    {
        if(saveit)
        {
            QPainter px(pix);
            px.drawLine(startp, endp);
            saveit = false;
        }


        QPainter p(this);
        p.drawPixmap(0, 0, *pix);//把以前的照片放在背景板上
        p.drawLine(startp, endp);//画直线
    }
//在这段代码中,update()函数被调用时,会触发paintEvent事件。具体来说,当鼠标释放时,调用mouseReleaseEvent函数设置saveit标志为true,并调用update()函数。在update()函数中,会先绘制直线到pix上,然后再调用paintEvent函数进行绘制。
private:
    QPoint startp;
    QPoint endp;
    QPixmap *pix;//图片
    bool saveit;
};

#endif // WIDGET_H
#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    pix = new QPixmap(this->width(), this->height());
    pix->fill();

    saveit = false;
}
//对象需要在以下几种情况下使用new来动态创建:

//对象是在堆上分配内存空间。在上述代码中,pix是一个QPixmap对象,使用new关键字在堆上分配了一块内存空间来存储该对象。

// 对象的生命周期需要超出其所在作用域。在上述代码中,pix是一个成员变量,如果不使用new来动态创建,它将在函数执行结束后被销毁,而我们可能需要在其他函数中继续使用它。

 //对象需要在多个位置共享。使用new创建的对象可以通过指针在多个位置访问和共享。

 //需要注意的是,使用new创建的对象需要在适当的时候使用delete来手动释放内存,以避免内存泄漏。在上述代码中,可能在类的析构函数中使用delete来释放pix对象所占用的内存。
Widget::~Widget()
{

}
//在这段代码中,析构函数中没有看到对pix指针进行delete释放内存的操作是因为pix指针是通过new操作创建的,并且在构造函数中进行了初始化。在这种情况下,析构函数中并不需要手动释放pix指针所指向的内存,因为在对象被销毁时,会自动调用析构函数,析构函数中会自动调用pix指针的析构函数来释放内存。所以在这段代码中,pix指针的内存会在对象销毁时自动释放。

事件过滤

class A:public Qobject{
};

class B:public Qobject{
Public:
	bool eventFilter(Qobject *sender, Qevent *event){
		return QObject::eventFilter(obj, event); 
	}
};
A x;
B y;
x.installeventfilter(&y);
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QPushButton>
#include <QFileDialog>
#include <QStringList>
#include <QEvent>
#include <QKeyEvent>

class Widget : public QWidget
{
    Q_OBJECT
public slots:
    void openfiles()
    {
        index = 0;
        files = QFileDialog::getOpenFileNames();//files = QFileDialog::getOpenFileNames() 是调用QFileDialog类的getOpenFileNames()方法,并将返回的文件路径列表赋值给变量files。

        //getOpenFileNames()方法用于打开一个文件对话框,允许用户选择一个或多个文件,并返回所选文件的路径列表。这个方法通常用于选择需要打开的文件。
        QPixmap pix(files[index]);//这段代码中,QPixmap pix(files[index])创建了一个名为pix的QPixmap对象。

        //QPixmap是Qt中的一个类,用于表示和操作图像数据。它可以加载图像文件,也可以通过绘制操作来创建图像。在这里,QPixmap的构造函数接受一个文件路径作为参数,表示要加载的图像文件路径。

         //根据代码上下文来看,files是一个QStringList类型的对象,index是一个整数变量,表示要加载的图像文件在files中的索引。通过 files[index] 可以获取到指定索引位置的图像文件的路径。

         //因此,QPixmap pix(files[index])的意思是使用指定文件路径(files[index])创建一个QPixmap对象pix,即加载该路径对应的图像文件内容到pix中,以便后续进行操作,例如显示在GUI界面中或进行绘制操作。
        lb->setPixmap(pix);
    }

    void showr()
    {
        if(index+1 < files.length() )//+1小于数组长度
            index++;
        else
            index = 0;

        QPixmap pix(files[index]);
        lb->setPixmap(pix);
    }

    void showl()
    {
        if(index-1 >= 0 )
            index--;
        else
            index = files.length()-1;

        QPixmap pix(files[index]);
        lb->setPixmap(pix);
    }

    bool eventFilter(QObject *watched, QEvent *event)
    {
        lb->setFocus();//不能脱焦
        if(watched == lb)
        {
            if(event->type()==QEvent::KeyPress)
            {
                //QKeyEvent *keyevent = static_cast<QKeyEvent*>(event); 的作用是将事件对象 event 转换为 QKeyEvent 类型的指针 keyevent。

                //在使用事件过滤器处理小部件的事件时,通过 event 参数可以获取到具体的事件对象。然而,event 参数的类型通常是基类 QEvent 的指针,而不是具体的事件类型。

                //为了能够访问和操作特定类型的事件,比如键盘事件 QKeyEvent,需要将 event 强制转换为对应的事件类型指针。这就是 static_cast 的作用,将 event 转换为 QKeyEvent 类型的指针 keyevent。

                //通过这样的转换,可以使用 keyevent 指针来访问和操作 QKeyEvent 类型的属性和方法,例如获取按下的键值、键盘状态等。这样,可以在事件过滤器中针对键盘事件进行自定义处理和响应。
                QKeyEvent *keyevent = static_cast<QKeyEvent*>(event);
                if(keyevent->key() == Qt::Key_Left)//l
                    showl();
                else
                    if(keyevent->key() == Qt::Key_Right)//r
                        showr();
                return true;
            }
        }

        return QWidget::eventFilter(watched,event);
    }
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    QLabel *lb,*lb1;
    QPushButton *lbt, *rbt, *openbt;

    QStringList files;//QStringList files是一个QStringList类型的变量,用于存储一组QString类型的数据,即一个字符串列表。
    int index;
};

#endif // WIDGET_H
#include "widget.h"
#include <QVBoxLayout>
#include <QHBoxLayout>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    lb = new QLabel;
    lb->setMinimumSize(640, 480);
    lb->setScaledContents(true);//根据照片自动缩放
    lb->setFocus();//lb->setFocus(); 的作用是将焦点设置在一个小部件(widget)上。在这种情况下,"lb" 可能是指向一个 QLabel 小部件的指针。通过在 QLabel 小部件上调用 "setFocus()",该小部件将接收输入焦点,意味着它将被突出显示,并准备好接收用户输入。这对于需要用户输入的小部件(如文本框)非常有用,因为它们可以直接接收键盘输入或其他用户交互。
    lb->installEventFilter(this);//lb->installEventFilter(this); 的作用是将事件过滤器(event filter)安装到一个小部件上。在这种情况下,"lb" 可能是指向一个小部件的指针,而 "this" 可能是指向当前对象的指针。

    //通过调用 installEventFilter(),可以将当前对象设置为小部件的事件过滤器。事件过滤器可以捕获和处理小部件的事件,包括鼠标事件、键盘事件、焦点事件等。通过安装事件过滤器,可以扩展小部件的功能,对其事件进行自定义处理,而不需要修改小部件的源代码。

    //  在安装了事件过滤器后,当小部件接收到事件时,事件将首先传递给事件过滤器进行处理。事件过滤器可以根据事件的类型、属性等进行相应的处理,并决定是否将事件继续传递给小部件进行默认处理。这样,可以在不修改小部件的情况下,对其事件进行拦截、修改或扩展操作。
    lb1 = new QLabel;
    lbt = new QPushButton("<");
    rbt = new QPushButton(">");
    openbt = new QPushButton("open");
    QHBoxLayout *hbox = new QHBoxLayout;//水平布局
    hbox->addStretch();//两侧加弹簧
    hbox->addWidget(lbt);
    hbox->addWidget(openbt);
    hbox->addWidget(rbt);
    hbox->addStretch();

    QVBoxLayout *vbox = new QVBoxLayout;//垂直布局
    vbox->addWidget(lb);
    vbox->addLayout(hbox);
    setLayout(vbox);

    index = 0;

    connect(openbt, SIGNAL(clicked(bool)), this, SLOT(openfiles()));
    connect(lbt, SIGNAL(clicked(bool)), this, SLOT(showl()));
    connect(rbt, SIGNAL(clicked(bool)), this, SLOT(showr()));
}

Widget::~Widget()
{

}

事件过滤程序无法运行,报错:

The inferior stopped because it received a signal from the operating system.
Signal name :
SIGSEGV
Signal meaning : Segmentation fault

原因分析:

这是一个段错误(Segmentation fault)的错误报告。这个错误通常是由于访问了无效的内存地址或者使用了空指针引起的。

在你的代码中,出现这个错误的地方可能是在以下几处:

1. 在打开文件对话框之后,没有检查用户是否选择了文件,如果用户没有选择文件,那么files列表将为空,但是在showr和showl函数中还是会尝试访问该列表。

2. eventFilter函数中,当检测到QKeyEvent事件时,没有检查keyevent的有效性,可能导致访问无效的指针。

3. 其他可能导致访问无效地址的地方。

可以通过使用调试器来定位错误发生的具体位置。使用调试器可以在发生错误的地方打断点,并逐行执行代码,观察每一步的变化,从而找到错误的原因。有时间在进行排查问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值