【问题标题】:How to fix: custom QGraphicsItem receiving mousePressEvent coordinates late/laggy?如何修复:自定义 QGraphicsItem 接收 mousePressEvent 坐标延迟/滞后?
【发布时间】:2020-01-28 16:59:09
【问题描述】:

我有一个“标准”Qt5 QWidgets 应用程序,其 MainWindow 包含在 QtCreator 中创建的 mainwindow.ui 中的 QGraphicsView。 QGraphicsView 将其场景设置为 QGraphicsScene 的一个简单子类,它在背景中有一个大矩形,它是 QGraphicsRectItem 的子类,它重新实现了 QGraphicsRectItem 的 mousePressEvent() 和 mouseReleaseEvent() 处理程序。在 Ubuntu 18.04 上运行,这无关紧要,但只是以防万一...

一切正常,除了...第二次和以后我按下左(或任何)鼠标按钮时,mousePressEvent 的 QGraphicsSceneMouseEvent buttonDownScenePos 中报告的坐标是“陈旧的” - 与之前的鼠标单击相同,而不是新点击发生时鼠标所在的新位置。 mouseReleaseEvent 按预期报告坐标。

有什么方法可以让 mousePressEvent 的 buttonDownScenePos 在点击时保持当前鼠标的实际位置,而不是之前的鼠标位置?

我觉得我过去处理过一个与双击处理有关的类似问题,即在知道是否发生双击之前报告事件。在这种情况下,双击事件并不重要,但如果能够在单击发生时立即响应,而不是等待释放事件,那就太好了。

相关代码:

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

class Board;
class BoardScene;
#include <QMainWindow>
#include <QPointer>
#include "board.h"
#include "boardscene.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{ Q_OBJECT
public:
    explicit  MainWindow(QWidget *parent = nullptr);
             ~MainWindow();
        void  drawBoard();

private:
     Ui::MainWindow *ui;
     QPointer<Board> board;
QPointer<BoardScene> boardScene;
};

#endif // MAINWINDOW_H

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    board      = new Board( this );
    boardScene = new BoardScene( board, this );
    ui->boardView->setScene( boardScene );
    ui->boardView->setDragMode( QGraphicsView::ScrollHandDrag );
    ui->boardView->scale( 40.0, 40.0 );
    drawBoard();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::drawBoard()
{ }

boardscene.h

#ifndef BOARDSCENE_H
#define BOARDSCENE_H

class Board;
#include <QGraphicsScene>
#include "board.h"
#include "boardrect.h"

class BoardScene : public QGraphicsScene
{ Q_OBJECT
public:
            BoardScene( Board *pbp, QObject *parent = nullptr );
      void  drawGrid();

     Board *bp;
    QBrush  backBrush,blackBrush,whiteBrush;
      QPen  linePen;
};

#endif // BOARDSCENE_H

boardscene.cpp

#include "boardscene.h"
#include <QGraphicsLineItem>
#include <QGraphicsRectItem>

BoardScene::BoardScene( Board *pbp, QObject *parent ) : QGraphicsScene ( parent )
{ bp = pbp;
  backBrush  = QBrush( QColor( 224,152, 64 ) );
  blackBrush = QBrush( QColor(   0,  0,  0 ) );
  whiteBrush = QBrush( QColor( 255,255,255 ) );
  linePen    = QPen  ( QColor(   0,  0,  0 ) );
  linePen.setWidth( 0 );
  drawGrid();
}

void BoardScene::drawGrid()
{ QGraphicsLineItem *lip;
  BoardRect *rip;
  setBackgroundBrush( blackBrush );
  rip = new BoardRect( QRectF( -2.0, -2.0, (qreal)(bp->Xsize +3), (qreal)(bp->Ysize + 3) ), nullptr );
  rip->setBrush( backBrush );
  rip->setPen( linePen );
  addItem( rip );

  for ( int x = 0; x < bp->Xsize; x++ )
    { lip = addLine( QLineF( (qreal)x, 0.0, (qreal)x, (qreal)(bp->Ysize - 1) ), linePen );
      lip->setAcceptedMouseButtons( Qt::NoButton );
    }
  for ( int y = 0; y < bp->Ysize; y++ )
    { lip = addLine( QLineF( 0.0, (qreal)y, (qreal)(bp->Xsize - 1), (qreal)y ), linePen );
      lip->setAcceptedMouseButtons( Qt::NoButton );
    }
}

