I have drawn a chart by PyQtChart, and I want to move a series by mouse. Press right button to select a series, then move it to target location, after release right button put the series to target location.
I can get the selected series in update_select_series
, if I can get the original coordinates when I press right button and target coordinates, thus I can move the series to target location in update_series
, but I don't know how to implement it.
import sys
from PyQt5.QtChart import QAreaSeries, QChart, QChartView, QLineSeries, QValueAxis, QCategoryAxis
from PyQt5.QtCore import QPointF, Qt, QTimer
from PyQt5.QtGui import QColor, QGradient, QLinearGradient, QPainter, QPen
from PyQt5.QtWidgets import QApplication, QMainWindow
app = QApplication(sys.argv)
series0 = QLineSeries()
series0 << QPointF(1, 15) << QPointF(3, 17) << QPointF(7, 16) << QPointF(9, 17) \
<< QPointF(12, 16) << QPointF(16, 17) << QPointF(18, 15)
chart = QChart()
chart.addSeries(series0)
chart.createDefaultAxes()
chartView = QChartView(chart)
def update_select_series():
print('update_select_series')
def update_series():
print('update_series')
series0.pressed.connect(update_select_series)
series0.released.connect(update_series)
window = QMainWindow()
window.setCentralWidget(chartView)
window.resize(400, 300)
window.show()
sys.exit(app.exec_())
the pressed
signal contains the information of the pressed point, and the same happens with released
signal, that is, both points are the same, so the released signal will only tell us when the mouse was released, but not where.
To solve this problem you must obtain the following point where the mouse is released, for this you can use the event mouseReleaseEvent
, this returns the point in coordinates of QGraphicsView
, then we must change it to the coordinates of the plot so we can use this response.
Then you must transmit to the series for it you can create a custom event and send it through postEvent()
, in the series the method customEvent()
is used to obtain the information of the endpoint.
To move the series you get the points and the displacement is added, and you must insert it again.
import sys
from PyQt5.QtChart import QChart, QChartView, QLineSeries
from PyQt5.QtCore import QPointF, QEvent
from PyQt5.QtWidgets import QApplication, QMainWindow
class ReleasePosEvent(QEvent):
EventType = QEvent.Type(QEvent.registerEventType())
def __init__(self, point):
QEvent.__init__(self, ReleasePosEvent.EventType)
self.point = point
class ChartView(QChartView):
def mouseReleaseEvent(self, event):
p1 = event.pos()
p2 = self.mapToScene(p1)
p3 = self.chart().mapFromScene(p2)
p4 = self.chart().mapToValue(p3)
if self.chart():
for serie in self.chart().series():
QApplication.postEvent(serie, ReleasePosEvent(p4))
QChartView.mouseReleaseEvent(self, event)
class LineSeries(QLineSeries):
def __init__(self, *args, **kwargs):
QLineSeries.__init__(self, *args, **kwargs)
self.start = QPointF()
self.pressed.connect(self.on_pressed)
def on_pressed(self, point):
self.start = point
print("on_pressed", point)
def shift(self, delta):
if not delta.isNull():
for ix in range(self.count()):
p = self.at(ix)
p += delta
self.replace(ix, p)
def customEvent(self, event):
if event.type() == ReleasePosEvent.EventType:
if not self.start.isNull():
dpoint = event.point - self.start
self.shift(dpoint)
self.start = QPointF()
app = QApplication(sys.argv)
series0 = LineSeries()
series0 << QPointF(1, 15) << QPointF(3, 17) << QPointF(7, 16) << QPointF(9, 17) \
<< QPointF(12, 16) << QPointF(16, 17) << QPointF(18, 15)
chart = QChart()
chart.addSeries(series0)
chart.createDefaultAxes()
chartView = ChartView(chart)
window = QMainWindow()
window.setCentralWidget(chartView)
window.resize(400, 300)
window.show()
sys.exit(app.exec_())