Access coordinates from the parent of a widget - c++

I have a QGraphicsView inside the MainWindow that has implemented a QGraphicScene. I need to pop up a widget when I right click the mouse on a certain portion of the QGraphicScene. The parent of the widget needs to be MainWindow.
My problem is that I need to verify the validity of the portion on witch I clicked inside a mousePressEvent in QGraphicScene and to pop up the widget at the exact same location but the coordinates of the QGraphicScene and MainWindow are obvious not the same. For that I use a custom signal that trigger a slot inside MainWindow and get the coordinates from the mousePressEvent of the MainWindow. The problem is that the mouseEvent from the QGraphicsScene is triggered before the mouseEvent from MainWindow. This makes perfect sense and works if I right click twice but I need it to work from the first right click.
I can not implement a filter or change the focus because I have tons of events in the application.
QGraphicScene:
void CGraphicScene :: mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(event -> button() == Qt::RightButton)
{
//test stuff
emit signalChangeContextualMenuPosition();
m_contextualMenu -> show();
}
}
MainWindow:
CGraphicScene *scene;
CContextualMenu *m_contextualMenu;
m_contextualMenu = new CContextualMenu(this);
m_contextualMenu ->close();
scene = new CGraphicScene(m_contextualMenu);
ui->gvInterface -> setScene(scene);
connect(scene, SIGNAL(signalChangeContextualMenuPosition()), this, SLOT(openPopUp()));
void MainWindow :: openPopUp()
{
m_contextualMenu ->move(m_xCoordPopMenu, m_yCoordPopMenu);
}
void MainWindow :: mousePressEvent(QMouseEvent *event)
{
if(event -> button() == Qt::RightButton)
{
m_xCoordPopMenu = event -> x();
m_yCoordPopMenu = event -> y();
}
}

Use the QGraphicsView::mapFromScene() to map scene coordinates to the view widget coordinates and then QWidget::mapToParent() to map the coordinates to it's parent widget, which is probably your main window. You can also find useful the method QWidget::mapTo().

Related

How to create Mouse right click menu option using eventFilter in Qt?

I have a QGraphicsView which contains many QGraphicsItem. If I click mouse right click on any QGraphicsItem, the item should get select and right menu options should appear and then I will choose one of the options among them.To do that I have installed eventFilter and through it, I am using ContextMenu to create right click menu. Right click menu are getting cretaed properly. But propblem is I am not getting how to connect them to some function so that I can write logic for it.
It means if I clicked on save option that particular QGraphicsItem should get select and I should be able to go to some function where I will write logic for saving.
bool myClass::eventFilter(QObject *watched, QEvent *event)
{
switch(event->type())
{
case QEvent::ContextMenu:
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
menu = new QMenu(this);
option = menu->addMenu("CopyOption");
option->addAction("save");
menu->exec(mouseEvent->globalPos());
break;
}
default:
break;
}
}
In your approach you show a context menu when you have no information if any item is selected. It is rather bad idea. You don't want to show the context menu in any location of view. You have to check if a cursor mouse is over an item.
Why not to derive from QGraphicsItem and just overload mousePressEvent method. Inside this method check if right button of mouse is clicked. If so, show context menu and test which action is clicked. Minimal code would be:
class TItem : public QGraphicsItem
{
bool _selected = false;
public:
TItem(QGraphicsItem* parent = nullptr) : QGraphicsItem(parent) {}
QRectF boundingRect() const override { return QRectF(0,0,20,20); }
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override {
painter->fillRect(QRectF(0,0,20,20),_selected ? QColor(0,255,255) : QColor(255,255,0));
}
void mousePressEvent(QGraphicsSceneMouseEvent* e) override {
QGraphicsItem::mousePressEvent(e);
if (e->button() & Qt::RightButton) {
QMenu menu;
QAction* a1 = menu.addAction(QString("test1"));
QAction* a2 = menu.addAction(QString("test2"));
if(a2 == menu.exec(e->screenPos())) {
test2();
_selected = true;
update();
}
}
}
void test2() {
QMessageBox::information(nullptr,"test2","test2");
}
};
All the job with checking is an item is under mouse is done by QT, mousePressEvent is invoked only if it is necessary.
Another approach would be override mousePressEvent on QGraphicsView. Inside which:
get all items belonging to the scene
iterate over them, checking if an item is under mouse -> QGraphicsItem has isUnderMouse method
if any item is under mouse, create QMenu and show it
check selected QAction, if it is save call a proper method which doing the save and mark the item as selected

Qt mouseMoveEvent not firing when mouse pressed

I have a custom QGraphicsScene in which I have a mouseMoveEvent(QGraphicsSceneMouseEvent *event);
When I hover on the scene with the mouse, the mouseMoveEvent gets properly fired. However when I hover with a mouse button pressed, then it does not get fired anymore.
This is how I setup the whole scene in the main window:
scene = new NodeScene(this); -> My Custom QGraphicsScene class
scene->setSceneRect(QRectF(0, 0, 5000, 5000));
QHBoxLayout *layout = new QHBoxLayout;
view = new QGraphicsView(scene);
layout->addWidget(view);
view->setDragMode(QGraphicsView::RubberBandDrag);
view->setMouseTracking(true);
QWidget *widget = new QWidget;
widget->setLayout(layout);
setCentralWidget(widget);
scene->setCentralWidget(widget);
And here is the code where I do handle mouse events (it's for Maya execution):
void NodeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Move");
QGraphicsScene::mouseMoveEvent(event);
}
void NodeScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Press");
QGraphicsScene::mousePressEvent(event);
}
void NodeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Release");
QGraphicsScene::mouseReleaseEvent(event);
}
Any idea how I can get the mouseMoveEvents even when a mouse button is pressed ?
It sounds like you're not implementing all of the mouse events, just the mouseMoveEvent.
When overriding a mouse event, you should handle all of them (move, press and release events).
You can then set a boolean in the press event to know whether or not the mouse button is held down when entering the mouseMove event.
Found the issue by comparing my code to other examples, and it is due to the setDragMode(QGraphicsView::RubberBandDrag);
line. The code should by default be on QGraphicsView::NoDrag and the RubberBandDrag be enabled only upon press.

