0

QGraphicsItemまたはその子から派生したいくつかの異なるクラスがあります(のようにQGraphicsRectItem)。どのクラスをコピーするのか正確にわからないまま、これらのクラスの選択したオブジェクトをコピーする必要があるときです。

選択したアイテムのリストを返すので、それを使用することにしましたが、抽象クラスでQGraphicsScene::selectedItems()あるためコピーできません。QGraphicsItemこれに対処するために、 and を使用してオブジェクトをコピーしようとしていmallocますmemcpy

  1. MainWindow.cpp

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        scene = new QGraphicsScene();
        item = new QGraphicsRectItem(50,50,50,50);
        item->setFlag(QGraphicsItem::ItemIsSelectable);
        scene->addItem(item);
        item->setSelected(true);
        ui->graphicsView->setScene(scene);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::on_pushButton_clicked()
    {
        for(QGraphicsItem *item : scene->selectedItems())
        {
            QGraphicsItem *copiedItem=(QGraphicsItem *)malloc(sizeof(*item));  
            memcpy(copiedItem, item, sizeof(*copiedItem));   
            copiedItem->moveBy(50, 50);
            scene->addItem(copiedItem);
    
            qDebug() << item;
            qDebug() << copiedItem;
        }
    }
    
  2. MainWindow.h

    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
        public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
        QGraphicsScene *scene;
        QGraphicsRectItem *item;
    
        private slots:
            void on_pushButton_clicked();
    
        private:
            Ui::MainWindow *ui;
    };
    

この例では、QGraphicsView と QPushButton で構成される GUI で十分です。

このコードは機能しているようで、itemアドレスcopiedItemは異なりますが、戻り値と同じプロパティを持っていqDebug()ます。

ただし、シーンは次のエラーを返します。

QGraphicsScene::addItem: item has already been added to this scene

住所が違うのに同じものだとシーンが考える理由がよくわかりません。この問題を解決する方法はありますか?

編集: 可能であればQGraphicsItem、から派生したクラスのコードを変更せずにこれを行いたいと考えています。これはグループ作業であり、他の機能をバグにしたくないためです。

4

3 に答える 3

5

qgraphicsitem.h 内のクラス定義を見ると、次のように表示されます。

private:
    Q_DISABLE_COPY(QGraphicsItem)
    Q_DECLARE_PRIVATE(QGraphicsItem)

これが意味することは、設計上、 をコピーすることは想定されておらずQGraphicsItem、各オブジェクトは一意であることが想定されているということです。

編集:コピー機能が拒否された理由は、 QGraphicsItem がComposite Design Patternに従っているためだと思います。子アイテムを持つ 1 つのオブジェクトのコピーを作成すると、子アイテムが複数の親を持つことになります。それを回避するには、関心のあるアイテムだけでなく、子階層内のすべての子もコピーする必要があります。非常に大きな階層の場合、これは非常に時間のかかる操作になる可能性があります。

コピーを作成する必要があると本当に感じている場合は、すべてのオブジェクトのプロパティを調べて、それらを新しく作成された QGraphicsItem に転送することにより、QGraphicsItem とそのすべての子のクローンを作成するクローン ファクトリ関数/クラスを作成できます。

これが不可能な場合は、別の方法で目標を達成することを検討してください。

于 2013-08-19T14:33:19.593 に答える
3

andではなく 、コピー コンストラクターまたは代入演算子を使用する必要があります。これは、C++ でオブジェクトをコピーする方法です。mallocmemcpy

QGraphicsItem copiedItem = *item; 
于 2013-08-19T13:35:47.107 に答える
1

malloc を使用してメモリをブロック コピーすることによってクラスをコピーする場合の問題は、クラスにオブジェクトまたは配列へのポインターが含まれている場合、浅いコピーしか行われないことです。

QGraphicsItem へのポインターを取得する場合、コピーするアイテムのタイプ (基本クラスではなく、実際の子クラス) を識別し、コピー コンストラクターを使用する必要があります。QGraphicsItem には type() と呼ばれる関数が含まれており、どのアイテムかを示す int を返します。type() 関数を実装することにより、独自の派生クラスにこれを追加することもできます。たとえば、Qt ドキュメントから: -

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

   int type() const
   {
       // Enable the use of qgraphicsitem_cast with this item.
       return Type;
   }
   ...
};

または、すべてのクラスが独自の型である場合は、独自のシステムを使用できます。タイプがわかったら、コピー コンストラクターを使用してアイテムをコピーできます。

// Example, assuming type denotes a QGraphicsItemRect    
QGraphicsItemRect rect = (*originalRect);

QGraphicsItem から継承し、ポインターであるメンバーを追加した場合は、独自のコピー コンストラクターを追加して、浅いコピーではなく深いコピーが確実に行われるようにする必要があることに注意してください。

于 2013-08-19T14:13:57.727 に答える