Реализовать выбор в QChartView
Я хочу сделать реализацию выбора диаграммы на основе QChart и QChartView.
Семейство классов имеет большое преимущество- простое использование openGL и анимации, например:
QLineSeries *series = new QLineSeries();
series->setUseOpenGL(true); // <==
QChart *chart = new QChart();
chart->addSeries(series);
chart->setAnimationOptions(QChart::AllAnimations); // <==
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
КлассQChartView предоставляет полезную функцию масштабирования - QChartView:: setRubberBand():
chartView->setRubberBand(QChartView::RectangleRubberBand);
Основная проблема заключается в том, что резинку можно использовать только для масштабирования, но мне нужно реализовать он предназначен для горизонтального выделения без увеличения, так как эта функция обычно реализована в аудиоредакторах:

Теперь, когда я унаследовал QChartView, я могу отключить масштабирование после выбора:
class ChartView : public QChartView
...
bool m_drawRubberBand;
QRubberBand m_rubberBand;
...
ChartView::ChartView(QChart *chart, QWidget *parent)
: QChartView(chart, parent)
{
setRubberBand(QChartView::HorizontalRubberBand);
}
...
// Just copy-paste from the Qt 5 sources - file Srcqtchartssrcchartsqchartview.cpp:
/*!
If the rubber band rectangle is displayed in the press event specified by
a event, the event data is used to update the rubber band geometry.
Otherwise, the default QGraphicsView::mouseMoveEvent() implementation is called.
*/
void ChartView::mouseMoveEvent(QMouseEvent *event)
{
if (m_drawRubberBand && m_rubberBand.isVisible())
{
QRect rect = chart()->plotArea().toRect();
int width = event->pos().x() - m_rubberBandOrigin.x();
int height = event->pos().y() - m_rubberBandOrigin.y();
if (!rubberBand().testFlag(VerticalRubberBand))
{
m_rubberBandOrigin.setY(rect.top());
height = rect.height();
}
if (!rubberBand().testFlag(HorizontalRubberBand))
{
m_rubberBandOrigin.setX(rect.left());
width = rect.width();
}
m_rubberBand.setGeometry(QRect(m_rubberBandOrigin.x(), m_rubberBandOrigin.y(), width, height).normalized());
}
else
{
QGraphicsView::mouseMoveEvent(event);
}
}
Тогда я могу просто не реализовывать действие масштабирования на событии отпускания клавиши мыши:
void ChartView::mouseReleaseEvent(QMouseEvent *event)
{
if (m_rubberBand.isVisible())
{
if (event->button() == Qt::LeftButton)
{
m_drawRubberBand = false;
do_nothing(); // <==
}
}
}
Итак, мои вопросы теперь:
Как границы визуальной резинки могут быть сопоставлены с реальными координатами диаграммы. То есть, как можно отобразить выделение в линию серия на графике? Теперь я получаю те же неправильные координаты:
void MyView::resizeEvent(QResizeEvent *event)
{
QChartView::resizeEvent(event);
QRect rct(QPoint(10, 10), QPoint(20, 20));
qDebug() << mapToScene(rct); <==
}
Вывод:
QPolygonF(QPointF(10,10)QPointF(21,10)QPointF(21,21)QPointF(10,21))
QPolygonF(QPointF(10,10)QPointF(21,10)QPointF(21,21)QPointF(10,21))
QPolygonF(QPointF(10,10)QPointF(21,10)QPointF(21,21)QPointF(10,21))
QPolygonF(QPointF(10,10)QPointF(21,10)QPointF(21,21)QPointF(10,21))
...
- как можно пропорционально изменить размер существующей резиновой выборки вместе с видом?
Edit: может быть, это полезное ключевое слово - QGraphicsScene::setSelectionArea().
Пример чипа Qt 5, который обеспечивает хороший выбор резинки , но пример, основанный на QGraphicsView, а не на QChartView.
1 ответ:
Вопрос решается благодаря ответу на этот ответ: получить координаты мыши в системе осей QChartView
Ключевой момент: необходимо было вызвать QChart:: mapToValue () для корректного преобразования координат:
QPointF ChartView::point_to_chart(const QPoint &pnt) { QPointF scene_point = mapToScene(pnt); QPointF chart_point = chart()->mapToValue(scene_point); return chart_point; }И обратное преобразование:
QPoint ChartView::chart_to_view_point(QPointF char_coord) { QPointF scene_point = chart()->mapToPosition(char_coord); QPoint view_point = mapFromScene(scene_point); return view_point; }Вот как я реализовал изменение размера резинки на resizeEvent.
Во-первых , я сохраняю текущую резинку при отпускании мыши событие:void ChartView::mouseReleaseEvent(QMouseEvent *event) { if (m_rubberBand.isVisible()) { update_rubber_band(event); m_drawRubberBand = false; save_current_rubber_band(); <== } }Где:
void ChartView::update_rubber_band(QMouseEvent * event) { QRect rect = chart()->plotArea().toRect(); int width = event->pos().x() - m_rubberBandOrigin.x(); int height = event->pos().y() - m_rubberBandOrigin.y(); if (!rubberBand().testFlag(VerticalRubberBand)) { m_rubberBandOrigin.setY(rect.top()); height = rect.height(); } if (!rubberBand().testFlag(HorizontalRubberBand)) { m_rubberBandOrigin.setX(rect.left()); width = rect.width(); } m_rubberBand.setGeometry(QRect(m_rubberBandOrigin.x(), m_rubberBandOrigin.y(), width, height).normalized()); }И:
void ChartView::save_current_rubber_band() { QRect rect = m_rubberBand.geometry(); QPointF chart_top_left = point_to_chart(rect.topLeft()); m_chartRectF.setTopLeft(chart_top_left); QPointF chart_bottom_right = point_to_chart(rect.bottomRight()); m_chartRectF.setBottomRight(chart_bottom_right); }И как я перекрашиваю резину на событии resize:
void ChartView::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); if (m_rubberBand.isVisible()) { restore_rubber_band(); } apply_nice_numbers(); }Где:
void ChartView::restore_rubber_band() { QPoint view_top_left = chart_to_view_point(m_chartRectF.topLeft()); QPoint view_bottom_right = chart_to_view_point(m_chartRectF.bottomRight()); m_rubberBandOrigin = view_top_left; m_rubberBand.setGeometry(QRect(view_top_left, view_bottom_right)); }И не забывайте о "хороших числах":
void ChartView::apply_nice_numbers() { QList<QAbstractAxis*> axes_list = chart()->axes(); for each(QAbstractAxis* abstract_axis in axes_list) { QValueAxis* value_axis = qobject_cast<QValueAxis*>(abstract_axis); if (value_axis) { value_axis->applyNiceNumbers(); } } }



Comments