嵌套QGraphicsScenes中的选择排除



我有一个包含项目的QGraphicsScene(让我们称之为母场景(,其中一些场景还包含一个QGraphicsSene(让我们将其称为子场景(。

观察:女儿场景和母亲场景中的选择互不干扰。这意味着,如果我在母亲场景中选择了一个项目,我可以在女儿场景中选择项目,而母亲场景中的项目将保持选中状态。

我的预期结果:我希望我在一个场景中的选择可以清除任何其他场景中的选项。

[为清晰起见进行编辑]当我在场景中选择一个项目时,我希望在其他场景中取消选择所选项目,而不是在不同的场景中有多个焦点。

我的动机:我想这么做,因为当我使用键盘快捷键时,我不知道Qt会选择哪个场景。当我只有一个女儿时,会选择母亲(我更喜欢女儿(。

到目前为止我的解决方案:在子场景容器项中,mousePressEvent清除母场景的选择。我觉得这个解决方案很难看,我想知道是否有人知道一个更好的解决方案,可以使用一些内部Qt功能。现在看来,这是一个糟糕的DIY解决方案,会带来许多问题。

提前感谢!

[编辑:最小示例]在本例中,我们可以同时选择两个嵌套元素。我宁愿在我的整个场景中一次只有一个选择。

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QMainWindow>
#include <QGraphicsItem>
#include <QGraphicsLinearLayout>
#include <QGraphicsWidget>
#include <QGraphicsProxyWidget>
// Item that gets red contour when selected
class SimpleItem : public QGraphicsItem
{
public :
SimpleItem():QGraphicsItem()
{
setFlag(QGraphicsItem::ItemIsSelectable, true);
}
QRectF boundingRect() const override { return QRectF(-20, -20, 40, 40);}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
{
painter->setPen(Qt::black);
if(isSelected())
painter->setPen(Qt::red);
painter->setBrush(Qt::gray);
painter->drawRect(boundingRect());
}
};
// Item that contains a QGraphicsScene in a layout
// This item gets also a red contour when selected
class SceneItem : public QGraphicsWidget
{
public :
SceneItem():QGraphicsWidget()
{
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFocusPolicy(Qt::ClickFocus);
// Create the inner scene
QGraphicsLinearLayout * layout = new QGraphicsLinearLayout;
setLayout(layout);
QGraphicsScene * scene = new QGraphicsScene;
QGraphicsView * view = new QGraphicsView(scene);
QGraphicsProxyWidget * proxy = new QGraphicsProxyWidget;
layout->addItem(proxy);
proxy->setWidget(view);
// Add a simple item
SimpleItem * simpleItem = new SimpleItem;
scene->addItem(simpleItem);
}
QRectF boundingRect() const override { return QRectF(0, 0, 100, 100);}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override
{
painter->setPen(Qt::black);
if(isSelected())
painter->setPen(Qt::red);
painter->setBrush(Qt::lightGray);
painter->drawRect(boundingRect());
}
};
// Main
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QGraphicsScene * scene = new QGraphicsScene;
QGraphicsView * view = new QGraphicsView(scene);
view->setDragMode(QGraphicsView::RubberBandDrag);
w.setCentralWidget(view);
SceneItem * item = new SceneItem;
scene->addItem(item);
w.show();
return a.exec();
}

免责声明

我个人不建议在QGraphicsScene:中嵌入小部件

图形视图高性能的关键是减少每帧的绘制量。QGraphicsWidget和QGraphicsProxyWidget一起是巨大的性能杀手,因为它们无法以有效的方式进行渲染。

这篇引文的来源以及有关该主题的更多信息可以在这篇博客文章中找到:

您是否仍应使用QGraphicsView?

解决方案

如果我必须不惜任何代价使用OP使用的确切方法,我的解决方案将是:

  1. 使用QGraphicsScene::selectionChanged对选择更改做出反应
  2. 使用QGraphicsScene::selectedItems检查是否选择了项目

示例

以下是OP提供的MVCE,我对其进行了修改,以演示如何实现所提出的解决方案:

#include <QApplication>
#include <QMainWindow>
#include <QGraphicsLinearLayout>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QPainter>
class SimpleItem : public QGraphicsItem
{
public :
explicit SimpleItem(QGraphicsItem *parent = nullptr) :
QGraphicsItem(parent) { setFlag(ItemIsSelectable, true); }
QRectF boundingRect() const override { return QRectF(-20, -20, 40, 40); }
void paint(QPainter *painter, const QStyleOptionGraphicsItem *,
QWidget *) override {
painter->setPen(isSelected() ? Qt::red : Qt::black);
painter->setBrush(Qt::gray);
painter->drawRect(boundingRect());
}
};
class SceneItem : public QGraphicsWidget
{
QGraphicsScene *m_scene;
public:
explicit SceneItem(QGraphicsItem *parent = nullptr) :
QGraphicsWidget(parent),
m_scene(new QGraphicsScene(this)) {
auto *layout = new QGraphicsLinearLayout;
auto *view = new QGraphicsView(m_scene);
auto *proxy = new QGraphicsProxyWidget(this);
auto *simpleItem = new SimpleItem(this);
m_scene->addItem(simpleItem);
proxy->setWidget(view);
layout->addItem(proxy);
setLayout(layout);
setFocusPolicy(Qt::ClickFocus);
setFlag(QGraphicsItem::ItemIsSelectable, true);
}
QGraphicsScene *scene() const { return m_scene; }
QRectF boundingRect() const override { return QRectF(0, 0, 100, 100);}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *,
QWidget *) override {
painter->setPen(isSelected() ? Qt::red : Qt::black);
painter->setBrush(Qt::lightGray);
painter->drawRect(boundingRect());
}
int type() const override { return UserType; }
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
auto *scene = new QGraphicsScene;
auto *view = new QGraphicsView(scene);
auto *item = new SceneItem;
scene->addItem(item);
view->setDragMode(QGraphicsView::RubberBandDrag);
QObject::connect(item->scene(), &QGraphicsScene::selectionChanged, [item, scene](){
if (!item->scene()->selectedItems().isEmpty())
scene->clearSelection();
});
QObject::connect(scene, &QGraphicsScene::selectionChanged, [scene](){
if (scene->selectedItems().isEmpty())
return;
for (auto *item : scene->items())
if (item->type() == QGraphicsItem::UserType)
static_cast<SceneItem *>(item)->scene()->clearSelection();
});
w.setCentralWidget(view);
w.show();
return a.exec();
}

最新更新