boardrect.h

#ifndef BOARDRECT_H
#define BOARDRECT_H

#include <QGraphicsRectItem>
#include <QGraphicsSceneMouseEvent>


class BoardRect : public QGraphicsRectItem
{
public:
          BoardRect( const QRectF &rect, QGraphicsItem *parent = nullptr );
         ~BoardRect() {}

protected:
    void  mousePressEvent(QGraphicsSceneMouseEvent *event);
    void  mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};

#endif // BOARDRECT_H

boardrect.cpp

#include "boardrect.h"

BoardRect::BoardRect( const QRectF &rect, QGraphicsItem *parent ) : QGraphicsRectItem( rect, parent )
{}

void  BoardRect::mousePressEvent(QGraphicsSceneMouseEvent *event)
{ QString msg = QString("press %1 %2").arg(event->buttonDownScenePos(event->button()).rx())
                                      .arg(event->buttonDownScenePos(event->button()).ry());
  qDebug( qPrintable( msg ) );
  QGraphicsRectItem::mousePressEvent(event);
  event->accept();
}

void  BoardRect::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ QString msg = QString("release %1 %2").arg(event->buttonDownScenePos(event->button()).rx())
                                        .arg(event->buttonDownScenePos(event->button()).ry());
  qDebug( qPrintable( msg ) );
  QGraphicsRectItem::mousePressEvent(event);
  event->accept();
}

在运行后的第一次单击时,报告的坐标与网格上单击鼠标的位置非常吻合,无论是按下还是释放 - 它们都显示了按钮按下的位置。

但是,在第 2 次及以后的点击中,mousePressEvent 报告与之前的 mousePress 和 Release 事件相同的坐标,而 mouseReleaseEvent 报告当前事件中鼠标按钮“按下”的坐标。

最后一个奇怪的地方:当左击右击再左击时,mousePressEvent 报告的第二次左击的坐标是之前的左击坐标,跳过右击坐标回到鼠标所在的位置按钮在最后一次左键单击时按下。

有什么想法吗?谢谢。

【问题讨论】:

  • 我有一个问题,你想让鼠标按下哪个坐标?在屏幕的坐标中,还是在视口或场景的坐标中,或在项目的坐标中,等等? QGraphicsView 和 QGraphicsScene 处理不同的坐标系,阅读doc.qt.io/qt-5/graphicsview.html
  • 我想要场景坐标中的坐标,这就是我得到的,但只是以第 2 次及以后的按下事件描述的奇怪方式显示先前的 mouseDown 位置。 FWIW,Windows 10 中的行为完全相同。

标签: c++ qt qgraphicsitem qgraphicsrectitem


【解决方案1】:

我有一个使用相同组件的应用程序:一个 qgraphicsview 和一个由一些 qgraphicsitems 组成的 qgraphicsscene。这是一个virtual MIDI piano keyboard,以防您想查看代码。在我的例子中,所有的 qgraphicsitems(钢琴键)都有setAcceptedMouseButtons(Qt::NoButton),并且鼠标事件在场景级别而不是图形项目上处理。我从来没有发现像你这样的问题。

【讨论】:

    【解决方案2】:

    QGraphicsSceneMouseEvent::buttonDownPos(Qt::MouseButton button)

    返回鼠标光标在项目坐标中的位置,其中 指定的按钮被点击。

    它返回您单击的图形项的坐标(如文档所述)。也许你只是点击同一个地方? 如果你想要场景位置,只需使用mapToSceneQGraphicsSceneMouseEvent::buttonDownScenePos(Qt::MouseButton button)event-&gt;scenePos()

    PS。 并使用QPointF::x()QPointF::y() 而不是rx()ry()。您不需要参考和操纵位置。

    【讨论】:

      猜你喜欢
      • 2016-04-25
      • 2017-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多