子类化QPdfView实现PDF矩形绘制:绘制内容需切换页面才显示问题排查
问题分析与解决
你的猜测方向没错,但直接导致矩形无法实时显示的核心原因是重绘触发对象错误,而非单纯是绘制到控件上的问题:
- 你当前调用
self.update()触发的是整个QPdfView控件的重绘,但实际负责显示PDF内容的是它的子部件viewport,PDF渲染会优先覆盖viewport的绘制内容,普通的控件重绘无法触发viewport的实时刷新,只有切换页面时PDF的渲染流程会顺带触发viewport重绘,这才让你看到矩形。 - 当然,你确实是把矩形绘制在控件的viewport上,而非修改PDF文件本身,但这只是“矩形不会保存到PDF”的原因,不是实时显示的问题。
代码修改方案
只需要把所有self.update()替换为self.viewport().update(),同时可以给矩形加上更明显的样式(比如红色边框),避免被PDF内容淹没:
FREE_STATE = 1 BUILDING_SQUARE = 2 BEGIN_SIDE_EDIT = 3 END_SIDE_EDIT = 4 class customQPdfView(QPdfView): def __init__(self,parent): super().__init__(parent) self.setGeometry(30, 30, 600, 400) self.begin = QPoint() self.end = QPoint() self.state = FREE_STATE # 定义矩形绘制的画笔,让边框更明显 self.rect_pen = QPen(Qt.red, 2) def paintEvent(self, event): super().paintEvent(event) painter = QPainter(self.viewport()) painter.setPen(self.rect_pen) painter.drawRect(QRect(self.begin, self.end)) def mousePressEvent(self, event): print('press') if not self.begin.isNull() and not self.end.isNull(): p = event.pos() y1, y2 = sorted([self.begin.y(), self.end.y()]) if y1 <= p.y() <= y2: if abs(self.begin.x() - p.x()) <= 3: self.state = BEGIN_SIDE_EDIT return elif abs(self.end.x() - p.x()) <= 3: self.state = END_SIDE_EDIT return self.state = BUILDING_SQUARE self.begin = event.pos() self.end = event.pos() self.viewport().update() def applye_event(self, event): if self.state == BUILDING_SQUARE: self.end = event.pos() elif self.state == BEGIN_SIDE_EDIT: self.begin.setX(event.x()) elif self.state == END_SIDE_EDIT: self.end.setX(event.x()) def mouseMoveEvent(self, event): print('move') self.applye_event(event) self.viewport().update() def mouseReleaseEvent(self, event): print('release') self.applye_event(event) self.state = FREE_STATE self.viewport().update()
额外说明
如果后续需要把矩形永久保存到PDF文件中,你需要使用QPdfWriter或PDF处理库(如PyPDF2)操作PDF文档本身——当前的绘制只是临时显示在界面上,不会修改原始PDF文件。
内容的提问来源于stack exchange,提问作者ScottyCov
相关产品推荐
相关产品推荐

