How to dehighlight single and multiple items from QGraphicsScene in Qt?
-
I have a QGraphicsScene which has 100+ items. Sometimes I need to highlight and dehighlight multiple items.
Here is the code:
HighlightObject(QEvent* event) { //Finding object under cursor QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); QPointF mousePoint = _view->mapToScene(mouseEvent->pos()); QGraphicsItem* itemUnderClick = scene->itemAt(mousePoint, QTransform()); QGraphicsPathItem* polylineItem = qgraphicsitem_cast<QGraphicsPathItem*>(itemUnderClick); if (polylineItem ) { //polylineItem ->setFlag(QGraphicsItem::ItemIsSelectable);//I have set this flag while drawing polyline. polylineItem ->setSelected(true); QPen mPen(Qt::SolidLine); mPen.setWidth(1); polylineItem ->setPen(mPen); } }
My scene has 1 button which refreshes the scene. (which dehighlight all the items in the scene)
Refresh() { foreach (QGraphicsItem* currentItem, scene->items()) { myPoly* pItem = qgraphicsitem_cast<myPoly*>(currentItem); if (pItem) { pItem->setSelected(false); pItem->setPen(QPen(QColor("red")); // original color of polyline is red. } }
Above code works fine. But my scene has many elements so this Refresh() becomes costly.
So in Refresh() I tried :foreach (QGraphicsItem* currentItem, scene->selectedItems())
But above does not work for multiple selection. It means if I have selected 2 itms from the scene, and now I want to dehighlight both of them, then it always dehighlight 1 item.
I tried to print the value ofscene->selectedItems().size() => 1
So I want to :
1) Dehighlight multiple object. 2) To dehighlight 1 object, I do not want to iterate over all scene.
-
I have a QGraphicsScene which has 100+ items. Sometimes I need to highlight and dehighlight multiple items.
Here is the code:
HighlightObject(QEvent* event) { //Finding object under cursor QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); QPointF mousePoint = _view->mapToScene(mouseEvent->pos()); QGraphicsItem* itemUnderClick = scene->itemAt(mousePoint, QTransform()); QGraphicsPathItem* polylineItem = qgraphicsitem_cast<QGraphicsPathItem*>(itemUnderClick); if (polylineItem ) { //polylineItem ->setFlag(QGraphicsItem::ItemIsSelectable);//I have set this flag while drawing polyline. polylineItem ->setSelected(true); QPen mPen(Qt::SolidLine); mPen.setWidth(1); polylineItem ->setPen(mPen); } }
My scene has 1 button which refreshes the scene. (which dehighlight all the items in the scene)
Refresh() { foreach (QGraphicsItem* currentItem, scene->items()) { myPoly* pItem = qgraphicsitem_cast<myPoly*>(currentItem); if (pItem) { pItem->setSelected(false); pItem->setPen(QPen(QColor("red")); // original color of polyline is red. } }
Above code works fine. But my scene has many elements so this Refresh() becomes costly.
So in Refresh() I tried :foreach (QGraphicsItem* currentItem, scene->selectedItems())
But above does not work for multiple selection. It means if I have selected 2 itms from the scene, and now I want to dehighlight both of them, then it always dehighlight 1 item.
I tried to print the value ofscene->selectedItems().size() => 1
So I want to :
1) Dehighlight multiple object. 2) To dehighlight 1 object, I do not want to iterate over all scene.
@tushu said in How to dehighlight single and multiple items from QGraphicsScene in Qt?:
foreach (QGraphicsItem* currentItem, scene->selectedItems())
This principle ought work, but the problem may be (I don't know, I haven't tried) that this list changes dynamically, e.g. as you unhighlight the first item the second item becomes the first item but your loop then moves onto what was the third item which is now second, skipping what was second that is now first!
You could try taking a copy of
scene->selectedItems()
so that it does not change and iterate through that. Or use the "lazy trick" I sometimes do for this sort of "remove from iterating list" by counting down from the end to the beginning of the list, like:for (int i = scene->selectedItems().size() - 1; i >= 0; i--) scene->selectedItems()[i].setSelected(false);
If you want to deselect all selected items quickly don't forget there is QGraphicsScene::clearSelection()!
If you have a single graphics item pointer you want deselected you can of course just deselect that directly without any iteration.
-
@tushu said in How to dehighlight single and multiple items from QGraphicsScene in Qt?:
foreach (QGraphicsItem* currentItem, scene->selectedItems())
This principle ought work, but the problem may be (I don't know, I haven't tried) that this list changes dynamically, e.g. as you unhighlight the first item the second item becomes the first item but your loop then moves onto what was the third item which is now second, skipping what was second that is now first!
You could try taking a copy of
scene->selectedItems()
so that it does not change and iterate through that. Or use the "lazy trick" I sometimes do for this sort of "remove from iterating list" by counting down from the end to the beginning of the list, like:for (int i = scene->selectedItems().size() - 1; i >= 0; i--) scene->selectedItems()[i].setSelected(false);
If you want to deselect all selected items quickly don't forget there is QGraphicsScene::clearSelection()!
If you have a single graphics item pointer you want deselected you can of course just deselect that directly without any iteration.
@JonB Thank for your reply.
I tried what you have suggested. But it always showsscene->selectedItems().size() = 1
So I used
vector<QGraphicsItem*> currentSelectedObject;
And when I select object, I pushed it into currentSelectedObject and iterate over it when I want to deselect , selected items.
I tried slot QGraphicsScene::clearSelection() in above example but I could not implement it properly.
Can you help me in that ? -
@JonB Thank for your reply.
I tried what you have suggested. But it always showsscene->selectedItems().size() = 1
So I used
vector<QGraphicsItem*> currentSelectedObject;
And when I select object, I pushed it into currentSelectedObject and iterate over it when I want to deselect , selected items.
I tried slot QGraphicsScene::clearSelection() in above example but I could not implement it properly.
Can you help me in that ?@tushu
No, because I don't know what you are doing wrong, or what you are expecting that isn't happening. For example, ifscene->selectedItems().size() == 1
then there is only only selected object, yet you claim there are many.QGraphicsScene::clearSelection()
clears all selections, so I don't know what "I could not implement it properly" means or what your problem is or what it is not doing.I assume you would mention if you were using
QGraphicsItemGroup
s which might affect this. -
@tushu
No, because I don't know what you are doing wrong, or what you are expecting that isn't happening. For example, ifscene->selectedItems().size() == 1
then there is only only selected object, yet you claim there are many.QGraphicsScene::clearSelection()
clears all selections, so I don't know what "I could not implement it properly" means or what your problem is or what it is not doing.I assume you would mention if you were using
QGraphicsItemGroup
s which might affect this.@JonB Thank you for your response.
You are right. I am using
QGraphicsItemGroups
for my digital gates ( AND,NAND,NOT etc ) which containslines
,arcs
andcircles
If you want to know, how I created
QGraphicsItemGroups
please visit this question, I have written code there.( If you want I can explain that code here also )
( I did not give complete code bcoz, in polylines I was facing issue so I showed that code only. )
Complete HighlightObject() code :* HighlightObject(QEvent* event) { //Finding object under cursor QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); QPointF mousePoint = _view->mapToScene(mouseEvent->pos()); QGraphicsItem* itemUnderClick = scene->itemAt(mousePoint, QTransform()); QGraphicsPathItem* polylineItem = qgraphicsitem_cast<QGraphicsPathItem*>(itemUnderClick); if (polylineItem ) { //polylineItem ->setFlag(QGraphicsItem::ItemIsSelectable);//I have set this flag while drawing polyline. polylineItem ->setSelected(true); QPen mPen(Qt::SolidLine); mPen.setWidth(1); polylineItem ->setPen(mPen); } else { QGraphicsItemGroup* gItem = qgraphicsitem_cast<QGraphicsItemGroup*>(itemUnderClick); if (gItem) { gItem->setFlag(QGraphicsItem::ItemIsSelectable);//need to remove as it is done while creating gItem->setSelected(true); } }
And Refresh() code :
std::cout<<"Before Refresh size = : "<<_scene->selectedItems().size()<<std::endl; //foreach (QGraphicsItem* currentItem, _scene->items()) { for (int i = _scene->selectedItems().size() - 1; i >= 0; i--){ myPoly* pItem = qgraphicsitem_cast<myPoly*>(_scene->selectedItems()[i]); if (pItem ) { pItem->setSelected(false); QPen mPen; mPen.setWidth(1); pItem->setPen(mPen); pItem->setPen(QPen(QColor("red"), 1)); } else { QGraphicsItemGroup* sItem = dynamic_cast<QGraphicsItemGroup*>(_scene->selectedItems()[i]); if (sItem) { sItem->setSelected(false); } } } }
-
@JonB Thank you for your response.
You are right. I am using
QGraphicsItemGroups
for my digital gates ( AND,NAND,NOT etc ) which containslines
,arcs
andcircles
If you want to know, how I created
QGraphicsItemGroups
please visit this question, I have written code there.( If you want I can explain that code here also )
( I did not give complete code bcoz, in polylines I was facing issue so I showed that code only. )
Complete HighlightObject() code :* HighlightObject(QEvent* event) { //Finding object under cursor QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); QPointF mousePoint = _view->mapToScene(mouseEvent->pos()); QGraphicsItem* itemUnderClick = scene->itemAt(mousePoint, QTransform()); QGraphicsPathItem* polylineItem = qgraphicsitem_cast<QGraphicsPathItem*>(itemUnderClick); if (polylineItem ) { //polylineItem ->setFlag(QGraphicsItem::ItemIsSelectable);//I have set this flag while drawing polyline. polylineItem ->setSelected(true); QPen mPen(Qt::SolidLine); mPen.setWidth(1); polylineItem ->setPen(mPen); } else { QGraphicsItemGroup* gItem = qgraphicsitem_cast<QGraphicsItemGroup*>(itemUnderClick); if (gItem) { gItem->setFlag(QGraphicsItem::ItemIsSelectable);//need to remove as it is done while creating gItem->setSelected(true); } }
And Refresh() code :
std::cout<<"Before Refresh size = : "<<_scene->selectedItems().size()<<std::endl; //foreach (QGraphicsItem* currentItem, _scene->items()) { for (int i = _scene->selectedItems().size() - 1; i >= 0; i--){ myPoly* pItem = qgraphicsitem_cast<myPoly*>(_scene->selectedItems()[i]); if (pItem ) { pItem->setSelected(false); QPen mPen; mPen.setWidth(1); pItem->setPen(mPen); pItem->setPen(QPen(QColor("red"), 1)); } else { QGraphicsItemGroup* sItem = dynamic_cast<QGraphicsItemGroup*>(_scene->selectedItems()[i]); if (sItem) { sItem->setSelected(false); } } } }
@tushu said in How to dehighlight single and multiple items from QGraphicsScene in Qt?:
You are right. I am using QGraphicsItemGroups
It would really have helped if you had stated this. Maybe that affects how the count of selected items works? Maybe you have to go into the members of the group?
-
@tushu said in How to dehighlight single and multiple items from QGraphicsScene in Qt?:
You are right. I am using QGraphicsItemGroups
It would really have helped if you had stated this. Maybe that affects how the count of selected items works? Maybe you have to go into the members of the group?