Как исправить: пользовательский QGraphicsItem получает координаты mousePressEvent поздно / с задержкой?
У меня есть "стандартное" приложение Qt5 QWidgets с MainWindow, которое включает QGraphicsView в mainwindow.ui, созданном в QtCreator. Этот QGraphicsView имеет свою сцену, установленную на простой подкласс QGraphicsScene, который имеет большой прямоугольник на заднем плане, который является подклассом QGraphicsRectItem, который повторно реализует обработчики mousePressEvent() и mouseReleaseEvent() QGraphicsRectItem. Работает на Ubuntu 18.04, что не имеет значения, но на всякий случай...
Все работает, кроме... 2-го и более поздних раз, когда я нажимаю левую (или любую) кнопку мыши, координаты, указанные в QGraphicsSceneMouseEvent buttonDownScenePos в mousePressEvent, являются "устаревшими" - такими же, как и предыдущий щелчок мыши, а не новое место, где мышь - это когда произошел новый щелчок. MouseReleaseEvent сообщает координаты, как и ожидалось.
Есть ли способ заставить buttonDownScenePos события mousePressEvent оставаться в курсе фактического положения мыши при щелчке вместо предыдущего местоположения мыши?
Мне кажется, что я уже сталкивался с подобной проблемой в прошлом, которая имела какое-то отношение к обработке двойного щелчка, когда событие сообщается до того, как он узнает, произошел ли двойной щелчок или нет. В этом случае события двойного щелчка не важны, но было бы неплохо иметь возможность реагировать на одиночный щелчок, как только он произойдет, вместо ожидания события выпуска.
Соответствующий код:
mainwindow.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
mainwindow.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()
{ }
Boardcene.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
Boardcene.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 для 2-го щелчка левой кнопкой мыши, является предыдущей координатой щелчка левой кнопкой мыши, пропуская координату щелчка правой кнопкой мыши, чтобы вернуться туда, где кнопка мыши была нажата на последнем левом клике.
Есть идеи? Спасибо.
2 ответа
QGraphicsSceneMouseEvent::buttonDownPos(Qt::MouseButton button)
Возвращает положение курсора мыши в координатах элемента, в котором была нажата указанная кнопка.
Он возвращает координаты графического элемента, на который вы нажимаете (как сказано в документации). Может быть, вы просто щелкаете в том же месте? Если вам нужна позиция сцены, просто используйтеmapToScene
или QGraphicsSceneMouseEvent::buttonDownScenePos(Qt::MouseButton button)
или event->scenePos()
.
PS. и использоватьQPointF::x()
а также QPointF::y()
вместо того rx()
а также ry()
. Вам не нужна ссылка и манипулировать позицией.
У меня есть приложение, использующее те же компоненты: qgraphicsview и qgraphicsscene, состоящее из некоторого количества qgraphicsitems. Это виртуальная MIDI-клавиатура для фортепиано на случай, если вы захотите взглянуть на код. В моем случае все qgraphicsitems (клавиши пианино) имеютsetAcceptedMouseButtons(Qt::NoButton)
, а события мыши обрабатываются на уровне сцены, а не на уровне графического элемента. Я никогда не наблюдал такой проблемы, как ваша.