Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在QGraphicsView中自动正确设置rect?_Python_Qgraphicsview_Qgraphicsscene_Pyside2_Qgraphicswidget - Fatal编程技术网

Python 如何在QGraphicsView中自动正确设置rect?

Python 如何在QGraphicsView中自动正确设置rect?,python,qgraphicsview,qgraphicsscene,pyside2,qgraphicswidget,Python,Qgraphicsview,Qgraphicsscene,Pyside2,Qgraphicswidget,我有两个不同的问题,我正试图解决,但我无法解决。我以前没有使用过QGraphicsView等,但我创建了一个QGraphicsView,我正在尝试加载图像,并尝试使用QSpinBox动态控制图像每行使用的列数。例如,如果我有16个图像,并且QSpinBox设置为4“我默认设置为4”,则应该有4行4列图像。这部分我似乎有工作正常,但代码不是很好。我无法找到一种方法来控制图像的列数和行数,除非每次计数改变时都将它们全部删除并重新加载。我最终清理了整个场景,重新加载了所有内容,因为我无法单独移除项目

我有两个不同的问题,我正试图解决,但我无法解决。我以前没有使用过
QGraphicsView
等,但我创建了一个
QGraphicsView
,我正在尝试加载图像,并尝试使用
QSpinBox
动态控制图像每行使用的列数。例如,如果我有16个图像,并且
QSpinBox
设置为4“我默认设置为4”,则应该有4行4列图像。这部分我似乎有工作正常,但代码不是很好。我无法找到一种方法来控制图像的列数和行数,除非每次计数改变时都将它们全部删除并重新加载。我最终清理了整个场景,重新加载了所有内容,因为我无法单独移除项目

我现在面临的主要问题是自动正确设置行和列的rect。我试图让场景随着变化而调整大小,而不会留下一堆空白的滚动条

下面是加载图像时它在开始时的外观

下面是稍微滚动
QSpinBox
后的效果。此时应该只有一个垂直滚动条,而不是一堆空白的水平滚动条

