PyQt5 使用 keyPressEvent() 触发paintEvent()

Posted

技术标签:

【中文标题】PyQt5 使用 keyPressEvent() 触发paintEvent()【英文标题】:PyQt5 triggering a paintEvent() with keyPressEvent() 【发布时间】:2017-10-25 14:02:30 【问题描述】:

我正在尝试学习 PyQt 矢量绘画。目前我一直在尝试将信息传递给我猜应该调用其他方法的paintEvent() 方法:

我正在尝试将不同的数字绘制到一个基本块(这里是 drawFundBlock() 方法,它应该画一些线)。代码试图检查是否按下了右箭头-> drawFundamental 块,如果按下了数字(现在试图简单地绘制“5”),它将在该基本块的某个区域上绘制该数字。但我似乎无法让 QPainter 工作。似乎它现在调用了两次paintEvent() 覆盖方法(为什么?)。有人建议使用 update() 方法,但我不知道如何仍将任何参数传递给paintEvent(),它应该确定是绘制“fundblock”还是“number”。现在代码使用 update() 进行演示,但这只是移动了行 - 但是已经添加的行应该保留!

有什么帮助吗?

# Test QPainter etc.

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QPen, QColor, QFont
from PyQt5.QtCore import Qt, QPoint, pyqtSignal, QRect
import sys

class Example(QWidget):

    paintTrigger = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.initUI()
        self.ydist = 15
        self.eveType = "drawBlock"
        self.currentRegion = QRect(50,50,50,80)
        #self.paintTrigger[self.eveType].connect(lambda:self.paintEvent())

        self.x0=5
        self.x1=25
        self.y0=5
        self.y1=25

    def initUI(self):
        self.setGeometry(300,300,280,270)
        self.setWindowTitle('Painter training')
        self.show()

    # How to pass info here, which type of drawing should be done (block or number)?
    def paintEvent(self,event):
        qp = QPainter(self)
        qp.begin(self)  
        self.drawFundBlock(qp)
        qp.end()

    def drawFundBlock(self,qp):
        pen = QPen(Qt.black, 2, Qt.SolidLine)
        pen.setStyle(Qt.DashLine)

        qp.setPen(pen)
        for i in range(1,10):
            #qp.drawLine(0,i*self.ydist,40,i*self.ydist)
            qp.drawLine(self.x0,i*self.y0,self.x1,self.y0*i)

        #notePoint=QPoint(200,200)
        #qp.drawText(notePoint,"5")

    def drawNumber(self,qp,notePoint):
        pen = QPen(Qt.black,2,Qt.SolidLine)
        #qp.setPen(QColor(200,200,200))
        qp.setPen(pen)
        qp.setFont(QFont('Arial', 10))
        qp.drawText(notePoint,"5")

    def nextRegion(self):
        self.x0=self.x0+30
        self.x1=self.x1+30
        self.y0=self.y0+30
        self.y1=self.y1+30

    def keyPressEvent(self,event):
        # Did the user press a button??
        gey=event.key()
        if gey == Qt.Key_M: 
            print("Key 'm' pressed!")
        elif gey == Qt.Key_Right:
            print("Right key pressed!, call drawFundBlock()")
            #self.paintTrigger["drawBlock"].emit()
            #self.paintEvent()
            self.update()
            self.nextRegion()

        elif gey == Qt.Key_5:
            print("#5 pressed, call drawNumber()")
            #self.paintTrigger["drawNo"].emit()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

【问题讨论】:

我也尝试创建一个连接到 self.paintEvent() 的 pyqtSignal() 但同样,它不起作用,我无法将相关信息传递给paintEvent 【参考方案1】:

QPaintEvent不应该直接调用,我们必须通过update()进行,这将在必要时在内部调用它。

每次QPaintEvent 被称为这个干净的空间是它要绘制的空间,因此它不会保存以前的绘图的内存,一个简单的解决方案是首先绘制一个QPixmap,它将存储你绘制的内容之前,然后使用 QPixmap 绘制小部件。

另外一点是下面两条指令是等价的:

1.


painter = QPainter(some_QPaintDevice)

2.


painter = QPainter()
painter.begin(some_QPaintDevice)

这两种方法都用于传递将要绘制的对象,在您的情况下,您分配了 2 次相同的小部件。

为了方便画图我提出了drawBackground的方法,这个方法需要填写self.func,第一个参数必须是函数名,第二个是字典,除了需要的参数QPainter.

代码

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.mModified = True
        self.initUI()
        self.currentRegion = QRect(50, 50, 50, 80)
        self.x0 = 5
        self.x1 = 25
        self.y0 = 5
        self.y1 = 25
        self.mPixmap = QPixmap()
        self.func = (None, None)

    def initUI(self):
        self.setGeometry(300, 300, 280, 270)
        self.setWindowTitle('Painter training')
        self.show()

    def paintEvent(self, event):
        if self.mModified:
            pixmap = QPixmap(self.size())
            pixmap.fill(Qt.white)
            painter = QPainter(pixmap)
            painter.drawPixmap(0, 0, self.mPixmap)
            self.drawBackground(painter)
            self.mPixmap = pixmap
            self.mModified = False

        qp = QPainter(self)
        qp.drawPixmap(0, 0, self.mPixmap)

    def drawBackground(self, qp):
        func, kwargs = self.func
        if func is not None:
            kwargs["qp"] = qp
            func(**kwargs)

    def drawFundBlock(self, qp):
        pen = QPen(Qt.black, 2, Qt.SolidLine)
        pen.setStyle(Qt.DashLine)

        qp.setPen(pen)
        for i in range(1, 10):
            qp.drawLine(self.x0, i * self.y0, self.x1, self.y0 * i)

    def drawNumber(self, qp, notePoint):
        pen = QPen(Qt.black, 2, Qt.SolidLine)
        qp.setPen(pen)
        qp.setFont(QFont('Arial', 10))
        qp.drawText(notePoint, "5")

    def nextRegion(self):
        self.x0 += 30
        self.x1 += 30
        self.y0 += 30
        self.y1 += 30

    def keyPressEvent(self, event):
        gey = event.key()
        self.func = (None, None)
        if gey == Qt.Key_M:
            print("Key 'm' pressed!")
        elif gey == Qt.Key_Right:
            print("Right key pressed!, call drawFundBlock()")
            self.func = (self.drawFundBlock, )
            self.mModified = True
            self.update()
            self.nextRegion()
        elif gey == Qt.Key_5:
            print("#5 pressed, call drawNumber()")
            self.func = (self.drawNumber, "notePoint": QPoint(100, 100))
            self.mModified = True
            self.update()

【讨论】:

谢谢!它似乎工作。现在我必须了解 Pixmap/背景的用法。

以上是关于PyQt5 使用 keyPressEvent() 触发paintEvent()的主要内容,如果未能解决你的问题,请参考以下文章

不能通过 keyPressEvent 使用 QPlainTextEdit 中的其他键

为 keyPressEvent 子类化 QTextEdit 是唯一的方法吗?

QMainWindow 没有收到 keyPressEvent,即使有事件过滤器

Qt keyPressEvent

PyQt / PySide keyPressEvent 默认行为

释放按钮后调用的 keyPressEvent