I have a QChart with a number of QLineSeries on it.
I have created my own chart class CPlotView
derifed from QChartView and overridden the mousePressEvent, mouseMoveEvent and mouseReleaseEvent as shown below.
I want to implement both rubberband zoom and rubberband select separately, and I can choose which to do based on checkable QPushButtons (code not shown but its just a member of CPlotView which holds an enum value which defined what 'mode' its in (Zoom or Select)
void CPlotView::mousePressEvent(QMouseEvent *event)
{
if(PlotRubberBand)
{
if (PlotCursorMode == ECursorMode::eIsolate || PlotCursorMode == ECursorMode::eZoom)
{
QRectF plotArea = chart()->plotArea();
if (PlotRubberBand->isEnabled()
&& event->button() == Qt::LeftButton
&& plotArea.contains(event->pos()))
{
DrawRubberBand = true;
PlotRubberBandOrigin = event->pos();
PlotRubberBand->setVisible(true);
PlotRubberBand->setGeometry(QRect(PlotRubberBandOrigin, QSize()));
event->accept();
}
QGraphicsView::mousePressEvent(event);
}
else
{
QChartView::mousePressEvent(event);
}
}
QChartView::mousePressEvent(event);
}
void CPlotView::mouseMoveEvent(QMouseEvent *event)
{
if (GetPlotCursorMode() == ECursorMode::eIsolate)
{
if (DrawRubberBand && PlotRubberBand->isVisible())
{
QRect rect = chart()->plotArea().toRect();
int width = event->pos().x() - PlotRubberBandOrigin.x();
int height = event->pos().y() - PlotRubberBandOrigin.y();
PlotRubberBand->setGeometry(QRect(PlotRubberBandOrigin.x(), PlotRubberBandOrigin.y(), width, height).normalized());
}
else
{
QGraphicsView::mouseMoveEvent(event);
}
}
else if (GetPlotCursorMode() == ECursorMode::eZoom)
{
if (DrawRubberBand && PlotRubberBand->isVisible())
{
QChartView::mouseMoveEvent(event);
}
else
{
QGraphicsView::mouseMoveEvent(event);
}
}
else if (GetPlotCursorMode() == ECursorMode::eSelect)
{
QGraphicsView::mouseMoveEvent(event);
}
else
{
QChartView::mouseMoveEvent(event);
}
}
void CPlotView::mouseReleaseEvent(QMouseEvent *event)
{
if (PlotRubberBand->isVisible())
{
if (PlotCursorMode == ECursorMode::eIsolate)
{
DrawRubberBand = false;
PlotRubberBand->setVisible(false);
QGraphicsView::mouseReleaseEvent(event);
QList<QGraphicsItem *> selected_items = QGraphicsView::items(PlotRubberBand->rect(), Qt::IntersectsItemShape);
qDebug() << "found " << selected_items.size() << " items"; // this appears to show a number of items, but how do I detect which items are my data series, if any are?
for (auto& item : selected_items)
{
// detect which are my data series and highlight them as selected
}
}
else
{
DrawRubberBand = false;
PlotRubberBand->setVisible(false);
QChartView::mouseReleaseEvent(event);
}
}
}
I have now got the zoom mode working - clicking the 'zoom' mode button then dragging the rubberband on the plot zooms into that area. Clicking the select mode button draws the rubberband but doesn't zoom. I want to now select all data series in the rubberband in select mode.
In mouseReleaseEvent
in select mode, I am attempting to capture all selected QGraphicsItems
inside the rubberband rect (I'm hoping that is what is returned by QGraphicsView::items(PlotRubberBand->rect(), Qt::IntersectsItemShape);
), but I don't know how to detect my data series (I actually have a mixture of QLineSeries and QScatterSeries.
There are some QGraphicsItems
being returned by QGraphicsView::items(PlotRubberBand->rect(), Qt::IntersectsItemShape);
even when I don't intersect the rubberband with any of my data so it is obviously returning some other items in the scene.
I tried doing a dynamic_cast
of what is returned by QGraphicsView::items
to a QLineSeries
, but that didn't work. I can't help but think I'm making this more complicated than it should be.
UPDATE1: I have also tried capturing the signals fired when the mouse hovers over the data series during the rubberband select using:
connect(line_series, SIGNAL(hovered(const QPointF &, bool)), this, SLOT(OnDataHovered(const QPointF&, bool)));
but the signal doesn't fire when rubberband dragging (perhaps when left mouse button is down it doesn't fire?). :(
UPDATE 2: I have tried setting the selectionArea in the mouseReleaseEvent() call, and again, some this are returned as selected, far fewer than calling QGraphicsView::items()
, but not my series as far as I can tell:
void ewbearinghistorychart::CEwBearingHistoryChartView::mouseReleaseEvent(QMouseEvent *event)
{
if (PlotRubberBand->isVisible())
{
if (PlotCursorMode == ECursorMode::eIsolate)
{
DrawRubberBand = false;
PlotRubberBand->setVisible(false);
QRect rubberband_rect = PlotRubberBand->rect();
QGraphicsView::mouseReleaseEvent(event);
// ************** new code **************
QPolygonF p = chart()->mapToScene(PlotRubberBand->rect().normalized());
QPainterPath path;
path.addPolygon(p);
chart()->scene()->setSelectionArea(path, Qt::IntersectsItemShape);
QList<QGraphicsItem *> selected_items = chart()->scene()->selectedItems();
qDebug() << "selected items: " << selected_items.size();
// ************** /new code **************
}
else
{
DrawRubberBand = false;
PlotRubberBand->setVisible(false);
QChartView::mouseReleaseEvent(event);
}
}
}
Here is how I get the QGraphicsItem representation of a QLineSeries.