经过一些尝试和错误,我发现在我的代码中,我可以像这样设置scene rect
self.scene.setscen直立(QRectF(self.graphics\u widget.rect())
,它似乎可以很好地解决滚动条问题,但我只能在手动触发它时才能让它工作,在本例中,这就是“set rect”按钮可以

这里有一个例子。单击“Set Rect”按钮后,垂直滚动条被正确删除,水平滚动条是整行的确切宽度

如果我尝试在加载所有内容后自动设置场景矩形,它会给我错误的宽度和高度,但由于某些原因,如果我使用按钮等手动设置,则可以正常工作

我遇到的另一个小问题是让顶部的红色条比视口区域延伸得更远。如果我试图在水平滚动条显示时水平滚动,它看起来是这样的,我希望它能拉伸整个宽度

不过这没什么大不了的,我相信我能弄明白。我主要关心的是自动设置scene rect,这样所有内容都可以正常运行,而不会在滚动条上留下一堆空白。
有人有什么建议吗?谢谢

这是我的密码:

from PySide2.QtCore import QRectF, QSizeF, QRect, Qt, QPointF
from PySide2.QtGui import QPixmap, QFont, QColor, QPen, QBrush
from PySide2.QtWidgets import QGraphicsWidget, QWidget, QVBoxLayout, QPushButton, QHBoxLayout, \
    QSpinBox, QGraphicsView, QGraphicsScene, QGraphicsGridLayout, QApplication


class PixmapItem(QGraphicsWidget):
    def __init__(self, image, parent=None):
        super(PixmapItem, self).__init__(parent)
        self.pic = QPixmap(image)
        self._boundingRect = QRectF()
        self.pic_size = self.pic.rect().size()

    def boundingRect(self):
        width = self.pic_size.width()
        height = self.pic_size.height()
        pix_rect = QRectF(0.0, 0.0, width, height)
        self._boundingRect = pix_rect
        return pix_rect

    def sizeHint(self, which, constraint=QSizeF()):
        return self._boundingRect.size()

    def paint(self, painter, option, widget):
        painter.drawPixmap(QRect(0, 40, self.pic_size.width(), self.pic_size.height()), self.pic, self.pic.rect())

class MyScene(QGraphicsScene):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def drawBackground(self, painter, rect):
        bg_brush = QBrush(QColor(255, 255, 255), Qt.SolidPattern)
        painter.fillRect(rect, bg_brush)
        #Red bar on top
        painter.setPen(QPen(Qt.NoPen))
        brush = QBrush(QColor(139, 0, 0), Qt.SolidPattern)
        r = QRectF(QPointF(0, 0), QSizeF(rect.width(), 30))
        painter.fillRect(r, brush)
        self.update()

class Widget(QWidget):
    def __init__(self):
        super(Widget, self).__init__()
        self.resize(330, 330)
        self.imglist = ["py.png", "py.png","py.png","py.png","py.png","py.png",
                        "py.png","py.png","py.png","py.png","py.png","py.png"]

        self._layout = QVBoxLayout()
        self._layout2 = QHBoxLayout()

        self.btn = QPushButton("Load")
        self.column_spinbox = QSpinBox()
        self.column_spinbox.setRange(1, 25)
        self.column_spinbox.setValue(4)
        self.column_spinbox.setSingleStep(1)
        self.btn2 = QPushButton("Set Rect")

        self._layout2.addWidget(self.btn)
        self._layout2.addWidget(self.column_spinbox)
        self._layout2.addWidget(self.btn2)
        self._layout.addLayout(self._layout2)

        self._layout3 = QHBoxLayout()
        self.view = QGraphicsView()
        self.view.setAlignment(Qt.AlignLeft | Qt.AlignTop)
        self.scene = MyScene()
        self.view.setScene(self.scene)
        self.graphics_widget = QGraphicsWidget()
        self.scene.addItem(self.graphics_widget)
        self.graphics_layout = QGraphicsGridLayout()
        self.graphics_widget.setLayout(self.graphics_layout)
        self._layout3.addWidget(self.view)
        self._layout.addLayout(self._layout3)
        self.setLayout(self._layout)
        self.btn.clicked.connect(self._load_pix)
        self.btn2.clicked.connect(self._set_rect)
        self.column_spinbox.valueChanged.connect(self.set_columns)

    def _set_rect(self):
        self.scene.setSceneRect(QRectF(self.graphics_widget.rect()))

    def _load_pix(self):
        for img in range(len(self.imglist)):
            pixmap = PixmapItem(self.imglist[img])
            row, column = divmod(img, self.column_spinbox.value())
            self.graphics_layout.addItem(pixmap, row, column)
            self.graphics_layout.setColumnSpacing(column, 15)
            self.graphics_layout.setRowSpacing(row, 15)
        self.scene.setSceneRect(QRectF(self.graphics_widget.rect()))
        # Add text to top
        item = self.scene.addText("Some Sample Text.", QFont("Arial", 16, QFont.Light))
        item.setDefaultTextColor(QColor(255, 255, 255))

    def set_columns(self):
        self.view.scene().clear()
        #After clearing the scene, re-add the widgets
        self.graphics_widget = QGraphicsWidget()
        self.scene.addItem(self.graphics_widget)
        self.graphics_layout = QGraphicsGridLayout()
        self.graphics_widget.setLayout(self.graphics_layout)
        for img in range(len(self.imglist)):
            pixmap = PixmapItem(self.imglist[img], self.graphics_widget)
            row, column = divmod(img, self.column_spinbox.value())
            self.graphics_layout.addItem(pixmap, row, column)
            self.graphics_layout.setColumnSpacing(column, 15)
            self.graphics_layout.setRowSpacing(row, 15)
        self.scene.setSceneRect(QRectF(self.graphics_widget.rect()))
        #Add text to top again
        item = self.scene.addText("Some Sample Text.", QFont("Arial", 16, QFont.Light))
        item.setDefaultTextColor(QColor(255, 255, 255))

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    widget = Widget()
    widget.show()
    app.exec_()

造成第二个问题的原因是,从DrackGround获得的矩形与场景有关,而不是与视口有关,因此解决方案是复制该矩形并设置高度:

class MyScene(QGraphicsScene):
    def drawBackground(self, painter, rect):
        bg_brush = QBrush(QColor(255, 255, 255), Qt.SolidPattern)
        painter.fillRect(rect, bg_brush)
        #Red bar on top
        painter.setPen(QPen(Qt.NoPen))
        brush = QBrush(QColor(139, 0, 0), Qt.SolidPattern)
        r = QRectF(rect)
        r.setY(0)
        r.setHeight(30)
        painter.fillRect(r, brush)
仍在处理第一个问题

完整解决方案:

我已经适应了您的代码,因为有许多重复的东西,但主要任务是实现adjust_scene方法,该方法使用itemsBoundingRect()和视口计算视口。诀窍是在设置新的QGraphicsWidget后立即调用该函数,在QGraphicsView的resizeEvent中调用它也很好

from PySide2 import QtCore, QtGui, QtWidgets

class PixmapItem(QtWidgets.QGraphicsWidget):
    def __init__(self, image, parent=None):
        super(PixmapItem, self).__init__(parent)
        self.pic = QtGui.QPixmap(image)

    def boundingRect(self):
        return QtCore.QRectF(self.pic.rect())

    def sizeHint(self, which, constraint=QtCore.QSizeF()):
        return self.boundingRect().size()

    def paint(self, painter, option, widget):
        painter.drawPixmap(QtCore.QPoint(), self.pic)

class GraphicsScene(QtWidgets.QGraphicsScene):
    def drawBackground(self, painter, rect):
        bg_brush = QtGui.QBrush(QtGui.QColor(255, 255, 255), QtCore.Qt.SolidPattern)
        painter.fillRect(rect, bg_brush)
        #Red bar on top
        painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
        brush = QtGui.QBrush(QtGui.QColor(139, 0, 0), QtCore.Qt.SolidPattern)
        r = QtCore.QRectF(rect)
        r.setY(0)
        r.setHeight(30)
        painter.fillRect(r, brush)

class GraphicsView(QtWidgets.QGraphicsView):
    def adjust_scene(self):
        if self.scene() is None: return
        r = self.scene().itemsBoundingRect()
        view_rect = self.mapToScene(self.viewport().rect()).boundingRect()
        w = max(r.size().width(), view_rect.size().width())
        h = max(r.size().height(), view_rect.size().height())
        self.scene().setSceneRect(QtCore.QRectF(QtCore.QPointF(), QtCore.QSizeF(w, h)))

    def resizeEvent(self, event):
        super(GraphicsView, self).resizeEvent(event)
        self.adjust_scene()

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.load_button = QtWidgets.QPushButton(text="Load")
        self.load_button.clicked.connect(self.load)
        self.column_spinbox = QtWidgets.QSpinBox(
            value=4,
            minimum=1,
            maximum=25,
            enabled=False
        )
        self.column_spinbox.valueChanged[int].connect(self.set_columns)
        self.scene = GraphicsScene()
        self.view = GraphicsView(self.scene)
        lay = QtWidgets.QVBoxLayout(self)
        hlay = QtWidgets.QHBoxLayout()
        hlay.addWidget(self.load_button)
        hlay.addWidget(self.column_spinbox)
        lay.addLayout(hlay)
        lay.addWidget(self.view)

    @QtCore.Slot()
    def load(self):
        self.imglist = ["py.png", "py.png","py.png","py.png","py.png","py.png",
            "py.png","py.png","py.png","py.png","py.png","py.png"]
        self.set_columns(self.column_spinbox.value())
        self.column_spinbox.setEnabled(True)

    @QtCore.Slot(int)
    def set_columns(self, column):
        self.view.scene().clear()
        item = self.scene.addText("Some Sample Text.", QtGui.QFont("Arial", 16, QtGui.QFont.Light))
        item.setDefaultTextColor(QtGui.QColor(255, 255, 255))

        top = item.mapToScene(item.boundingRect().bottomLeft())
        self.graphics_widget = QtWidgets.QGraphicsWidget()
        graphics_layout = QtWidgets.QGraphicsGridLayout(self.graphics_widget)
        self.view.scene().addItem(self.graphics_widget)
        self.graphics_widget.setPos(top)

        for i, img in enumerate(self.imglist):
            item = PixmapItem(img)
            row, col = divmod(i, column)
            graphics_layout.addItem(item, row, col)
            graphics_layout.setColumnSpacing(column, 15)
            graphics_layout.setRowSpacing(row, 15)
        QtCore.QTimer.singleShot(0, self.view.adjust_scene)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())


谢谢。这对第二个问题确实有效,我必须在末尾添加self.update()以使其平滑滚动。我知道我最初做了一些类似的事情,但后来我尝试做一些其他的事情,并把它改成现在的样子。现在我不记得为什么了。整个上午我都在胡闹,尝试了很多东西。非常感谢你,伙计!它工作得很好,我感谢你的时间和努力。