QCustomPlot Discussion and Comments

Move a vertical line on a plot and display its x-value on a labelReturn to overview

Hi,
as the title says I'd like to move a vertical line (QCPItemLine previously added to a plot in a given position) to a different x-position, and then read its new x-coordinate.
Is there a simple way to do that?

The main goal is to use this line as a "marker" for the x-coordinate, so maybe if this is not feasible there is another way to do it?

I attach the simple code I used to create the "markers":

    ui->plot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables | QCP::iSelectItems);

    QCPItemLine *min1 = new QCPItemLine(ui->plot);
    QCPItemLine *max1 = new QCPItemLine(ui->plot);
    QCPItemLine *min2 = new QCPItemLine(ui->plot);
    QCPItemLine *max2 = new QCPItemLine(ui->plot);

    QPen pen(Qt::black); pen.setWidth(2);
    min1->setPen(pen); max1->setPen(pen);
    min2->setPen(pen); max2->setPen(pen);

    min1->setSelectable(true);
    max1->setSelectable(true);
    min2->setSelectable(true);
    max2->setSelectable(true);

    //Adding the vertical lines to the plot
    ui->plot->addItem(min1);
    min1->start->setCoords(x01, -1e7);
    min1->end->setCoords(x01, 1e7);

    ui->plot->addItem(max1);
    max1->start->setCoords(x11, -1e7);
    max1->end->setCoords(x11, 1e7);

    ui->plot->addItem(min2);
    min2->start->setCoords(x02, -1e7);
    min2->end->setCoords(x02, 1e7);

    ui->plot->addItem(max2);
    max2->start->setCoords(x12, -1e7);
    max2->end->setCoords(x12, 1e7);

    ui->plot->replot();

Thanks for any advice! :)

Hello Elisa,
you have to Connect the Signal of a mouse move or mouse click of QCP ( its called itemclick i think ), then you get event of the emitted signal. With event->pos you can set the coords of the selected Item.
To get the Line you clicked on you can check the name of the Item Object name. This name you can get with the emitted QCPAbstractItem *item => item.objectName().

I hope it helps

I'm revisiting this page after having the same question some time ago. Hope my code will help next visitiors find a solution faster.

#ifndef SW_QCPITEMLINE_H
#define SW_QCPITEMLINE_H

#include "qcustomplot.h"
enum class ColorTheme
{
    Light,
    Dark,
    TOS
};

class SW_VerticalQCPItemLine : public QCPItemLine
{
public:
    SW_VerticalQCPItemLine(QCustomPlot *parentPlot, ColorTheme color);
    virtual ~SW_VerticalQCPItemLine();

    void UpdateLabel(double x, double y, QString text);
    void SetVisibleCustom(bool value);

    QCPItemText* m_lineLabel;
};

#endif // SW_QCPITEMLINE_H

#include "sw_verticalqcpitemline.h"

SW_VerticalQCPItemLine::SW_VerticalQCPItemLine(QCustomPlot *parentPlot, ColorTheme color)
    : QCPItemLine(parentPlot)
{
    m_lineLabel = new QCPItemText(parentPlot);
    m_lineLabel->setText("");

    if (color == ColorTheme::Light)
    {
        this->setPen(QPen(Qt::lightGray));
        m_lineLabel->setColor(Qt::darkGray);
    }
    else
    {
        this->setPen(QPen(QColor(100, 100, 100)));
        m_lineLabel->setColor(Qt::lightGray);
    }
}

SW_VerticalQCPItemLine::~SW_VerticalQCPItemLine()
{
   // delete m_lineLabel;
}

void SW_VerticalQCPItemLine::UpdateLabel(double x, double y, QString text)
{
    m_lineLabel->setText(text);
    m_lineLabel->position->setType(QCPItemPosition::ptAbsolute);
    m_lineLabel->position->setCoords(x, y);
}

void SW_VerticalQCPItemLine::SetVisibleCustom(bool value)
{
    m_lineLabel->setVisible(value);
    this->setVisible(value);
}

Usage:
mainwindow.cpp constructor:

m_intraVerticalLine = new SW_VerticalQCPItemLine(ui->plot, m_settings.colorTheme);

inside plot mouse move:

// crosshairs ------------------------------------------

if (ui->plot->axisRectCount() > 0)
{
	QCPAxis* xAxis = ui->plot->axisRect(0)->axis(QCPAxis::atBottom);
	QCPAxis* yAxis = ui->plot->axisRect(0)->axis(QCPAxis::atLeft);

	if (xAxis != NULL && yAxis != NULL)
	{
		//vertical
		double priceStart = yAxis->pixelToCoord(0);
		double priceEnd = yAxis->pixelToCoord(ui->plot->size().height() - 115); //100 is volume rectangle

		double key;
		if (!m_isIntraMousePressed)
			key = xAxis->pixelToCoord(event->x());
		else
			key = m_intraVerticalLine->start->coords().rx();

		m_intraVerticalLine->start->setCoords(key, priceStart);
		m_intraVerticalLine->end->setCoords(key, priceEnd);

		//vertical labels
		bool isTooCloseToTheRight = xAxis->coordToPixel(key) - xAxis->coordToPixel(xAxis->range().upper) > -40;
		if (isTooCloseToTheRight)
			x = xAxis->coordToPixel(key) - 25; //on the left side;
		else
			x = xAxis->coordToPixel(key) + 25; //on the right side
		y = yAxis->coordToPixel(priceEnd) - 10;

		m_intraVerticalLine->UpdateLabel(x, y, GetDateTimeLabelFromXAxisKey(key, true));
		
		//...
	}
}

With any questions, please ping me at andrew.myhalchuk@gmail.com