How can I Pass the mouse event that created a delegate editor to that editor.
I need to use a custom widget as a persistent editor delegate in a QTableView, but for performance reasons, I can't make that many instances of the widget.
How can I pass a mouse event to a delegate editor that I just created?
Here's the working test code: http://pastebin.com/vjDSgNW5
Basically I just want to be able to click on the FilePicker widget lineEdits and buttons and have them work.
Any help would be greatly appreciated.
def init(self, parent):
#gotta set the parent of the helper to get the correct style
self._helperPicker = FilePickerWidget(parent)
def createEditor(self, parent, option, index): return FilePickerWidget(parent) def setEditorData(self, editor, index): editor.setFilePath(r'C:\temp\temp.txt') def setModelData(self, editor, model, index): model.setData(index, editor.filePath()) def paint(self, painter, option, index): # Draws the self._helperPicker as the background painter.save() painter.translate(option.rect.topLeft()) self._helperPicker.resize(option.rect.size()) self._helperPicker.render(painter, QPoint(), QRegion(), QWidget.DrawChildren) painter.restore() #continue on with the regularly scheduled program super(FilePickerDelegate, self).paint(painter, option, index) def editorEvent(self, event, model, option, index): if event.type() & event.MouseButtonPress: #recreate what happens normally with the delegate par = self.parent().viewport() ed = self.createEditor(par, option, index) self.setEditorData(ed, index) ed.mousePressEvent(event) ### Doesn't work return True return super(FilePickerDelegate, self).editorEvent(event, model, option, index)
You can't just send on a mousePressEvent like that, because the pos() and posF() members don't fit for the newly created editor. There might be other issues with passing on an event like that, but I'm not currently aware of any.
Three ideas pop up that you could try:
- Map the coordinates of the MouseEvent to the new item before passing on the event
- Achieve whatever the event would do on the editor via code yourself
- Create an event filter, so you know about the arrival of the event before it's actually forwarded to the widgets. Create the editor in the event filter, then the event might normally propagate to the editor (this depends a bit on the internal implementation of the event distribution, but the same goes for the 1st item)
So after working with your suggestions for a while (Thanks!), I have a MUCH better idea how mouse events are handled in qt. Unfortunately, it means I need to change my approach.
The way I'm understanding this, qt recursively calls through the event
filters down widget hierarchy to find where the event should be handled. But there's no way to tell qt to continue handling events once you're in the chosen handler method. So once you're handling an event (in this case, where the click is being handled by the delegate), it's over because the recursion termination condition has already been met and your event won't get passed down the chain.
So it seems that the general way to do this would be your suggestion with event filters. Hopefully I can use the delegate directly in the event filter, then continue on as if the click hadn't been handled by the delegate.
Well crap. It seems the event filter is in the same boat as the events. Meaning by the time I enter the event filter and create the delegate widget (which is a child of my viewport), the viewport's children are already done handling any events.
Any other ideas? I'm at a loss here, and I really don't want to have to write an explicit "Handle First Click" method for every widget I try to use as a delegate in this table.
Another idea: Normally, when you ignore() events, they should continue to propagate. Of course, this does not always work, because some base classes will make sure to accept() the event, preventing any propagation.
So you could try to explicitly ignore() the event after creating the delegate, and see if that works.
I can't actually check the code right now, but wouldn't that give the same problem? From the documentation: "Unwanted events might be propagated to the parent widget."
The event would propagate from child to parent, while I need it to propagate the other way. That way the parent can make a new child in response to the event, and the new child will handle the event that prompted its creation.
Why don't I just open the editor on cell entered?
It's simpler, plays nicer with other mouse events, and I don't have to deal with the event hierarchy.