Python Qt绑定:setCosmetic()和sceneRect(),边距问题 [英] Python Qt bindings: setCosmetic() and sceneRect(), problems with margins

查看:498
本文介绍了Python Qt绑定:setCosmetic()和sceneRect(),边距问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用以下简单示例(与PySide或PyQt4均适用):

  import sys 
import从PySide导入QtGui,QtCore

类窗口(QtGui.QWidget)中随机抽取
numpy


def __init __(self):
超级(Window,self).__ init __()

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

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

#样式
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):
行= QtCore.QLineF(x0,-y0,x1,-y1)
pen = QtGui.QPe n(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 =无):
self.fit()


如果__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_())

我能够绘制一个矩形和两条穿过它的蓝线。请注意,使用宽度 0 QtGui.QPen 如何使蓝线的宽度恒定,而无论正方形/线条或窗口的大小:






这是因为默认情况下零宽度笔是装饰性的。根据Qt文档:


化妆品笔用于绘制具有恒定宽度
的笔触,而无需进行任何变换 QPainter 是与它们一起使用的
。用化妆笔绘制形状可确保其轮廓
在不同的比例因子下具有相同的厚度。


也可以使用 setCosmetic(True)方法将零宽度笔设置为化妆品。因此,将示例的 addLine()方法中的笔宽设置为 2 并将笔设置为化妆笔:

  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)

给出以下输出:






您可以看到,利润很大,我真的希望交叉线在窗口的左下角和右上角处开始和结束,而没有空白。



似乎这些空白之所以添加,是因为修改了 scene.sceneRect()好像该行不是装饰性的。例如,在这种情况下,宽度也设置为 2 ,但笔未设置为化妆品:

  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)



为什么会这样?仅当 isCosmetic()== False 时才不应该添加额外的边距吗?如果这种行为是故意的,那么有人可以解释原因吗?



还可以避免这种情况吗?一种干净的东西,不同于在将线添加到场景之前手动更改线的边界(或不同于从场景中减去多余的边距)。也许有一个配置参数或将线添加到场景的另一种方法?



EDIT



设置上限样式设置为扁平会产生较小的边距,尽管问题仍然存在:

  def addLine(self,x0,y0 ,x1,y1):
行= 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)



再一次,我们可以看到边距与使用非化妆笔的边距相同:



解决方案

这并不是完全的答案,但我认为这可能会有所帮助:



我用C ++做到了,但是翻译起来很容易。在您的QGraphicsView中,设置滚动条策略:

  view-> setVerticalScrollBarPolicy(Qt :: ScrollBarAlwaysOff); 
view-> setHorizo​​ntalScrollBarPolicy(Qt :: ScrollBarAlwaysOff);

然后在对fitInView的调用中,添加以下标志:

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


With the following simple example (which works well with either 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 am able to draw one rectangle and two blue lines crossing it. Notice how, using a QtGui.QPen with width 0 makes the blue lines have a constant width no matters the size of the square/lines nor the size of the window:

That is because a zero width pen is cosmetic by default. According to the Qt documentation:

Cosmetics pens are used to draw strokes that have a constant width regarless of any transformations applied to the QPainter they are used with. Drawing a shape with a cosmetic pen ensures that its outline will have the same thickness at different scale factors.

A non-zero width pen can be also set as cosmetic, using the method setCosmetic(True). So, setting the pen width in the example's addLine() method 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:

As you can see, the margins are huge, and I really would expect the crossing line to start and end at the lower-left and upper-right corners of the window, with no margins.

It seems that those margins were added because the scene.sceneRect() was modified as if the line was not cosmetic. See for example this case, in which the width is set to 2 as well, but the pen is not set 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)
        l = self.scene.addLine(line, pen)

Why is this happening? Shouldn't the extra margins be added only when isCosmetic() == False? If this behavior is intentional, could someone explain the reason?

Also, is there a way to avoid it? Something "clean", different from manually changing the boundings of the line before adding it to the scene (or different from substracting the extra margins later from the scene). Perhaps there is a configuration parameter or another way of adding the line to the scene?

EDIT

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

    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)

And once again, we can see how the margins are the same as if we used a non-cosmetic pen:

解决方案

This isn't quite the answer but I thought it might help:

I did this in C++ but it's easy enough to translate. In your QGraphicsView, set the scrollbar 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);

这篇关于Python Qt绑定:setCosmetic()和sceneRect(),边距问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