我从QGraphicsItem
或其子类(如QGraphicsRectItem
)派生了几个不同的类。当我需要复制这些类的选定对象时,却不知道要复制哪一个。
由于QGraphicsScene::selectedItems()
返回了一个所选项目的列表,我决定使用它,但是我不能复制QGraphicsItem
,因为它是一个抽象类。为了解决这个问题,我尝试使用malloc
和memcpy
复制对象。
-
主窗口.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; } }
-
主窗口.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
派生的类的代码的情况下完成这项工作,因为这是一项小组工作,我不想bug其他功能。
如果您查看qgraphicitem.h中的类定义,您将看到以下内容:
private:
Q_DISABLE_COPY(QGraphicsItem)
Q_DECLARE_PRIVATE(QGraphicsItem)
这意味着,在设计中,不应该复制QGraphicsItem
,每个对象都应该是唯一的。
编辑:我想,您被拒绝复制能力的原因是因为QGraphicsItem遵循复合设计模式。创建具有子项的单个对象的副本会导致子项具有多个父项。为了绕过这一点,你不仅要复制你感兴趣的项目,还要复制子层次结构中的每个子项。对于非常大的层次结构,这可能会成为一项非常耗时的操作。
如果您真的觉得需要进行复制,可以创建一个克隆工厂函数/类,通过遍历对象的所有属性并将其传输到新创建的QGraphicsItem,来创建QGraphicsIItem及其所有子项的克隆。
如果这不可行,也许可以考虑用不同的方式来实现你的目标。
您确实希望使用复制构造函数或赋值运算符,而不是malloc
和memcpy
。这就是在C++中复制对象的方法:
QGraphicsItem copiedItem = *item;
通过使用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继承并添加了作为指针的成员,则需要添加自己的复制构造函数,以确保发生深度复制,而不是浅层复制。