Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to override PySide2 widget's method generated by Qt Designer?
QtWS25 Last Chance

How to override PySide2 widget's method generated by Qt Designer?

Scheduled Pinned Locked Moved Solved Qt for Python
qt for pythonpyside2
13 Posts 3 Posters 2.9k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    johnjml
    wrote on last edited by johnjml
    #1

    I'm trying to learn PySide2 by creating a mimic executable like powerrename tool in powertoys.
    I created all the visible UI part in Qt Designer.
    Then generated a class named Ui_PowerRenameDialog and import the class into the code showed below.
    I wanted to accomplish a functionality which can let users drag and drop files from Windows Explorer to the QTreeWidget instance in the window.

    I encountered a error when trying to override the dragEnterEvent and dropEvent methods of the QTreeWidget instance.
    The Error message shows here:

    TypeError: dragEnterEvent() missing 1 required positional argument: 'evt'.
    

    Here is my full code:

    import sys
    from PySide6 import QtWidgets
    from PySide6 import QtCore
    from ui_powerRename import Ui_PowerRenameDialog
    
    class MyPowerRenameDialog(QtWidgets.QDialog):
        def __init__(self,parent=None):
            super().__init__(parent)
    
            self.ui = Ui_PowerRenameDialog()
            self.ui.setupUi(self)
    
            self.modify_ui()
            self.create_connections()
    
    
        def modify_ui(self):
            self.ui.previewTreeWidget.setAcceptDrops(True)
    #######################    The Overloading Part   ######################################
            def dragEnterEvent(self,evt):
                if evt.mimeData().hasUrls():
                    evt.accept()
                else:
                    evt.ignore()
    
            def dropEvent(self,evt):
                for url in evt.mimeData().urls():
                    newItem = QtWidgets.QTreeWidgetItem(url)
                    self.addTopLevelItem(newItem)
    
            self.ui.previewTreeWidget.dragEnterEvent = dragEnterEvent
            self.ui.previewTreeWidget.dropEvent = dropEvent
    ########################################################################################
            
            items = QtWidgets.QTreeWidgetItemIterator(self.ui.previewTreeWidget)
            for item in items:
                item.value().setFlags(item.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                item.value().setCheckState(0,QtCore.Qt.Checked)
    
        def create_connections(self):
            self.ui.cancelButton.clicked.connect(self.close)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
    
        window = MyPowerRenameDialog()
        window.show()
    
        sys.exit(app.exec_())
    
    • I wonder what is the proper way to achieve that functionality?
    • And is there a way to override the method of widget instance which is generated by Qt Designer?
    JonBJ 1 Reply Last reply
    0
    • J johnjml

      I'm trying to learn PySide2 by creating a mimic executable like powerrename tool in powertoys.
      I created all the visible UI part in Qt Designer.
      Then generated a class named Ui_PowerRenameDialog and import the class into the code showed below.
      I wanted to accomplish a functionality which can let users drag and drop files from Windows Explorer to the QTreeWidget instance in the window.

      I encountered a error when trying to override the dragEnterEvent and dropEvent methods of the QTreeWidget instance.
      The Error message shows here:

      TypeError: dragEnterEvent() missing 1 required positional argument: 'evt'.
      

      Here is my full code:

      import sys
      from PySide6 import QtWidgets
      from PySide6 import QtCore
      from ui_powerRename import Ui_PowerRenameDialog
      
      class MyPowerRenameDialog(QtWidgets.QDialog):
          def __init__(self,parent=None):
              super().__init__(parent)
      
              self.ui = Ui_PowerRenameDialog()
              self.ui.setupUi(self)
      
              self.modify_ui()
              self.create_connections()
      
      
          def modify_ui(self):
              self.ui.previewTreeWidget.setAcceptDrops(True)
      #######################    The Overloading Part   ######################################
              def dragEnterEvent(self,evt):
                  if evt.mimeData().hasUrls():
                      evt.accept()
                  else:
                      evt.ignore()
      
              def dropEvent(self,evt):
                  for url in evt.mimeData().urls():
                      newItem = QtWidgets.QTreeWidgetItem(url)
                      self.addTopLevelItem(newItem)
      
              self.ui.previewTreeWidget.dragEnterEvent = dragEnterEvent
              self.ui.previewTreeWidget.dropEvent = dropEvent
      ########################################################################################
              
              items = QtWidgets.QTreeWidgetItemIterator(self.ui.previewTreeWidget)
              for item in items:
                  item.value().setFlags(item.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                  item.value().setCheckState(0,QtCore.Qt.Checked)
      
          def create_connections(self):
              self.ui.cancelButton.clicked.connect(self.close)
      
      
      if __name__ == "__main__":
          app = QtWidgets.QApplication(sys.argv)
      
          window = MyPowerRenameDialog()
          window.show()
      
          sys.exit(app.exec_())
      
      • I wonder what is the proper way to achieve that functionality?
      • And is there a way to override the method of widget instance which is generated by Qt Designer?
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @johnjml
      Hi and welcome.

      Did you come across this code, or something like it, in a Python/PySide/PyQt example or thread? In which case please post the link so I can read.

      Or, is this just your own code for how you think to go about overloading Qt methods? Your code is very "Pythony", one couldn't do anything like it in C++, so need to understand where you are coming from.

      J 1 Reply Last reply
      0
      • J Offline
        J Offline
        johnjml
        wrote on last edited by johnjml
        #3
        This post is deleted!
        1 Reply Last reply
        0
        • JonBJ JonB

          @johnjml
          Hi and welcome.

          Did you come across this code, or something like it, in a Python/PySide/PyQt example or thread? In which case please post the link so I can read.

          Or, is this just your own code for how you think to go about overloading Qt methods? Your code is very "Pythony", one couldn't do anything like it in C++, so need to understand where you are coming from.

          J Offline
          J Offline
          johnjml
          wrote on last edited by
          #4

          Hi, @JonB
          Thanks for your reply.

          First,I must say sorry. It's all about 'overriding'. 'overload' is my typo,edited that.Sorry if you feel confused.

          It's my own code. As I mentioned,I'm trying to learn PySide,and my knowledge of C++ is very poor,which is limited to basic syntax(sorry for my stupidity).

          I came across the basic idea from this PySide documentation example.
          I have watched some tutorials about PySide, such as this Zurbrigg PySide tutorial.

          Sorry that I cannot find systematic instructions of learning PySide and I really think the documentation of PySide is a little bit messy for beginners like me.Sometimes I have to navigate to C++ version of the documents to fetch some information of a class or a method (such as return types).

          I know that I can derive a custom QTreeWidget class from the basic QTreeWidget and override the methods there.

          But I do what to know is there a way to override methods of widget generated from Qt Designer?

          And beginner-friendly resources of learning Pyside will be much appreciated.

          Thank you.

          JonBJ 1 Reply Last reply
          0
          • J johnjml

            Hi, @JonB
            Thanks for your reply.

            First,I must say sorry. It's all about 'overriding'. 'overload' is my typo,edited that.Sorry if you feel confused.

            It's my own code. As I mentioned,I'm trying to learn PySide,and my knowledge of C++ is very poor,which is limited to basic syntax(sorry for my stupidity).

            I came across the basic idea from this PySide documentation example.
            I have watched some tutorials about PySide, such as this Zurbrigg PySide tutorial.

            Sorry that I cannot find systematic instructions of learning PySide and I really think the documentation of PySide is a little bit messy for beginners like me.Sometimes I have to navigate to C++ version of the documents to fetch some information of a class or a method (such as return types).

            I know that I can derive a custom QTreeWidget class from the basic QTreeWidget and override the methods there.

            But I do what to know is there a way to override methods of widget generated from Qt Designer?

            And beginner-friendly resources of learning Pyside will be much appreciated.

            Thank you.

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #5

            @johnjml
            The example you used has nothing to say about either overloading or overriding. The way you have chosen to try to achieve that

                    self.ui.previewTreeWidget.dragEnterEvent = dragEnterEvent
                    self.ui.previewTreeWidget.dropEvent = dropEvent
            

            is a totally Pythonic feature of replacing am existing function pointer, or whatever this is referred to in Python ("monkey-patching?"). It would not be be available in C++, and it's not how we go about overriding an existing virtual method. I do not know whether your way can work in Python/PySide, perhaps not because of the error message you receive.

            The way I have done it in PySide is the same as I would in C++, and corresponds to Python examples I have seen. Basically we must subclass the widget, and the Python would look something like this:

            class PreviewTreeWidget(QTreeWidget):
                def __init__(self, parent=None):
                    super().__init__(parent)
            
                def dragEnterEvent(self, evt):
                    # your code
            
                def dropEvent(self, evt):
                    # your code
            

            An example for PyQt5 is shown in e.g. https://zetcode.com/gui/pyqt5/dragdrop/. Should be same for PySide2.

            When you need to do this against a widget in Qt Designer, you need to use its Promote feature to effectively declare your PreviewTreeWidget class as derived from and usable in place of a standard QTextWidget. I'm not sure how that works or how easy/difficult it is from PySide, Google for e.g. pyside2 designer promote widget (or pyqt5) and have a read.

            I am mentioning @SGaist here, in the hope he will see this and comment as to whether this is right or wrong for PySide. He is a general expert, but I know he has used PySide too. I will also mention @mrjj, who is a Designer UI expert for things like Promote, but I'm not sure if he knows about the PySide requirements for this.

            Finally, when you get past this issue, unless you know better than I this code

                        item.value().setFlags(item.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                        item.value().setCheckState(0,QtCore.Qt.Checked)
            

            does not look right. I don't see you can call these methods on value(). I would have thought you would remove .value() from both of these?

            J 1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              Hi,

              Monkey patching can work, no problem with that but at some point it becomes really hard to reason about it.

              Since you are doing several changes, you should follow @JonB´a suggestion and use the promote feature of Designer.

              If you have simple widgets, you might also want to learn to build your UI directly with code.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              J 1 Reply Last reply
              2
              • JonBJ JonB

                @johnjml
                The example you used has nothing to say about either overloading or overriding. The way you have chosen to try to achieve that

                        self.ui.previewTreeWidget.dragEnterEvent = dragEnterEvent
                        self.ui.previewTreeWidget.dropEvent = dropEvent
                

                is a totally Pythonic feature of replacing am existing function pointer, or whatever this is referred to in Python ("monkey-patching?"). It would not be be available in C++, and it's not how we go about overriding an existing virtual method. I do not know whether your way can work in Python/PySide, perhaps not because of the error message you receive.

                The way I have done it in PySide is the same as I would in C++, and corresponds to Python examples I have seen. Basically we must subclass the widget, and the Python would look something like this:

                class PreviewTreeWidget(QTreeWidget):
                    def __init__(self, parent=None):
                        super().__init__(parent)
                
                    def dragEnterEvent(self, evt):
                        # your code
                
                    def dropEvent(self, evt):
                        # your code
                

                An example for PyQt5 is shown in e.g. https://zetcode.com/gui/pyqt5/dragdrop/. Should be same for PySide2.

                When you need to do this against a widget in Qt Designer, you need to use its Promote feature to effectively declare your PreviewTreeWidget class as derived from and usable in place of a standard QTextWidget. I'm not sure how that works or how easy/difficult it is from PySide, Google for e.g. pyside2 designer promote widget (or pyqt5) and have a read.

                I am mentioning @SGaist here, in the hope he will see this and comment as to whether this is right or wrong for PySide. He is a general expert, but I know he has used PySide too. I will also mention @mrjj, who is a Designer UI expert for things like Promote, but I'm not sure if he knows about the PySide requirements for this.

                Finally, when you get past this issue, unless you know better than I this code

                            item.value().setFlags(item.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                            item.value().setCheckState(0,QtCore.Qt.Checked)
                

                does not look right. I don't see you can call these methods on value(). I would have thought you would remove .value() from both of these?

                J Offline
                J Offline
                johnjml
                wrote on last edited by
                #7

                @JonB
                Oh,I see.
                Seems the correct way of overriding is to declare and define my custom QTreeWidget and derive from the basic widget.
                The 'monkey-patching' thing is a python way to change function or method in runtime.I was thinking it might have the same effect like overriding,that why I used the term 'overriding' in the question.I can see I'm totally wrong about that.

                As for the .value() issue you mentioned, every item in that snippet is actually a Iterater object in python,so I have to use the .value() to get the actual QTreeWidgetItem to access the methods in QTreeWidgetItem instance.
                If I remove .value(),I will get an AttributeError: 'PySide6.QtWidgets.QTreeWidgetItemIterator' object has no attribute 'setFlags'.The official doc is referenced here.
                I'm also quite confued by this,hope the experts you mentioned can explain it.
                Maybe I should change my code to this so it can be undertood better:

                itemIter = QtWidgets.QTreeWidgetItemIterator(self.ui.previewTreeWidget)
                for iter in itemIter:
                    iter.value().setFlags(iter.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                    iter.value().setCheckState(0,QtCore.Qt.Checked)
                
                JonBJ 1 Reply Last reply
                0
                • J johnjml

                  @JonB
                  Oh,I see.
                  Seems the correct way of overriding is to declare and define my custom QTreeWidget and derive from the basic widget.
                  The 'monkey-patching' thing is a python way to change function or method in runtime.I was thinking it might have the same effect like overriding,that why I used the term 'overriding' in the question.I can see I'm totally wrong about that.

                  As for the .value() issue you mentioned, every item in that snippet is actually a Iterater object in python,so I have to use the .value() to get the actual QTreeWidgetItem to access the methods in QTreeWidgetItem instance.
                  If I remove .value(),I will get an AttributeError: 'PySide6.QtWidgets.QTreeWidgetItemIterator' object has no attribute 'setFlags'.The official doc is referenced here.
                  I'm also quite confued by this,hope the experts you mentioned can explain it.
                  Maybe I should change my code to this so it can be undertood better:

                  itemIter = QtWidgets.QTreeWidgetItemIterator(self.ui.previewTreeWidget)
                  for iter in itemIter:
                      iter.value().setFlags(iter.value().flags()|QtCore.Qt.ItemIsUserCheckable)
                      iter.value().setCheckState(0,QtCore.Qt.Checked)
                  
                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #8

                  @johnjml
                  For the overriding, see @SGaist's confirmation of my understand above.

                  The iterator is a small problem, which you will get right. I respect what you say. However you referred me to the PySide2 reference page and that starts with example:

                  it = QTreeWidgetItemIterator(treeWidget)
                  while it:
                      if (it).text(0) == itemText:
                          (it).setSelected(True)
                      it = it + 1
                  

                  Here you can see no use of .value(). However, looking at it I am concerned it might be some straight copy of the required C++ code, and nonsense for Python? I believe some/most/all of the PySide2 examples code may have been left as simple, automated translation from the C++ examples...?

                  J 1 Reply Last reply
                  0
                  • JonBJ JonB

                    @johnjml
                    For the overriding, see @SGaist's confirmation of my understand above.

                    The iterator is a small problem, which you will get right. I respect what you say. However you referred me to the PySide2 reference page and that starts with example:

                    it = QTreeWidgetItemIterator(treeWidget)
                    while it:
                        if (it).text(0) == itemText:
                            (it).setSelected(True)
                        it = it + 1
                    

                    Here you can see no use of .value(). However, looking at it I am concerned it might be some straight copy of the required C++ code, and nonsense for Python? I believe some/most/all of the PySide2 examples code may have been left as simple, automated translation from the C++ examples...?

                    J Offline
                    J Offline
                    johnjml
                    wrote on last edited by
                    #9

                    @JonB
                    Right,that example is the confusing point.I noticed the problem too.
                    See that is the 'messy' part in PySide doc I was talking about.
                    Some examples and descriptions are not so python user friendly.
                    Return types are not strictly listed.
                    Still,very appreciate your help.

                    JonBJ 1 Reply Last reply
                    0
                    • J johnjml

                      @JonB
                      Right,that example is the confusing point.I noticed the problem too.
                      See that is the 'messy' part in PySide doc I was talking about.
                      Some examples and descriptions are not so python user friendly.
                      Return types are not strictly listed.
                      Still,very appreciate your help.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #10

                      @johnjml
                      Sadly (depending on your POV!) Python is still very much a second-class citizen in the Qt world.

                      PyQt5 never had its own documentation, you just had to go look up the normal C++ documentation and figure for yourself.

                      PySide2 does have those documentation pages you reference. However, they seem to have been generated automatically by some translation tool from the literal C++ examples in their doc pages. Newer PySide6 docs do not seem to me to have changed in this respect. As we are both saying, I believe that while some of them work some will not. As witness the current case. I found the PySide2 docs useless, and always use the C++ ones, regardless of which language I am programming in. At least be aware that even if C++ is not your favored language it can be worth looking at the standard C++ docs as well as the PySide stuff.

                      1 Reply Last reply
                      0
                      • SGaistS SGaist

                        Hi,

                        Monkey patching can work, no problem with that but at some point it becomes really hard to reason about it.

                        Since you are doing several changes, you should follow @JonB´a suggestion and use the promote feature of Designer.

                        If you have simple widgets, you might also want to learn to build your UI directly with code.

                        J Offline
                        J Offline
                        johnjml
                        wrote on last edited by
                        #11

                        @SGaist
                        I see,monkey patching is really confusing me.Maybe it will work in some way.
                        I will dig in the promote feature right now.
                        Thanks for your help.

                        Could you please provide some PySide beginner-friendly learning resources,master SGaist?
                        It would help alot.
                        Again,huge thanks.

                        JonBJ 1 Reply Last reply
                        0
                        • J johnjml

                          @SGaist
                          I see,monkey patching is really confusing me.Maybe it will work in some way.
                          I will dig in the promote feature right now.
                          Thanks for your help.

                          Could you please provide some PySide beginner-friendly learning resources,master SGaist?
                          It would help alot.
                          Again,huge thanks.

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #12

                          @johnjml
                          Then don't use your monkey-patching code approach! If you do the Promote route there will be no monkey patching, and it will work by overriding the method in a subclass, like one would have to do in C++. The only issue then is how you get Designer Promote to work right for PySide2, there must be Googlable answers out there.....

                          J 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @johnjml
                            Then don't use your monkey-patching code approach! If you do the Promote route there will be no monkey patching, and it will work by overriding the method in a subclass, like one would have to do in C++. The only issue then is how you get Designer Promote to work right for PySide2, there must be Googlable answers out there.....

                            J Offline
                            J Offline
                            johnjml
                            wrote on last edited by johnjml
                            #13

                            @JonB
                            Yeah,I abandoned the monkey patching thing. It's not a good way to edit widgets.
                            I'll follow your promote solution.I'll try google it.I didn't even know there is a promote feature before.
                            I'm not a native english speaker,hope my codes and typos didn't make you angry.

                            Really appreciate the help of yours.Thanks alot.

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved