qt: add graph editor

This commit is contained in:
Jussi Kuokkanen 2019-12-08 15:39:05 +02:00
parent e1e10cc90f
commit 5fcc79c693
4 changed files with 275 additions and 0 deletions

View File

@ -0,0 +1,193 @@
#include "DragChartView.h"
#include <QDebug>
#include <QToolTip>
#include <QApplication>
#include <QValueAxis>
DragChartView::DragChartView(QWidget *parent) : QChartView(parent)
{
setRenderHint(QPainter::Antialiasing);
m_toolTipLabel = new QLabel;
m_toolTipLabel->setWindowFlag(Qt::ToolTip);
m_dragCanStart = false;
m_leftLineFillerItem = new QGraphicsLineItem;
m_rightLineFillerItem = new QGraphicsLineItem;
chart()->scene()->addItem(m_leftLineFillerItem);
chart()->scene()->addItem(m_rightLineFillerItem);
for (int i = 0; i < 5; i++) {
m_series.append(i * 5, i * 5);
auto item = new QGraphicsLineItem;
item->setPen(QPen(QBrush(QColor(Qt::blue)), 3));
m_lineFillerItems.append(item);
chart()->scene()->addItem(item);
}
connect(&m_series, &QScatterSeries::pressed, [=](QPointF point) {
qDebug() << "click at" << point;
m_dragCanStart = true;
m_latestScatterPoint = point;
});
m_xAxis.setRange(0, 25);
m_yAxis.setRange(0, 25);
m_series.attachAxis(&m_xAxis);
m_series.attachAxis(&m_yAxis);
chart()->addSeries(&m_series);
chart()->addAxis(&m_xAxis, Qt::AlignBottom);
chart()->addAxis(&m_yAxis, Qt::AlignLeft);
/*QLineF line(m_series.pointsVector()[0], m_series.pointsVector()[1]);
m_lineItem->setLine(line);
m_lineItem->setPen(QPen(QBrush(QColor(Qt::blue)), 3));
chart()->scene()->addItem(m_lineItem);*/
}
bool DragChartView::event(QEvent *event) {
qDebug() << event->type();
if (event->type() == QEvent::Resize || event->type() == QEvent::UpdateLater) {
// Chart has a geometry when this is true
//qDebug() << chart()->mapToPosition(QPointF(5, 5), &m_series);
//QLineF line(chart()->mapToPosition(m_series.pointsVector()[0]), chart()->mapToPosition(m_series.pointsVector()[1]));
drawFillerLines(&m_series);
}
return QChartView::event(event);
}
void DragChartView::mousePressEvent(QMouseEvent *event) {
qDebug() << event->type();
if (event->button() == Qt::LeftButton) {
m_dragStartPosition = event->pos();
}
QChartView::mousePressEvent(event);
}
void DragChartView::mouseMoveEvent(QMouseEvent *event) {
if (!(event->buttons() & Qt::LeftButton)) {
return;
}
if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance() || !m_dragCanStart) {
return;
}
//qDebug() << "start drag";
m_dragActive = true;
//QToolTip::showText(mapToGlobal(event->pos()), QString("%1, %2").arg(QString::number(m_latestScatterPoint.x()), QString::number(m_latestScatterPoint.y())));
if (m_toolTipLabel->isHidden()) {
m_toolTipLabel->show();
}
m_toolTipLabel->setText(QString("%1, %2").arg(QString::number(m_latestScatterPoint.x()), QString::number(m_latestScatterPoint.y())));
m_toolTipLabel->move(event->screenPos().toPoint());
replaceMovedPoint(m_latestScatterPoint, chart()->mapToValue(event->pos(), &m_series));
drawFillerLines(&m_series);
}
void DragChartView::mouseReleaseEvent(QMouseEvent *event) {
qDebug() << event->type();
m_dragCanStart = false;
qDebug() << chart()->mapToValue(event->pos(), &m_series);
if (m_dragActive) {
//replaceMovedPoint(m_latestScatterPoint, chart()->mapToValue(event->pos(), &m_series));
}
//QToolTip::hideText();
m_toolTipLabel->hide();
QChartView::mouseReleaseEvent(event);
}
void DragChartView::wheelEvent(QWheelEvent *event) {
qDebug() << event->angleDelta();
qreal factor = event->angleDelta().y() > 0 ? 0.5 : 2.0;
//chart()->zoom(factor);
event->accept();
drawFillerLines(&m_series);
QChartView::wheelEvent(event);
}
void DragChartView::replaceMovedPoint(const QPointF old, const QPointF new_) {
m_series.replace(old, new_);
m_latestScatterPoint = new_;
//m_dragActive = false;
}
QVector <QPointF> DragChartView::sortPointFByAscendingX(const QVector<QPointF> points) {
QVector <qreal> ascendingX;
QVector <qreal> originalY;
for (QPointF point : points) {
ascendingX.append(point.x());
originalY.append(point.y());
}
std::sort(ascendingX.begin(), ascendingX.end());
QVector <QPointF> sorted;
// Find the original y values for x values
for (qreal x : ascendingX) {
for (QPointF point : points) {
if (qFuzzyCompare(x, point.x())) {
sorted.append(QPointF(x, point.y()));
break;
}
}
}
return sorted;
}
void DragChartView::drawFillerLines(QScatterSeries *series) {
// Sort points by ascending x
QVector <QPointF> sorted = sortPointFByAscendingX(series->pointsVector());
if (sorted.isEmpty()) {
return;
}
for (int i = 0; i < sorted.length() - 1; i++) {
m_lineFillerItems[i]->setLine(QLineF(chart()->mapToPosition(sorted[i]),
chart()->mapToPosition(sorted[i + 1])));
}
m_leftLineFillerItem->setLine(QLineF(chart()->mapToPosition(QPointF(m_xAxis.min(), sorted[0].y())),
chart()->mapToPosition(sorted[0])));
m_rightLineFillerItem->setLine(QLineF(chart()->mapToPosition(sorted.last()),
chart()->mapToPosition(QPointF(m_xAxis.max(), sorted.last().y()))));
qDebug() << chart()->mapToValue(m_rightLineFillerItem->line().p2());
chart()->update();
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <QtCharts/QChartView>
#include <QtCharts/QScatterSeries>
#include <QLabel>
#include <QValueAxis>
using namespace QtCharts;
class DragChartView : public QChartView {
public:
DragChartView(QWidget *parent = nullptr);
QValueAxis *xAxis() {return &m_xAxis;}
QValueAxis *yAxis() {return &m_yAxis;}
protected:
bool event(QEvent*);
void mousePressEvent(QMouseEvent*);
void mouseMoveEvent(QMouseEvent*);
void mouseReleaseEvent(QMouseEvent*);
void wheelEvent(QWheelEvent*);
private:
QVector <QPointF> sortPointFByAscendingX(const QVector <QPointF> points);
void drawFillerLines(QScatterSeries *series);
QLabel *m_toolTipLabel;
QScatterSeries m_series;
QPoint m_dragStartPosition;
bool m_dragCanStart; // Was a point clicked and not released before drag should start
bool m_dragActive;
QPointF m_latestScatterPoint;
void replaceMovedPoint(const QPointF old, const QPointF new_);
QVector <QGraphicsLineItem*> m_lineFillerItems; // Filler lines between points whose amount is n - 1 for nonzero n
QGraphicsLineItem *m_leftLineFillerItem;
QGraphicsLineItem *m_rightLineFillerItem;
QValueAxis m_xAxis, m_yAxis;
};

View File

@ -0,0 +1,26 @@
#include "GraphEditor.h"
#include <QSizePolicy>
GraphEditor::GraphEditor(QWidget *parent) : QWidget(parent) {
m_layout = new QGridLayout;
// Layout is 4 x 2 layout with buttons spanning the lower right of the second row
m_layout->addWidget((m_dragChartView = new DragChartView), 0, 0, 1, 4);
m_dragChartView->chart()->setMargins(QMargins(0, 0, 0, 0));
m_layout->addWidget((m_saveButton = new QPushButton("Save")), 1, 2, 1, 1);
m_layout->addWidget((m_cancelButton = new QPushButton("Cancel")), 1, 3, 1, 1);
// Minimize button height
QSizePolicy buttonPolicy(QSizePolicy::Preferred, QSizePolicy::Minimum, QSizePolicy::PushButton);
m_saveButton->setSizePolicy(buttonPolicy);
m_cancelButton->setSizePolicy(buttonPolicy);
connect(m_cancelButton, &QPushButton::clicked, [=]() {
emit cancelled();
});
setLayout(m_layout);
}

View File

@ -0,0 +1,21 @@
#pragma once
#include "DragChartView.h"
#include <QGridLayout>
#include <QPushButton>
class GraphEditor : public QWidget {
public:
GraphEditor(QWidget *parent = nullptr);
DragChartView *dragChartView() {return m_dragChartView;}
private:
Q_OBJECT
QGridLayout *m_layout;
DragChartView *m_dragChartView;
QPushButton *m_saveButton;
QPushButton *m_cancelButton;
signals:
void cancelled();
};