Drawing straight line between two points using QPainterPath - python

I have a scene where I would like to draw a line between two points(mouse press should be the start point and mouse release as the endpoint) using the QPainterpath.
Here is a demonstration of how I want it to be.
Here is what's happening with my current code.
Below is the code I have tried
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, *args, **kwargs):
super(Scene, self).__init__(*args, **kwargs)
self.point = QtCore.QPointF(0.0, 0.0)
self.path = QtGui.QPainterPath()
self.start_point = None
self.end_point = None
self.start = False
def mousePressEvent(self, event):
self.start_point = event.scenePos()
self.start = True
self.path = QtGui.QPainterPath(self.start_point)
# self.addLine(self.line.setP1(self.start_point))
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.start:
self.path.lineTo(event.scenePos())
# self.path.moveTo(event.scenePos())
self.addPath(self.path, QtGui.QPen(QtCore.Qt.red))
super(Scene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.start:
print(self.path)
self.path.lineTo(event.scenePos())
# self.path.moveTo(event.scenePos())
self.addPath(self.path, QtGui.QPen(QtCore.Qt.red))
self.start = False
super(Scene, self).mouseReleaseEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
view = QtWidgets.QGraphicsView()
view.setRenderHint(QtGui.QPainter.Antialiasing)
view.setMouseTracking(True)
scene = Scene()
view.setScene(scene)
view.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Every time lineTo is used then a new line is created where the starting point is the last point added and the end point is the one that is passed to the function, so you see the curves since they are the union of those lines. The solution is to have 2 variables that store the start point and the end point, and be updated when necessary, then use that information to update the QGraphicsPathItem, not the QPainterPath. The same concept can be applied for QGraphicsLineItem with QLineF.
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, *args, **kwargs):
super(Scene, self).__init__(*args, **kwargs)
self.path_item = self.addPath(QtGui.QPainterPath())
self.start_point = QtCore.QPointF()
self.end_point = QtCore.QPointF()
def mousePressEvent(self, event):
self.start_point = event.scenePos()
self.end_point = self.start_point
self.update_path()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
self.end_point = event.scenePos()
self.update_path()
super(Scene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.end_point = event.scenePos()
self.update_path()
super(Scene, self).mouseReleaseEvent(event)
def update_path(self):
if not self.start_point.isNull() and not self.end_point.isNull():
path = QtGui.QPainterPath()
path.moveTo(self.start_point)
path.lineTo(self.end_point)
self.path_item.setPath(path)

Thx to #eyllanesc for anyone trying to achieve this using QLineF and QGraphicsLineItem
here is the code.
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, *args, **kwargs):
super(Scene, self).__init__(*args, **kwargs)
self.setSceneRect(QtCore.QRectF(0, 0, 500, 500))
self.line = None
self.graphics_line = None
self.start_point = QtCore.QPointF()
self.end_point = QtCore.QPointF()
def mousePressEvent(self, event):
self.start_point = event.scenePos()
self.end_point = self.start_point
self.line = QtCore.QLineF(self.start_point, self.end_point)
self.graphics_line = QtWidgets.QGraphicsLineItem(self.line)
self.update_path()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
self.end_point = event.scenePos()
self.update_path()
super(Scene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.end_point = event.scenePos()
self.update_path()
super(Scene, self).mouseReleaseEvent(event)
def update_path(self):
if not self.start_point.isNull() and not self.end_point.isNull():
self.line.setP2(self.end_point)
self.graphics_line.setLine(self.line)
self.addItem(self.graphics_line)
def main():
app = QtWidgets.QApplication(sys.argv)
view = QtWidgets.QGraphicsView()
view.setRenderHint(QtGui.QPainter.Antialiasing)
view.setMouseTracking(True)
scene = Scene()
view.setScene(scene)
view.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Related

screen snipping program leaves left over square after snip

I'm attempting to resolved an issue with a left over square after my snipping program is done snipping. I would like to delete any instance of the square drawing after the initial snip
.
Steps to replicate:
Select "mode" > select "snip" > drag rectangle and take a screen snip
Select "mode" > select "snip" > now observe the previous snip still has the rectangle on the screen (as shown in the picture)
My code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import ImageGrab
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QApplication
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle("Lil Snippy")
self.setWindowIcon(QtGui.QIcon("assets/lilSnippyIcon.png"))
self.setGeometry(400, 300, 400, 300)
# QApplication.setOverrideCursor(Qt.WaitCursor)
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu("File")
saveAct = QtWidgets.QAction(QtGui.QIcon("assets/saveIcon.png"), "Save", self)
saveAsAct = QtWidgets.QAction(
QtGui.QIcon("assets/saveAsIcon.png"), "Save As", self
)
modeMenu = menubar.addMenu("Mode")
snipAct = QtWidgets.QAction(QtGui.QIcon("assets/cameraIcon.png"), "Snip", self)
snipAct.setShortcut(QtGui.QKeySequence("F1"))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QtWidgets.QAction(QtGui.QIcon("assets/videoIcon.png"), "Video", self)
videoAct.setShortcut("F2")
soundAct = QtWidgets.QAction(QtGui.QIcon("assets/audioIcon.png"), "Sound", self)
soundAct.setShortcut("F3")
autoAct = QtWidgets.QAction(
QtGui.QIcon("assets/automationIcon.png"), "Automation", self
)
autoAct.setShortcut("F4")
optionsMenu = menubar.addMenu("Options")
helpMenu = menubar.addMenu("Help")
helpAct = QtWidgets.QAction(QtGui.QIcon("assets/helpIcon.png"), "Help", self)
aboutAct = QtWidgets.QAction(QtGui.QIcon("assets/aboutIcon.png"), "About", self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
self.snipper = SnippingWidget()
self.snipper.closed.connect(self.on_closed)
def activateSnipping(self):
self.snipper.showFullScreen()
QApplication.setOverrideCursor(QtCore.Qt.CrossCursor)
self.hide()
def on_closed(self):
self.show()
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setStyleSheet("background:transparent;")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.outsideSquareColor = "red"
self.squareThickness = 2
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
self.hide()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
QApplication.restoreOverrideCursor()
self.closed.emit()
def paintEvent(self, event):
trans = QtGui.QColor(22, 100, 233)
r = QtCore.QRectF(self.start_point, self.end_point).normalized()
qp = QtGui.QPainter(self)
trans.setAlphaF(0.2)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(r)
r_path = outer - inner
qp.drawPath(r_path)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans.setAlphaF(0)
qp.setBrush(trans)
qp.drawRect(r)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = App()
application.show()
sys.exit(app.exec_())
You have to reset self.start_point and self.end_point:
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
self.hide()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
QApplication.restoreOverrideCursor()
self.closed.emit()
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()

Screen Snipping Program - Transparent Snipping Area

I'm in the process of converting my successful screen snipping program from Tkinter to PYQT5. My question is how to create a fully transparent snipping area (a dynamically updating square region would be nice). The outside of the square will be semi-opaque. I've looked all over stack overflow and the internet and could not find an example of this (others are not a fully transparent drawing window). I've attached my code and a picture example of what I am looking for. The "SnippingWidget" is the class that does the snipping logic.
import sys
from PyQt5 import QtCore, QtGui
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction, QWidget
from PyQt5.QtGui import QIcon, QKeySequence
from PIL import ImageGrab
class App(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle('Lil Snippy')
self.setWindowIcon(QIcon('assets/lilSnippyIcon.png'))
self.setGeometry(400, 300, 400, 300)
self.show()
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
saveAct = QAction(QIcon('assets/saveIcon.png'), 'Save', self)
saveAsAct = QAction(QIcon('assets/saveAsIcon.png'), 'Save As', self)
modeMenu = menubar.addMenu('Mode')
snipAct = QAction(QIcon('assets/cameraIcon.png'), 'Snip', self)
snipAct.setShortcut(QKeySequence('F1'))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QAction(QIcon('assets/videoIcon.png'), 'Video', self)
videoAct.setShortcut('F2')
soundAct = QAction(QIcon('assets/audioIcon.png'), 'Sound', self)
soundAct.setShortcut('F3')
autoAct = QAction(QIcon('assets/automationIcon.png'), 'Automation', self)
autoAct.setShortcut('F4')
helpMenu = menubar.addMenu('Help')
helpAct = QAction(QIcon('assets/helpIcon.png'), 'Help', self)
aboutAct = QAction(QIcon('assets/aboutIcon.png'), 'About', self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
def activateSnipping(self):
print("yes")
self.Snipper = SnippingWidget()
application.hide()
class SnippingWidget(QMainWindow):
def __init__(self, parent = None):
super(SnippingWidget, self).__init__(parent)
self.setStyleSheet("background-color: transparent;")
self.setWindowOpacity(.2)
self.showFullScreen()
self.outsideSquareColor = 'red'
self.squareThickness = 4
self.startX = None
self.startY = None
self.endX = None
self.endY = None
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = self.begin
self.startX = event.x()
self.startY = event.y()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
self.destroy()
x1 = min(self.begin.x(), self.end.x())
y1 = min(self.begin.y(), self.end.y())
x2 = max(self.begin.x(), self.end.x())
y2 = max(self.begin.y(), self.end.y())
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
img.save('snips/testImage.png')
application.show()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(QtGui.QPen(QtGui.QColor('red'), self.squareThickness))
trans = QtGui.QColor(255,255,255,255)
qp.setBrush(trans)
rect = QtCore.QRectF(self.begin, self.end)
qp.drawRect(rect)
if __name__ == '__main__':
app = QApplication(sys.argv)
application = App()
sys.exit(app.exec_())
You have to use QPainterPath to subtract the rectangle from the window with the selected rectangle:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PIL import ImageGrab
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.topMenu()
def initUI(self):
self.setWindowTitle("Lil Snippy")
self.setWindowIcon(QtGui.QIcon("assets/lilSnippyIcon.png"))
self.setGeometry(400, 300, 400, 300)
def topMenu(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu("File")
saveAct = QtWidgets.QAction(QtGui.QIcon("assets/saveIcon.png"), "Save", self)
saveAsAct = QtWidgets.QAction(
QtGui.QIcon("assets/saveAsIcon.png"), "Save As", self
)
modeMenu = menubar.addMenu("Mode")
snipAct = QtWidgets.QAction(QtGui.QIcon("assets/cameraIcon.png"), "Snip", self)
snipAct.setShortcut(QtGui.QKeySequence("F1"))
snipAct.triggered.connect(self.activateSnipping)
videoAct = QtWidgets.QAction(QtGui.QIcon("assets/videoIcon.png"), "Video", self)
videoAct.setShortcut("F2")
soundAct = QtWidgets.QAction(QtGui.QIcon("assets/audioIcon.png"), "Sound", self)
soundAct.setShortcut("F3")
autoAct = QtWidgets.QAction(
QtGui.QIcon("assets/automationIcon.png"), "Automation", self
)
autoAct.setShortcut("F4")
helpMenu = menubar.addMenu("Help")
helpAct = QtWidgets.QAction(QtGui.QIcon("assets/helpIcon.png"), "Help", self)
aboutAct = QtWidgets.QAction(QtGui.QIcon("assets/aboutIcon.png"), "About", self)
fileMenu.addAction(saveAct)
fileMenu.addAction(saveAsAct)
modeMenu.addAction(snipAct)
modeMenu.addAction(videoAct)
modeMenu.addAction(soundAct)
modeMenu.addAction(autoAct)
helpMenu.addAction(helpAct)
helpMenu.addAction(aboutAct)
self.snipper = SnippingWidget()
self.snipper.closed.connect(self.on_closed)
def activateSnipping(self):
self.snipper.showFullScreen()
self.hide()
def on_closed(self):
self.snipper.hide()
self.show()
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setStyleSheet("background-color: transparent;")
self.setWindowOpacity(0.2)
self.outsideSquareColor = "red"
self.squareThickness = 4
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
self.closed.emit()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans = QtGui.QColor(255, 255, 255, 255)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(QtCore.QRectF(self.start_point, self.end_point).normalized())
r = outer - inner
qp.drawPath(r)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = App()
application.show()
sys.exit(app.exec_())
Update:
class SnippingWidget(QtWidgets.QMainWindow):
closed = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(SnippingWidget, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setStyleSheet("background:transparent;")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.outsideSquareColor = "red"
self.squareThickness = 4
self.start_point = QtCore.QPoint()
self.end_point = QtCore.QPoint()
def mousePressEvent(self, event):
self.start_point = event.pos()
self.end_point = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end_point = event.pos()
self.update()
def mouseReleaseEvent(self, QMouseEvent):
r = QtCore.QRect(self.start_point, self.end_point).normalized()
img = ImageGrab.grab(bbox=r.getCoords())
img.save("snips/testImage.png")
self.closed.emit()
def paintEvent(self, event):
trans = QtGui.QColor(255, 255, 255)
r = QtCore.QRectF(self.start_point, self.end_point).normalized()
qp = QtGui.QPainter(self)
trans.setAlphaF(0.2)
qp.setBrush(trans)
outer = QtGui.QPainterPath()
outer.addRect(QtCore.QRectF(self.rect()))
inner = QtGui.QPainterPath()
inner.addRect(r)
r_path = outer - inner
qp.drawPath(r_path)
qp.setPen(
QtGui.QPen(QtGui.QColor(self.outsideSquareColor), self.squareThickness)
)
trans.setAlphaF(0)
qp.setBrush(trans)
qp.drawRect(r)

Can't stop drawing rectangles in qgraphicsview

In my program I can select a button that sets self.rectmode=1. Once that variable is set to 1 it draws rectangles using mouse events on the qgraphicsview. After pressing a button to set self.rectmode=0 the program continues to draw rectangles using the mouse events. Am I missing some line to end the rectangle drawing event. My code is below thanks in advance:
def mousePressEvent(self, event):
if (self.rectmode==1 and event.button() == Qt.LeftButton and not self._photo.pixmap().isNull()):
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
else:
super(PhotoViewer, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.rectmode==1 and self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
else:
super(PhotoViewer, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.rectmode==1 and event.button() == Qt.LeftButton:
self.changeRubberBand = False
self.endpoint = event.pos()
print(self.origin.x())
print(self.origin.y())
print(self.endpoint.x())
print(self.endpoint.y())
else:
super(PhotoViewer, self).mouseReleaseEvent(event)
In your code rectmode is always 1, I think that is what's causing the problem, here is a working example, I also removed the variable changeRubberBand because the same can be achieved with only the variable rectMode:
import sys
from PyQt5.Qt import QApplication, QRect, QSize, Qt, QRubberBand, QVBoxLayout, pyqtSignal
from PyQt5.QtWidgets import QMainWindow
class PhotoViewer(QMainWindow):
rectChanged = pyqtSignal(QRect)
def __init__(self):
super().__init__()
self.origin = None
self.endpoint = None
self.rectMode = 0
self.setFixedSize(1024, 768)
self.layout = QVBoxLayout(self)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.rubberBand.hide()
self.layout.addChildWidget(self.rubberBand)
def mousePressEvent(self, event):
if self.rectMode == 0 and event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.rectMode = 1
else:
super(PhotoViewer, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.rectMode == 1:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
else:
super(PhotoViewer, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if self.rectMode == 1 and event.button() == Qt.LeftButton:
self.rectMode = 0
self.endpoint = event.pos()
print(self.origin.x())
print(self.origin.y())
print(self.endpoint.x())
print(self.endpoint.y())
else:
super(PhotoViewer, self).mouseReleaseEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = PhotoViewer()
mainWindow.show()
sys.exit(app.exec_())
Hope it helps.

Filling a drawn path using QPainterPath in pyqt5

I have a QGraphicsView which an image is loaded into. I then made it so you can draw over the image with your pointer with QPainterPath and then the path is closed by connecting the beginning and end points. I am wondering how to have that region then filled after the mouse is released and then make this object selectable but not movable.
I tried using QPaint and filling the path as seen in the addGraphicsItem function.
class GraphicsView(QGraphicsView):
def __init__(self, parent = None):
super(GraphicsView, self).__init__(parent)
self.setGeometry(300, 300, 250, 150)
self.setScene(GraphicsScene(self))
self.pixmapItem = QGraphicsPixmapItem() # check if everytime you open a new image the old image is still an item
self.scene().addItem(self.pixmapItem)
self.initial_path()
def initial_path(self):
self._path = QtGui.QPainterPath()
pen = QtGui.QPen(QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap)
self._path_item = self.scene().addPath(self._path, pen)
#QtCore.pyqtSlot()
def setImage(self):
filename, _ = QFileDialog.getOpenFileName(None, "select Image", "", "Image Files (*.png *.jpg *jpg *.bmp)")
if filename:
self.image = QPixmap(filename)
self.pixmapItem.setPixmap(QtGui.QPixmap(filename))
def mousePressEvent(self, event):
self.start = event.pos()
if not self.pixmapItem.pixmap().isNull():
self._path.moveTo(self.mapToScene(event.pos()))
self._path_item.setPath(self._path)
super(GraphicsView, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.pixmapItem.pixmap().isNull():
self._path.lineTo(self.mapToScene(event.pos()))
self._path_item.setPath(self._path)
super(GraphicsView, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.end = event.pos()
if not self.pixmapItem.pixmap().isNull():
self._path.lineTo(self.mapToScene(event.pos()))
self._path.closeSubpath()
self._path_item.setPath(self._path)
self.addGraphicsItem()
self.initial_path()
super(GraphicsView, self).mouseReleaseEvent(event)
def addGraphicsItem(self):
pixmap = self.pixmapItem.pixmap()
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
pen = QPen(QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap)
brush = QBrush(QColor('green'))
painter.fillPath(self._path, brush)
painter.end()
I expected the addGraphicsItem function to then fill in the object but nothing changes.
Instead of using QPainter you can continue to use the QGraphicsPainterPath using the setBrush method you can set the background color, plus you can set the flag QGraphicsItem::ItemIsSelectable to be selectable:
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.setGeometry(300, 300, 250, 150)
self.setScene(QtWidgets.QGraphicsScene(self))
self.pixmapItem = (
QtWidgets.QGraphicsPixmapItem()
) # check if everytime you open a new image the old image is still an item
self.scene().addItem(self.pixmapItem)
self._path_item = None
def initial_path(self):
self._path = QtGui.QPainterPath()
pen = QtGui.QPen(
QtGui.QColor("green"), 4, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap
)
self._path_item = self.scene().addPath(self._path, pen)
#QtCore.pyqtSlot()
def setImage(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
None, "select Image", "", "Image Files (*.png *.jpg *jpg *.bmp)"
)
if filename:
self.pixmapItem.setPixmap(QtGui.QPixmap(filename))
def mousePressEvent(self, event):
start = event.pos()
if (
not self.pixmapItem.pixmap().isNull()
and event.buttons() & QtCore.Qt.LeftButton
):
self.initial_path()
self._path.moveTo(self.mapToScene(start))
self._path_item.setPath(self._path)
super(GraphicsView, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if (
not self.pixmapItem.pixmap().isNull()
and event.buttons() & QtCore.Qt.LeftButton
and self._path_item is not None
):
self._path.lineTo(self.mapToScene(event.pos()))
self._path_item.setPath(self._path)
super(GraphicsView, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
end = event.pos()
if (
not self.pixmapItem.pixmap().isNull()
and self._path_item is not None
):
self._path.lineTo(self.mapToScene(end))
self._path.closeSubpath()
self._path_item.setPath(self._path)
self._path_item.setBrush(QtGui.QBrush(QtGui.QColor("red")))
self._path_item.setFlag(
QtWidgets.QGraphicsItem.ItemIsSelectable, True
)
self._path_item = None
super(GraphicsView, self).mouseReleaseEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = GraphicsView()
w.setImage()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

pyqt - contextmenu for QGraphicsScene

I have a QGraphicsScene and I will display a contextmenu. But nothing happend.
Here is my Code:
class graphicsScene(QtGui.QGraphicsScene):
def __init__ (self, parent = None):
super(graphicsScene, self).__init__ (parent)
def contextMenuEvent(self, event):
self.popMenu = QtGui.QMenu()
self.popMenu.addAction(QtGui.QAction('test0', None))
self.popMenu.addAction(QtGui.QAction('test1', None))
self.popMenu.addSeparator()
self.popMenu.addAction(QtGui.QAction('test2', None))
self.popMenu.exec_(event.globalPos())
def mousePressEvent(self, event):
super(graphicsScene, self).mousePressEvent(event)
pos = event.scenePos()
item = self.itemAt(pos)
if event.button() == QtCore.Qt.LeftButton:
#do something
elif event.button() == QtCore.Qt.RightButton:
self.contextMenuEvent(event)
I have no idea how to fix this problem.
Thank you for your help!!!
This may help:
class Table(QtGui.QGraphicsView):
def __init__(self, parent=None):
super(Table, self).__init__(parent)
self.setScene(QtGui.QGraphicsScene())
self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
def contextMenuEvent(self, event):
menu = QtGui.QMenu()
menu.addAction('sample')
menu.exec_(event.globalPos())

Categories

Resources