I want to draw polyline with mouse event. But I can't set endpoints by clicking, or choose pen type. I want to draw linear lines, but when i write this code it only shows dots instead of drawing a line. Here is my code:
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QPainter, QBrush, QColor, QPen, QPainterPath
from PyQt5.QtWidgets import QLabel, QGraphicsScene, QGraphicsView
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.beginList = []
self.endList = []
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QLabel(self)
self.label.resize(500, 40)
self.show()
def paintEvent(self, event):
qp = QPainter(self)
for i,j in zip(self.beginList, self.endList):
qp.drawLines(QtCore.QLineF(i,j))
def mouseMoveEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.beginList.append(self.begin)
self.endList.append(self.end)
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800,600)
sys.exit(app.exec_())
If the OP code is analyzed, the starting point and the end point coincide, so when drawing a line between 2 points of the same location, only one point will be drawn. The logic is to join the point obtained in the i-th step with the (i+1)-th point.
To do the above the simplest thing is to use a QPainterPath:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.paths = []
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QtWidgets.QLabel(self)
self.show()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
for path in self.paths:
qp.drawPath(path)
def mousePressEvent(self, event):
path = QtGui.QPainterPath()
path.moveTo(event.pos())
self.paths.append(path)
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.label.adjustSize()
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.update()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800, 600)
sys.exit(app.exec_())
Related
I have created a circle at random place in canvas, but I am unable to move or edit its properties like its label just by clicking and dragging it.
I want to create a circle that is movable by dragging and its properties like label are editable at any time please suggest the edits or new approach to do it. I am a beginner Please help...
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow,QPushButton,QWidget
from PyQt5 import QtGui
from PyQt5.QtCore import QRect,Qt
from PyQt5.QtGui import QPainter,QBrush, QPen
from PyQt5 import QtCore
from random import randint
class Window(QMainWindow):
def __init__(self):
super(Window,self).__init__()
title="layout management"
left=500
top=200
width=500
height=400
iconName="Ash.jpg"
self.setWindowTitle(title)
self.setWindowIcon(QtGui.QIcon(iconName))
self.setGeometry(left, top, width, height)
self.should_paint_circle = False
self.windowcomponents()
self.initUI()
self.show()
def initUI(self):
if self.should_paint_circle:
self.label=QtWidgets.QLabel(self)
self.label.setText('<h2>circle<h2>')
def windowcomponents(self):
button=QPushButton("Add", self)
button.setGeometry(QRect(0, 0, 50, 28))
button.setIcon(QtGui.QIcon("addbutton.png"))
button.setToolTip("<h3>This is for creating random circles<h3>")
button.clicked.connect(self.paintcircle)
button=QPushButton("Generate Report", self)
button.setGeometry(QRect(49,0,150,28))
button.setIcon(QtGui.QIcon("generatereport.png"))
button.setToolTip("This is for generating pdf report of connection between two circles")
button=QPushButton("Save", self)
button.setGeometry(QRect(199,0,120,28))
button.setIcon(QtGui.QIcon("saveicon.png"))
button.setToolTip("This is for saving an image of canvas area")
def paintEvent(self, event):
super().paintEvent(event)
if self.should_paint_circle:
painter = QtGui.QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
painter.drawEllipse(randint(0,500), randint(0,500), 100, 100)
self.initUI()
self.label.move(60,100)
def paintcircle(self, painter):
self.should_paint_circle = True
self.update()
app = QApplication(sys.argv)
circle=Window()
circle.show()
sys.exit(app.exec_())
Image showing a circle at random position in window, its not draggable
The solution is similar, the code only changed in how to determine if the pressed point is inside the circle:
import random
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.rect = QtCore.QRect()
self.drag_position = QtCore.QPoint()
button = QtWidgets.QPushButton("Add", self)
button.clicked.connect(self.on_clicked)
self.resize(640, 480)
#QtCore.pyqtSlot()
def on_clicked(self):
if self.rect.isNull():
self.rect = QtCore.QRect(
QtCore.QPoint(*random.sample(range(200), 2)), QtCore.QSize(100, 100)
)
self.update()
def paintEvent(self, event):
super().paintEvent(event)
if not self.rect.isNull():
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine))
painter.drawEllipse(self.rect)
def mousePressEvent(self, event):
if (
2 * QtGui.QVector2D(event.pos() - self.rect.center()).length()
< self.rect.width()
):
self.drag_position = event.pos() - self.rect.topLeft()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.drag_position.isNull():
self.rect.moveTopLeft(event.pos() - self.drag_position)
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag_position = QtCore.QPoint()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
Rect = Window()
Rect.show()
sys.exit(app.exec_())
I am creating a desktop application using PyQt5 where the user will be able to draw rectangles.
User should be able to select the top-left corner of the rectangle with first mouse click and the bottom-right corner with second mouse click. A rectangle should appear in that location with the perimeter well defined. I created application but have a problem when I draw another rectangle previous rectangle vanishes. I am not able to draw multiple rectangles.
Please find the below code for reference
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtGui, QtCore
from PyQt5.QtGui import QPainter, QPen, QBrush
from PyQt5.QtCore import Qt
class Windo(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(150,250,500,500)
self.setWindowTitle("Ammyyy")
self.setWindowIcon(QtGui.QIcon('a.jpeg'))
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.show()
def paintEvent(self,event):
qp = QPainter(self)
qp.begin(self)
qp.setPen(QPen(Qt.black, 6, Qt.SolidLine))
qp.drawRect(QtCore.QRect(self.begin, self.end))
qp.end()
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
app = QApplication(sys.argv)
win = Windo()
sys.exit(app.exec_())
If you want to draw n-rectangles then you must save that information in a list through QRect. On the other hand, the selection of 2 points does not imply that the QRect is valid, for example if the first point is on the right, the second point will not create a valid rectangle so that rectangle has to be normalized. Considering the above, the solution is:
import sys
from PyQt5.QtCore import Qt, QPoint, QRect
from PyQt5.QtGui import QPainter, QPen, QBrush, QIcon
from PyQt5.QtWidgets import QApplication, QWidget
class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(150, 250, 500, 500)
self.setWindowTitle("Ammyyy")
self.setWindowIcon(QIcon("a.jpeg"))
self.begin = QPoint()
self.end = QPoint()
self.rectangles = []
def paintEvent(self, event):
qp = QPainter(self)
qp.setPen(QPen(Qt.black, 6, Qt.SolidLine))
for rectangle in self.rectangles:
qp.drawRect(rectangle)
if not self.begin.isNull() and not self.end.isNull():
qp.drawRect(QRect(self.begin, self.end).normalized())
def mousePressEvent(self, event):
self.begin = self.end = event.pos()
self.update()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
r = QRect(self.begin, self.end).normalized()
self.rectangles.append(r)
self.begin = self.end = QPoint()
self.update()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
I have a PicButton class based on QAbtractButton that has the normal, hover and pressed. However, when clicked the button only changed to the pixmap_pressed briefly and then switch back to standard.
How can I make it behaves like a toggle button so that the pressed pixmap will stay after pressed?
import numpy as np
import time, sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QMainWindow
class PicButton(QAbstractButton):
def __init__(self, pixmap, pixmap_hover, pixmap_pressed, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
self.pixmap_hover = pixmap_hover
self.pixmap_pressed = pixmap_pressed
self.pressed.connect(self.update)
# self.released.connect(self.update)
def paintEvent(self, event):
pix = self.pixmap_hover if self.underMouse() else self.pixmap
if self.isDown():
pix = self.pixmap_pressed
painter = QPainter(self)
painter.drawPixmap(event.rect(), pix)
def enterEvent(self, event):
self.update()
def leaveEvent(self, event):
self.update()
def sizeHint(self):
return self.pixmap.size()
class App(QMainWindow):
def __init__(self):
super().__init__()
self.left = 0
self.top = 0
self.width = 800
self.height = 800
self.initUI()
def initUI(self):
self.setGeometry(self.left, self.top, self.width, self.height)
self.recBtn = PicButton(QPixmap('./img/playrecstop/rec_512.png'),QPixmap('./img/playrecstop/recHL_512.png'),\
QPixmap('./img/playrecstop/recActive_512.png'))
self.recBtn.setText("rec")
self.recBtn.clicked.connect(self.controlButtons)
self.stopBtn = PicButton(QPixmap('./img/playrecstop/stop_512.png'), QPixmap('./img/playrecstop/stopHL_512.png'),\
QPixmap('./img/playrecstop/stopActive_512.png'))
self.stopBtn.setText("stop")
self.stopBtn.clicked.connect(self.controlButtons)
self.leftLayout = QHBoxLayout()
self.rightLayout = QHBoxLayout()
self.rightLayout.addWidget(self.recBtn)
self.rightLayout.addWidget(self.stopBtn)
self.mainLayout = QHBoxLayout()
self.mainLayout.addLayout(self.leftLayout)
self.mainLayout.addLayout(self.rightLayout)
self.setCentralWidget(QWidget(self))
self.centralWidget().setLayout(self.mainLayout)
self.show()
def controlButtons(self):
sender = self.sender()
if (sender.text() == 'stop'):
print ("Stop")
elif (sender.text() == 'rec'):
print ("REC...")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Thanks
QAbstractButton has a checkable property that allows you to implement the logic you want:
class PicButton(QAbstractButton):
def __init__(self, pixmap, pixmap_hover, pixmap_pressed, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
self.pixmap_hover = pixmap_hover
self.pixmap_pressed = pixmap_pressed
self.setCheckable(True)
def paintEvent(self, event):
pix = self.pixmap_hover if self.underMouse() else self.pixmap
if self.isChecked():
pix = self.pixmap_pressed
painter = QPainter(self)
painter.drawPixmap(event.rect(), pix)
def enterEvent(self, event):
self.update()
def leaveEvent(self, event):
self.update()
def sizeHint(self):
return self.pixmap.size()
I am new on PyQt I am working on a project on which I should implement a feature that make the user able to draw a digit using the mouse (digit recognition system). So what I want is when the mouse button is pressed the app will start to draw till the button is released. I made this source code but it is still not working (I think I am struggling with sending a signal to PaintEvent()).
import sys
from PyQt5 import QtCore
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog,QGraphicsView,QGraphicsScene,QVBoxLayout
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication
class Communicate(QObject):
drawApp = pyqtSignal()
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Simple')
self.setMouseTracking(True)
self.label = QLabel(self)
self.label.resize(500, 40)
self.c = Communicate()
self.c.drawApp.connect(self.PaintEvent())
self.show()
def mousePressEvent(self, event):
self.c.drawApp.emit()
self.startingposx = event.x()
self.startingposy = event.y()
#super().mousePressEvent(event)
print ("mouse pressed")
def mouseMoveEvent(self, event):
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()) )
self.y = event.y()
self.x=event.x()
def PaintEvent(self,event):
qp = QPainter()
qp.begin(self)
#qp.setPen(Qt.red)
qp.drawPoints(self,qp)
qp.end()
self.update()
def mouseReleaseEvent(self,event):
self.endingposx = event.x()
self.endingposy = event.y()
super().mouseReleaseEvent(event)
print("starting point was",self.startingposx)
print("starting point y was ",self.startingposy)
print("ending point was ",self.endingposx)
print("ending point was y ",self.endingposy)
print("released")
def drawPoints(self,qp):
qp.setPen(Qt.red)
size = self.size()
x=self.x
y=self.y
qp.drawPoint(x,y)
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
app.exec_()
Python is sensitive to uppercase and lowercase so be more careful, the method is called paintEvent.
Also you should not call paintEvent directly, you must use the function update(), this method will internally call paintEvent().
But even correcting that error your problem is not solved, if you want to draw a path it is advisable to use QPainterPath as this stores the strokes.
class Drawer(QWidget):
newPoint = pyqtSignal(QPoint)
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.path = QPainterPath()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPath(self.path)
def mousePressEvent(self, event):
self.path.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
self.path.lineTo(event.pos())
self.newPoint.emit(event.pos())
self.update()
def sizeHint(self):
return QSize(400, 400)
class MyWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
label = QLabel(self)
drawer = Drawer(self)
drawer.newPoint.connect(lambda p: label.setText('Coordinates: ( %d : %d )' % (p.x(), p.y())))
self.layout().addWidget(label)
self.layout().addWidget(drawer)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
Screenshot:
I don't have the reputation to reply to eyllanesc's solution, but in case others are having issues, the imports were not complete. Here's is eyllanesc's solution with the imports. It will execute without error:
import sys
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import (QLabel, QWidget)
from PyQt5.QtGui import QPainter, QPainterPath
from PyQt5.QtCore import pyqtSignal, QPoint, QSize
from PyQt5.QtWidgets import QApplication
class Drawer(QWidget):
newPoint = pyqtSignal(QPoint)
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.path = QPainterPath()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPath(self.path)
def mousePressEvent(self, event):
self.path.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
self.path.lineTo(event.pos())
self.newPoint.emit(event.pos())
self.update()
def sizeHint(self):
return QSize(400, 400)
class MyWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
label = QLabel(self)
drawer = Drawer(self)
drawer.newPoint.connect(lambda p: label.setText('Coordinates: ( %d : %d )' % (p.x(), p.y())))
self.layout().addWidget(label)
self.layout().addWidget(drawer)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
I'm new to PyQt and I'm trying to use it to create a widget that returns the position of the mouse in real time.
Here's what I have:
import sys
from PyQt5.QtWidgets import (QWidget, QToolTip,
QPushButton, QApplication)
from PyQt5.QtGui import QFont
class MouseTracker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setMouseTracking(True)
self.installEventFilter(self)
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Mouse Tracker')
self.show()
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.MouseMove and
event.buttons() == QtCore.Qt.NoButton):
pos = event.pos()
print('Mouse coords: ( %d : %d )' % (pos.x(), pos.y()))
return QtGui.QWidget.eventFilter(self, source, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())
I'm confused on how to make this work. I set mouse tracking to True but I'm not sure how to apply the event filter. Any help?
The QMouseEvent function must be implemented since it is executed when the mouse is moved.
import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
class MouseTracker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setMouseTracking(True)
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Mouse Tracker')
self.label = QLabel(self)
self.label.resize(200, 40)
self.show()
def mouseMoveEvent(self, event):
self.label.setText('Mouse coords: ( %d : %d )' % (event.x(), event.y()))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())