PDA

View Full Version : QGraphicsView Copy and Paste



stevel
24th April 2008, 00:13
I need to implement copying and pasting the contents of a QGraphicsView, and/or just the selected QGraphicsItems. If anyone has any suggestions or pointers as to how to do this, I would appreciate hearing about it. I think I am going to need to implement a custom mime type to put this stuff on the clipboard. My QGraphicsItems are all overridden non-standard items, and I guess each one should have it's own copy method.

If someone could point me at some sample code, or offer some starting suggestions, I would appreciate it.

songqiming
24th April 2008, 06:21
you can save selected item's attribute in the QClipboardord when you save,and instantiate an object with the attribute in the QClipboardord when you paste;
Or make a flag = 1 when copy,and instantiate an object with the attribute by selected item's pointer and make flag = 0 when paste .hope can help you:)

aamer4yu
24th April 2008, 06:26
Firstly, graphicsView only shows the content of a scene. Items actually are in a scene.
Do u want copy-paste or drag drop ??

For copy paste it must be simple. You need to select the graphicItems and add the items in the other scene you want.
Pseudo code -


m_selectedItems = m_source_scene->selectedItems();
// The following slot is called when some action(paste) is triggered.
MyWindow::OnPaste()
{
//m_selectedItems contains a list of selected graphic items
foreach(item,m_selectedItems)
m_target_scene->add(item);
}



Also can we know where do u want to copy-paste from ? u want copy paste in the same application or from one application to other ?

Hope this helps :)

wysota
24th April 2008, 08:57
Ok, yet another solution :)

Provide a serialization mechanism for your items using QDataStream (or some other custom mechanism, like converting the item to XML representation). When the copy is performed, serialize the item into the mimedata object. When you paste - deserialize.

Remember that if your item can have child items, they need to be serialized with their parent as well so that pasting the item will paste children as well.

Such solution will be valid for pasting into the same or another application (contrary to operating on pointers). And it will respect undo/redo properly, if you have one. Pointers probably won't.

stevel
24th April 2008, 17:23
Thanks for the replies. I am trying to copy from a scene, so it is probably correct that I should have referred to a scene, not a view. The problem with the first solution, is the assumption that the first scene is still there. If I copy from a scene, then close that window, then paste into another scene, then that breaks.

I am trying to support both copying and pasting in multiple windows in my app, and into other apps. What I think I should do is put some kind of private data onto the clipboard for my application, and also put an image onto the clipboard for other applications. This will allow another app to paste in an image of my scene, and another scene in my app to paste in the GraphicsItems.

Wysota, I think that what you are saying about the QDataStream is right, but what I am unfamiliar with is the process of setting up my own mime type, and putting that into the clipboard. I guess what I have to do is to setMimeData in QClipboard with the QDataStream, and use QMimeData to build my mimeData. I think I just have to do some research.
I think my question was if I was missing something. I don't want to do this a harder way then I have to.

wysota
24th April 2008, 22:58
Wysota, I think that what you are saying about the QDataStream is right, but what I am unfamiliar with is the process of setting up my own mime type, and putting that into the clipboard.
You will not get away from that, no matter which solution you choose.


I guess what I have to do is to setMimeData in QClipboard with the QDataStream, and use QMimeData to build my mimeData.
No, you have to build your own mime data using QDataStream and then put it in QClipboard using QMimeData.


I don't want to do this a harder way then I have to.

Don't worry, it's very easy.

vinzzz
3rd January 2014, 14:11
hi i am a new to Qt, i couldn’t find how u will serialize selected items, if you copy an selected item like which i done below i just get a shallow copy of an item, how do we actually get this selected item and serialize it. plz show it with a small example

QList<QGraphicsItem *> copiedItem = this->selectedItems();

All i want to finally do is, i wanted to copy and paste QGraphicItem on my QGraphicScene .
thanks in advance

wysota
3rd January 2014, 14:40
You have to serialize the item using QDataStream in your own code. Serializing a list of pointers is exactly that -- serializing a list of pointers, not a list of objects. There is no ready code to serialize any possible graphics item, you need to write code dedicated to your item classes.

vinzzz
8th January 2014, 06:00
This is how i copy an item and serialize it


