Как переопределить QPaintEngine & QPaintDevice и установить соединения с QPaintEngineState - PullRequest
0 голосов
/ 19 марта 2020

После woboq QPaintDevice и woboq QPaintEngine , я попытался переопределить QPaintEngine & QPaintDevice. Подробнее, QPaintEngineState.

Это мое первое испытание, и я не смог найти достаточно решений.

Повторная реализация QPaintDevice, вероятно, не была проблемой, но в случае QPaintEngine Я не мог конвертировать из C++ в python код гладко. Если я создаю экземпляр QPaintEventState, приложение не работает.

Особенно, drawTextItem явно содержит C++ внутренний код, я не могу преобразовать в python, я в растерянности.

Возможно, было бы хорошо, если бы я делегировал выполнение по умолчанию QPaintEngine,

Например, вместо

def drawTextItem(self, p, textItem):
        path = QtGui.QPainterPath()
        path.setFillRule(QtCore.Qt.WindingFill);
        if not path.isEmpty():
            self.painter().save()
            self.painter().setRenderHint(QtGui.QPainter.Antialiasing,
                                     bool((self.painter().renderHints() & QtGui.QPainter.TextAntialiasing)
                                          and not (self.painter().font().styleStrategy() & QtGui.QFont.NoAntialias)))
            self.painter().translate(p.x(), p.y())
            self.painter().fillPath(path, self.painter().pen().brush())
            self.painter().restore()

def drawTextItem(self, p, textItem):
    #I write here before the default drawTextItem
    QtGui.QPaintEngine.drawTextItem(p, textItem)

вот так .

Или самого кода C++ недостаточно для создания подкласса? (поскольку QPaintDevice.width () возвращает pdmWidth, но по умолчанию его нет в функции metri c (dev).)

QPaintEngine, QPaintDevice, QPaintEngineState, как их правильно использовать ?

Как переопределить наименее исполняемый код, как мне это сделать? Я хочу получить любую информацию.

Это мой пробный код, может быть несколько проблемы ... В настоящее время мне удалось установить QPaintDevice подкласса на QAbstractTextDocumentLayout.setPaintDevice().

import os
import PySide2
from PySide2 import QtWidgets , QtGui , QtCore, QtPrintSupport, QtOpenGL
import sys
import math
dirname  =  os.path.dirname(PySide2.__file__)
plugin_path  =  os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH']  =  plugin_path

