Python QScrollArea和QPainter可能存在的渲染问题

Python QScrollArea和QPainter可能存在的渲染问题,python,pyqt,pyqt5,qpainter,qscrollarea,Python,Pyqt,Pyqt5,Qpainter,Qscrollarea,我正在尝试用PyQt5创建一个角色地图可视化工具。使用fontTools库,我提取给定ttf文件中支持的UNICODE代码点。然后使用QPainter.drawText在标签上绘制图示符。标签存储在QGridLayout中,布局位于qscrollara 一切正常,除了我尝试滚动的时候。每当我尝试滚动过快时,绘制的图像就会重叠。看起来像这样 当窗口失去焦点时,标签会被正确地重新绘制 这是我到目前为止所做的一切 import sys from PyQt5 import QtCore, QtWidg

我正在尝试用PyQt5创建一个角色地图可视化工具。使用fontTools库,我提取给定ttf文件中支持的UNICODE代码点。然后使用
QPainter.drawText
在标签上绘制图示符。标签存储在
QGridLayout
中,布局位于
qscrollara

一切正常,除了我尝试滚动的时候。每当我尝试滚动过快时,绘制的图像就会重叠。看起来像这样

当窗口失去焦点时,标签会被正确地重新绘制

这是我到目前为止所做的一切

import sys

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFontDatabase, QFont, QColor, QPainter

from fontTools.ttLib import TTFont

class App(QWidget):
    def __init__(self):
        super().__init__()
        self.fileName = "mukti.ttf" #the ttf file is located in the same path as the script

        self.initUI()

    def initUI(self):
        self.setWindowTitle("Glyph Viewer")
        self.setFixedSize(640, 480)
        self.move(100, 100)

        vBox = QtWidgets.QVBoxLayout()
        self.glyphView = GlyphView()
        vBox.addWidget(self.glyphView)

        self.setLayout(vBox)

        self.showGlyphs()

        self.show()

    def showGlyphs(self):
        #Using the fontTools libray, the unicode blocks are obtained from the ttf file
        font = TTFont(self.fileName)
        charMaps = list()
        for cmap in font['cmap'].tables:
            charMaps.append(cmap.cmap)
        charMap = charMaps[0]

        fontDB = QFontDatabase()
        fontID = fontDB.addApplicationFont("mukti.ttf")
        fonts = fontDB.applicationFontFamilies(fontID)
        qFont = QFont(fonts[0])
        qFont.setPointSize(28)

        self.glyphView.populateGrid(charMap, qFont)

class GlyphView(QtWidgets.QScrollArea):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setWidgetResizable(True)

    def populateGrid(self, charMap, qFont):
        glyphArea = QtWidgets.QWidget(self)
        gridLayout = QtWidgets.QGridLayout()
        glyphArea.setLayout(gridLayout)

        row, col = 1, 1
        for char in charMap:
            uni = charMap[char]
            gridLayout.addWidget(Glyph(qFont, chr(char)), row, col)
            if not col % 4:
                col = 1
                row += 1
            else:
                col += 1

        self.setWidget(glyphArea)

class Glyph(QtWidgets.QLabel):
    def __init__(self, font, char):
        super().__init__()
        self.font = font
        self.char = char

        self.initUI()

    def initUI(self):
        self.setFixedSize(48, 48)
        self.setToolTip(self.char)

    def paintEvent(self, event):
        qp = QPainter(self)
        qp.setBrush(QColor(0,0,0))
        qp.drawRect(0, 0, 48, 48)
        qp.setFont(self.font)
        qp.setPen(QColor(255, 255, 255))
        qp.drawText(event.rect(), Qt.AlignCenter, self.char)

app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
我不确定这是什么原因造成的。感谢您的帮助

paintEvent()方法为我们提供了一个属于
QPaintEvent
的对象,该对象通过
rect()
方法提供了一个
QRect
,该
QRect
是当前可见的区域,该信息可用于优化绘制,例如,假设我们有一个小部件,它在几行中显示文本,如果文本很大,那么几行看起来会很浪费资源,因此使用前面提到的
QRect
进行适当的计算,我们可以得到这些行,并用很少的资源绘制该部分。在中,我展示了一个使用event.rect()的示例

在您的情况下,不需要使用
event.rect()
,因为您将在小部件的一部分中绘制文本。您应该使用的是
self.rect()

我还认为没有必要覆盖
paintEvent()
方法,因为您可以直接指向
QLabel
字体、文本和对齐方式:

class Glyph(QtWidgets.QLabel):
    def __init__(self, font, char):
        super().__init__(font=font, text=char, alignment=Qt.AlignCenter, toolTip=char)
paintEvent()
方法为我们提供了一个属于
QPaintEvent
的对象,该对象通过
rect()
方法提供了一个
QRect
,该
QRect
是当前可见的区域,该信息可用于优化绘制,例如,假设我们有一个小部件,它在几行中显示文本,如果文本很大,那么几行看起来会很浪费资源,因此使用前面提到的
QRect
进行适当的计算,我们可以得到这些行,并用很少的资源绘制该部分。在中,我展示了一个使用event.rect()的示例

在您的情况下,不需要使用
event.rect()
,因为您将在小部件的一部分中绘制文本。您应该使用的是
self.rect()

我还认为没有必要覆盖
paintEvent()
方法,因为您可以直接指向
QLabel
字体、文本和对齐方式:

class Glyph(QtWidgets.QLabel):
    def __init__(self, font, char):
        super().__init__(font=font, text=char, alignment=Qt.AlignCenter, toolTip=char)

谢谢你的解释!谢谢你的解释!