使用橡皮筋选择在 QChartView 中选择 QLineSeries

Posted

技术标签:

【中文标题】使用橡皮筋选择在 QChartView 中选择 QLineSeries【英文标题】:Selecting QLineSeries in a QChartView using rubberband selection 【发布时间】:2018-05-21 12:13:42 【问题描述】:

我有一个 QChart,上面有许多 QLineSeries。

我创建了自己的图表类CPlotView,从 QChartView 派生并覆盖了 mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent,如下所示。

我想分别实现橡皮筋缩放和橡皮筋选择,我可以根据可检查的 QPushButtons 选择要执行的操作(代码未显示,但它只是 CPlotView 的一个成员,它包含一个枚举值,它定义了它所在的“模式” (缩放或选择)

void CPlotView::mousePressEvent(QMouseEvent *event)

     if(PlotRubberBand)
     
         if (PlotCursorMode == ECursorMode::eIsolate || PlotCursorMode == ECursorMode::eZoom)
         
             QRectF plotArea = chart()->plotArea();
             if (PlotRubberBand->isEnabled()
                 && event->button() == Qt::LeftButton
                 && plotArea.contains(event->pos()))
             

                 DrawRubberBand = true;
                 PlotRubberBandOrigin = event->pos();
                 PlotRubberBand->setVisible(true);
                 PlotRubberBand->setGeometry(QRect(PlotRubberBandOrigin, QSize()));
                 event->accept();
             
             QGraphicsView::mousePressEvent(event);

         
         else
         
             QChartView::mousePressEvent(event);
         
     

    QChartView::mousePressEvent(event);


void CPlotView::mouseMoveEvent(QMouseEvent *event)

    if (GetPlotCursorMode() == ECursorMode::eIsolate)
    
        if (DrawRubberBand && PlotRubberBand->isVisible())
        
            QRect rect = chart()->plotArea().toRect();
            int width = event->pos().x() - PlotRubberBandOrigin.x();
            int height = event->pos().y() - PlotRubberBandOrigin.y();

            PlotRubberBand->setGeometry(QRect(PlotRubberBandOrigin.x(), PlotRubberBandOrigin.y(), width, height).normalized());

        
        else
        
             QGraphicsView::mouseMoveEvent(event);
        
    
    else if (GetPlotCursorMode() == ECursorMode::eZoom)
    
        if (DrawRubberBand && PlotRubberBand->isVisible())
        
            QChartView::mouseMoveEvent(event);
        
        else
        
            QGraphicsView::mouseMoveEvent(event);
        
    
    else if (GetPlotCursorMode() == ECursorMode::eSelect)
    
        QGraphicsView::mouseMoveEvent(event);
    
    else
    
        QChartView::mouseMoveEvent(event);

    



void CPlotView::mouseReleaseEvent(QMouseEvent *event)

    if (PlotRubberBand->isVisible())
    
        if (PlotCursorMode == ECursorMode::eIsolate)
        
             DrawRubberBand = false;
             PlotRubberBand->setVisible(false);

            QGraphicsView::mouseReleaseEvent(event);

            QList<QGraphicsItem *> selected_items = QGraphicsView::items(PlotRubberBand->rect(), Qt::IntersectsItemShape);

            qDebug() << "found " << selected_items.size() << " items"; // this appears to show a number of items, but how do I detect which items are my data series, if any are?
            for (auto& item : selected_items)
            
                // detect which are my data series and highlight them as selected
            

        
        else
        
            DrawRubberBand = false;
            PlotRubberBand->setVisible(false);
            QChartView::mouseReleaseEvent(event);
        
    

我现在可以使用缩放模式 - 单击“缩放”模式按钮,然后将绘图上的橡皮筋拖动到该区域。单击选择模式按钮会绘制橡皮筋,但不会缩放。我现在想在选择模式下选择橡皮筋中的所有数据系列。

在选择模式下的mouseReleaseEvent 中,我试图在橡皮筋矩形内捕获所有选定的QGraphicsItems(我希望这是QGraphicsView::items(PlotRubberBand-&gt;rect(), Qt::IntersectsItemShape); 返回的内容),但我不知道如何检测我的数据系列(我实际上混合了 QLineSeries 和 QScatterSeries。

即使我没有将橡皮筋与我的任何数据相交,也有一些 QGraphicsItemsQGraphicsView::items(PlotRubberBand-&gt;rect(), Qt::IntersectsItemShape); 返回,因此它显然返回了场景中的其他一些项目。

我尝试对QGraphicsView::items 返回的内容执行dynamic_castQLineSeries,但这没有奏效。我忍不住想我让这件事变得比应该的更复杂。

UPDATE1:我也尝试过在橡皮筋选择过程中捕捉鼠标悬停在数据系列上时触发的信号:

connect(line_series, SIGNAL(hovered(const QPointF &, bool)), this, SLOT(OnDataHovered(const QPointF&, bool)));

但是当橡皮筋拖动时信号不会触发(也许当鼠标左键按下时它不会触发?)。 :(

更新 2: 我已尝试在 mouseReleaseEvent() 调用中设置 selectionArea,并且再次,有些返回为选中状态,远少于调用 QGraphicsView::items(),但不是我的系列据我所知:

void ewbearinghistorychart::CEwBearingHistoryChartView::mouseReleaseEvent(QMouseEvent *event)

    if (PlotRubberBand->isVisible())
    
        if (PlotCursorMode == ECursorMode::eIsolate)
        
            DrawRubberBand = false;
            PlotRubberBand->setVisible(false);
            QRect rubberband_rect = PlotRubberBand->rect();
            QGraphicsView::mouseReleaseEvent(event);

            // ************** new code **************
            QPolygonF p = chart()->mapToScene(PlotRubberBand->rect().normalized());
            QPainterPath path;
            path.addPolygon(p);
            chart()->scene()->setSelectionArea(path, Qt::IntersectsItemShape);
            QList<QGraphicsItem *> selected_items = chart()->scene()->selectedItems();
            qDebug() << "selected items: " << selected_items.size();
            // ************** /new code **************                
        
        else
        
            DrawRubberBand = false;
            PlotRubberBand->setVisible(false);
            QChartView::mouseReleaseEvent(event);
        
    

【问题讨论】:

【参考方案1】:

您遇到的问题是当启用橡皮筋模式时QChartView 重新实现MousePressEvent 并接受该事件。由于事件只向上传播,QLineSeriesQChartQChartView 的子级)永远不会得到备忘录。

解决办法是安装一个QEventFilter,这样就可以在QChartView接受之前拦截事件;但是,我还没有弄清楚如何检测它是否真的是被点击的QLineSeries

【讨论】:

【参考方案2】:

“我尝试将 QGraphicsView::items 返回的内容动态转换为 QLineSeries,但没有成功。”

这是我获得 QLineSeries 的 QGraphicsItem 表示的方法。

QChart        ch;
QLineSeries  srs;

QList<QGraphicsItem*> bfch.childItems();
ch.addSeries(&srs);
QList<QGraphicsItem*> afch.childItems();

QGraphicsItem * mf;

for(auto e: af)
    if(!bf.contains(e))
        mf = e;

qDebug().operator<<(mf->isUnderMouse());

【讨论】:

以上是关于使用橡皮筋选择在 QChartView 中选择 QLineSeries的主要内容,如果未能解决你的问题,请参考以下文章

如何在单词选择游戏中绘制橡皮筋或套索进行选择

coreldraw 怎么使用橡皮擦工具?我怎么老是擦不掉?

在coreldraw 里怎么用橡皮擦擦掉不需要的部分

cdr橡皮擦怎么越擦越多

强制QRubberBand具有特定的宽高比

GUI学习之二十二——QRubberBand学习总结