How to get QGridLayout item by clicked QPoint?

I have grid of QFrames in QGridLayout and a popup menu with some actions, which are targeted on the cell where mouse right click happens. On the implementation of ContextMenuEvent I get clicked QPoint using common event->pos() but how I get access to my correct cell object by that point? Or is there some better alternative solution path for this purpose?
void X::contextMenuEvent(QContextMenuEvent* event)
{ // QPoint target = event->pos();
// TODO: m_gridLayout-> ...
// myDerivedCell->setSomething();
}
There are a bunch of solutions here. The simplest is to go through your widgets, calling bool QWidget::underMouse () const. My favorite is this:
frame_i->setContextMenuPolicy(Qt::CustomContextMenu);
connect(frame_i, SIGNAL(customContextMenuRequested(QPoint))
, SLOT(onContextMenu(QPoint)));
...
void X::onContextMenu(const QPoint &pos)
{
QFrame *w = qobject_cast < QFrame * >(sender());
...
}

Click event for QGraphicsView Qt

I have made a GUI in Qt that is basically a widget with a QGraphicsView on it i have a function:
void GUI::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
QPointF mousePoint = ui->graphicsView->mapToScene(event->pos());
qDebug() << mousePoint;
}
}
which links to a public slot:
void mousePressEvent(QMouseEvent *event);
this shows me on the console the x,y coordinate of where i have clicked, however currently this is working on the entire widget and i ideally would like x,y(0,0) to be the top left of the QGraphicsView instead of the top left of the entire widget. does anyone have any idea how to make this work, i thought from my code that this is what it was doing but it turns out this is not so, iv had a look around for a while now but im coming up with nothing
any help would be really appreciated thanks.
Reimplement the mousePressEvent(QMouseEvent *event) of the QGraphicsView not your widget would be the 'proper' way of doing it. Otherwise you can hack it with:
// Detect if the click is in the view.
QPoint remapped = ui->graphicsView->mapFromParent( event->pos() );
if ( ui->graphicsView->rect().contains( remapped ) )
{
QPointF mousePoint = ui->graphicsView->mapToScene( remapped );
}
This assumes that the widget is the parent of the QGraphicsView.

Remove scroll functionality on mouse wheel QGraphics view

I have a QGraphicsView window on my widget and have just put in an event for mouse wheel which zooms in on the image.
However as soon as i zoom in scroll bars are displayed and the scroll functionality on the mouse wheel overrides the zoom function i have.
i was wondering if there is any way that i can remove scrolling all together and add a drag to move option or maybe a CTRL and mouse wheel to zoom and mouse wheel alone would control scrolling
here is my zoom function (Which im aware isnt perfect) but if anyone could shed some light on that it would be a bonus
cheers in advance
void Test::wheelEvent(QWheelEvent *event)
{
if(event->delta() > 0)
{
ui->graphicsView->scale(2,2);
}
else
{
ui->graphicsView->scale(0.5,0.5);
}
}
You reimplemented wheelEvent for QWidget/QMainWindow that contains your QGraphicsView, however, wheelEvent of QGraphicsView remains intact.
You can derive from QGraphicsView, reimplement wheelEvent for derived class and use derive class instead of QGraphicsView - this way you won't even need wheelEvent in your QWidget/QMainWindow, and you can customize reimplemented wheelEvent to do what you want. Something like that:
Header file:
class myQGraphicsView : public QGraphicsView
{
public:
myQGraphicsView(QWidget * parent = nullptr);
myQGraphicsView(QGraphicsScene * scene, QWidget * parent = nullptr);
protected:
virtual void wheelEvent(QWheelEvent * event);
};
Source file:
myQGraphicsView::myQGraphicsView(QWidget * parent)
: QGraphicsView(parent) {}
myQGraphicsView::myQGraphicsView(QGraphicsScene * scene, QWidget * parent)
: QGraphicsView(scene, parent) {}
void myQGraphicsView::wheelEvent(QWheelEvent * event)
{
// your functionality, for example:
// if ctrl pressed, use original functionality
if (event->modifiers() & Qt::ControlModifier)
{
QGraphicsView::wheelEvent(event);
}
// otherwise, do yours
else
{
if (event->delta() > 0)
{
scale(2, 2);
}
else
{
scale(0.5, 0.5);
}
}
}
Scrolling can be disabled with the following code:
ui->graphicsView->verticalScrollBar()->blockSignals(true);
ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->graphicsView->horizontalScrollBar()->blockSignals(true);
ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
I think your question has a bit simpler answer.. To disable scroll bars just set scroll bar policy (QGraphicsView is just QScrollView), so step 1)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
that will disable scroll bars..
step 2) (if you want to keep it simple)
QGraphicsView * pView; // pointer to your graphics view
pView->setInteractive(true);
pView->setDragMode(QGraphicsView::ScrollHandDrag);
thats the fastest way to get results you want