PyQt重绘事件处理函数paintEvent

PyQt中的重绘和Windows编程中的重绘差不多,但是Qt的重绘更有特色,更加智能。基础部件类QWidget提供的paintEvent函数是一个纯虚函数,继承它的子类想用它,就必须重新实现它。下列4种情况会发生重绘事件:

(1)当窗口部件第一次显示时,系统会自动产生一个绘图事件。

(2)repaint()与update()函数被调用时。

(3)当窗口部件被其他部件遮挡,然后又再次显示出来时,就会对隐藏的区域产生一个重绘事件。

(4)重新调整窗口大小时。

paintEvent()是一个虚函数槽,子类可以对父类的paintEvent进行重写。当调用update()、repaint()的时候,paintEvent()会被调用,另外,当界面有任何改变的时候,paintEvent()也会被调用,这种界面的改变包括界面从隐藏到显示,界面尺寸改变,当然界面内容改变的时候也会被调用。paintEvent()是已经被高度优化过的函数,它本身已经自动开启并实现了双缓冲(X11系统需要手动开启双缓冲),因此Qt中重绘不会引起任何闪烁。有了paintEvent的知识,现在再来看看update()和repaint()。update()和repaint()是一类的,需要重绘的对象主动去调用,然后重绘。update()和repaint()调用之后,都会调用paintEvent().repaint(),被调用之后立即执行重绘,因此repaint()是最快的,紧急情况下需要立刻重绘的可以使用repaint()。但是调用repaint()的函数不能放到paintEvent中调用。举个例子:有一个继承自QWidget的子类MyWidget,在子类中对paintEvent进行重写。我们在MyWidget::myrepaint()中调用repaint()。但是,myrepaint()又被重写的paintEvent()调用。这样调用repaint()的函数又被paintEvent()调用,由于repaint()是立即重绘,而且repaint()在调用paintEvent之前几乎不做任何优化操作,而会造成死循环,即先调用repaint(),继而调用paintEvent(),paintEvent()反过来又调用repaint()...,如此造成死循环。update()跟repaint()比较,update()更加有优越性。update()调用之后并不是立即重绘,而是将重绘事件放入主消息循环中,由main()的event loop来统一调度(其实也是比较快的)。update()在调用paintEvent()之前还做了很多优化,如果update()被调用了很多次,最后这些update()会合并到一个大的重绘事件加入消息队列中,最后只有这个大的update()被执行一次。同时也避免了repaint()中所提到的死循环。因此,一般情况下,我们调用update()就够了,跟repaint()比起来,update()是推荐使用的。

打个比方,QPainter相当于Qt中的画家,能够绘制各种基础图形,拥有绘图所需的画笔、画刷、字体。绘图常用的工具画笔类QPen、画刷类QBrush和字体类QFont都继承自QPainter。QPen用于绘制几何图形的边缘,由颜色、宽度、线风格等参数组成;QBrush用于填充几何图形的调色板,由颜色和填充风格组成;QFont用于文本绘制,由字体属性组成。

QPaintDevice相当于Qt中的画布、画家的绘图板,所有的QWidget类都继承自QPaintDevice。通常我们把绘图操作只需放在paintEvent函数中即可。在QWidget类中,paintEvent的声明如下:

def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ...

我们只需在QWidget的子类中重写paintEvent方法来实现画图,即把绘图函数放在paintEvent中调用,比如:

def paintEvent(self, evt):

    painter = QPainter(self)

    painter.drawLine(0, 0, 100,50); #画线函数

现在不熟悉这些绘图函数没关系,后面会详述,不过我们可以来看其效果。

【例8.1】第一个PyQt画图程序

(1)启动PyCharm,新建一个工程,工程名是PythonProject。

(2)启动Qt Designer,新建一个Dialog without Buttons对话框。从控件工具箱中拖拉一个按钮到对话框上,然后添加clicked信号的槽函数onc1。把这个界面设计的结果保存到mydlg.ui文件中,关闭Qt Designer。为了节省篇幅,在本章下面的实例中,这个过程就不再赘述了,代码也只演示paintEvent中的代码。

(3)回到PyCharm,转换mydlg.ui文件,在main.py中添加如下代码:

import sys
from PyQt5.QtGui import QPainter, QColor
from mydlg import Ui_Dialog
from PyQt5.QtWidgets import *

class CMainDlg(QDialog, Ui_Dialog):
    def __init__(self):
        super(CMainDlg, self).__init__()
        self.clr=255;
        self.setupUi(self)

    def paintEvent(self, evt):
        painter = QPainter(self)
        color = QColor()    			#建立一个颜色对象
        color.setRed(self.clr)   	#把颜色设为红色
        painter.setPen(color);  		#设置画笔的颜色
        w = self.size().width(); 	#获取窗口宽度
        h = self.size().height(); 	#获取窗口高度
        painter.drawLine(0, 0, w // 2, h); 	#画线函数
        painter.drawLine(w // 2, h,w,0);   	#画线函数

    def onc1(self):  		#按钮的clicked信号的槽函数
        if self.clr==255:
            self.clr=0;  		#黑色
        else:
            self.clr=255; 	#红色
        self.update();  		#更新窗口,此时将触发paintEvent函数的自动调用

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CMainDlg()
    window.show()
    sys.exit(app.exec())

在paintEvent函数中,我们定义了一个颜色对象color,并通过成员变量self.clr来设置具体的颜色值,然后通过setPen函数设置画笔的颜色。接着,获取对话框的客户区的宽度和高度,最后调用画线函数drawLine来画两条线。只要窗口或部件需要被重绘,paintEvent函数就会被调用。每个要显示输出的窗口部件都必须实现它。为了在窗口重绘时能显示我们绘制的图形,所以要把绘图函数放在paintEvent中。而在按钮的clicked信号的槽函数中,我们设置了不同的self.clr值,最后使用update函数更新窗口,此时将自动触发paintEvent函数的调用。

(4)按【Shift+F10】快捷键运行工程,运行结果如图8-1所示。

 

图8-1

本文节选自《PyQt 5从入门到精通》,内容发布获得作者和出版社授权。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值