4

我正在使用QCustomPlot并在屏幕上绘制了多个图形,我希望能够单击并指向然后能够获取我单击的点的数据或坐标等,我知道这对于整个绘图都是可能的自己使用QCP::iSelectPlottables,但这是否可能仅用于单个点,或者是否有人找到了解决方法来使这成为可能。

4

2 回答 2

3

没有简单的方法可以做到这一点。至少 QCustomPlot 中没有这样的功能。

QCPItemEllipse但是您可以创建表示单点的类(例如,从 派生)并用鼠标移动它。

我在我的(尚未发布的)软件中有类似的功能,所以看看和学习......它也可以用 shift-modifier 移动(只改变初始位置的一个坐标)。另外,当它移动到项目(以及它移动到的项目的边框)时,它会更改光标。

绘图点.h

class PlotPoint : public QCPItemEllipse
{
    Q_OBJECT
public:
    explicit PlotPoint(QCustomPlot *parentPlot, int halfSize = 5);

    QPointF pos() const;
    const QColor &color() const;
    void setColor(const QColor &color);
    void startMoving(const QPointF &mousePos, bool shiftIsPressed);

public slots:
    void setVisible(bool on);

signals:
    void activated(); ///< emitted on mouse over
    void disactivated(); ///< emitted when cursor leave us

    void moved(const QPointF &pos);
    void stoppedMoving();

public slots:
    void move(double x, double y, bool signalNeeded = true);
    void movePx(double x, double y);
    void setActive(bool isActive);

private slots:
    void onMouseMove(QMouseEvent *event);
    void stopMoving();
    void moveToWantedPos();
    void onShiftStateChanged(bool shiftPressed);

private:
    QCPItemTracer *mCenterTracer;
    QPointF mGripDelta;
    QPointF mInitialPos;
    bool mIsChangingOnlyOneCoordinate;
    QList<QCPAbstractItem *> mHelperItems;
    QPointF mLastWantedPos;
    QTimer *mMoveTimer;
    QPointF mCurWantedPosPx;
};

绘图点.cpp

PlotPoint::PlotPoint(QCustomPlot *parentPlot, int halfSize)
    : QCPItemEllipse(parentPlot)
    , mCenterTracer(new QCPItemTracer(parentPlot))
    , mGripDelta()
    , mInitialPos()
    , mLastWantedPos()
    , mMoveTimer(new QTimer(this))
    , mCurWantedPosPx()
{
    mCenterTracer->setStyle(QCPItemTracer::tsNone);

    topLeft->setParentAnchor(mCenterTracer->position);
    bottomRight->setParentAnchor(mCenterTracer->position);
    topLeft->setType(QCPItemPosition::ptAbsolute);
    bottomRight->setType(QCPItemPosition::ptAbsolute);

    topLeft->setCoords(-halfSize, -halfSize);
    bottomRight->setCoords(halfSize, halfSize);

    setSelectable(true); // plot moves only selectable points, see Plot::mouseMoveEvent
    setColor(QColor(qrand()%256, qrand()%256, qrand()%256, 100));
    setPen(QPen(Qt::black));
    setSelectedPen(QPen(Qt::black, 3));

    mMoveTimer->setInterval(25); // 40 FPS
    connect(mMoveTimer, SIGNAL(timeout()), this, SLOT(moveToWantedPos()));
}

QPointF PlotPoint::pos() const
{
    return mCenterTracer->position->coords();
}

const QColor &PlotPoint::color() const
{
    return brush().color();
}

void PlotPoint::setColor(const QColor& color)
{
    setBrush(color);
    setSelectedBrush(color);
}

void PlotPoint::startMoving(const QPointF &mousePos, bool shiftIsPressed)
{
    mGripDelta.setX(parentPlot()->xAxis->coordToPixel(mCenterTracer->position->key()) - mousePos.x());
    mGripDelta.setY(parentPlot()->yAxis->coordToPixel(mCenterTracer->position->value()) - mousePos.y());

    mInitialPos = pos();
    mLastWantedPos = mInitialPos;
    mCurWantedPosPx = QPointF();
    mIsChangingOnlyOneCoordinate = shiftIsPressed;

    mMoveTimer->start();

    QCPItemStraightLine *horizontal = new QCPItemStraightLine(parentPlot());
    horizontal->setAntialiased(false);
    horizontal->point1->setCoords(mInitialPos.x(), mInitialPos.y());
    horizontal->point2->setCoords(mInitialPos.x() + 1, mInitialPos.y());
    parentPlot()->addItem(horizontal);

    QCPItemStraightLine *vertical = new QCPItemStraightLine(parentPlot());
    vertical->setAntialiased(false);
    vertical->point1->setCoords(mInitialPos.x(), mInitialPos.y());
    vertical->point2->setCoords(mInitialPos.x(), mInitialPos.y() + 1);
    parentPlot()->addItem(vertical);

    static const QPen linesPen(Qt::darkGray, 0, Qt::DashLine);
    horizontal->setPen(linesPen);
    vertical->setPen(linesPen);

    mHelperItems << vertical << horizontal;

    if (!mIsChangingOnlyOneCoordinate) {
        vertical->setVisible(false);
        horizontal->setVisible(false);
    }

    connect(parentPlot(), SIGNAL(mouseMove(QMouseEvent*)),
            this, SLOT(onMouseMove(QMouseEvent*)));

    connect(parentPlot(), SIGNAL(mouseRelease(QMouseEvent*)),
            this, SLOT(stopMoving()));

    connect(parentPlot(), SIGNAL(shiftStateChanged(bool)),
            this, SLOT(onShiftStateChanged(bool)));

    parentPlot()->grabKeyboard();
    QApplication::setOverrideCursor(Qt::ClosedHandCursor);
}

