我正在尝试重新设计我的物品类。我无法想象事物应该如何工作。

当前实现:

class Item : public QGraphicsItem
{
public:
    typedef enum  { PolygonType = QGraphicsItem::UserType + 1 } ShapeType;
    Item() {...}
    Item(const Item &copyItem) // copy constructor
    {   m_shapeType = copyItem.getItemShape();
        m_color = copyItem.getItemColor();
        setPos(copyItem.pos()); ...}
    QRectF boundingRect() const;
    QPainterPath shape() const;
    void setItemShape(ShapeType s) { m_shapeType = s; }
    ShapeType getItemShape() const { return m_shapeType; }
    int type() const { return m_shapeType; }   // this will replace the above to allow QGraphicsItem casts
    void setItemColor(QColor c)    { m_color = c; }
    QColor getItemColor() const    { return m_color; }
    ....
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget);
    QColor m_color;
    ShapeType m_shapeType;
    ....
};

QPainterPath Item::shape() const
{
    QPainterPath path;
    switch (m_shapeType)
    {
    case Item::PolygonType:
        ...
        break;
    ....
    }
}
QRectF Item::boundingRect() const
{
    return QRectF(...);
}
void Item::paint(QPainter *painter, const QStyleOptionGraphicsItem */*option*/, QWidget */*widget*/)
{
    switch (m_shapeType)
    {
    case Item::PolygonType:
            painter->drawPolygon(shape().toFillPolygon());
            break;
    ....
    }
}

根据选择,我创建一个项目并添加到 Canvas 上...然后,在完成所有更改后,我将其添加到QGraphicsScene中。

必需的任务:

场景的处理包含类型的迭代
Item* item1 = new Item(*renderArea->item);
// make some changes on the item copy, then add it to a scene
collectionView->scene()->addItem(item1);

// in another function...
for(int i = 0; i < collectionView->scene()->items().size(); ++i)
{
    Item* item = new Item(*(dynamic_cast<Item*>(
                           collectionView->scene()->items().at(i))));
   ...
}

我要达到的目的

这是一种最小的方法,但是我必须将功能扩展到扩展其他类的项,例如QGraphicsPixmapItem(无需向不需要的每个项添加一个像素图)或QGraphicsSvgItem(再次,而不必增加太多开销)不需要的物品)。

所以我正在尝试:
class PolyItem : public Item
{
public:
    PolyItem(): Item()
    {
        m_shapeType = Item::PolygonType;
    }
    PolyItem(PolyItem& copy): Item::Item(copy)
    {
    }
    virtual void paint(QPainter* painter,
                       const QStyleOptionGraphicsItem* option,
                       QWidget* widget = NULL)
    {
        painter->drawPolygon(shape().toFillPolygon());
    }
};

要么
class PixMapItem : public Item, public QGraphicsPixmapItem
{
public:
    PixMapItem(): Item()
    {
        m_shapeType = Item::PixmapType;
        setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
    }
    PixMapItem(PixMapItem& copy): Item::Item(copy)
    {
        setPixmap(copy.pixmap());
        setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
    }
    virtual void paint(QPainter* painter,
                       const QStyleOptionGraphicsItem* option,
                       QWidget* widget = NULL)
    {
        painter->drawPixmap(boundingRect(), pixmap());
    }
};

问题:
  • 如何使其工作?选择形状时如何创建PolygonItem实例(并且仍然能够使用通用Item修改其他属性,例如color?)

  • ----->我当时正在考虑在Item类中创建一个可创建正确形状的其他构造函数-但这似乎意味着Item需要类多边形,而多边形需要类Item ...循环依赖?
  • 更复杂的是,无论形状如何,如何执行上述任务,修改通用项目,遍历项目?

  • 我无法想象的是:
    collectionView->scene()->addItem(item1);
    如果我的商品是多边形类型,是否会调用Item::paint()函数以及所有其他相关函数,或者PolyItem::paint()
    我是否必须插入切换用例代码来确定和转换每种类型的每个实例?

    最佳答案

    将您的Item类简化为BaseItem可能值得,其中包含您自己添加到Item的所有内容以及您希望任何Item具有的所有功能(如果没有QGraphics *则无法实现,则为纯虚函数):

    class BaseItem {
    public:
        void setItemColor(QColor c)    { m_color = c; }
        QColor getItemColor() const    { return m_color; }
        ....
    protected:
        QColor m_color;
        ShapeType m_shapeType;
    };
    

    然后
    class Item : public BaseItem, public QGraphicsItem
    class PixMapItem : public BaseItem, public QGraphicsPixmapItem
    

    等等-避免循环依赖。任何项都可以称为BaseItem,并提供由BaseItem定义的公共(public)接口(interface)。每个 child 都为适当的QGraphics *提供该接口(interface)的特殊化。

    原始设计的问题是该项目不应该继承自QGraphicsItem,因为您计划将其专门用于QGraphicsPixmapItem,该项目本身已经包含QGraphicsItem。

    编辑

    现在,当您遍历所有项目时,将它们视为BaseItem-这意味着BaseItem必须提供所有Items遵守的接口(interface)。给您在问题中提供的示例,这是解决问题的一种方法:
    class BaseItem {
      virtual void AddToScene(QGraphicsScene* scene) = 0;
      // Caller takes ownership.
      virtual BaseItem* CreateCopy() = 0;
    };
    

    必需的任务:

    场景的处理包含类型的迭代
    BaseItem* item1 = renderArea->item->CreateCopy();
    // make some changes on the item copy, then add it to a scene
    item1->AddToScene(collectionView->scene());
    

    每个派生类都实现了BaseItem定义的接口(interface),而您在常规操作中将所有Items都视为BaseItem。这也使代码易于扩展-添加新的Item类型仅需要实现派生类,而现有代码保持不变-因此,BaseItem需要仔细设计以提供所有项目通用操作的接口(interface)。
    class Item : public BaseItem, public QGraphicsItem {
          void AddToScene(QGraphicsScene* scene) override { scene->addItem(this); }
          // Caller takes ownership.
          BaseItem* CreateCopy() override { return new Item; }
    };
    

    10-01 18:59