• Qt之在控件上绘图


    1.总述

    Qt的要在当前类对应的窗口上绘图一般需要重写paintEvent函数,但是Qt的事件过滤器默认是把父窗口下子控件的绘图事件给过滤了的,因此重写父窗口的paintEvent函数是无法在子控件上进行绘图的,下面举一个例子。

     1 void MainWindow::myDraw(QLabel * label)
     2 {
     3     QPainter painter(label);
     4     painter.setPen(Qt::gray);
     5     painter.setBrush(Qt::green);
     6     painter.drawRect(10,10,20,20);
     7 }
     8 
     9 void MainWindow::paintEvent(QPaintEvent *)
    10 {
    11     myDraw(ui->label);
    12     myDraw(ui->label_2);
    13 }

    如上所示,重写MainWindow的paintEvent(QPaintEvent *)函数,然后在里面对子控件绘图是没有用的。

    2.解决方案

    还是以上面的例子为例。

    法一

    自己定义一个Mylabel类继承于QLabel,然后在这个类中重写paintEvent(QPaintEvent *)函数,并在里面绘图。然后在ui界面中把对应的QLabel提升为Mylabel。这种方式不是很灵活,因此不多介绍,详见https://blog.csdn.net/seanwang_25/article/details/18667871。

    法二

    在介绍法二之前,先补充一下qt中的事件机制,qt程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件(鼠标事件,键盘事件,绘图事件等)。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件先传给事件过滤器:

    virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

    在事件过滤器中可以对感兴趣的事件进行处理或屏蔽,令函数返回 true,不感兴趣的事件继续转发,令函数返回 false或者交给父类处理

    通过事件过滤器的事件将交给事件分发器:

    virtual  bool QObject::event(QEvent *e)

    event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler),比如paintEvent(QPaintEvent *ev),mouseMoveEvent(QMouseEvent *ev).....

    法二的实现思想:

    使用事件过滤器,在子控件的绘图事件被过滤前对子控件的绘图事件进行处理。下面的示例代码实现了点击界面上的画图按钮进行画图,点击清除按钮不进行画图。

     1 //mainwindow.cpp
     2 #include "mainwindow.h"
     3 #include "ui_mainwindow.h"
     4 #include<QPushButton>
     5 #include<QPaintEvent>
     6 #include<QPainter>
     7 #include<QPen>
     8 #include<QColor>
     9 #include<QString>
    10 #include<QDebug>
    11 #include<QFont>
    12 #include<QPixmap>
    13 #include<QVector>
    14 MainWindow::MainWindow(QWidget *parent) :
    15     QMainWindow(parent),
    16     ui(new Ui::MainWindow)
    17 {
    18     ui->setupUi(this);
    19     labels.push_back(ui->label);
    20     labels.push_back(ui->label_2);
    21     ui->label->installEventFilter(this);//在label上安装事件过滤器,this指针指定当事件发生时调用当前类中的事件过滤器进行处理
    22     ui->label_2->installEventFilter(this);//在label_2上安装事件过滤器
    23     connect(ui->pushButton,&QPushButton::clicked,this,[&]()
    24     {
    25         flag =1;
    26         update();//手动产生绘图事件
    27     });
    28     connect(ui->pushButton_2,&QPushButton::clicked,this,[&]()
    29     {
    30         flag =0;
    31         update();//手动产生绘图事件
    32     });
    33 }
    34 
    35 MainWindow::~MainWindow()
    36 {
    37     delete ui;
    38 }
    39 
    40 void MainWindow::myDraw(QLabel * label)
    41 {
    42     QPainter painter(label);
    43     painter.setPen(Qt::gray);
    44     painter.setBrush(Qt::green);
    45     painter.drawRect(10,10,20,20);
    46 }
    47 
    48 //void MainWindow::paintEvent(QPaintEvent *)
    49 //{
    50 //    myDraw(ui->label);
    51 //    myDraw(ui->label_2);
    52 //}
    53 
    54 bool MainWindow::eventFilter(QObject *watched, QEvent *event)
    55 {
    56     if(watched == ui->label && event->type() == QEvent::Paint)//发生绘图事件,且是在label上发生的
    57     {
    58             if(flag == 1)//标志位为1才在label上绘图,否者不绘图
    59             {
    60                 myDraw(ui->label);
    61                 return true;
    62             }
    63             else
    64                 return false;
    65     }
    66     else if(watched == ui->label_2 && event->type() == QEvent::Paint)
    67     {
    68             if(flag == 1)
    69             {
    70                 myDraw(ui->label_2);
    71                 return true;
    72             }
    73             else
    74                 return false;
    75     }
    76     else
    77         return QMainWindow::eventFilter(watched,event);//其它绘图事件交给父类处理
    78 }

    上述写法还是有一个不方便的地方,就是当控件很多的时候,要对每一个控件都单独的像第21行和第22行那样单独的安装事件过滤器。因此可以向QApplication或者QCoreApplication添加事件过滤器,这样就相当于当前应用程序下所有的控件都安装了事件过滤器。

     1 //main.cpp
     2 #include "mainwindow.h"
     3 #include <QApplication>
     4 
     5 int main(int argc, char *argv[])
     6 {
     7     QApplication a(argc, argv);
     8     MainWindow w;
     9     w.show();
    10     a.installEventFilter(&w);//给整个应用程序安装事件过滤器
    11     return a.exec();
    12 }
     1 //mainwindow.cpp
     2 #include "mainwindow.h"
     3 #include "ui_mainwindow.h"
     4 #include<QPushButton>
     5 #include<QPaintEvent>
     6 #include<QPainter>
     7 #include<QPen>
     8 #include<QColor>
     9 #include<QString>
    10 #include<QDebug>
    11 #include<QFont>
    12 #include<QPixmap>
    13 #include<QVector>
    14 MainWindow::MainWindow(QWidget *parent) :
    15     QMainWindow(parent),
    16     ui(new Ui::MainWindow)
    17 {
    18     ui->setupUi(this);
    19     labels.push_back(ui->label);
    20     labels.push_back(ui->label_2);
    21     //ui->label->installEventFilter(this);//在label上安装事件过滤器,this指针指定当事件发生时调用当前类中的事件过滤器进行处理
    22     //ui->label_2->installEventFilter(this);//在label_2上安装事件过滤器
    23     connect(ui->pushButton,&QPushButton::clicked,this,[&]()
    24     {
    25         flag =1;
    26         update();//产生绘图事件
    27     });
    28     connect(ui->pushButton_2,&QPushButton::clicked,this,[&]()
    29     {
    30         flag =0;
    31         update();//产生绘图事件
    32     });
    33 }
    34 
    35 MainWindow::~MainWindow()
    36 {
    37     delete ui;
    38 }
    39 
    40 void MainWindow::myDraw(QLabel * label)
    41 {
    42     QPainter painter(label);
    43     painter.setPen(Qt::gray);
    44     painter.setBrush(Qt::green);
    45     painter.drawRect(10,10,20,20);
    46 }
    47 
    48 //void MainWindow::paintEvent(QPaintEvent *)
    49 //{
    50 //    myDraw(ui->label);
    51 //    myDraw(ui->label_2);
    52 //}
    53 
    54 bool MainWindow::eventFilter(QObject *watched, QEvent *event)
    55 {
    56     if(event->type() == QEvent::Paint)//绘图事件
    57     {
    58         if(flag == 1)//标志位为1才在label上绘图,否者不绘图
    59         {
    60             for(QVector<QLabel *>::iterator it=labels.begin();it!=labels.end();it++)
    61             {
    62                 if(watched == *it)//限制条件,只处理label上的绘图事件
    63                 {
    64                     myDraw(*it);
    65                     return true;//返回true表示处理完成该事件,否者该事件还会继续向下转发
    66                 }
    67             }
    68             return QMainWindow::eventFilter(watched,event);//其它绘图事件交给父类处理
    69         }
    70         else
    71             return QMainWindow::eventFilter(watched,event);//其它绘图事件交给父类处理
    72 
    73     }else
    74         return QMainWindow::eventFilter(watched,event);
    75     
    76 }
  • 相关阅读:
    AGC030 简要题解
    CF1601 简要题解
    CSP2021 题解
    2021.11.1-2021.11.7总结
    超快速梅森旋转SFMT(SIMD-oriented Fast Mersenne Twister)一览
    2021.10.25-2021.10.31总结
    CSP 2021 游记
    在Windows vs2015环境下编译使用Libevent
    在Windows环境下实现一个简单的libevent服务器
    Thinking in C++ 课后习题自己实现 第二章
  • 原文地址:https://www.cnblogs.com/LifeoFHanLiu/p/10194924.html
Copyright © 2020-2023  润新知