QFile file("fileName.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);

QList<QGraphicsItem *> list1= this->selectedItems();
itemListSize = list1.size();
out<<itemListSize;
foreach( QGraphicsItem* item, list1)
{
out << item->x();
out << item->y();
}

and for pasting it back i use the following code


QFile file("fileName.dat");
QList<QGraphicsItem *> list1 = this->selectedItems();
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in>>itemListSize;
foreach(QGraphicsItem *item, list1)
{
in >> item->x();
in >> item->y();

}

scene1->addItem(item);
file.close();


but i cannot get the items x and y position while reading data. Am i serializing in the correct way, plz help me out.

wysota
8th January 2014, 07:46
Your deserializing code is incorrect. To set x and y values you need to use setX() and setY() and not redirect to x() and y(). Moreover this code won't work because you're adding the item outside the for loop.

vinzzz
8th January 2014, 09:44
sorry wysota i am new to Qt plz elaborate it, and show me any small example for serialization and deserialization

wysota
8th January 2014, 10:11
sorry wysota i am new to Qt
Your problem is C++ not Qt.


and show me any small example for serialization and deserialization
There are examples in QDataStream docs.

vinzzz
8th January 2014, 10:52
Ya now that error has been cleared, but i could'nt get what attributes should i serialize. below is the code how i create a rect item

This is the function written in my mousePressEvent



{
if (mouseEvent->button() != Qt::LeftButton)
return;

DiagramItem *item;
switch (myMode) {
case InsertItem:
item = new DiagramItem(myItemType);
item->setBrush(myItemColor);
addItem(item);
item->setPos(mouseEvent->scenePos());
emit itemInserted(item);
break;

;
}

QGraphicsScene::mousePressEvent(mouseEvent);
}

This is the code written for creating a polygon item in my DiagramItem's class constructor


myDiagramType = diagramType;
QPainterPath path;
switch (myDiagramType) {
case Step:
myPolygon << QPointF(-100, -100) << QPointF(100, -100)
<< QPointF(100, 100) << QPointF(-100, 100)
<< QPointF(-100, -100);
}
setPolygon(myPolygon);

setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);

}

I am getting a perfect rect but could'nt cut, copy and paste my QRect Item

d_stranz
8th January 2014, 17:58
Think about what you are doing in the serialization code you posted:



QFile file("fileName.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);

QList<QGraphicsItem *> list1= this->selectedItems();
itemListSize = list1.size();
out<<itemListSize;
foreach( QGraphicsItem* item, list1)
{
out << item->x();
out << item->y();
}


What's going to be in this file after you are finished? In case you can't guess, it starts with an integer (the number of selected graphics items), and then continues with a series of floating point numbers, two for every item in the list. That's it. Absolutely no information about what kind of graphics item you are serializing (or even that the file results from serializing anything). So how can you possibly expect that the code that reads it in will have any clue what to do with it?

If what you want to do is save the state of the selected items to a file, and then sometime later, read that file and restore those items to exactly the same state, then, at a minimum, you need to save:

1 - the number of items (you did that part OK)
2 - for each item:


- what kind of item it is
- every property needed to re-create that item with the same appearance and put it in the right place in the scene (like, including its place in the object hierarchy)



And when you restore the items from the file, you need to reverse this process (and by the way, your de-serialization code is buggy: what happens if the currently selected items list is a different size from what is in the file, or the selected item types don't match?)

1 - read the number of items to restore
2 - for each item:


- read the item's type
- create an item of that type
- read the properties
- set the properties (correctly) on the item you just created
- add the item to the scene (in the correct place in the object hierarchy)

vinzzz
13th January 2014, 09:43
thanks d_stranz now i am getting what i have done and what i am supposed to do but still i have confusions


This is what i did for serializing the items



QFile file("fileName.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);

QList<QGraphicsItem *> list1= this->selectedItems();

itemListSize = list1.size();
DiagramItem *itm = static_cast<DiagramItem *>(list1.front());
out<<itemListSize;
foreach( QGraphicsItem* item, list1)
{
QPointF sp = itm->scenePos();


myItemType1=itm->myDiagramType;

out << sp ;
out << myItemType;

}


and for de-serialization i implemented this code



QFile file("fileName.dat");
QList<QGraphicsItem *> list1 = this->selectedItems();
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
in>>itemListSize;

foreach(QGraphicsItem *item, list1)
{
in >> sp;


// in>> myItemType; // i dono whats the problem in de-serialization of this "myItemType"

item1 = new DiagramItem(myItemType1);
addItem(item1);
item1->setPos(sp);
item1->moveBy(50 ,50);


}

file.close();

this code does not performing proper serialization, i am able to copy the item but couldn't paste it... what i have done is

In the 1st part i am casting the list into DiagramItem and serializing those properties of that class, in the 2nd part i am not casting back the DiagramItem back to list is that the problem i am facing....?
Is cut functionality can be performed, if yes just give some directions for it....?


thanx in advance