class PE(QtGui.QPaintEngine):
    def __init__(self, features = QtGui.QPaintEngine.AllFeatures):
        super(PE, self).__init__(features=features)

        self.qt_polygon_recursion = 0
        self.paintEngineEx = {}   
        self.types = [QtGui.QPaintEngine.Type.X11, QtGui.QPaintEngine.Type.Windows, QtGui.QPaintEngine.MacPrinter, QtGui.QPaintEngine.CoreGraphics,\
                 QtGui.QPaintEngine.Type.QuickDraw, QtGui.QPaintEngine.QWindowSystem, QtGui.QPaintEngine.PostScript, QtGui.QPaintEngine.OpenGL,\
                 QtGui.QPaintEngine.Type.Picture, QtGui.QPaintEngine.SVG, QtGui.QPaintEngine.Raster, QtGui.QPaintEngine.Direct3D,\
                 QtGui.QPaintEngine.Type.Pdf, QtGui.QPaintEngine.OpenVG, QtGui.QPaintEngine.User, QtGui.QPaintEngine.MaxUser, QtGui.QPaintEngine.OpenGL2,\
                 QtGui.QPaintEngine.Type.PaintBuffer, QtGui.QPaintEngine.Blitter]
    def begin(self, paintDevice):      

        if isinstance(paintDevice, QtGui.QPaintDevice):
            print(24, "in begin func")
            return True
        else:
            return False
    def drawPolygon(self, points, pointCount, mode):
        if type(points[0]) == QtCore.QPointF:            
            self.qt_polygon_recursion = self
            p = [QtCore.QPointF() for i in range(pointCount)]
            for i in range(pointCount):
                p[i].x = round(points[i].x())
                p[i].y = round(points[i].y())  
            self.drawPolygon(p, pointCount, mode)
            self.qt_polygon_recursion = 0  
        elif type(points[0]) == QtCore.QPoint:
            self.qt_polygon_recursion = self
            p = [QtCore.QPointF() for i in range(pointCount)]
            for i in range(pointCount):
                p[i].x = round(points[i].x())
                p[i].y = round(points[i].y())
            self.drawPolygon(p, pointCount, mode)
            self.qt_polygon_recursion = 0
    def drawPoints(self, points, pointCount):
        if type(points[0]) == QtCore.QPoint:
            fp = [QtCore.QPointF() for i in range(256)]
            while pointCount:
                i = 0
                while i < pointCount and i < 256:
                    fp[i].x = points[i].x()
                    fp[i].y = points[i].y()
                    i += 1
                self.drawPoints(QtCore.QPointF(fp), i)
                points += i
                pointCount -= i
        elif type(points[0]) == QtCore.QPointF:            
            p = self.painter()
            pen = p.pen()        
            penWidth = pen.widthF()
            if penWidth == 0:
                penWidth = 1
            ellipses = pen.capStyle() == QtCore.Qt.RoundCap
            p.save()
            transForm = QtGui.QTransform()
            if self.qt_pen_is_cosmetic(pen, p.renderHints()):
                p.setTransform(transForm)        
            p.setBrush(pen.brush())
            p.setPen(QtCore.Qt.NoPen)        
            for i in range(pointCount):
                pos = transForm.map(points[i])
                rectF = QtCore.QRectF(pos.x() - penWidth /2, pos.y() - penWidth / 2, penWidth, penWidth)
                if ellipses:
                    p.drawEllipse(rectF)
                else:
                    p.drawRect(rectF)
            p.restore()
    def drawEllipse(self, rect):
        if type(rect) == QtCore.QRect:
            self.drawEllipse(QtCore.QRectF(rect))
        elif type(rect) == QtCore.QRectF:
            path = QtGui.QPainterPath()
            path.addEllipse(rect)
            if self.hasFeature(QtGui.QPaintEngine.PainterPaths):
                self.drawPath(path)
            else:
                polygon = path.toFillPolygon()
                self.drawPolygon(polygon.data(), polygon.size(), QtGui.QPaintEngine.ConvexMode)
    def qt_fill_tile(self, tile, pixmap):
        p = QtGui.QPainter(tile)
        p.drawPixmap(0, 0, pixmap)
        x = pixmap.width()
        while x < tile.width():
            p.drawPixmap(x, 0, tile, 0, 0, x, pixmap.height())
            x *= 2
        y = pixmap.height()
        while y < tile.height():
            p.drawPixmap(0, y, tile, 0, 0, tile.width(), y)
            y *= 2  
    def qt_draw_tile(self, gc, x, y, w, h, pixmap, xOffset, yOffset):
       yPos = y
       yOff = yOffset
       while yPos < y+h:
           drawH = pixmap.height() - yOff
           if (yPos + drawH > y + h):
               drawH = y + h - yPos
           xPos = x
           xOff = xOffset
           while (xPos < x + w):
                drawW = pixmap.width() - xOff
                if (xPos + drawW > x + w):
                   drawW = x + w - xPos
                if (drawW > 0 and drawH > 0):
                    gc.drawPixmap(QtCore.QRectF(xPos, yPos, drawW, drawH), pixmap, QtCore.QRectF(xOff, yOff, drawW, drawH))
                xPos += drawW
                xOff = 0
           yPos += drawH
           yOff = 0            
    def drawTiledPixmap(self, rect, pixmap, p):
        sw = pixmap.width()
        sh = pixmap.height()
        if sw*sh < 8192 and sw*sh < 16*rect.width()*rect.height():
            tw = sw, th = sh
            while (tw*th < 32678 and tw < rect.width()/2):
                tw *= 2
            while (tw*th < 32678 and th < rect.height()/2):
                th *= 2
            tile = QtGui.QPixmap()
            if pixmap.depth() == 1:
                tile = QtGui.QBitmap(tw, th)
            else:
                tile = QtGui.QPixmap(tw, th)
                if pixmap.hasAlphaChannel():
                    tile.fill(QtCore.Qt.transparent)
            self.qt_draw_fill(tile, pixmap)
            self.qt_draw_tile(self, rect.x(), rect.y(), rect.width(), rect.height(), tile, p.x(), p.y())
        else:
            self.qt_draw_tile(self, rect.x(), rect.y(), rect.width(), rect.height(), pixmap, p.x(), p.y()) 
    def drawImage(self, r, image, sr, flags = QtCore.Qt.AutoColor):
        #Confirmed
        baseSize = QtCore.QRectF(0, 0, image.width(), image.height())
        im = image
        if baseSize != sr:
            im = im.copy(math.floor(sr.x()), math.floor(sr.y()), math.ceil(sr.width()), math.ceil(sr.height()))
        pm = QtGui.QPixmap.fromImage(im, flags)
        self.drawPixmap(r, pm, QtCore.QRectF(QtCore.QPointF(0, 0), pm.size()))
    def drawPath(self, path):
        #confirmed

        if self.hasFeature(QtGui.QPaintEngine.PainterPaths):
            print(path.isEmpty())
            print("QPaintEngine::drawPath: Must be implemented when feature PainterPaths is set")
    def drawTextItem(self, p, textItem):
        path = QtGui.QPainterPath()
        path.setFillRule(QtCore.Qt.WindingFill);
        if not path.isEmpty():
            self.painter().save()
            self.painter().setRenderHint(QtGui.QPainter.Antialiasing,
                                     bool((self.painter().renderHints() & QtGui.QPainter.TextAntialiasing)
                                          and not (self.painter().font().styleStrategy() & QtGui.QFont.NoAntialias)))
            self.painter().translate(p.x(), p.y())
            self.painter().fillPath(path, self.painter().pen().brush())
            self.painter().restore()

    def drawLines(self, lines, lineCount):        
        if type(lines[0]) == QtCore.QLine:
            pts = []

            for i in range(lineCount):
                pts = [QtCore.PointF(lines[i].p1()), QtCore.QPointF(lines[i].p2())]
                if pts[0] == pts[1]:
                    if self.state.pen().capStyle() != QtCore.Qt.FlatCap:
                        self.drawPoints(pts, 1)
                        continue
        else:            
            pts = []
            for i in range(lineCount):
                pts = [lines[i].p1(), lines[i].p2()]
                if pts[0] == pts[1]:
                    if self.state.pen().capStyle() != QtCore.Qt.FlatCap:
                        self.drawPoints(pts, 1)
                        continue
        self.drawPolygon(pts, 2, self.PolylineMode)   
    def drawRects(self, rects, rectCount):

        print(rects)
        if type(rects[0]) == QtCore.QRect:
            fr = [QtCore.QRectF() for i in range(256)]
            while rectCount:
                i = 0
                while (i < rectCount and i < 256):
                    fr[i].x = rects[i].x()
                    fr[i].y = rects[i].y()
                    fr[i].w = rects[i].width()
                    fr[i].h = rects[i].height()
                    i+=1
                self.drawRects(fr, i)
                rects += i
                rectCount -= i
        elif type(rects[0]) == QtCore.QRectF:            
            if self.hasFeature(self.PainterPaths) :
                for i in range(rectCount):
                    path = QtGui.QPainterPath()
                    path.addRect(rects[i])
                    if path.isEmpty():
                        continue                    
                    self.drawPath(path)
            else:
                for i in range(rectCount):
                    rf = rects[i]
                    pts = [QtCore.QPointF(rf.x(), rf.y()),
                           QtCore.QPointF(rf.x() + rf.width(), rf.y()),
                           QtCore.QPointF(rf.x() + rf.width(), rf.y() + rf.height()),
                           QtCore.QPointF(rf.x() + rf.y() + rf.height())]
                    self.drawPolygon(pts, 4, self.ConvexMode)        
    def coordinateOffset(self):        
        return QtCore.QPoint()    
    def qt_pen_is_cosmetic(self, pen, hints):
        return pen.isCosmetic()|(hints and QtGui.QPainter.Qt4CompatiblePainting)    
    def end(self):
        return True
    def type(self):

        return QtGui.QPaintEngine.Type.Windows
    def updateState(self, state):
        self.state = state
