我有几个不同的类派生自QGraphicsItem
或其子代(如QGraphicsRectItem
)。我现在需要复制这些类的选定对象,而不知道我确切地复制了哪一个。
由于QGraphicsScene::selectedItems()
返回所选项目的列表,我决定使用它,但是我不能复制QGraphicsItem
,因为它是一个抽象类。为解决此问题,我尝试使用malloc
和memcpy
复制对象。
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;
}
}
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
派生的类的代码,因为这是一个小组工作,我不想错过其他功能。
答案 0 :(得分:5)
如果你看一下qgraphicsitem.h中的类定义,你会看到以下内容:
private:
Q_DISABLE_COPY(QGraphicsItem)
Q_DECLARE_PRIVATE(QGraphicsItem)
这意味着,根据设计,您不应该复制QGraphicsItem
,每个对象都应该是唯一的。
编辑: 我认为你被拒绝复制能力的原因是因为QGraphicsItem跟随Composite Design Pattern。创建具有子项的单个对象的副本将导致子项具有多个父项。为了解决这个问题,你不仅要复制你感兴趣的项目,还要复制子层次结构中的每个孩子。对于非常大的层次结构,这可能会成为非常耗时的操作。
如果您真的觉得需要复制,可以创建一个克隆工厂函数/类,通过遍历所有对象的属性并将它们传输到新创建的QGraphicsItem来创建QGraphicsItem及其所有子元素的克隆。
如果这不可行,或许可以考虑以不同的方式实现目标。
答案 1 :(得分:3)
您确实希望使用复制构造函数或赋值运算符 not malloc
和memcpy
。这是你用C ++复制对象的方法:
QGraphicsItem copiedItem = *item;
答案 2 :(得分:1)
使用malloc通过块复制内存来复制类的问题是,如果类包含指向对象或数组的指针,那么只会发生shallow copy。
在获取指向QGraphicsItem的指针的情况下,您需要确定要复制的项目类型(其实际的子类,而不是基类)并使用复制构造函数。 QGraphicsItem包含一个名为type()的函数,它返回一个int,指示它是哪个项目。您还可以通过实现type()函数在您自己的派生类中添加此项。例如,来自Qt docs: -
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并添加了指针成员,那么您需要添加自己的复制构造函数以确保发生深层复制,而不是浅层复制。