概述
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
事件”
代买如下
-
bool Widget::eventFilter(QObject *watched, QEvent *event)
-
{
-
if(watched == ui->label && event->type() == QEvent::Paint)
-
{
-
magicTime();
-
}
-
return QWidget::eventFilter(watched,event);
-
}
然后就是在magicTime()函数中实现自己的绘制了
如下demo
-
void Widget::magicTime()
-
{
-
QPainter painter(ui->label);
-
painter.setPen(Qt::gray);
-
painter.setBrush(Qt::green);
-
painter.drawRect(10,10,200,200);
-
}
不过在此之间,还有一个步骤是要做的
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.如果使用按钮来控制画图
-
m_flag = true;
-
update();
代码展示如下:
头文件:
-
#ifndef MAINWINDOW_H
-
#define MAINWINDOW_H
-
#include <QMainWindow>
-
#include<QPaintEvent>
-
#include<QPainter>
-
namespace Ui {
-
class MainWindow;
-
}
-
class MainWindow : public QMainWindow
-
{
-
Q_OBJECT
-
public:
-
explicit MainWindow(QWidget *parent = nullptr);
-
~MainWindow();
-
// void paintEvent(QPaintEvent *p);
-
QPainter *painter;
-
private slots:
-
void on_pushButton_clicked();
-
private:
-
Ui::MainWindow *ui;
-
bool m_flag = false;//绘图标志
-
bool eventFilter(QObject *watched, QEvent *event);
-
void graphChart(QWidget *w);
-
};
-
#endif // MAINWINDOW_H
Cpp文件 :
-
#include "mainwindow.h"
-
#include "ui_mainwindow.h"
-
MainWindow::MainWindow(QWidget *parent) :
-
QMainWindow(parent),
-
ui(new Ui::MainWindow)
-
{
-
ui->setupUi(this);
-
ui->widget->installEventFilter(this);
-
}
-
MainWindow::~MainWindow()
-
{
-
delete ui;
-
}
-
void MainWindow::on_pushButton_clicked()
-
{
-
m_flag = true;
-
update();
-
}
-
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
-
{
-
if(watched ==ui->widget&&event->type()==QEvent::Paint)
-
{
-
graphChart(ui->widget);
-
}
-
return QWidget::eventFilter(watched,event);
-
}
-
void MainWindow::graphChart(QWidget *w)
-
{
-
if(m_flag)
-
{
-
painter = new QPainter();
-
painter->begin(w);
-
QPen pen;
-
pen.setColor(Qt::red);
-
painter->setPen(pen);
-
painter->drawText(100,100,"Paintevent");
-
painter->end();
-
}
-
}
补充:
画了个等边三角形
-
void MainWindow::drawTriangle(QPainter *painter)
-
{
-
painter->save();
-
double radius =100;
-
painter->setPen(Qt::NoPen);
-
static const QPointF points[3]={QPointF(radius,0),QPointF(0,0),QPointF(radius/2,sqrt(pow(radius,2)-pow(radius/2,2)))};
-
painter->setBrush(Qt::red);
-
painter->drawConvexPolygon(points,3);
-
painter->restore();
-
}
最后
以上就是笨笨萝莉为你收集整理的Qt中在控件上绘图Qt 在控件上面绘图 label,pushbuttonQt在子部件上绘图的全部内容,希望文章能够帮你解决Qt中在控件上绘图Qt 在控件上面绘图 label,pushbuttonQt在子部件上绘图所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复