因工作需要,要利用鼠标移动曲线上的数据点,采用的控件是Qwt 。
QwtPlot的鼠标移动操作有点麻烦,费了一下午时间才调通,参考了官方例程 itemeditor
主要的几个函数是下面的
private:
bool pressed( const QPoint & );
bool moved( const QPoint & );
void released( const QPoint & );
QwtPlotShapeItem* itemAt( const QPoint& ) const;
void raiseItem( QwtPlotShapeItem * );
QRegion maskHint( QwtPlotShapeItem * ) const;
void setItemVisible( QwtPlotShapeItem *item, bool on );
bool d_isEnabled;
QPointer<QwtWidgetOverlay> d_overlay;
// Mouse positions
QPointF d_currentPos;
QwtPlotShapeItem* d_editedItem;
bool Editor::eventFilter( QObject* object, QEvent* event )
{
QwtPlot *plot = qobject_cast<QwtPlot *>( parent() );
if ( plot && object == plot->canvas() )
{
switch( event->type() )
{
case QEvent::MouseButtonPress:
{
const QMouseEvent* mouseEvent =
dynamic_cast<QMouseEvent* >( event );
if ( d_overlay == NULL &&
mouseEvent->button() == Qt::LeftButton )
{
const bool accepted = pressed( mouseEvent->pos() );
if ( accepted )
{
d_overlay = new Overlay( plot->canvas(), this );
d_overlay->updateOverlay();
d_overlay->show();
}
}
break;
}
case QEvent::MouseMove:
{
if ( d_overlay )
{
const QMouseEvent* mouseEvent =
dynamic_cast< QMouseEvent* >( event );
const bool accepted = moved( mouseEvent->pos() );
if ( accepted )
d_overlay->updateOverlay();
}
break;
}
case QEvent::MouseButtonRelease:
{
const QMouseEvent* mouseEvent =
static_cast<QMouseEvent* >( event );
if ( d_overlay && mouseEvent->button() == Qt::LeftButton )
{
released( mouseEvent->pos() );
delete d_overlay;
d_overlay = NULL;
}
break;
}
default:
break;
}
return false;
}
return QObject::eventFilter( object, event );
}
bool Editor::pressed( const QPoint& pos )
{
d_editedItem = itemAt( pos );
if ( d_editedItem )
{
d_currentPos = pos;
setItemVisible( d_editedItem, false );
return true;
}
return false; // don't accept the position
}
bool Editor::moved( const QPoint& pos )
{
if ( plot() == NULL )
return false;
const QwtScaleMap xMap = plot()->canvasMap( d_editedItem->xAxis() );
const QwtScaleMap yMap = plot()->canvasMap( d_editedItem->yAxis() );
const QPointF p1 = QwtScaleMap::invTransform( xMap, yMap, d_currentPos );
const QPointF p2 = QwtScaleMap::invTransform( xMap, yMap, pos );
#if QT_VERSION >= 0x040600
const QPainterPath shape = d_editedItem->shape().translated( p2 - p1 );
#else
const double dx = p2.x() - p1.x();
const double dy = p2.y() - p1.y();
QPainterPath shape = d_editedItem->shape();
for ( int i = 0; i < shape.elementCount(); i++ )
{
const QPainterPath::Element &el = shape.elementAt( i );
shape.setElementPositionAt( i, el.x + dx, el.y + dy );
}
#endif
d_editedItem->setShape( shape );
d_currentPos = pos;
return true;
}
void Editor::released( const QPoint& pos )
{
Q_UNUSED( pos );
if ( d_editedItem )
{
raiseItem( d_editedItem );
setItemVisible( d_editedItem, true );
}
}
QwtPlotShapeItem* Editor::itemAt( const QPoint& pos ) const
{
const QwtPlot *plot = this->plot();
if ( plot == NULL )
return NULL;
// translate pos into the plot coordinates
double coords[ QwtPlot::axisCnt ];
coords[ QwtPlot::xBottom ] =
plot->canvasMap( QwtPlot::xBottom ).invTransform( pos.x() );
coords[ QwtPlot::xTop ] =
plot->canvasMap( QwtPlot::xTop ).invTransform( pos.x() );
coords[ QwtPlot::yLeft ] =
plot->canvasMap( QwtPlot::yLeft ).invTransform( pos.y() );
coords[ QwtPlot::yRight ] =
plot->canvasMap( QwtPlot::yRight ).invTransform( pos.y() );
QwtPlotItemList items = plot->itemList();
for ( int i = items.size() - 1; i >= 0; i-- )
{
QwtPlotItem *item = items[ i ];
if ( item->isVisible() &&
item->rtti() == QwtPlotItem::Rtti_PlotShape )
{
QwtPlotShapeItem *shapeItem = static_cast<QwtPlotShapeItem *>( item );
const QPointF p( coords[ item->xAxis() ], coords[ item->yAxis() ] );
if ( shapeItem->boundingRect().contains( p )
&& shapeItem->shape().contains( p ) )
{
return shapeItem;
}
}
}
return NULL;
}
主要是将 QwtPlotShapeItem 改成QwtPlotSeriesItem;具体实现到下面的链接下载