Qt中在控件上绘图

余生颓废 提交于 2020-10-26 21:24:51

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 }

复制代码

 

Qt 在控件上面绘图 label,pushbutton

Qt 之所以不能在在任意控件上面绘图,是因为Qt的事件过滤器把控件的绘图事件给过滤了,自己知识不够,盗用狗哥的话

“在事件过滤器eventFilter() 中拦截 Label 的 QEvent::Paint 事件”

代买如下

  1. bool Widget::eventFilter(QObject *watched, QEvent *event)

  2. {

  3. if(watched == ui->label && event->type() == QEvent::Paint)

  4. {

  5. magicTime();

  6. }

  7. return QWidget::eventFilter(watched,event);

  8. }


然后就是在magicTime()函数中实现自己的绘制了

如下demo

  1. void Widget::magicTime()

  2. {

  3. QPainter painter(ui->label);

  4. painter.setPen(Qt::gray);

  5. painter.setBrush(Qt::green);

  6. painter.drawRect(10,10,200,200);

  7. }


不过在此之间,还有一个步骤是要做的

ui->label->installEventFilter(this);

这句话是必不可少啊,

 

运行截图

Qt在子部件上绘图

本文记录如何使用qpainter在子部件上绘图。

1.需要在子部件上安装事件过滤器

frame->installEventFilter(this); //安装事件过滤器到窗口

2.头文件中声明如下

bool eventFilter(QObject *watched, QEvent *event);
bool m_flag=false;//绘图标志

3.声明画图函数

void graphChart(QWidget *w);

4.如果使用按钮来控制画图

 
  1. m_flag = true;

  2. update();

代码展示如下:

头文件:

 
  1. #ifndef MAINWINDOW_H

  2. #define MAINWINDOW_H

  3.  
  4. #include <QMainWindow>

  5. #include<QPaintEvent>

  6. #include<QPainter>

  7. namespace Ui {

  8. class MainWindow;

  9. }

  10.  
  11. class MainWindow : public QMainWindow

  12. {

  13. Q_OBJECT

  14.  
  15. public:

  16. explicit MainWindow(QWidget *parent = nullptr);

  17. ~MainWindow();

  18. // void paintEvent(QPaintEvent *p);

  19. QPainter *painter;

  20.  
  21. private slots:

  22. void on_pushButton_clicked();

  23.  
  24. private:

  25. Ui::MainWindow *ui;

  26. bool m_flag = false;//绘图标志

  27. bool eventFilter(QObject *watched, QEvent *event);

  28. void graphChart(QWidget *w);

  29. };

  30.  
  31. #endif // MAINWINDOW_H

Cpp文件 :

 
  1. #include "mainwindow.h"

  2. #include "ui_mainwindow.h"

  3.  
  4. MainWindow::MainWindow(QWidget *parent) :

  5. QMainWindow(parent),

  6. ui(new Ui::MainWindow)

  7. {

  8. ui->setupUi(this);

  9. ui->widget->installEventFilter(this);

  10. }

  11.  
  12. MainWindow::~MainWindow()

  13. {

  14. delete ui;

  15. }

  16.  
  17.  
  18.  
  19. void MainWindow::on_pushButton_clicked()

  20. {

  21. m_flag = true;

  22. update();

  23. }

  24.  
  25. bool MainWindow::eventFilter(QObject *watched, QEvent *event)

  26. {

  27. if(watched ==ui->widget&&event->type()==QEvent::Paint)

  28. {

  29. graphChart(ui->widget);

  30. }

  31.  
  32. return QWidget::eventFilter(watched,event);

  33. }

  34.  
  35. void MainWindow::graphChart(QWidget *w)

  36. {

  37. if(m_flag)

  38. {

  39. painter = new QPainter();

  40. painter->begin(w);

  41. QPen pen;

  42. pen.setColor(Qt::red);

  43. painter->setPen(pen);

  44. painter->drawText(100,100,"Paintevent");

  45. painter->end();

  46.  
  47. }

  48.  
  49. }

补充:

画了个等边三角形 

 
  1. void MainWindow::drawTriangle(QPainter *painter)

  2. {

  3. painter->save();

  4. double radius =100;

  5. painter->setPen(Qt::NoPen);

  6. static const QPointF points[3]={QPointF(radius,0),QPointF(0,0),QPointF(radius/2,sqrt(pow(radius,2)-pow(radius/2,2)))};

  7.  
  8. painter->setBrush(Qt::red);

  9. painter->drawConvexPolygon(points,3);

  10. painter->restore();

  11. }

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!