PDA

View Full Version : How do i select a QwtPlotMarker using a QPlotPicker ?



codematic
23rd July 2009, 21:02
Greetings,

I am using QwtPlotPicker to track the mouse and get selection events... but how do i translate that to actually selecting a marker ?

The brute force way (below) in the select signal...doesnt really work because the Markers return a bounding rect that has a 0 width/height...

Whats the best way to do this ?



void PitchSightPlot::cursorSelected(const QwtDoublePoint &Point)
{
List = itemList();
Iter = List.begin();

while(Iter != List.end())
{
QwtPlotItem *pItem = (QwtPlotItem *)(*Iter);

if(pItem->rtti() == QwtPlotItem::Rtti_PlotMarker)
if(pItem->boundingRect().contains(Point))
qDebug()<< "MATCH" << Point;

Iter++;
}
}

Uwe
24th July 2009, 13:18
Use pixel coordinates instead of plot coordinates and add some pixels around the translated marker position.

Uwe

rambo83
24th November 2009, 15:31
Hello,

I have got the same problem, because of size 0 of the boundingRect() the item cannot be found:


void Plot::cursorSelected(const QwtDoublePoint &Point)
{
//selectedPoint = NULL;
std::cout << "in Plot::cursorSelected, selectedPoint = " << selectedPoint << std::endl;
const QwtPlotItemList& List = itemList();
QwtPlotItemIterator Iter = List.begin();
for ( QwtPlotItemIterator it = List.begin();it != List.end(); ++it )
{
std::cout << "(*it) "<< (*it) << std::endl;
if ( (*it)->rtti() == QwtPlotItem::Rtti_PlotMarker )
{
QwtPlotMarker *mark = ((QwtPlotMarker*)(*it));
QwtDoubleRect rec = mark->boundingRect();
std::cout << "mark->boundingRect()" <<rec.width()<<rec.height()<< std::endl;
if(mark->boundingRect().contains(Point)){
std::cout << "MATCH" << std::endl;
selectedPoint = dynamic_cast<QwtPlotMarker*>(mark);
std::cout << "selectedPoint = " << selectedPoint << std::endl;
}
else selectedPoint = NULL;
}
}


What do you mean by using Pixel coordinates? Di you mean I have to transform them like that? :

double x = this->transform(mark->xAxis(),Point.x());
double y = this->transform(mark->yAxis(),Point.y());
QwtDoublePoint trPoint = QwtDoublePoint(x,y);

I also uses this, but it does not work too. Perhaps because I did not expansed the size of boundingRect. How can I do it?

Uwe
25th November 2009, 07:08
If you want to decide if a mouse click matches a point on a widgets you have to think ( and implement ) in widgets coordinates:

1) Translate the position of your marker to widget coordinates.
2) Create a rectangle around the mouse click position ( adding a tolerance of a couple of pixels )
3) Check if the marker position ( or the rectangle in symbol size around it) is inside the rectangle.

If you have many points you might have to introduce some spatial index (like a quadtree) to speed up your implemetation.

HTH,
Uwe

rambo83
25th November 2009, 10:37
Thank you, Uwe!

I followed your advice and managed to translate the coordinates of items into Plot coordinates and can now select the corresponding items as well as drag them on the plot. There is only one little bad behaviour (perhaps it depends on my bad c++ code :o ), namely that if I release the mouse the pointer to the dragged items is not set to NULL and thus if I don't select any other items, but drag just the empty area, the last selected or dragged item is moved there. How can I set the pointer to this item to NULL after the MouseButtonRelease event is called?

Here is the code for those, who had similar problem:


...
// create QwtPlotPicker to allow user moving the points on the plot

picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
QwtPicker::PointSelection | QwtPicker::DragSelection,
QwtPlotPicker::CrossRubberBand, QwtPicker::AlwaysOn,
this->canvas());

