我有两个不同的问题要解决,我无法弄清楚。我之前并没有使用QGraphicsView
等工具,但是我创建了一个QGraphicsView
,我试图在其中加载图像,并且试图使用QSpinBox
动态地控制每行使用图像。例如,如果我有16张图像,并且QSpinBox
设置为4“我默认拥有”,则应该有4行4列图像。那部分我似乎工作正常,但是代码不是很好。我想不出一种方法来控制有多少列和多少行图像,除非每次计数改变时都删除并重新加载它们。我最终清理了整个场景并重新加载了所有内容,因为我无法单独删除项目。
我现在遇到的主要问题是自动正确设置行和列的rect。我正在尝试使场景随着更改而调整大小,而不会在scrollabars上留出一堆空白。
这是加载图像时的开始样子。
这是滚动QSpinBox
后的外观。此时应该只有一个垂直滚动条,而没有一堆空白的水平滚动条。
经过反复试验,我发现我可以在代码中像这样self.scene.setSceneRect(QRectF(self.graphics_widget.rect()))
来设置场景rect,它似乎可以很好地解决滚动条的问题,但是只有当我手动操作时,它才能工作以某种方式触发它,对于此示例,这就是“设置矩形”按钮的作用。
这里是一个例子。单击“设置矩形”按钮后,垂直滚动条被正确删除,水平滚动条是整行的正确宽度。
如果我尝试在所有内容加载后自动设置场景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_()
答案 0 :(得分:2)
第二个问题是由于您从drawBackground获得的矩形是关于场景而不是视口的,所以解决方案是复制该矩形并设置高度:
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_())