QGraphicsView 和 QSplitter:折叠和展开区域不恢复图像

问题描述 投票:0回答:2

我正在尝试创建一个具有两个并排面板的基本程序:一个带有图像,一个带有文本。我使用分离器来调整两个区域的大小,直到完全折叠其中一个区域。这与

QTextEdit
配合得很好。

但是,当我折叠

QGraphicsView
(使用修复除零错误的附加代码)时,图像和我设置为默认值的背景都不会重新出现。我发现自己不知道该怎么做才能使图像和背景重新出现。

这是加载图像后的图像 - 移动分割器也会调整图像的大小(这也是所需的最终状态):

这是我完全折叠图像并将分离器移回中心后的样子:

Debug表示

QPixMap
仍有数据,但无法正常显示。我尝试添加
self.scene().update()
,但这仍然没有影响结果。

代码:

from PyQt5 import QtCore, QtGui, QtWidgets

class ImageViewer(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        self._empty = True
        self._scene = QtWidgets.QGraphicsScene(self)
        self._photo = QtWidgets.QGraphicsPixmapItem()
        self._scene.addItem(self._photo)
        self.setScene(self._scene)

        self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
        self.setFrameShape(QtWidgets.QFrame.NoFrame)

    def setPhoto(self, pixmap=None):
        if pixmap and not pixmap.isNull():
            self._empty = False
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
            self._photo.setPixmap(pixmap)
            self.fitInView()
        else:
            self._empty = True
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
            self._photo.setPixmap(QtGui.QPixmap())

    def fitInView(self, scale=True):
        if self._empty:
            return

        rect = QtCore.QRectF(self._photo.pixmap().rect())
        if not rect.isNull():
            self.setSceneRect(rect)
            viewrect = self.viewport().rect()
            scenerect = self.transform().mapRect(rect)
            if scenerect.width() == 0 or scenerect.height() == 0:
                return
            factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height())
            self.scale(factor, factor)

    def resizeEvent(self, event):
        if not self._empty:
            self.fitInView()

class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.setWindowTitle("Panel Editor")
        self.setGeometry(250, 150, 1600, 1200)

        self.centralWidget = QtWidgets.QWidget()
        self.setCentralWidget(self.centralWidget)

        self.splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
        self.viewer = ImageViewer()
        self.splitter.addWidget(self.viewer)

        self.textEditor = QtWidgets.QTextEdit()
        self.splitter.addWidget(self.textEditor)

        # Set the initial sizes of the splitter's panels to divide the space equally
        self.splitter.setSizes([800, 800])

        layout = QtWidgets.QVBoxLayout(self.centralWidget)
        layout.addWidget(self.splitter)

        self.createMenu()

    def createMenu(self):
        self.menuBar = QtWidgets.QMenuBar()
        self.setMenuBar(self.menuBar)
        
        fileMenu = self.menuBar.addMenu('&File')
        openAction = QtWidgets.QAction('&Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.setStatusTip('Open image')
        openAction.triggered.connect(self.openImage)
        fileMenu.addAction(openAction)

    def openImage(self):
        imagePath, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open Image", "", "Image Files (*.png *.jpg *.bmp)")
        if imagePath:
            self.viewer.setPhoto(QtGui.QPixmap(imagePath))

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
qt pyqt pyqt5 qt5 qgraphicsview
2个回答
1
投票

您只是检查场景,但不能确保视口大小实际上有效。结果是,您最终可能会得到视口的空尺寸(宽度和/或高度),这将导致

viewrect/scenerect
分数等于零,这将成为因子。

由于 current 因子也用于

self.transform().mapRect(rect)
,恢复视图的大小将不会有任何效果,因为当前变换使用上面的 0 因子。

解决方案是仅在视口矩形有效时应用变换(高度和宽度> 0),这可以通过检查这些值或辅助函数

isValid()
isNull()来完成

或者,只需将比例设置为

factor > 0
即可。


0
投票

基于musicamante的优秀解决方案,我修改了

fitInView
以使其能够与以下代码一起使用:

def fitInView(self, scale=True):
    print("fitInView called.")
    if self._empty:
        print("No photo to fit in view.")
        return

    rect = QtCore.QRectF(self._photo.pixmap().rect())
    if not rect.isNull():
        self.setSceneRect(rect)
        viewrect = self.viewport().rect()

        # Ensure the viewrect is valid before proceeding
        if not viewrect.isValid():
            print("Viewport rect is invalid; cannot fitInView.")
            return

        scenerect = self.transform().mapRect(rect)
        if scenerect.width() > 0 and scenerect.height() > 0:
            factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height())

            # Apply scaling only if factor is greater than 0
            if factor > 0:
                self.scale(factor, factor)
                print(f"Photo fitted with factor: {factor}")
            else:
                print("Scaling factor is zero or negative; cannot fitInView.")
        else:
            print("Scene rect is zero sized; cannot fitInView.")
    else:
        print("Pixmap rect is null; cannot fitInView.")
© www.soinside.com 2019 - 2024. All rights reserved.