QGraphicsObject: ContextMenu does not show up
-
I have a class derived from
QGraphicsObject
like this:class Room : public QGraphicsObject { Q_OBJECT public: //... public: QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; //.... }
painting ect works already. Just the contextMenu does not show up. I implemented it like this:
void Room::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QAction guessWumpusAction{tr("&Has Wumpus")}; guessWumpusAction.setCheckable(true); connect(&guessWumpusAction, &QAction::triggered, this, &Room::guessWumpus); QAction guessBatAction{tr("&Has Bat")}; if (mHasBat) { guessBatAction.setChecked(true); guessBatAction.setEnabled(false); } else { guessBatAction.setCheckable(true); } connect(&guessBatAction, &QAction::triggered, this, &Room::guessBat); QAction guessPitAction{tr("&Has Pit")}; guessPitAction.setCheckable(true); connect(&guessPitAction, &QAction::triggered, this, &Room::guessPit); QMenu menu; menu.addAction(&guessWumpusAction); menu.addAction(&guessBatAction); menu.addAction(&guessPitAction); menu.popup(event->screenPos()); qDebug() << event->screenPos(); }
I can see that the event is called on mouse right click on the widget as expected. However the context Menu does not pop up. Whats wrong here?
For test i call the class like this:
#include <QApplication> #include "room.h" #include <QGraphicsView> #include <QGraphicsScene> int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; QGraphicsView view; view.setScene(&scene); auto room = new Room; room->setVisible(true); scene.addItem(room); view.show(); return QApplication::exec(); }
-
@sandro4912
Two guesses:
Are your co-ordinates right inmenu.popup(event->screenPos())
(no mapping needed, I don't know)?
YourQMenu menu
goes out of scope immediately afterpopup()
(notexec()
)? You would need outside storage if you want to usepopup()
; test it withexec()
instead? (I think it's this regardless of first point.) -
I added
exec
and now it shows up. I could swear i saw an example with onlypopup
. However now that it shows up it is only is triggered when I right click in the first 1/4 of the widget.(like if the widget has half the height and width.I define
boundingRect
like this:QRectF Room::boundingRect() const { return QRectF{ QPointF{0, 0}, roomImage().size()}; }
were
roomImage
is a ressource:QImage Room::roomImage() const { return QImage{":/ressources/room.png"}; }
to paint i do this:
void Room::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) drawRoom(painter); }
void Room::drawRoom(QPainter *painter) { painter->drawImage(boundingRect(), roomImage()); }
-
@sandro4912
popup()
can be used, but not with a stack variableQMenu
like you had. Usually you'dnew
it.For the area now: does
":/ressources/room.png"
match how you spellresources
on disk? Or you need to look atroomImage().size()
. -
if i create menu dynamically who deallocates it later? I can't assign the
Room
to it as a parent since is not derrived fromQWidget
.Also i tryed:
void Room::drawRoom(QPainter *painter) { qDebug() << boundingRect(); qDebug() << roomImage().size(); painter->drawImage(boundingRect(), roomImage()); }
Which outputs:
QRectF(0,0 100x100) QSize(100, 100)
So it should theoretically pop the menu in the whole image but it doesn't?
-
Hi,
Make it a member variable and delete it in your class destructor.
-
@sandro4912
For dynamically createdQMenu
, then as @SGaist says.But are you sure you need
QMenu:popUp()
and not justQMenu::exec()
for your use case? It depends how you want it to work. If the simpleexec()
suffices you should be able to just use a stack (local) variableQMenu menu
. You don't need the menu after it has returned the action the user clicked.For your coordinates/click area, I don't think we're going to know. Is your image indeed 100x100 size, or is that maybe some default? Why don't you play with a bigger/smaller image and see what the pattern is?
-
there is nothing wrong with the image but to sort it out i did this:
void Room::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QRectF rect{boundingRect()}; painter->setPen(Qt::black); painter->drawRect(rect); }
QRectF Room::boundingRect() const { return QRectF{ 0, 0, 200, 200}; }
Still the Menu is not popped up on the whole rect. It only appeas like on 1/3 of the size of
QRectF{ 0, 0, 200, 200};
so is not always half. DoescontextMenuEvent
maybe check the size from somewhere else but not from theboundingRect
? Or is this simply a bug in QT?I also compiled the code an a second OS to sort out that its not annother bug with KDE/Neon. But on Windows 10 same behaviour.
Also I stayed with the local Menu:
void Room::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { qDebug() << boundingRect(); qDebug() << roomImage().size(); QMenu menu; menu.addAction(mGuessWumpusAction); menu.addAction(mGuessBatAction); menu.addAction(mGuessPitAction); menu.exec(event->screenPos()); }
Any more ideas??
-
let me know if you need more information to find a solution for this issue. Maybe is even a qt bug.
-
@sandro4912 said in QGraphicsObject: ContextMenu does not show up:
Still the Menu is not popped up on the whole rect. It only appeas like on 1/3 of the size of QRectF{ 0, 0, 200, 200}; so is not always half. Does contextMenuEvent maybe check the size from somewhere else but not from the boundingRect ?
I don't understand what you say here - does the popup / context menu event only works on 1/3 of your widget? Is the popup not as big as you expect?
-
the popup itself looks perfect.
The problem is it does not get triggered in the whole 200x200 area of the widget. It only looks like it gets shown in a smaller rectangle from the top left point.
so in 200x200 maybe only in 80x80 from top left point it gets created.
I would expect in the whole rectangle the context menu gets triggere.
maybe i should make a minimal running example so it can be verifyed.
-
Ok, now it's clear to me. There are two examples (diagramscene, boxes) which work fine for me. Maybe you can try them out.
-
I made a minimal program and it works:
#ifndef RECTANGLE_H #define RECTANGLE_H #include <QGraphicsObject> class Rectangle : public QGraphicsObject { Q_OBJECT public: explicit Rectangle(QGraphicsObject *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; }; #endif // RECTANGLE_H
#include "rectangle.h" #include <QGraphicsSceneContextMenuEvent> #include <QPainter> #include <QMenu> Rectangle::Rectangle(QGraphicsObject *parent) : QGraphicsObject(parent) { } QRectF Rectangle::boundingRect() const { return QRectF{ 0, 0, 100, 100}; } void Rectangle::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) QRectF rect{boundingRect()}; painter->setPen(Qt::black); painter->drawRect(rect); } void Rectangle::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction("Action 1"); menu.addAction("Action 2"); menu.exec(event->screenPos()); }
#include "rectangle.h" #include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; Rectangle rectangle; scene.addItem(&rectangle); QGraphicsView view; view.setScene(&scene); view.show(); return QApplication::exec(); }
Everything fine here the popup shows up in all the widget. The reason it does not work in my programm is. At some point i changed the class from
QGraphicsObject
toQGraphicsWidget
. If we modify the minimal programm to haveQGraphicsWidget
as a base forRectangle
we get the Issue again:#ifndef RECTANGLE_H #define RECTANGLE_H #include <QGraphicsWidget> class Rectangle : public QGraphicsWidget { Q_OBJECT public: explicit Rectangle(QGraphicsWidget *parent = nullptr); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; }; #endif // RECTANGLE_H
#include "rectangle.h" #include <QGraphicsSceneContextMenuEvent> #include <QPainter> #include <QMenu> Rectangle::Rectangle(QGraphicsWidget *parent) : QGraphicsWidget(parent) { } QRectF Rectangle::boundingRect() const { return QRectF{ 0, 0, 100, 100}; } void Rectangle::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) QRectF rect{boundingRect()}; painter->setPen(Qt::black); painter->drawRect(rect); } void Rectangle::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction("Action 1"); menu.addAction("Action 2"); menu.exec(event->screenPos()); }
#include "rectangle.h" #include <QApplication> #include <QGraphicsScene> #include <QGraphicsView> int main(int argc, char *argv[]) { QApplication app(argc, argv); QGraphicsScene scene; Rectangle rectangle; scene.addItem(&rectangle); QGraphicsView view; view.setScene(&scene); view.show(); return QApplication::exec(); }
So why is the behaviour different with
QGraphicWidget
? How can it get fixed there? -
You forgot to set a proper size of the QGraphicsWidget: https://doc.qt.io/qt-5/qgraphicswidget.html#size-prop - since it's a widget you have to treat it like a widget which also means you have to set a proper size since there is no layout from where the size could be calculated from.
-
I solved the issue by resize in the constructor:
resize(boundingRect().size());
That should be it or any other things to concern?
-
@sandro4912 said in QGraphicsObject: ContextMenu does not show up:
That should be it or any other things to concern?
That's fine.