QWidget::mousePressEvent() not called
-
I'm working on a TreeViewNode class derived from QObject and QGraphicsItem, responsible for creating the individual nodes of the tree view (which displays a family tree) and adding them to the scene. I made sure to include the
setFlag(QGraphicsItem::ItemIsSelectable);method in the class constructor and I overloaded mousePressEvent like so:void TreeViewNode::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { qDebug() << "Mouse pressed on node: " << m_node->getPatient()->get_Name().c_str(); emit clicked(this); } QGraphicsItem::mousePressEvent(event); }The clicked signal is defined in the header file as
void clicked(TreeViewNode* node);
Then I have aupdateSelectedPatientslot in MainWindowvoid MainWindow::updateSelectedPatient(TreeViewNode* node) { selected->setSelectedPatient(node->getNode()->getPatient()); }and the corresponding connect statement in the MainWindow constructor
connect(treeView, &TreeViewNode::clicked, this, &MainWindow::updateSelectedPatient);When I execute I see the nodes that have been added to the scene in the view but when I click on them nothing happens (I know through debugging and also because the setSelectedPatient() method updates a widget that shows the patient information of the currently selected patient); it seems like mousePressEvent() is not being called at all.. any help would be really appreciated, thank you for your time!
-
I'm working on a TreeViewNode class derived from QObject and QGraphicsItem, responsible for creating the individual nodes of the tree view (which displays a family tree) and adding them to the scene. I made sure to include the
setFlag(QGraphicsItem::ItemIsSelectable);method in the class constructor and I overloaded mousePressEvent like so:void TreeViewNode::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { qDebug() << "Mouse pressed on node: " << m_node->getPatient()->get_Name().c_str(); emit clicked(this); } QGraphicsItem::mousePressEvent(event); }The clicked signal is defined in the header file as
void clicked(TreeViewNode* node);
Then I have aupdateSelectedPatientslot in MainWindowvoid MainWindow::updateSelectedPatient(TreeViewNode* node) { selected->setSelectedPatient(node->getNode()->getPatient()); }and the corresponding connect statement in the MainWindow constructor
connect(treeView, &TreeViewNode::clicked, this, &MainWindow::updateSelectedPatient);When I execute I see the nodes that have been added to the scene in the view but when I click on them nothing happens (I know through debugging and also because the setSelectedPatient() method updates a widget that shows the patient information of the currently selected patient); it seems like mousePressEvent() is not being called at all.. any help would be really appreciated, thank you for your time!
@nance97 said in QWidget::mousePressEvent() not called:
I'm working on a TreeViewNode class derived from QObject and QGraphicsItem,
Another option is to inherit from QGraphicsObject.
I made sure to include the
setFlag(QGraphicsItem::ItemIsSelectable);method in the class constructor and I overloaded mousePressEvent like so:void TreeViewNode::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { qDebug() << "Mouse pressed on node: " << m_node->getPatient()->get_Name().c_str();Making the item selectable isn't necessary to receive mouse events. In the following example, the left half of the item receives mouse presses because that falls within the area reported by QGraphicsItem::shape(). The right half of the text is displayed, but does not respond to clicks.
class Item : public QGraphicsTextItem { Q_OBJECT protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) { qDebug() << "mousePressEvent" << event->pos(); } public: Item(QGraphicsItem *parent = nullptr): QGraphicsTextItem(parent) { setPlainText("A|B"); setFlag(QGraphicsItem::GraphicsItemFlag::ItemIsSelectable, false); } QPainterPath shape() const { QPainterPath path; QRectF rect = boundingRect(); rect.setWidth(rect.width() / 2); path.addRect(rect); return path; } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; QGraphicsView view(&scene); Item item; scene.addItem(&item); view.show(); return a.exec(); } -
@nance97 said in QWidget::mousePressEvent() not called:
I'm working on a TreeViewNode class derived from QObject and QGraphicsItem,
Another option is to inherit from QGraphicsObject.
I made sure to include the
setFlag(QGraphicsItem::ItemIsSelectable);method in the class constructor and I overloaded mousePressEvent like so:void TreeViewNode::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { qDebug() << "Mouse pressed on node: " << m_node->getPatient()->get_Name().c_str();Making the item selectable isn't necessary to receive mouse events. In the following example, the left half of the item receives mouse presses because that falls within the area reported by QGraphicsItem::shape(). The right half of the text is displayed, but does not respond to clicks.
class Item : public QGraphicsTextItem { Q_OBJECT protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) { qDebug() << "mousePressEvent" << event->pos(); } public: Item(QGraphicsItem *parent = nullptr): QGraphicsTextItem(parent) { setPlainText("A|B"); setFlag(QGraphicsItem::GraphicsItemFlag::ItemIsSelectable, false); } QPainterPath shape() const { QPainterPath path; QRectF rect = boundingRect(); rect.setWidth(rect.width() / 2); path.addRect(rect); return path; } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QGraphicsScene scene; QGraphicsView view(&scene); Item item; scene.addItem(&item); view.show(); return a.exec(); } -
@jeremy_k thank you, I ended up deriving TreeViewNode from QGraphicsObject but its overriden version of mousePressEvent still doesn't get triggered when clicking the nodes in the view; I might have to consider a different solution
@nance97 said in QWidget::mousePressEvent() not called:
I might have to consider a different solution
You dont have to, since it's the right way. Both ways (
QGraphicsObjectsubclass or custom class derived fromQGraphicsItemandQObject, which actually is the same asQGraphicsObject) should work.Maybe you can post the whole class, since there must be something going on, so that you dont receive click events
Eventually aboundingRectissue, as mentioned by @jeremy_k or something else... -
@nance97 said in QWidget::mousePressEvent() not called:
I might have to consider a different solution
You dont have to, since it's the right way. Both ways (
QGraphicsObjectsubclass or custom class derived fromQGraphicsItemandQObject, which actually is the same asQGraphicsObject) should work.Maybe you can post the whole class, since there must be something going on, so that you dont receive click events
Eventually aboundingRectissue, as mentioned by @jeremy_k or something else... -
@nance97 said in QWidget::mousePressEvent() not called:
I might have to consider a different solution
You dont have to, since it's the right way. Both ways (
QGraphicsObjectsubclass or custom class derived fromQGraphicsItemandQObject, which actually is the same asQGraphicsObject) should work.Maybe you can post the whole class, since there must be something going on, so that you dont receive click events
Eventually aboundingRectissue, as mentioned by @jeremy_k or something else...@Pl45m4 said in QWidget::mousePressEvent() not called:
Maybe you can post the whole class
I'll do that since it's not too long and I really have no idea what is going on, thank you both for taking a look in the first place! Not shown is the mousePressEvent method declared protected in the header file and implemented as shown above, am I doing something blatantly wrong?
//TreeViewNode.h class TreeViewNode : public QGraphicsObject { Q_OBJECT private: node* m_node; Family_tree* m_family; QGraphicsScene* m_scene; static std::set<node*> addedNodes; public: TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene); TreeViewNode* getTreeViewNode(node* n); node* getNode() const; static void clearAddedNodes(); void updateNode(Patient& patient); QRectF boundingRect() const override; void drawBranches(QPainter* painter); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; }; ////TreeViewNode.cpp std::set<node*> TreeViewNode::addedNodes; TreeViewNode::TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene) : m_node(node), m_family(family), m_scene(scene) { setFlag(ItemIsFocusable); m_scene->addItem(this); addedNodes.insert(m_node); qDebug() << "Scene item count: " << m_scene->items().count(); if (m_node->getFather()) { auto father = m_node->getFather(); if (addedNodes.count(father) > 0) {return;} TreeViewNode* fatherNode = new TreeViewNode(m_node->getFather(), family, m_scene); fatherNode->setPos(-50, -100); } if (m_node->getMother()) { auto mother = m_node->getMother(); if (addedNodes.count(mother) > 0) {return;} TreeViewNode* motherNode = new TreeViewNode(m_node->getMother(), family, m_scene); motherNode->setPos(50, -100); } if (m_node->getSpouse()) { auto spouse = m_node->getSpouse(); if (addedNodes.count(spouse) > 0) {return;} TreeViewNode* spouseNode = new TreeViewNode(m_node->getSpouse(), family, m_scene); spouseNode->setPos(100, 0); } int childCount = 0; for (auto child : m_node->getChildren()) { if (addedNodes.count(child) > 0) {return;} TreeViewNode* childNode = new TreeViewNode(child, family, m_scene); childCount++; double xPos, yPos; xPos = pos().x() + 50 + 100 * (childCount - (m_node->getChildren().size() + 1) / 2.0); yPos = pos().y() + 100; childNode->setPos(xPos, yPos); } } TreeViewNode* TreeViewNode::getTreeViewNode(node* n) { for (auto item : m_scene->items()) { TreeViewNode* treeViewNode = dynamic_cast<TreeViewNode*>(item); if (treeViewNode && treeViewNode->getNode() == n) { return treeViewNode; } } return nullptr; } node* TreeViewNode::getNode() const { return m_node; } void TreeViewNode::clearAddedNodes() { addedNodes.clear(); } void TreeViewNode::updateNode(Patient& patient) { m_node->setPatient(patient); } QRectF TreeViewNode::boundingRect() const { return QRectF(); } void TreeViewNode::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) painter->drawEllipse(-25, -25, 50, 50); painter->drawText(QRectF(-25, -25, 50, 50), Qt::AlignCenter, QString::fromStdString(m_node->getPatient()->get_Name())); } -
@Pl45m4 said in QWidget::mousePressEvent() not called:
Maybe you can post the whole class
I'll do that since it's not too long and I really have no idea what is going on, thank you both for taking a look in the first place! Not shown is the mousePressEvent method declared protected in the header file and implemented as shown above, am I doing something blatantly wrong?
//TreeViewNode.h class TreeViewNode : public QGraphicsObject { Q_OBJECT private: node* m_node; Family_tree* m_family; QGraphicsScene* m_scene; static std::set<node*> addedNodes; public: TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene); TreeViewNode* getTreeViewNode(node* n); node* getNode() const; static void clearAddedNodes(); void updateNode(Patient& patient); QRectF boundingRect() const override; void drawBranches(QPainter* painter); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; }; ////TreeViewNode.cpp std::set<node*> TreeViewNode::addedNodes; TreeViewNode::TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene) : m_node(node), m_family(family), m_scene(scene) { setFlag(ItemIsFocusable); m_scene->addItem(this); addedNodes.insert(m_node); qDebug() << "Scene item count: " << m_scene->items().count(); if (m_node->getFather()) { auto father = m_node->getFather(); if (addedNodes.count(father) > 0) {return;} TreeViewNode* fatherNode = new TreeViewNode(m_node->getFather(), family, m_scene); fatherNode->setPos(-50, -100); } if (m_node->getMother()) { auto mother = m_node->getMother(); if (addedNodes.count(mother) > 0) {return;} TreeViewNode* motherNode = new TreeViewNode(m_node->getMother(), family, m_scene); motherNode->setPos(50, -100); } if (m_node->getSpouse()) { auto spouse = m_node->getSpouse(); if (addedNodes.count(spouse) > 0) {return;} TreeViewNode* spouseNode = new TreeViewNode(m_node->getSpouse(), family, m_scene); spouseNode->setPos(100, 0); } int childCount = 0; for (auto child : m_node->getChildren()) { if (addedNodes.count(child) > 0) {return;} TreeViewNode* childNode = new TreeViewNode(child, family, m_scene); childCount++; double xPos, yPos; xPos = pos().x() + 50 + 100 * (childCount - (m_node->getChildren().size() + 1) / 2.0); yPos = pos().y() + 100; childNode->setPos(xPos, yPos); } } TreeViewNode* TreeViewNode::getTreeViewNode(node* n) { for (auto item : m_scene->items()) { TreeViewNode* treeViewNode = dynamic_cast<TreeViewNode*>(item); if (treeViewNode && treeViewNode->getNode() == n) { return treeViewNode; } } return nullptr; } node* TreeViewNode::getNode() const { return m_node; } void TreeViewNode::clearAddedNodes() { addedNodes.clear(); } void TreeViewNode::updateNode(Patient& patient) { m_node->setPatient(patient); } QRectF TreeViewNode::boundingRect() const { return QRectF(); } void TreeViewNode::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) painter->drawEllipse(-25, -25, 50, 50); painter->drawText(QRectF(-25, -25, 50, 50), Qt::AlignCenter, QString::fromStdString(m_node->getPatient()->get_Name())); } -
@nance97
Always start by marking an overridden method asoverridein the header file, in case it does not exist or you have the signature wrong.... -
@JonB it is, like so
protected: void mousePressEvent(QGraphicsSceneMouseEvent* event) override; -
@Pl45m4 said in QWidget::mousePressEvent() not called:
Maybe you can post the whole class
I'll do that since it's not too long and I really have no idea what is going on, thank you both for taking a look in the first place! Not shown is the mousePressEvent method declared protected in the header file and implemented as shown above, am I doing something blatantly wrong?
//TreeViewNode.h class TreeViewNode : public QGraphicsObject { Q_OBJECT private: node* m_node; Family_tree* m_family; QGraphicsScene* m_scene; static std::set<node*> addedNodes; public: TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene); TreeViewNode* getTreeViewNode(node* n); node* getNode() const; static void clearAddedNodes(); void updateNode(Patient& patient); QRectF boundingRect() const override; void drawBranches(QPainter* painter); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; }; ////TreeViewNode.cpp std::set<node*> TreeViewNode::addedNodes; TreeViewNode::TreeViewNode(node* node, Family_tree* family, QGraphicsScene* scene) : m_node(node), m_family(family), m_scene(scene) { setFlag(ItemIsFocusable); m_scene->addItem(this); addedNodes.insert(m_node); qDebug() << "Scene item count: " << m_scene->items().count(); if (m_node->getFather()) { auto father = m_node->getFather(); if (addedNodes.count(father) > 0) {return;} TreeViewNode* fatherNode = new TreeViewNode(m_node->getFather(), family, m_scene); fatherNode->setPos(-50, -100); } if (m_node->getMother()) { auto mother = m_node->getMother(); if (addedNodes.count(mother) > 0) {return;} TreeViewNode* motherNode = new TreeViewNode(m_node->getMother(), family, m_scene); motherNode->setPos(50, -100); } if (m_node->getSpouse()) { auto spouse = m_node->getSpouse(); if (addedNodes.count(spouse) > 0) {return;} TreeViewNode* spouseNode = new TreeViewNode(m_node->getSpouse(), family, m_scene); spouseNode->setPos(100, 0); } int childCount = 0; for (auto child : m_node->getChildren()) { if (addedNodes.count(child) > 0) {return;} TreeViewNode* childNode = new TreeViewNode(child, family, m_scene); childCount++; double xPos, yPos; xPos = pos().x() + 50 + 100 * (childCount - (m_node->getChildren().size() + 1) / 2.0); yPos = pos().y() + 100; childNode->setPos(xPos, yPos); } } TreeViewNode* TreeViewNode::getTreeViewNode(node* n) { for (auto item : m_scene->items()) { TreeViewNode* treeViewNode = dynamic_cast<TreeViewNode*>(item); if (treeViewNode && treeViewNode->getNode() == n) { return treeViewNode; } } return nullptr; } node* TreeViewNode::getNode() const { return m_node; } void TreeViewNode::clearAddedNodes() { addedNodes.clear(); } void TreeViewNode::updateNode(Patient& patient) { m_node->setPatient(patient); } QRectF TreeViewNode::boundingRect() const { return QRectF(); } void TreeViewNode::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget) painter->drawEllipse(-25, -25, 50, 50); painter->drawText(QRectF(-25, -25, 50, 50), Qt::AlignCenter, QString::fromStdString(m_node->getPatient()->get_Name())); }@nance97 said in QWidget::mousePressEvent() not called:
QRectF TreeViewNode::boundingRect() const {
return QRectF();
}void TreeViewNode::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
Q_UNUSED(option)
Q_UNUSED(widget)
painter->drawEllipse(-25, -25, 50, 50);
painter->drawText(QRectF(-25, -25, 50, 50), Qt::AlignCenter, QString::fromStdString(m_node->getPatient()->get_Name()));
}This looks suspicious. Verify that your position and your
boundingRectare where you expect them to be.
You could start by painting theboundingRectand compare it with your drawn item. If you paint outside the item's boundings, you wont receive events, when clicking inside this area.There is a lot stuff going on, that is not needed or could/should be done "cleaner".
For example, aQGraphicsItem/-Objectdoesn't need to hold the scene as member, since you can access it any time withscene()
(https://doc.qt.io/qt-6/qgraphicsitem.html#scene) -
@nance97 said in QWidget::mousePressEvent() not called:
QRectF TreeViewNode::boundingRect() const {
return QRectF();
}void TreeViewNode::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
Q_UNUSED(option)
Q_UNUSED(widget)
painter->drawEllipse(-25, -25, 50, 50);
painter->drawText(QRectF(-25, -25, 50, 50), Qt::AlignCenter, QString::fromStdString(m_node->getPatient()->get_Name()));
}This looks suspicious. Verify that your position and your
boundingRectare where you expect them to be.
You could start by painting theboundingRectand compare it with your drawn item. If you paint outside the item's boundings, you wont receive events, when clicking inside this area.There is a lot stuff going on, that is not needed or could/should be done "cleaner".
For example, aQGraphicsItem/-Objectdoesn't need to hold the scene as member, since you can access it any time withscene()
(https://doc.qt.io/qt-6/qgraphicsitem.html#scene)@Pl45m4 said in QWidget::mousePressEvent() not called:
@nance97 said in QWidget::mousePressEvent() not called:
QRectF TreeViewNode::boundingRect() const {
return QRectF();
}This looks suspicious. Verify that your position and your
boundingRectare where you expect them to be.I would call it more than suspicious.
This pure virtual function defines the outer bounds of the item as a rectangle; all painting must be restricted to inside an item's bounding rect. QGraphicsView uses this to determine whether the item requires redrawing.
boundingRect() is also used for the default
QGraphicsItem::shape()The shape is used for many things, including collision detection, hit tests, and for the QGraphicsScene::items() functions.
The default implementation calls boundingRect() to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items. For example, a round item may choose to return an elliptic shape for better collision detection. -
@Pl45m4 said in QWidget::mousePressEvent() not called:
@nance97 said in QWidget::mousePressEvent() not called:
QRectF TreeViewNode::boundingRect() const {
return QRectF();
}This looks suspicious. Verify that your position and your
boundingRectare where you expect them to be.I would call it more than suspicious.
This pure virtual function defines the outer bounds of the item as a rectangle; all painting must be restricted to inside an item's bounding rect. QGraphicsView uses this to determine whether the item requires redrawing.
boundingRect() is also used for the default
QGraphicsItem::shape()The shape is used for many things, including collision detection, hit tests, and for the QGraphicsScene::items() functions.
The default implementation calls boundingRect() to return a simple rectangular shape, but subclasses can reimplement this function to return a more accurate shape for non-rectangular items. For example, a round item may choose to return an elliptic shape for better collision detection.@jeremy_k Adding this
QRectF TreeViewNode::boundingRect() const { return QRectF(-25, -25, 50, 50); }fixed it instantly.. such a silly mistake, it's almost as if I started learning about Qt last week.. (it's true).
What can I say, thank you so much to everyone for your time and your suggestions, I'll make sure to remove m_scene and use scene() as well and keep learning more in detail about the classes I'm using. Thank you!