2013-07-23 274 views
1

我创建了一个公共QGraphicsItem Node类,它为与我的应用程序相关的一组属性提供了getter/setter方法。该应用程序是用户设计模型的图编辑器。这个Node类用于填充也是公共QGraphicsScene Diagram类。Qt - 使用自定义QGraphicsItems保存自定义QGraphicsScene

我现在试图在应用中实现一个加载/保存机制,使用户能够保存和重用模型 - 按照他们保存时的编辑方式进行编辑。我在计算如何解决这个问题时遇到了一些麻烦。

我已经知道我必须获取QGraphicsItem对象的相关属性并将它们保存到文件,然后在加载时使用我保存的数据重建场景。我的问题是:当我使用QGraphicsScene::items()函数时,它返回一个QList<QGraphicsItem *>。我能做些什么来让它返回QList<Node *>

如果我得到了我追加到场景中的所有节点的列表,我知道接下来要做什么。

我开始意识到我可能不得不在我的Diagram类中重新实现items()函数,但我希望能更轻松地摆脱它。在这种情况下,有人可以解释怎么做吗?

回答

1

我建议实施QGraphicsItem::type()方法,并使用qgraphicsitem_cast投入到所需的类。在你的情况下,你可以从一个公共的基类继承所有你自定义的GraphicsItem。

你的基类是这样的:

class MyGraphicsItem: public QGraphicsItem 
{ 
    enum { Type = UserType + 1 }; 

    int type() const { return Type; } 
}; 

您的节点和你的Link类将继承这一基地:

class Node : public MyGraphicsItem 
{ 
    // ... 
}; 

class Link : public MyGraphicsItem 
{ 
    // ... 
}; 

别的地方,你可以投出的QGraphicsItem到您的基类MyGraphicsItem像例如:

QList<QGraphicsItem*> allItems = graphicsScene->items(); 
foreach (QGraphicsItem *item, allItems) { 
    // Using qgraphicsitem_cast 
    MyGraphicsItem* graphicsItem = qgraphicsitem_cast<MyGraphicsItem*>(item); 
    if (graphicsItem) { 
     // Do something with MyGraphicsItem 
    } 
} 
+0

我忘了提及我也有一个公共的QGraphicsItem'Link'类。 'items()'方法也会返回这些实例。如果该项目是'Node'类,那么如何将代码调整为_test_?我不希望/不需要处理'Link'对象... – Joum

+1

您可以通过为所有项目使用通用基类并从中继承您的'Node'和''Link'类来解决此问题。稍后,您可以使用'qgraphicsitem_cast'将其转换为该基类。我已经更新了代码来证明这一点。 – tomvodi

+0

如果我没有弄错,从我在网上找到的,我的问题的_test_部分只是测试'if(graphicsItem!= 0)'。只有在转换后,'graphicsItem'不是'MyGraphicsItem'类型,对吗? – Joum

1

尽管项目func并返回一个QGraphicsItem指针列表,你可以尝试dynamic_casting来检查它是否是Node指针,或者使用Qt元数据和type()函数。

但是,我经常使用的方法也可以帮助您以其他方式帮助您,方法是为每种类型的对象和项目ID的静态列表维护一个唯一的ID。例如: -

class BaseItem : public QGraphicsItem 
{ 
    public: 
     BaseItem(QGraphicsItem* parent) 
      : QGraphicsItem(parent), m_Id(m_NextId++) // initialising the object's unique Id 
     { 
     } 

     unsigned int ID() const 
     { 
      return m_Id; 
     } 

    private: 
     static unsigned int m_NextId; // the next Object Id, initialised to 0 in implementation 
     unsigned int m_Id; // the object's unique Id 

} 

class Node : public BaseItem 
{ 
    public: 
     Node(QGrahicsItem* parent) 
      : BaseItem(parent) 
     { 
      m_NodesList.push_back(m_Id); 
     } 

    private: 
     static QList<unsigned int> m_sNodesList; // all Node ids in the scene 

     QList<unsigned int> m_linkedNodeList; // linked nodes 
} 

所有项目加入到GraphicsScene从BaseItem继承

你也有节点ID的静态列表,这样你就可以通过所有这些用于加载/保存和你迭代可以在基类中添加一个静态辅助函数来返回节点列表,方法是搜索节点ID列表并将它们匹配到场景中的节点指针。

该体系结构还允许您在每个节点对象中包含一个链接节点ID列表,而不是使用Qt的父/子系统,在节点图的情况下,它并不总是需要的。总体而言,我已经将这种体系结构用于许多QGraphicsScene应用程序,并且对于与其他项目具有复杂链接的项目而言,它确实使开发变得非常容易。

+0

谢谢,这似乎很有趣!虽然我认为@thomas_b的做法似乎更简单。我意识到索引对象类型的好处,但对于我所需要的可能太多了。 +1虽然:) – Joum

+1

没问题,我只是认为我把它放在那里作为参考,也许其他人将在未来受益。 – TheDarkKnight