I'm trying to draw a circle instead of dots Here is the class where it paints red dots on pressing event at any place in the widget I want to draw a circle (hollow circle) as an outline not a solid circle that hide part of my picture
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Canvas(QWidget):
def __init__(self, photo, *args, **kwargs):
super().__init__(*
args, **kwargs)
self.image = QImage(photo)
self.setFixedSize(self.image.width(), self.image.height())
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
qp = QPainter(self.image)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(QPen(Qt.red, 5))
qp.setBrush(Qt.red)
qp.drawPoint(event.pos())
self.update()
def paintEvent(self, event):
qp = QPainter(self)
rect = event.rect()
qp.drawImage(rect, self.image, rect)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
w = QWidget()
self.setCentralWidget(w)
grid = QGridLayout(w)
grid.addWidget(Canvas('photo.jpeg'))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
gui.show()
sys.exit(app.exec_())
I believe this is what you're trying to do.
In which case you need to take advantage of which paint device to pass to QPainter. During mousePressEvent
and mouseMoveEvent
use QPainter(self)
so anything painted will only last until the next update. Then in mouseReleaseEvent
when satisfied with the size of the circle, you can paint on the QImage with QPainter(self.image)
to permanently draw the circle.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Canvas(QWidget):
def __init__(self, photo, *args, **kwargs):
super().__init__(*args, **kwargs)
self.image = QImage(photo)
self.setFixedSize(self.image.width(), self.image.height())
self.pressed = self.moving = False
self.revisions = []
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.pressed = True
self.center = event.pos()
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.moving = True
r = (event.pos().x() - self.center.x()) ** 2 + (event.pos().y() - self.center.y()) ** 2
self.radius = r ** 0.5
self.update()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.revisions.append(self.image.copy())
qp = QPainter(self.image)
self.draw_circle(qp) if self.moving else self.draw_point(qp)
self.pressed = self.moving = False
self.update()
def paintEvent(self, event):
qp = QPainter(self)
rect = event.rect()
qp.drawImage(rect, self.image, rect)
if self.moving:
self.draw_circle(qp)
elif self.pressed:
self.draw_point(qp)
def draw_point(self, qp):
qp.setPen(QPen(Qt.black, 5))
qp.drawPoint(self.center)
def draw_circle(self, qp):
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(QPen(Qt.black, 3, Qt.DashLine))
qp.drawEllipse(self.center, self.radius, self.radius)
def undo(self):
if self.revisions:
self.image = self.revisions.pop()
self.update()
def reset(self):
if self.revisions:
self.image = self.revisions[0]
self.revisions.clear()
self.update()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
w = QWidget()
self.setCentralWidget(w)
canvas = Canvas('photo.png')
grid = QGridLayout(w)
grid.addWidget(canvas)
QShortcut(QKeySequence('Ctrl+Z'), self, canvas.undo)
QShortcut(QKeySequence('Ctrl+R'), self, canvas.reset)
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
gui.show()
sys.exit(app.exec_())