如何解决:自定义QGraphics项目接收鼠标新闻事件坐标延迟/滞后?

How to fix: custom QGraphicsItem receiving mousePressEvent coordinates late/laggy?

本文关键字:事件 新闻 鼠标 坐标 延迟 滞后 项目 何解决 解决 QGraphics 自定义      更新时间:2023-10-16

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

一切都在工作,除了...第二次及以后我按下左(或任何(鼠标按钮,mousePressEvent 的 QGraphicsSceneMouseEvent 按钮 DownScenePos 中报告的坐标是"过时的" - 与上次鼠标单击相同,而不是新单击发生时鼠标所在的新位置。 鼠标发布事件报告按预期进行坐标。

有没有办法让鼠标按下事件的按钮向下场景与单击时鼠标的实际位置保持同步,而不是以前的鼠标位置?

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

相关代码:

主窗口.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

板场景.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 );
}
}

板直角.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

板直.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();
}

在运行后的第一次单击中,报告的坐标与单击鼠标的网格上的位置非常吻合,无论是新闻还是发布 - 它们都显示按钮的位置。

但是,在第二次及以后的单击中,mousePressEvent 报告与上一个 mousePress 和 Release 事件相同的坐标,而 mouseReleaseEvent 报告当前事件中鼠标按钮"下降"的坐标。

最后一点奇怪:当向左单击,然后向右单击,然后再次向左单击时,mousePressEvent 报告的第二次左键单击坐标是上一次左键单击坐标,跳过右键单击坐标以返回到鼠标按钮在最后一次左键单击时下降的位置。

有什么想法吗? 谢谢。

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

QGraphicsSceneMouseEvent::buttonDownPos(Qt::MouseButton button)

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

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

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