【问题标题】:Possible rendering issue with QScrollArea and QPainterQScrollArea 和 QPainter 可能出现的渲染问题
【发布时间】:2018-10-18 05:09:20
【问题描述】:

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

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

当窗口失去焦点时,标签会正确重绘。

这是我迄今为止所做的 MWE。

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_())

我不确定是什么原因造成的。任何帮助表示赞赏!

【问题讨论】:

    标签: python pyqt pyqt5 qpainter qscrollarea


    【解决方案1】:

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

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

    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))
        # change event.rect() to self.rect()
        qp.drawText(self.rect(), Qt.AlignCenter, self.text())
    

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

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

    【讨论】:

    • 感谢您的解释!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 2016-01-25
    • 1970-01-01
    • 2013-07-30
    • 1970-01-01
    相关资源
    最近更新 更多