PyQt重绘事件处理函数paintEvent

news/2025/1/8 8:29:29/

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从入门到精通》,内容发布获得作者和出版社授权。

 


http://www.ppmy.cn/news/122536.html

相关文章

稳健地对时间序列光学卫星图像进行配准教程

一、引言 几何误差会导致连续卫星图像采集之间的错位,进而影响土地监测和变化检测分析。在这篇博客文章中,我们研究了如何稳健地对时间序列光学卫星图像进行配准,以减少这种错位的影响。 在本篇博客的末尾,给出用Python配准大区域…

基于Redis实现的两种分布式锁实现方式

一、基于redis实现的分布式锁 1.引入依赖:在pom.xml文件中添加Spring Cloud的依赖和缓存组件的依赖。例如,可以选择使用Redis作为缓存组件,需要添加spring-boot-starter-data-redis和jedis的依赖。 2.配置缓存:在application.yml…

【Daily Share】觉得浏览器low?手写一个浏览器扩展程序,让自己的浏览器变得与众不同!!!!

浏览器扩展 概念 扩展为浏览器添加了特性与功能。它通过我们所熟悉的 Web 技术-HTML,CSS 还有 JavaScript 来创建。扩展可以利用与 JavaScript 相同的网页 API,但是扩展也可以访问它自己专有的 JavaScript API。这意味着,和在网页里编码相比…

搭建一个AI对话机器人——前端ChatUI使用纪录

最近在使用 OpenAI 的 gpt api 搞着玩玩,然后就遇上了前端对话交互实现的需求场景,如何快速实现 CUI(Chat User Interface)成了问题。最后选择了来自阿里达摩院的ChatUI,本人便用于整理其使用经验。 介绍 服务于对话领…

Maven高级2-聚合与继承

1. 聚合 注意打包方式&#xff0c;不是默认的jar包形式&#xff0c;也不是web的war包形式&#xff0c;而是pom形式&#xff1b; <groupId>org.example</groupId> <artifactId>springmvc_08_parent</artifactId> <version>1.0-SNAPSHOT</versi…

谷歌android wear智能腕表 价格,谷歌Android Wear 2.0更新推送:仅三款智能手表可享受...

经过一段时间的等待之后&#xff0c;谷歌的最新一代可穿戴平台Android Wear 2.0终于正式发布。此后便有多个品牌宣布将推出搭载Android Wear 2.0的新款智能手表。在近日举办的瑞士巴塞尔国际珠宝钟表展上&#xff0c;各大品牌发布的全新Android Wear 2.0智能手表让人眼花缭乱。…

LG华为抢先苹果发布智能手表

据外媒报道&#xff0c;3月1日&#xff0c;也就是2015年西班牙巴塞罗那世界移动通讯大会召开的前一天&#xff0c;韩国LG公司和中国华为公司均抢先美国苹果公司发布了智能手表产品&#xff0c;显示出2015年智能手表领域的竞争将更加激烈。 LG公司推出的新款Urbane智能手表基本款…

Withings发布Activité Pop智能手表 价格150美元

继去年12月上市的Withings Actvit手表以450美元的价格发售后&#xff0c;其复古的外观设计&#xff0c;内置加速度仪和蓝牙功能受到了人们关注。现在&#xff0c;新版Withings Activit Pop在2015 CES展会上发布&#xff0c;价格更亲民&#xff0c;为150美元。于美国当地时间1月…