最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Python function eventFilter does not receive drag or drop after installEventFilter - Stack Overflow

programmeradmin2浏览0评论

I am using PySide6. I have an application with the user interfaces defined in files apart from the code of each window and a file with the main window that makes use of them. So far a fairly standard construction. I want a text field to be able to either drag text or a file, in which case it should read it and load its contents. The problem arises when I set the field to accept drops and install a filter for the events, but the events that are received are neither drag nor drop. I have prepared a minimal example with a user interface file, a file with the event control code and a main window file. Once running, if you drag a text file into the text field, the only thing that loads is the Url of the file. The print() shows that the filter is entered, but neither drag nor drop is received. What is going on here?

Explanatory note: It is not possible to modify the file with the user interface, it is developed separately and cannot be touched. The solution proposed by @Marijn, extending the QPlainTextEdit class is the most practical, but I can't do it, that's why I'm using an event filter, but I can't get it to work.

File with the user interface up_ui.py

from PySide6.QtWidgets import (QPlainTextEdit,  QVBoxLayout)

class Ui_Up(object):
    def setupUi(self, Up):
        if not Up.objectName():
            Up.setObjectName(u"Up")
        Up.resize(420, 600)
        Up.setModal(True)

        self.txtInput = QPlainTextEdit(Up)
        self.txtInput.setEnabled(True)

        self.VL = QVBoxLayout(Up)
        self.VL.addWidget(self.txtInput)

File with the User interface code up.py

from PySide6.QtCore import QEvent
from PySide6.QtWidgets import QDialog

from up_ui import Ui_Up

class Up(QDialog, Ui_Up):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # Accept drop events
        self.txtInput.setAcceptDrops(True)
        self.txtInput.installEventFilter(self)

    def eventFilter(self, obj, event):
        print(f"Event: {event.type()}")
        print(f"QEvent.DragEnter = {QEvent.DragEnter}")
        print(f"QEvent.Drop = {QEvent.Drop}")
        if id(obj) == id(self.txtInput):
            print("txtInput")
            if event.type() == QEvent.DragEnter:
                print("Drag")
                if (event.mimeData().hasText() or
                    event.mimeData().hasUrls()):
                    event.acceptProposedAction()
                    return True
            elif event.type() == QEvent.Drop:
                print("Drop")
                if event.mimeData().hasUrls():
                    # URL list
                    for url in event.mimeData().urls():
                        print(url)
                        # Link or file
                        link = url.toString()
                        file_path = url.toLocalFile()
                        print(file_path)
                        if file_path.lower().endswith(('.txt', '.text')):
                            # Text file 
                            try:
                                with open(file_path, 'r', encoding='utf-8') as file:
                                    content = file.read()
                                    # Load content 
                                    self.txtInput.setPlainText(content)
                            except Exception as e:
                                self.txtInput.setPlainText(f"Error:\n{e}")
                elif event.mimeData().hasText():
                    # Text
                    text = event.mimeData().text()
                    # Load text
                    self.txtInput.setPlainText(text)
                event.acceptProposedAction()
                return True
        return super().eventFilter(obj, event)

File with the main window main.py

from PySide6.QtWidgets import (QApplication, QMainWindow)

from up import Up

class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        #self.setupUi(self)

        self.update = Up()
        self.update.show()


if __name__ == "__main__":
    app = QApplication([])
    wMain = Main()
    wMain.show()
    app.exec()

I am using PySide6. I have an application with the user interfaces defined in files apart from the code of each window and a file with the main window that makes use of them. So far a fairly standard construction. I want a text field to be able to either drag text or a file, in which case it should read it and load its contents. The problem arises when I set the field to accept drops and install a filter for the events, but the events that are received are neither drag nor drop. I have prepared a minimal example with a user interface file, a file with the event control code and a main window file. Once running, if you drag a text file into the text field, the only thing that loads is the Url of the file. The print() shows that the filter is entered, but neither drag nor drop is received. What is going on here?

Explanatory note: It is not possible to modify the file with the user interface, it is developed separately and cannot be touched. The solution proposed by @Marijn, extending the QPlainTextEdit class is the most practical, but I can't do it, that's why I'm using an event filter, but I can't get it to work.

File with the user interface up_ui.py

from PySide6.QtWidgets import (QPlainTextEdit,  QVBoxLayout)

class Ui_Up(object):
    def setupUi(self, Up):
        if not Up.objectName():
            Up.setObjectName(u"Up")
        Up.resize(420, 600)
        Up.setModal(True)

        self.txtInput = QPlainTextEdit(Up)
        self.txtInput.setEnabled(True)

        self.VL = QVBoxLayout(Up)
        self.VL.addWidget(self.txtInput)

File with the User interface code up.py

from PySide6.QtCore import QEvent
from PySide6.QtWidgets import QDialog

