无法将图像加载到 QGraphicsView(浮点除以零)。识别矩形,但不会设置场景
Posted
技术标签:
【中文标题】无法将图像加载到 QGraphicsView(浮点除以零)。识别矩形,但不会设置场景【英文标题】:Fail to load image into QGraphicsView (float division by zero). Recognizes the rect, but won't set the scene 【发布时间】:2021-12-16 22:14:13 【问题描述】:我有一个基本的图像查看器(主要是试图了解 QGraphicsView 而不是标签的怪癖),我试图允许一些基本的缩放和平移功能。它加载用户可以单击的图像目录,但无法加载图像。它将返回尺寸,但在尝试设置场景时会收到零箭头的浮点除法。我尝试设置为 QImage,但似乎没有什么不同。
actions_test.py
from PyQt5.QtWidgets import QGraphicsView, QGraphicsPixmapItem
from PyQt5 import QtCore, QtGui, QtWidgets
class ImageViewer(QGraphicsView):
def __init__(self, parent):
super(ImageViewer, self).__init__(parent)
self._zoom = 0
self._empty = True
self._scene = QtWidgets.QGraphicsScene(self)
self._image = QGraphicsPixmapItem()
self._scene.addItem(self._image)
self.setScene(self._scene)
def hasImage(self):
return not self._empty
def fitInView(self, scale=True):
rect = QtCore.QRectF(self._image.pixmap().rect())
print(rect)
if not rect.isNull():
self.setSceneRect(rect)
if self.hasImage():
unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setImage(self, pixmap=None):
self._zoom = 0
if pixmap and not pixmap.isNull():
self._empty = False
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self._image.setPixmap(pixmap)
else:
self._empty = True
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
self._image.setPixmap(QtGui.QPixmap())
self.fitInView()
main_test.py
from PyQt5 import QtGui, QtWidgets, uic
from PyQt5.QtWidgets import QApplication
from actions_test import ImageViewer
import sys, os
gui = uic.loadUiType("viewer.ui")[0]
VALID_FORMAT = ('.BMP', '.GIF', '.JPG', '.JPEG',
'.PNG', '.PBM', '.PGM', '.PPM', '.TIFF','.XBM')
def getImages(folder):
image_list = []
if os.path.isdir(folder):
for file in os.listdir(folder):
if file.upper().endswith(VALID_FORMAT):
im_path = os.path.join(folder, file)
image_obj = 'name': file, 'path': im_path
image_list.append(image_obj)
return image_list
class Window(QtWidgets.QWidget, gui):
def __init__(self):
super(Window, self).__init__()
self.setupUi(self)
self.image_viewer = ImageViewer(self.qgraphic_image)
self.cntr, self.numImages = -1, -1
self._connectEvents()
def _connectEvents(self):
self.open_folder.clicked.connect(self.selectDir)
self.qlist_images.itemClicked.connect(self.item_click)
def loadImage(self, img):
self.image_viewer.setImage(QtGui.QPixmap(img))
def selectDir(self):
self.folder = str(QtWidgets.QFileDialog.getExistingDirectory(self, "Select Image
Directory"))
if not self.folder:
QtWidgets.QMessageBox.warning(self, 'None selected',
'Select a valid directory')
return
self.logs = getImages(self.folder)
self.numImages = len(self.logs)
self.items = [QtWidgets.QListWidgetItem(log['name']) for log in self.logs]
for item in self.items:
self.qlist_images.addItem(item)
# Show first image in the list
self.cntr = 0
self.loadImage(self.logs[self.cntr]['path'])
self.qlist_images.setCurrentItem(self.items[self.cntr])
if self.numImages > 1:
self.next_im.setEnabled(True)
def item_click(self, item):
self.cntr = self.items.index(item)
self.loadImage(self.logs[self.cntr]['path'])
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
来自 QT 设计器的viewer.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>672</width>
<height>521</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 198, 144, 255), stop:1 rgba(46, 0, 0, 255));</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>651</width>
<height>501</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="48,12">
<property name="spacing">
<number>12</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0,12">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="Line" name="line_2">
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>2</number>
</property>
<item>
<widget class="QToolButton" name="save_im">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string notr="true" extracomment="Save Image">Save Image</string>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/download.png</normaloff>icons/download.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="prev_im">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Load Previous Image</string>
</property>
<property name="text">
<string>Prev</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/arrow-left.png</normaloff>icons/arrow-left.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="next_im">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Load Next Image</string>
</property>
<property name="text">
<string>Next</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/arrow-right.png</normaloff>icons/arrow-right.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_5">
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="zoom_plus">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>+</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/zoom-in.png</normaloff>icons/zoom-in.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="reset_zoom">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Fit Image to Canvas</string>
</property>
<property name="text">
<string>Fit</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/enlarge2.png</normaloff>icons/enlarge2.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="zoom_minus">
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string>-</string>
</property>
<property name="icon">
<iconset>
<normaloff>icons/zoom-out.png</normaloff>icons/zoom-out.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QGraphicsView" name="qgraphic_image">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="backgroundBrush">
<brush brushstyle="NoBrush">
<color alpha="255">
<red>30</red>
<green>30</green>
<blue>30</blue>
</color>
</brush>
</property>
<property name="dragMode">
<enum>QGraphicsView::ScrollHandDrag</enum>
</property>
<property name="transformationAnchor">
<enum>QGraphicsView::AnchorUnderMouse</enum>
</property>
<property name="resizeAnchor">
<enum>QGraphicsView::AnchorUnderMouse</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_10" stretch="1,3,48">
<property name="spacing">
<number>5</number>
</property>
<item>
<widget class="QPushButton" name="open_folder">
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">background-color: black; /* Blue */
padding:10px;
color:white;</string>
</property>
<property name="text">
<string>Open Folder</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<family>Sans Serif</family>
<pointsize>10</pointsize>
<weight>50</weight>
<bold>false</bold>
<kerning>true</kerning>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color:white</string>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="text">
<string>Image List</string>
</property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="margin">
<number>4</number>
</property>
<property name="indent">
<number>-1</number>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="qlist_images">
<property name="styleSheet">
<string notr="true">background-color:white</string>
</property>
<property name="frameShape">
<enum>QFrame::Box</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
<property name="batchSize">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
【问题讨论】:
【参考方案1】:问题是您正在使用您在 Qt 设计器中创建的另一个 QGraphicsView“qgraphic_image”作为其父级来构建 ImageViewer。这使它成为该父图形视图内的子小部件,并且它实际上是不可见的,因为它的视口矩形没有大小(这就是您得到除以 0 错误的原因)。
你可以从你的 UI 文件中删除“qgraphic_image”,现在我只是在布局中替换它来尝试它:
class Window(QtWidgets.QWidget, gui):
def __init__(self):
super(Window, self).__init__()
self.setupUi(self)
self.image_viewer = ImageViewer(None)
self.horizontalLayout_2.replaceWidget(self.qgraphic_image, self.image_viewer)
self.cntr, self.numImages = -1, -1
self._connectEvents()
我也看不到重新实现QGraphicsView.fitInView
的目的,因为您似乎只是想让图像适合查看器。你可以使用现有的方法。
def setImage(self, pixmap=None):
# ...
self.fitInView(self.sceneRect(), QtCore.Qt.KeepAspectRatio)
【讨论】:
以上是关于无法将图像加载到 QGraphicsView(浮点除以零)。识别矩形,但不会设置场景的主要内容,如果未能解决你的问题,请参考以下文章