PDA

View Full Version : Adding marker to scale widget



SeanM
15th August 2014, 16:25
Is there a convenient way to add a marker to the scale widget? I've got a vertical marker enabled on the plot itself, but I'd like for that marker to be extended onto the x-axis scale widget as well.

I didn't see any obvious function, but it looks like maybe I could use something like QwtScaleDraw::drawTick() to help?

Cah
15th August 2014, 21:49
but it looks like maybe I could use something like QwtScaleDraw::drawTick() to help?

That's exactly what I did a little while back..


class ScaleDraw: public QwtScaleDraw
{
public:
ScaleDraw(QwtPlotMarker* marker): m_marker(marker)
{

}
protected:
void drawTick (QPainter *p, double val, double len) const
{
p->save();
p->setPen(m_marker->linePen());
double x= m_marker->xValue();
x = m_marker->plot()->transform(QwtPlot::xBottom, x);
p->drawLine(x-1,0, x-1, 50); //x-1 instead of x is a little tweak
p->restore();
QwtScaleDraw::drawTick (p, val, len);
}
private:
QwtPlotMarker* m_marker;

};


int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QwtPlot * plot = new QwtPlot();
QwtPlotMarker* marker = new QwtPlotMarker;
marker->setLinePen("red");
plot->setAxisScaleDraw(QwtPlot::xBottom, new ScaleDraw(marker));
marker->setLineStyle( QwtPlotMarker::VLine);
marker->setXValue(420);
marker->attach(plot);
plot->replot();
plot->show();
return a.exec();
}

I did not test the code snippets... Let me know how it went

SeanM
18th August 2014, 16:31
Thanks for the reply, although now that I'm playing with your sample, I'm realizing I asked my question a bit incorrectly. First, I'm using a QwtPlotPicker, not a QwtPlotMarker, but I'm using the picker as a vertical moving cursor position, not actually using it to select anything. So I want the additional tick mark that I'm drawing on the scale widget to update in real-time whenever the mouse moves, just like the plot picker does on the actual plot.

The bigger picture: I've got multiple vertically aligned plots. All these plots have a common timescale, but completely different vertical scales. As the user moves the mouse over any individual plot, I emit a signal of the x-position, and then draw a plot marker on all the other plots, so that it looks like there's one big vertical cursor that is moving through all the plots. Right now, I've got the x-axis enabled on all the plots, but since it's the same timescale on each plot, I'm just wasting a lot of vertical pixels displaying the same information multiple times. So I'd like to move to a single scale widget, but have that cursor show up on it as well, just to help visually tie everything together.

SeanM
18th August 2014, 19:47
Ok, it appears that I've got it working the way I want, I had to make a few tweaks to your code, here's what I'm using now:

class ScaleDraw: public QwtDateScaleDraw
{
public:
ScaleDraw(QwtPlotMarker* marker): m_marker(marker)
{
}
void invalidate()
{
invalidateCache();
}
protected:
void drawTick (QPainter *p, double val, double len) const
{
if (mMarker && mMarker->isVisible()) // visibility of this follows that of plot marker
{
p->save();
p->setPen(mMarker->linePen());
double x = mMarker->xValue();
x = scaleMap().transform(x);
p->drawLine(x, 0, x, 10);
p->restore();
}
QwtScaleDraw::drawTick (p, val, len);
}
private:
QwtPlotMarker* m_marker;

};

The big change I had to make was where you transform the marker's x value into the pixel's x-coordinate, previously you had:


x = m_marker->plot()->transform(QwtPlot::xBottom, x);
p->drawLine(x-1, 0, x-1, 10);
but that didn't seem to work correctly, the line on the plot wasn't lining up with the line on the scale widget. I played around with it a little, and noticed that the amount of pixels I was off by varied as the number of characters in the scale's leftmost label changed, which makes sense because the lowest valued tick is centered on that label text. So, switching to:

x = scaleMap().transform(x);
p->drawLine(x, 0, x, 10); seemed to work better, and doesn't require the x-1 you were doing before.

My class that inherits from a QwtPicker emits a custom signal time(double x) whenever the cursor moves over the plot, where x is x value of the picker (in scaled values). I connect that to:

void MainWindow::slotIndex(const double &pos)
{
if (pos == mPrevPos)
{
// no need to do anything if we were triggered because of a y axis move
return;
}
mPrevPos = pos;
if (xLimitMin <= pos && pos <= xLimitMax)
{
marker->setXValue(pos);
marker->show();
markedScaleDraw* sd = dynamic_cast<markedScaleDraw*>(centralPlot->axisScaleDraw(QwtPlot::xBottom));
if (sd)
{
sd->invalidate(); // clear the scale draw's cache
}
} else {
marker->hide();
}
centralPlot->replot();
centralPlot->axisWidget(QwtPlot::xBottom)->update(); // cause scale draw to repaint
}