Unsolved How QDataStream and QByteArray work together with QMimeData?
-
Hi expert!
I checked about this topic and I didn't find a clear thread that was covering my questions, then I decided to post this.
I'd like to ask you some general questions regarding the use of these 3 classes.All starts from an issue I have related to the drag and drop, however I don't want to dwell on this for now, I rather want to understand the general "mechanism" exists behind the scene to "transfer" data within Qt.
At the beginning I thought that QDataStream was acting like a "pipe" to transfer data, but since it needs QByteArray to "store" data, I didn't find an equivalence for that. If I talk about a QDataStream what metaphor can i use?
While QByteArray is just a buffer which clearly represents the data container isn't it?
Then there is also the QMimeData which is defined as: Multipurpose Internet Mail Extensions. This description applied to the Qt programming environment sounds to me a bit misleading...
So to wrap-up, this is what I understood so far:
To transmit "something" using a mechanism like drag and drop I have to:
- Create a QDataStream object (based on the QByteArray "container").
- Load my data (for this example just consider plain text) into the QDataStream.
- Create a QMimeData object.
- "Encode" the QDataStream into the QMimeData specifying which type of "media" I'm transmitting (text/plain).
Is this correct or not?
To receive the data, i.e. in the dropEvent, I should clearly "unwrap" my data following the opposite process isn't it?
Kind regards,
AGA -
QDataStream is a stream - it streams data to/from a buffer. But since QDataStream uses an internal format to store the data it's not really usable with QMimeData when someone outside your app should retrieve it.
QMimeData has a lot of functions to send / receive data without the need of a QByteArray and QDataStream. -
many thanks for your answer, this already shed some light on my problem.
I saw some examples (like this) were a "combination" of QDataStream, QByteArray and QMimeData, were used, but now that you wrote me: QMimeData has a lot of functions to send / receive data without the need of a QByteArray and QDataStream, I can clearly see (from other examples) that the "drag and drop" can be achieved using only the QDataStream.
Why then some examples used them?
So, focusing only on the QMimeData class, I've been able to make the drag and drop code work, but probably I need some advice to polish it a bit.
Since I wrote it in Python, do I need to move this post in the Python section or can I leave it here?
I started the post here in the General and Desktop section because I think that it is more related to a workflow question, so anyone could benefit.--------------------------------------------------------------------------------------------------------------------------
Here what I did:
- I have a dialog with 2 QListWidget where I want to copy the left items into the right items using the drag and drop action.
Although I've been able to make the code work I need some advice to understand better what "should stay", what is superfluous and what I miss.
- Since I had to add 2 QListWidget I decided to re-implement the QListWidget class in a generic way that I could use for both the Host and the Target (see more in the code below).
- In the class I re-implemented "only" these drag and drop methods: QDragEnterEvent, QDragMoveEvent and QDropEvent.
- I used the startDrag method to "load" the selected item into the mime data.
In the "main" code I created the 2 QListWidget as:
Host:... # create a list - host self.listHostTestFiles = ListView() self.listHostTestFiles.setDragEnabled(True) self.listHostTestFiles.setDropIndicatorShown(True) ...
- To the left QListWidget I added these "options": drag enable and drop indicator because is the one where the drag starts.
Target:
... # create a list - target self.listTargetTestFiles = ListView() self.listTargetTestFiles.setAcceptDrops(True) ...
- To the right QlistView I added only the accept drop "option" since it just need to receive the drop.
The code for the entire re-implemented class is instead:
class ListView(QListWidget): def __init__(self, parent=None) -> None: super().__init__(parent) # this method is called when the mouse starts to enter over the widget def dragEnterEvent(self, event) -> None: if event.mimeData().hasFormat("text/plain"): event.accept() else: event.ignore() # this method is called when the drag and drop action is in progress def dragMoveEvent(self, event) -> None: if event.mimeData().hasFormat("text/plain"): #event.setDropAction(Qt.DropAction.CopyAction) event.accept() else: event.ignore() # if the dragEnterEvent is accepted, then the dropEvent is called def dropEvent(self, event) -> None: if event.mimeData().hasFormat("text/plain"): item = event.mimeData().text() self.addItem(item) event.setDropAction(Qt.DropAction.CopyAction) event.accept() else: event.ignore() def startDrag(self, dropActions) -> None: item = self.currentItem() mimeData = QMimeData() mimeData.setText(item.text()) drag = QDrag(self) drag.setMimeData(mimeData) drag.exec(Qt.DropAction.CopyAction)
Here my questions:
- Is it a good practice, or it would be better to re-implement a custom class for each of the 2 QlistWidget?
- When do I need to use the QDragLeaveEvent? I didn't really figure out when I should.
- To be fair, I didn't understand even why do I need both the dragEnterEvent and the dragMoveEvent.
I tried commenting out first one and then the other but the "demo" didn't work. - Why do I need to use both "together"? Of course I already had a look to the doc, but unfortunately it is still not clear to me.
- Is there an order in which the methods are triggered?
- To be fair, I didn't understand even why do I need both the dragEnterEvent and the dragMoveEvent.
- For each method I always checked for the mimeData format, is it necessary? Or can I use it just for the first method called?
- What about the setDropAction? Can I use it only one time (i.e. in the startDrag, or do I need to use it also in the last dropEvent?
To close all these questions: on the official drag and drop page I saw that a very different example is made using the mouseXEvent.
At this point I'm confused about the right approach to use for the drag and drop.
- Which approach should I prefer?
- Is there a reason why there are these 2 different "way": dragEvents or mouseEvents?
Many thanks!
AGA -
@superaga said in How QDataStream and QByteArray work together with QMimeData?:
can be achieved using only the QDataStream.
Why then some examples used them?Did not read the rest but I never said it's not possible:
usable with QMimeData when someone outside your app should retrieve it.
Your example does internal drag'n'drop so all is fine.
-
many thanks for your help.
It is clear that the first is related to the fact that something starts when the mouse is pressed, so it can happen in any part of the GUI, while the second happens just when you are on the widget.
Now, it is clear to me that even the first approach, when acts as drag and drop action, will falls within the second case, so there are no differences.Could you please just explain me a bit those questions (sorry to be repetitive)? 😅
- Why do I need both the dragEnterEvent and the dragMoveEvent?
- I tried commenting out first one and then the other but the "demo" didn't work.
Why do I need to use both "together"? Of course I already had a look to the doc, but unfortunately it is still not clear to me.
- I tried commenting out first one and then the other but the "demo" didn't work.
- Is there an order in which the methods are triggered?
- For each method I always checked for the mimeData format, is it necessary? Or can I use it just for the first method called?
- What about the setDropAction? Can I use it only one time (i.e. in the startDrag, or do I need to use it also in the last dropEvent)?
Many thanks!
AGA - Why do I need both the dragEnterEvent and the dragMoveEvent?
-
Hi,
Determine on enter whether further processing shall be done.
And for the move, your entire widget might not be a target for dropping or might change the outcome based on some condition. -
Hi @SGaist,
many thanks for your explanation.
Now I'm seeing more using than just a drag and drop case...So just to answer to my questions and close this thread:
Why do I need both the dragEnterEvent and the dragMoveEvent?
Really depends by what you need. For a simple drag and drop just use only the dropEvent. -> That (inexplicably) didn't work. I still need to re-implement also the dragEnterEvent and the dragMoveEvent. 🤷♂️
Is there an order in which the methods are triggered?
Yes, it follows the mouse movements, so it should be from the external to the internal: dragEnterEvent, dragMoveEvent, dropEvent and finally dragLeaveEvent.
For each method I always checked for the mimeData format, is it necessary? Or can I use it just for the first method called?
I think that this could be related just to the first method used to "validate" the "action type" for that event.
Pay attention that the same event might accept and perform different actions based on the different file format dragged on.
What about the setDropAction? Can I use it only one time (i.e. in the startDrag, or do I need to use it also in the last dropEvent)?
It is still not clear to me, although I might assume that it depends by the kind of action that event needs to execute.
Kind reagards,
AGA -
The dragEnterEvent is the first step that will determine whether D&D handling shall start. The dragMoveEvent is the continuous handling of the drag and dropEvent is the end of it.