connect( picker, SIGNAL(moved(const QwtDoublePoint& ) ),
this, SLOT(cursorMoved( const QwtDoublePoint& ) ) );

connect( picker, SIGNAL(selected( const QwtDoublePoint& ) ),
this, SLOT(cursorSelected( const QwtDoublePoint& ) ) );
...

void Plot::cursorSelected(const QwtDoublePoint &Point)
{
//selectedPoint = NULL;
std::cout << "in Plot::cursorSelected, selectedPoint = " << selectedPoint << std::endl;
const QwtPlotItemList& List = itemList();
QwtPlotItemIterator Iter = List.begin();

while(Iter != List.end())
{
if((*Iter)->rtti() == QwtPlotItem::Rtti_PlotMarker){
QwtPlotMarker *mark = ((QwtPlotMarker*)(*Iter));
double x = this->transform(mark->xAxis(),mark->xValue());
double y = this->transform(mark->yAxis(),mark->yValue());
std::cout << "mark.xValue()=" << mark->xValue() << ", mark.yValue()=" << mark->yValue()<< std::endl;
std::cout << "transformed mark coord = " << x << ", " << y<< std::endl;
QwtDoublePoint trPoint = QwtDoublePoint(x,y);
double xClick = this->transform(mark->xAxis(),Point.x());
double yClick = this->transform(mark->yAxis(),Point.y());
QwtDoubleRect recOfClick(xClick-10, yClick-10, 20,20);
std::cout << "recOfClick(x,y,width, height) =" <<recOfClick.x()<<", " << recOfClick.y() << ", " << recOfClick.width()<< ", "<<recOfClick.height()<< std::endl;
if(recOfClick.contains(trPoint)){
std::cout << "MATCH" << std::endl;
selectedPoint = mark;
std::cout << "selectedPoint = " << selectedPoint << std::endl;
}
/* else{
selectedPoint = NULL; // at the beginning this pointer should be NULL
}*/
}
Iter++;
}
}
//################################################## ################
void Plot::cursorMoved( const QwtDoublePoint& Point){
std::cout << "in Plot::cursorMoved, selectedPoint = " << selectedPoint << std::endl;
std::cout << "Point.x()= " << Point.x() <<"Point.y()= " << Point.y() << std::endl;
if(selectedPoint!=NULL){
selectedPoint->setValue(Point); // set the new coordinates to the moved item
//std::cout << "selectedPoint->xValue(): " << selectedPoint->xValue() <<"selectedPoint->yValue(): " << selectedPoint->yValue()<< std::endl;
this->replot(); // replot the plot widget after the selected point was moved
}
}

rambo83
25th November 2009, 12:55
I expected that the QwtPlotPicker can handle both the PointSelection and RectSeletion modes, so that if I click one time on an item then the SIGNAL selected(const QwtDoublePoint &pos) is called and if drag a rectangle around several items then the SIGNAL selected(const QwtDoubleRect &rect) would be called. Obviosly my expectations are not right, because I can only use one of this two selection modes. How shall be the QwtPlotPicker parameterized to fulfill my expectation? The following code does not do the right thing:


picker = new QwtPlotPicker(QwtPlot::xBottom, QwtPlot::yLeft,
QwtPicker::PointSelection | QwtPicker::RectSelection | QwtPicker::DragSelection,
QwtPlotPicker::RectRubberBand, QwtPicker::AlwaysOn,
this->canvas());

// connect the signals coming from QwtPlotPicker with the member functions
connect( picker, SIGNAL(moved(const QwtDoublePoint& ) ),
this, SLOT(cursorMoved( const QwtDoublePoint& ) ) );

connect( picker, SIGNAL(selected( const QwtDoublePoint& ) ),
this, SLOT(cursorSelected( const QwtDoublePoint& ) ) );

connect( picker, SIGNAL(selected (const QwtDoubleRect &) ),
this, SLOT(RectangleSelected( const QwtDoubleRect& ) ) );

Or is here another logical problem? Help me please.

Thank you