Возможная проблема рендеринга с QScrollArea и QPainter - PullRequest
0 голосов
/ 18 октября 2018

Я пытаюсь создать инструмент визуализации карты персонажей с помощью PyQt5.С помощью библиотеки fontTools я извлекаю кодовые точки UNICODE, поддерживаемые в данном файле ttf.Затем, используя QPainter.drawText, я рисую глифы на ярлыках.Ярлыки хранятся в QGridLayout, а макет - в QScrollArea

Все отлично работает, кроме случаев, когда я пытаюсь прокрутить.Рисованные изображения накладываются друг на друга, когда я пытаюсь прокрутить слишком быстро.Похоже на это.screen cap

Надписи перерисовываются должным образом в тот момент, когда окно теряет фокус.

Вот 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_())

Я не уверен, что является причиной этого.Любая помощь приветствуется!

1 Ответ

0 голосов
/ 18 октября 2018

Метод paintEvent() дает нам объект, принадлежащий QPaintEvent, этот объект предоставляет QRect с помощью метода rect(), что QRect - это область, которая видна в данный момент, и эта информация может бытьнапример, используется для оптимизации рисования. Допустим, у нас есть виджет, который отображает текст в несколько строк. Если текст большой, то несколько строк будут выглядеть так, что рисование - пустая трата ресурсов, поэтому при правильном расчете с использованием вышеупомянутого QRectмы могли бы получить эти строки и нарисовать эту часть, потратив немного ресурсов.В этом ответе я показываю пример использования 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)
...