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 }
来源:oschina
链接:https://my.oschina.net/u/4287236/blog/4503358