from up_ui import Ui_Up

class Up(QDialog, Ui_Up):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # Accept drop events
        self.txtInput.setAcceptDrops(True)
        self.txtInput.installEventFilter(self)

    def eventFilter(self, obj, event):
        print(f"Event: {event.type()}")
        print(f"QEvent.DragEnter = {QEvent.DragEnter}")
        print(f"QEvent.Drop = {QEvent.Drop}")
        if id(obj) == id(self.txtInput):
            print("txtInput")
            if event.type() == QEvent.DragEnter:
                print("Drag")
                if (event.mimeData().hasText() or
                    event.mimeData().hasUrls()):
                    event.acceptProposedAction()
                    return True
            elif event.type() == QEvent.Drop:
                print("Drop")
                if event.mimeData().hasUrls():
                    # URL list
                    for url in event.mimeData().urls():
                        print(url)
                        # Link or file
                        link = url.toString()
                        file_path = url.toLocalFile()
                        print(file_path)
                        if file_path.lower().endswith(('.txt', '.text')):
                            # Text file 
                            try:
                                with open(file_path, 'r', encoding='utf-8') as file:
                                    content = file.read()
                                    # Load content 
                                    self.txtInput.setPlainText(content)
                            except Exception as e:
                                self.txtInput.setPlainText(f"Error:\n{e}")
                elif event.mimeData().hasText():
                    # Text
                    text = event.mimeData().text()
                    # Load text
                    self.txtInput.setPlainText(text)
                event.acceptProposedAction()
                return True
        return super().eventFilter(obj, event)

File with the main window main.py

from PySide6.QtWidgets import (QApplication, QMainWindow)

from up import Up

class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        #self.setupUi(self)

        self.update = Up()
        self.update.show()


if __name__ == "__main__":
    app = QApplication([])
    wMain = Main()
    wMain.show()
    app.exec()
Share Improve this question edited Mar 18 at 0:42 JLPrieto asked Mar 16 at 15:44 JLPrietoJLPrieto 1231 silver badge4 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

You can implement the DragEnter and Drop events in a custom class that inherits from QPlainTextEdit. This is done with two special functions dragEnterEvent() and dropEvent(). Note that this means setting the text content is done with self.setPlainText() and not with self.txtInput.setPlainText() as the function setting the text is now inside the TextEdit class.

The hasText() function specifically looks for text/plain and does not accept 'text/plain;charset=utf8', so in case the dragging source application provides only the latter you can add that to the condition for event.accept() in dragEnterEvent() specifically.

Full code (combined into a single file for easier reproducibility):

from PySide6.QtWidgets import QPlainTextEdit,  QVBoxLayout
from PySide6.QtCore import QEvent
from PySide6.QtWidgets import QDialog
from PySide6.QtWidgets import QApplication, QMainWindow

class DropTextEdit(QPlainTextEdit):
    def __init__(self, parent):
        super().__init__()
        self.setEnabled(True)
        self.setAcceptDrops(True)
    
    def dragEnterEvent(self, event):
        mime_data = event.mimeData()
        print("Formats:", mime_data.formats())
        if event.mimeData().hasUrls() or mime_data.hasText() or mime_data.hasFormat('text/plain;charset=utf8'):
            event.accept()

    def dropEvent(self, event):
        print("Drop event")
        if event.mimeData().hasUrls():
            # URL list
            for url in event.mimeData().urls():
                print(url)
                # Link or file
                link = url.toString()
                file_path = url.toLocalFile()
                print(file_path)
                if file_path.lower().endswith(('.txt', '.text')):
                    # Text file 
                    try:
                        with open(file_path, 'r', encoding='utf-8') as file:
                            content = file.read()
                            # Load content 
                            self.setPlainText(content)
                    except Exception as e:
                        self.setPlainText(f"Error:\n{e}")
        elif event.mimeData().hasText():
            # Text
            text = event.mimeData().text()
            # Load text
            self.setPlainText(text)
        event.acceptProposedAction()
        return True
        
class Ui_Up(object):
    def setupUi(self, Up):
        if not Up.objectName():
            Up.setObjectName(u"Up")
        Up.resize(420, 600)
        Up.setModal(True)

        self.txtInput = DropTextEdit(Up)
        
        self.VL = QVBoxLayout(Up)
        self.VL.addWidget(self.txtInput)
        
class Up(QDialog, Ui_Up):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        # Accept drop events
        self.txtInput.setAcceptDrops(True)
        
class Main(QMainWindow):
    def __init__(self):
        super().__init__()
        #self.setupUi(self)

        self.update = Up()
        self.update.show()


if __name__ == "__main__":
    app = QApplication([])
    wMain = Main()
    wMain.show()
    app.exec()

发布评论

评论列表(0)

  1. 暂无评论