Python Qt bindings: setCosmetic () and sceneRect (), field issues

With the following simple example (which works well with PySide or PyQt4):

import sys
import random
import numpy
from PySide import QtGui, QtCore

class Window(QtGui.QWidget):

    def __init__(self):
        super(Window, self).__init__()

        self.resize(600, 400)
        self.view = QtGui.QGraphicsView()
        self.scene = QtGui.QGraphicsScene()
        self.view.setScene(self.scene)
        self.setWindowTitle('Example')

        # Layout
        layout = QtGui.QGridLayout()
        layout.addWidget(self.view, 0, 0)
        self.setLayout(layout)

        # Styles
        self.pen = QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine)
        self.brush = QtGui.QBrush(QtGui.QColor(255, 255, 255, 0))

    def addLine(self, x0, y0, x1, y1):
        line = QtCore.QLineF(x0, -y0, x1, -y1)
        pen = QtGui.QPen(QtGui.QColor(0, 0, 255, 255), 0, QtCore.Qt.SolidLine)
        l = self.scene.addLine(line, pen)

    def addRect(self, left, top, width, height):
        rect = QtCore.QRectF(left, -top, width, abs(height))
        r = self.scene.addRect(rect, self.pen, self.brush)

    def fit(self):
        self.view.fitInView(self.scene.sceneRect())

    def resizeEvent(self, event = None):
        self.fit()


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    window.addLine(-1, -1, 2, 2)
    window.addLine(0, 1, 1, 0)
    window.addRect(0, 1, 1, 1)
    window.fit()
    sys.exit(app.exec_())

      

I can draw one rectangle and two blue lines crossing it. Note that when using QtGui.QPen

with width 0

, the width of the blue lines will have a constant width, no matter the size of the square / lines or the size of the window:

enter image description hereenter image description here

This is because a zero-width pen is cosmetic by default. According to Qt documentation:

Cosmetic pens are used to draw strokes that have a constant width with no transformations applied to QPainter

, they are used with. Drawing a shape with a cosmetic pen ensures that its outline has the same thickness at different scale factors.

A handle with a non-zero width can also be set as cosmetic using the method setCosmetic(True)

. So, setting the pen width in the example addLine()

to 2

and setting the pen as cosmetic:

    def addLine(self, x0, y0, x1, y1):
        line = QtCore.QLineF(x0, -y0, x1, -y1)
        pen = QtGui.QPen(QtGui.QColor(0, 0, 255, 255), 2, QtCore.Qt.SolidLine)
        pen.setCosmetic(True)
        l = self.scene.addLine(line, pen)

      

Gives the following output:

enter image description hereenter image description here

As you can see the margins are huge and I would really expect the intersection line to start and end at the bottom left and top right corners of the borderless window.

It seems that these fields were added because it scene.sceneRect()

was changed, as if the line was not cosmetic. See for example this case where the width is also set to 2

, but the feather is not set to cosmetic:

    def addLine(self, x0, y0, x1, y1):
        line = QtCore.QLineF(x0, -y0, x1, -y1)
        pen = QtGui.QPen(QtGui.QColor(0, 0, 255, 255), 2, QtCore.Qt.SolidLine)
        l = self.scene.addLine(line, pen)

      

enter image description here

Why is this happening? Shouldn't you add extra fields only when isCosmetic() == False

? If this behavior is intentional, can someone explain the reason?

Also, is there a way to avoid this? Something "clean", other than manually changing the line boundaries before adding it to the scene (or subtracting additional fields later from the scene). Perhaps there is a config parameter or some other way to add a row to the scene?

EDIT

Setting the cap style to "flat" results in smaller margins, although the problem still exists:

    def addLine(self, x0, y0, x1, y1):
        line = QtCore.QLineF(x0, -y0, x1, -y1)
        pen = QtGui.QPen(QtGui.QColor(0, 0, 255, 255), 2, QtCore.Qt.SolidLine)
        pen.setCosmetic(True)
        pen.setCapStyle(QtCore.Qt.FlatCap)
        l = self.scene.addLine(line, pen)

      

enter image description here

Again, we see how the margins are the same as if we were using a non-cosmetic pen:

enter image description here

+3


source to share


1 answer


It's not really an answer, but I thought this might help:

I did it in C ++, but it's easy enough to translate. In QGraphicsView, set scroll policies:

view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

      



Then, in your call to fitInView, add the following flag:

view->fitInView(scene->sceneRect(), Qt::KeepAspectRatioByExpanding);

      

0


source







All Articles