void PlotPoint::setVisible(bool on)
{
    setSelectable(on);  // we are movable only when visible
    QCPItemEllipse::setVisible(on);
}

void PlotPoint::stopMoving()
{
    disconnect(parentPlot(), SIGNAL(mouseMove(QMouseEvent*)),
            this, SLOT(onMouseMove(QMouseEvent*)));

    disconnect(parentPlot(), SIGNAL(mouseRelease(QMouseEvent*)),
            this, SLOT(stopMoving()));

    disconnect(parentPlot(), SIGNAL(shiftStateChanged(bool)),
            this, SLOT(onShiftStateChanged(bool)));

    mMoveTimer->stop();
    moveToWantedPos();

    if (!mHelperItems.isEmpty()) {
        while (!mHelperItems.isEmpty()) {
            QCPAbstractItem *item = mHelperItems.takeFirst();
            mParentPlot->removeItem(item);
        }

        mParentPlot->replot();
    }

    parentPlot()->releaseKeyboard();
    QApplication::restoreOverrideCursor();

    emit stoppedMoving();
}

void PlotPoint::move(double x, double y, bool signalNeeded)
{
    mLastWantedPos.setX(x);
    mLastWantedPos.setY(y);
    if (mIsChangingOnlyOneCoordinate) {
        double x1 = parentPlot()->xAxis->coordToPixel(x);
        double x2 = parentPlot()->xAxis->coordToPixel(mInitialPos.x());
        double y1 = parentPlot()->yAxis->coordToPixel(y);
        double y2 = parentPlot()->yAxis->coordToPixel(mInitialPos.y());
        if (qAbs(x1 - x2) < qAbs(y1 - y2)) {
            x = mInitialPos.x();
        } else {
            y = mInitialPos.y();
        }
    }

    mCenterTracer->position->setCoords(x, y);

    parentPlot()->replot();

    if(signalNeeded) {
        emit moved(QPointF(x, y));
    }
}

void PlotPoint::movePx(double x, double y)
{
    move(parentPlot()->xAxis->pixelToCoord(x),
        parentPlot()->yAxis->pixelToCoord(y));
}

void PlotPoint::setActive(bool isActive)
{
    setSelected(isActive);
    emit (isActive ? activated() : disactivated());
}

void PlotPoint::onMouseMove(QMouseEvent *event)
{
    mCurWantedPosPx = QPointF(event->localPos().x() + mGripDelta.x(),
                              event->localPos().y() + mGripDelta.y());
}

void PlotPoint::moveToWantedPos()
{
    if (!mCurWantedPosPx.isNull()) {
        movePx(mCurWantedPosPx.x(), mCurWantedPosPx.y());
        mCurWantedPosPx = QPointF();
    }
}

void PlotPoint::onShiftStateChanged(bool shiftPressed)
{
    if (shiftPressed != mIsChangingOnlyOneCoordinate) {
        mIsChangingOnlyOneCoordinate = shiftPressed;
        foreach (QCPAbstractItem *item, mHelperItems) {
            item->setVisible(shiftPressed);
        }
        move(mLastWantedPos.x(), mLastWantedPos.y());
    }
}

(部分)plot.cpp

void Plot::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && mPointUnderCursor) {
        mPointUnderCursor->startMoving(event->localPos(),
                                       event->modifiers().testFlag(Qt::ShiftModifier));
        return;
    }

    QCustomPlot::mousePressEvent(event);
}

void Plot::mouseMoveEvent(QMouseEvent *event)
{
    QCustomPlot::mouseMoveEvent(event);
    if (event->buttons() == Qt::NoButton) {
        PlotPoint *plotPoint = qobject_cast<PlotPoint*>(itemAt(event->localPos(), true));
        if (plotPoint != mPointUnderCursor) {
            if (mPointUnderCursor == NULL) {
                // cursor moved from empty space to item
                plotPoint->setActive(true);
                setCursor(Qt::OpenHandCursor);
            } else if (plotPoint == NULL) {
                // cursor move from item to empty space
                mPointUnderCursor->setActive(false);
                unsetCursor();
            } else {
                // cursor moved from item to item
                mPointUnderCursor->setActive(false);
                plotPoint->setActive(true);
            }
            mPointUnderCursor = plotPoint;
            replot();
        }
    }
}

void Plot::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Shift) {
        emit shiftStateChanged(true);
    }
    QCustomPlot::keyPressEvent(event);
}

void Plot::keyReleaseEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Shift) {
        emit shiftStateChanged(false);
    }
    QCustomPlot::keyReleaseEvent(event);
}

抱歉,代码中几乎没有评论。我只是懒得把俄文翻译成英文。

无论如何,我希望你能得到一切。

于 2013-11-10T18:02:00.967 回答
-1

@Obey-Kun 的巨大贡献,如果有人感兴趣,我想进一步讨论,尤其是 Kun :)

(1) 基本思想是

  • 创建一个椭圆项目PlotPoint
  • 随之而来的是2个直线项目 horizontal& vertical(用于正交移动)
  • 和一个跟踪项mCenterTracer(椭圆的中心,用于连接鼠标操作)。

(2)根据plot.cpp(part),我想机制可能是:

  • 左键,(确认有一点可以移动)
  • 移动鼠标。(通过跟踪器移动点)
  • 释放leftButton。(将点放在最后想要的位置)

但是,我对中的逻辑感到困惑

无效绘图::mouseMoveEvent(QMouseEvent *事件)

. 它看起来像一个悬停检测程序,因为一切都是在 .Qt::NoButton用户移动鼠标(没有按下任何按钮)以检测鼠标是否在 plotPoint 下完成的,如果是,则转移*plotPoint*mPointUnderCursor。然后按,然后移动,然后释放。

有什么我想念的吗?

于 2014-04-12T03:16:38.687 回答