Как рисовать стрелки (с помощью мыши) PyQt QPainter
Я знаю как рисовать линии в PyQt при помощи метода drawLine, а вот как стрелки рисовать не знаю.
Как рисовать стрелки?
Знаю в Tkinter это можно делать с помощью create_line, думаю в PyQt должен быть какой-то способ сделать это.
main.py
import sys
from PyQt5.Qt import *
class drawingProcess(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.is_pressed = False
self.drawingPath = None
self.begin, self.destination = QPoint(), QPoint()
self.resize(500, 500)
self.image = QPixmap(500, 500)
self.image.fill(Qt.white)
def draw(self, parent):
painter = QPainter(parent)
if self.drawingPath:
if not self.begin.isNull() and not self.destination.isNull():
painter.setPen(QPen(QColor(0, 0, 0), 5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
painter.drawLine(self.begin, self.destination)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(QPoint(), self.image)
if self.is_pressed:
self.draw(self)
def mousePressEvent(self, event):
self.is_pressed = True
if event.button() == Qt.LeftButton:
self.drawingPath = QPainterPath()
self.drawingPath.moveTo(event.pos())
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() and Qt.LeftButton and self.drawingPath:
self.drawingPath.lineTo(event.pos())
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.is_pressed = False
self.draw(self.image)
self.update()
class Main(QWidget):
def __init__(self):
super().__init__()
self.drawing_proc = drawingProcess(self)
self.resize(500, 500)
self.show()
self.drawing_proc.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Main()
sys.exit(app.exec_())
Ответы (2 шт):
Автор решения: Alexander Chernin
→ Ссылка
Для рисования таких сложных объектов рекомендую использовать SVG и классы типа QSvgRenderer.
Вот небольшой пример:
from PyQt5.QtSvg import QSvgRenderer
# другие импорты в том числе файл-ресурсов
class DrawArrow(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.svgRen = QSvgRenderer(":/arrow.svg") # из файла ресурсов
self.arrowRect = QRectF() # Рамка, выделяемая мышкой
def mousePressEvent(self, event):
super().mousePressEvent(event)
# инициализируем рамку-область отрисовки стрелки
self.arrowRect.setTopLeft(event.pos())
self.arrowRect.setBottomRight(event.pos())
self.update()
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if not self.arrowRect.topLeft().isNull():
self.arrowRect.setBottomRight(event.pos())
self.update()
def paintEvent(self, event)
super().paintEvent(event)
# Рамка валидна и файл со стрелкой загрузился
if self.arrowRect.isValid() and self.svgRen.isValid():
painter = QPainter(self)
painter.setPen(Qt.DashLine)
painter.drawRect(self.arrowRect)
# Расчитываем и устанавливаем угол поворота изображения
# painter.rotate(...)
# Рисуем стрелку
self.svgRen.render(painter, self.arrowRect)
Автор решения: S. Nick
→ Ссылка
Мне кажется, что довольно сложно для вас будет сделать такой рывок в рисовании от линии до фигуры, которую вы показали.
Предлагаю начать со стрелки, которая выглядит попроще. Ну, а затем переходить к рисованию более сложных вещей.
main.py
import sys
from math import acos, degrees, sqrt
from PyQt5.Qt import *
class DrawingProcess(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
self.is_pressed = False
self.drawingPath = None
self.begin, self.destination = QPoint(), QPoint()
self.resize(500, 500)
self.image = QPixmap(500, 500)
self.image.fill(Qt.white)
def draw(self, parent):
painter = QPainter(parent)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
if self.drawingPath:
if not self.begin.isNull() and not self.destination.isNull():
painter.setPen(
QPen(
QColor(0, 0, 0),
5,
Qt.SolidLine,
Qt.RoundCap,
Qt.RoundJoin
)
)
painter.drawLine(self.begin, self.destination)
l = 30
x_right = QPointF(self.destination + QPointF(15, 0))
right_triangle = QPainterPath()
right_triangle.lineTo(-0.5 * sqrt(3) * l, 0.5 * l)
right_triangle.lineTo(-0.5 * sqrt(3) * l, -0.5 * l)
right_triangle.closeSubpath()
right_triangle.translate(x_right)
painter.setBrush(QColor("blue"))
painter.translate(self.destination)
x1, y1 = self.begin.x(), self.begin.y()
x2, y2 = self.destination.x(), self.destination.y()
a = y2 - y1
c = x2 - x1
b = sqrt(a**2 + c**2)
angle = 0
if a==0 and b==c:
angle = 0
elif c==0 and -a==b:
angle = 90
elif a==0 and b==-c:
angle = 180
elif c==0 and a==b:
angle = 270
elif a<0 and b>0:
angle = degrees(acos((b*b + c*c - a*a)/(2.0 * b * c)))
else:
angle = 360 - degrees(acos((b*b + c*c - a*a)/(2.0 * b * c)))
painter.rotate(-angle)
painter.translate(-self.destination)
painter.drawPath(right_triangle)
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(QPoint(), self.image)
if self.is_pressed:
self.draw(self)
def mousePressEvent(self, event):
self.is_pressed = True
if event.button() == Qt.LeftButton:
self.drawingPath = QPainterPath()
self.drawingPath.moveTo(event.pos())
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() and Qt.LeftButton and self.drawingPath:
self.drawingPath.lineTo(event.pos())
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.is_pressed = False
self.draw(self.image)
self.update()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.drawing_proc = DrawingProcess(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