class PD(QtGui.QPaintDevice):
    def __init__(self, parent=None):
        super(PD, self).__init__(parent=None)
        self._paintEngine = PE()      
    def devType(self):
        #I think this is a deviceType() QPrinter, QImage, QPicture, QPixmap, QTextEdit, and so on.
        paintEngine = self.paintEngine()
        device = paintEngine.paintDevice()
        print(device)
        if type(device) == QtGui.QImage:
            return QtGui.QImage.devType()
        elif type(device) == QtGui.QPicture:
            return QtGui.QPicture.devType()
        elif type(device) == QtGui.QPixmap:
            return QtGui.QPixmap.devType()
        elif type(device) == QtPrintSupport.QPrinter:
            return QtPrintSupport.QPrinter.devType()
        elif type(device) == QtOpenGL.QGLPixelBuffer:
            return QtOpenGL.QGLPixelBuffer.devType()
        elif type(device) == QtWidgets.QWidget:
            return QtWidgets.QWidget.devType()
        else:
            return 0
    def redirected(self, point):
        return self
    def sharedPainter(self):
        painter = QtGui.QPainter()
        return painter
    def initPainter(self, painter):
        print(painter)
        pass
    def metric(self, m):
        if m == self.PdmDevicePixelRatioScaled:
            return self.metric(self.PdmDevicePixelRatio) * self.devicePixelRatioFScale()
        if m == self.PdmDpiX:
            return 72
        elif m == self.PdmDpiY:
            return 72
        elif m == self.PdmNumColors:
            return 256
        elif m == self.PdmDevicePixelRatio:
            return 1
        else:
            print("Unrecognized metric %d!", m)
            return 0
    def paintEngine(self):        
        paintEngine = self._paintEngine
        print(277, paintEngine)
        return self._paintEngine
class TextEdit(QtWidgets.QTextEdit):
    def __init__(self, parent=None):
        super(TextEdit, self).__init__(parent=None)
        paintDevice = PD()                     
        self.document().documentLayout().setPaintDevice(paintDevice)



def main():
    if QtWidgets.QApplication.instance() is None:
        app = QtWidgets.QApplication([])
    else:
        app = QtWidgets.QApplication.instance()
    textEdit = TextEdit()    
    textEdit.show()
    sys.exit(app.exec_())
if __name__ ==  "__main__":
    main()
...