PYQT 在图片上绘制选择矩形
PYQT Draw selection rectangle over picture
我对如何在用户加载的图片上单击并绘制矩形感到困惑。我找到了几个我尝试遵循的示例,但似乎没有任何效果,我不确定为什么或如何着手修复它。
我在其中放置了一些断点,它似乎没有进入 mouseMoveEvent
函数,但我不确定为什么。非常感谢任何帮助。
我想要什么
我希望能够单击并拖动我加载到 QGraphics
中的图片并让它绘制一个框,然后在状态栏中输出两个点的 X 和 Y 坐标矩形。我还希望矩形停留在那里,直到用户第二次点击图片。
我找到的例子
当前代码
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.setUpMainUiFunction()
def setUpMainUiFunction(self):
self.actionOpen.triggered.connect(self.OpenDialog)
self.Button_LoadPhoto.clicked.connect(self.OpenDialog)
open = QAction(QIcon("icons/open.bmp"), "open", self)
save = QAction(QIcon("icons/save.bmp"), "save", self)
NormalCursor = QAction(QIcon("icons/cursor-normal.png"), "NormalCursor", self)
CrosshairCursor = QAction(QIcon("icons/crosshair.png"), "CrosshairCursor", self)
self.TopToolBar.addAction(open)
self.TopToolBar.addAction(save)
self.LeftToolBar.addAction(NormalCursor)
self.LeftToolBar.addAction(CrosshairCursor)
# self.TopToolBar.actionTriggered[QAction].connect(self.toolbtnpressed)
def OpenDialog(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
PicturePath = QStandardPaths.standardLocations(QStandardPaths.PicturesLocation)[0]
filenames, _ = QFileDialog.getOpenFileNames(self, "Open File", PicturePath, "JPEG File (*.png)", options=options)
for filename in filenames:
pixmap = QPixmap(filename)
self.showPicture(pixmap)
self.statusbar.showMessage("Successfully Loaded: {}".format(filename))
def showPicture(self, picture):
sub = QMdiSubWindow(self)
loadPicture = LoadPicture(picture, sub)
sub.setWidget(loadPicture)
sub.setObjectName("Load_Picture_window")
sub.setWindowTitle("New Photo")
self.mdiArea.addSubWindow(sub)
sub.show()
sub.resize(picture.size())
loadPicture.log.MousePixmapSignal.connect(self.updatePixel)
def updatePixel(self, point, color):
self.UserInput_PixelValue_X.setText("{}".format(point.x()))
self.UserInput_PixelValue_Y.setText("{}".format(point.y()))
self.UserInput_PixelValue_R.setText("{}".format(color.red()))
self.UserInput_PixelValue_G.setText("{}".format(color.green()))
self.UserInput_PixelValue_B.setText("{}".format(color.blue()))
这是一个单独的文件。
class LogObject(QObject):
MousePixmapSignal = pyqtSignal(QPoint, QColor)
class PictureItem(QGraphicsPixmapItem):
def __init__(self, log, *args, **kwargs):
QGraphicsPixmapItem.__init__(self, *args, **kwargs)
self.setAcceptHoverEvents(True)
self.log = log
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
color = QColor(self.pixmap().toImage().pixel(point.x(), point.y()))
self.log.MousePixmapSignal.emit(point, color)
QGraphicsPixmapItem.hoverMoveEvent(self, event)
def hoverEnterEvent(self, event):
QApplication.setOverrideCursor(Qt.CrossCursor)
QGraphicsPixmapItem.hoverMoveEvent(self, event)
def hoverLeaveEvent(self, event):
QApplication.setOverrideCursor(Qt.ArrowCursor)
QGraphicsPixmapItem.hoverLeaveEvent(self, event)
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
QGraphicsPixmapItem.mousePressEvent(self, event)
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
QGraphicsPixmapItem.mouseMoveEvent(self, event)
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
QGraphicsPixmapItem.mouseReleaseEvent(self, event)
self.update()
class LoadPicture(QWidget, Ui_GraphicsArea):
def __init__(self, pixmap, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.log = LogObject(self)
self.PictureArea.setScene(QGraphicsScene())
self.item = PictureItem(self.log, pixmap)
self.PictureArea.scene().addItem(self.item)
self.resize(pixmap.size())
为了实现这个功能,我们必须覆盖 QGraphicsView 的 mouseMoveEvent、mousePressEvent、mouseReleaseEvent 方法,为此我们创建了以下文件:
QGraphicsView.py
class GraphicsView(QGraphicsView):
rectChanged = pyqtSignal(QRect)
def __init__(self, *args, **kwargs):
QGraphicsView.__init__(self, *args, **kwargs)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
def mousePressEvent(self, event):
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
QGraphicsView.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self, event)
def mouseReleaseEvent(self, event):
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self, event)
这个 class 必须在 GraphicsArea_GUI.py 中使用,为此我们更改如下:
self.PictureArea = QtWidgets.QGraphicsView(self.scrollAreaWidgetContents)
至:
from GraphicsView import GraphicsView
[...]
self.PictureArea = GraphicsView(self.scrollAreaWidgetContents)
初始 class 使用 QRubberBand,我们在其中更新其几何形状,因为您需要左上角位置和右下角位置,我们发出由关联的 QRect 发送的信号,它连接到插槽。
[...]
loadPicture.log.MousePixmapSignal.connect(self.updatePixel)
loadPicture.PictureArea.rectChanged.connect(self.onRectChanged)
def onRectChanged(self, r):
topLeft = r.topLeft()
bottomRight = r.bottomRight()
print(topLeft.x(), topLeft.y(), bottomRight.x(), bottomRight.y())
我对如何在用户加载的图片上单击并绘制矩形感到困惑。我找到了几个我尝试遵循的示例,但似乎没有任何效果,我不确定为什么或如何着手修复它。
我在其中放置了一些断点,它似乎没有进入 mouseMoveEvent
函数,但我不确定为什么。非常感谢任何帮助。
我想要什么
我希望能够单击并拖动我加载到 QGraphics
中的图片并让它绘制一个框,然后在状态栏中输出两个点的 X 和 Y 坐标矩形。我还希望矩形停留在那里,直到用户第二次点击图片。
我找到的例子
当前代码
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.setUpMainUiFunction()
def setUpMainUiFunction(self):
self.actionOpen.triggered.connect(self.OpenDialog)
self.Button_LoadPhoto.clicked.connect(self.OpenDialog)
open = QAction(QIcon("icons/open.bmp"), "open", self)
save = QAction(QIcon("icons/save.bmp"), "save", self)
NormalCursor = QAction(QIcon("icons/cursor-normal.png"), "NormalCursor", self)
CrosshairCursor = QAction(QIcon("icons/crosshair.png"), "CrosshairCursor", self)
self.TopToolBar.addAction(open)
self.TopToolBar.addAction(save)
self.LeftToolBar.addAction(NormalCursor)
self.LeftToolBar.addAction(CrosshairCursor)
# self.TopToolBar.actionTriggered[QAction].connect(self.toolbtnpressed)
def OpenDialog(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
PicturePath = QStandardPaths.standardLocations(QStandardPaths.PicturesLocation)[0]
filenames, _ = QFileDialog.getOpenFileNames(self, "Open File", PicturePath, "JPEG File (*.png)", options=options)
for filename in filenames:
pixmap = QPixmap(filename)
self.showPicture(pixmap)
self.statusbar.showMessage("Successfully Loaded: {}".format(filename))
def showPicture(self, picture):
sub = QMdiSubWindow(self)
loadPicture = LoadPicture(picture, sub)
sub.setWidget(loadPicture)
sub.setObjectName("Load_Picture_window")
sub.setWindowTitle("New Photo")
self.mdiArea.addSubWindow(sub)
sub.show()
sub.resize(picture.size())
loadPicture.log.MousePixmapSignal.connect(self.updatePixel)
def updatePixel(self, point, color):
self.UserInput_PixelValue_X.setText("{}".format(point.x()))
self.UserInput_PixelValue_Y.setText("{}".format(point.y()))
self.UserInput_PixelValue_R.setText("{}".format(color.red()))
self.UserInput_PixelValue_G.setText("{}".format(color.green()))
self.UserInput_PixelValue_B.setText("{}".format(color.blue()))
这是一个单独的文件。
class LogObject(QObject):
MousePixmapSignal = pyqtSignal(QPoint, QColor)
class PictureItem(QGraphicsPixmapItem):
def __init__(self, log, *args, **kwargs):
QGraphicsPixmapItem.__init__(self, *args, **kwargs)
self.setAcceptHoverEvents(True)
self.log = log
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
color = QColor(self.pixmap().toImage().pixel(point.x(), point.y()))
self.log.MousePixmapSignal.emit(point, color)
QGraphicsPixmapItem.hoverMoveEvent(self, event)
def hoverEnterEvent(self, event):
QApplication.setOverrideCursor(Qt.CrossCursor)
QGraphicsPixmapItem.hoverMoveEvent(self, event)
def hoverLeaveEvent(self, event):
QApplication.setOverrideCursor(Qt.ArrowCursor)
QGraphicsPixmapItem.hoverLeaveEvent(self, event)
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
QGraphicsPixmapItem.mousePressEvent(self, event)
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
QGraphicsPixmapItem.mouseMoveEvent(self, event)
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
QGraphicsPixmapItem.mouseReleaseEvent(self, event)
self.update()
class LoadPicture(QWidget, Ui_GraphicsArea):
def __init__(self, pixmap, parent=None):
QWidget.__init__(self, parent)
self.setupUi(self)
self.log = LogObject(self)
self.PictureArea.setScene(QGraphicsScene())
self.item = PictureItem(self.log, pixmap)
self.PictureArea.scene().addItem(self.item)
self.resize(pixmap.size())
为了实现这个功能,我们必须覆盖 QGraphicsView 的 mouseMoveEvent、mousePressEvent、mouseReleaseEvent 方法,为此我们创建了以下文件:
QGraphicsView.py
class GraphicsView(QGraphicsView):
rectChanged = pyqtSignal(QRect)
def __init__(self, *args, **kwargs):
QGraphicsView.__init__(self, *args, **kwargs)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
def mousePressEvent(self, event):
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
QGraphicsView.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self, event)
def mouseReleaseEvent(self, event):
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self, event)
这个 class 必须在 GraphicsArea_GUI.py 中使用,为此我们更改如下:
self.PictureArea = QtWidgets.QGraphicsView(self.scrollAreaWidgetContents)
至:
from GraphicsView import GraphicsView
[...]
self.PictureArea = GraphicsView(self.scrollAreaWidgetContents)
初始 class 使用 QRubberBand,我们在其中更新其几何形状,因为您需要左上角位置和右下角位置,我们发出由关联的 QRect 发送的信号,它连接到插槽。
[...]
loadPicture.log.MousePixmapSignal.connect(self.updatePixel)
loadPicture.PictureArea.rectChanged.connect(self.onRectChanged)
def onRectChanged(self, r):
topLeft = r.topLeft()
bottomRight = r.bottomRight()
print(topLeft.x(), topLeft.y(), bottomRight.x(), bottomRight.y())