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. Using Signals in QGraphicsItem

Using Signals in QGraphicsItem

Scheduled Pinned Locked Moved Solved Qt for Python
25 Posts 5 Posters 1.3k 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.
  • A Offline
    A Offline
    adrien-lsh
    wrote on last edited by
    #6

    Thank you all for your answers
    I think I'll go with the easier implementation and just add the QObject inheritance to my custom QGraphicsLineItem class.

    1 Reply Last reply
    0
    • A adrien-lsh has marked this topic as solved on
    • A Offline
      A Offline
      adrien-lsh
      wrote on last edited by
      #7

      Ok I'm having another problem now :/ The program crashes when I try to move the lines (without any information in the console)

      class CroppingLine(QGraphicsLineItem, QObject):
          moved = Signal(object, QPointF)
      
          def __init__(self, x1: float, y1: float, x2: float, y2: float, is_vertical: bool):
              super().__init__(x1, y1, x2, y2)
      
              self.is_vertical = is_vertical
              self.setPen(QPen(Qt.GlobalColor.black, 2))
              self.setCursor(Qt.CursorShape.SizeVerCursor if is_vertical
                             else Qt.CursorShape.SizeHorCursor)
              self.setFlags(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
      
          def mouseMoveEvent(self, event):
              super().mouseMoveEvent(event)
              self.moved.emit(self, self.scenePos())
      

      Is there something I did wrong ?

      JonBJ 1 Reply Last reply
      0
      • A adrien-lsh

        Ok I'm having another problem now :/ The program crashes when I try to move the lines (without any information in the console)

        class CroppingLine(QGraphicsLineItem, QObject):
            moved = Signal(object, QPointF)
        
            def __init__(self, x1: float, y1: float, x2: float, y2: float, is_vertical: bool):
                super().__init__(x1, y1, x2, y2)
        
                self.is_vertical = is_vertical
                self.setPen(QPen(Qt.GlobalColor.black, 2))
                self.setCursor(Qt.CursorShape.SizeVerCursor if is_vertical
                               else Qt.CursorShape.SizeHorCursor)
                self.setFlags(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
        
            def mouseMoveEvent(self, event):
                super().mouseMoveEvent(event)
                self.moved.emit(self, self.scenePos())
        

        Is there something I did wrong ?

        JonBJ Online
        JonBJ Online
        JonB
        wrote on last edited by
        #8

        @adrien-lsh
        What happens if you do not attach a slot to the signal?
        What happens if you do not emit the signal?
        What happens if you define and emit a signal without any parameters?

        1 Reply Last reply
        0
        • A Offline
          A Offline
          adrien-lsh
          wrote on last edited by adrien-lsh
          #9

          @JonB
          I tried all of that already, when the signal is emitted (even without or with different parameters) it crashes: the line does not move, it waits a bit, then the window closes.
          It crashes on the Signal.emit().

          btw sorry I cannot respond faster I have the 10m new guy cooldown

          JonBJ 1 Reply Last reply
          1
          • A adrien-lsh

            @JonB
            I tried all of that already, when the signal is emitted (even without or with different parameters) it crashes: the line does not move, it waits a bit, then the window closes.
            It crashes on the Signal.emit().

            btw sorry I cannot respond faster I have the 10m new guy cooldown

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

            @adrien-lsh
            So you are claiming if you inherit from QObject, define a signal and emit it without a slot attached it crashes?

            Try swapping the inheritance order to make QObject the first class inherited from (i.e. (QObject, QGraphicsLineItem). This would be required for moc from C++, I don't know if it might be required from Python. I am (then) also slightly unsure about plain super() calls from Python, I don't know if you need to qualify that to indicate which of the two super classes to use.

            You have not said what version of Qt you are using and whether PySide or PyQt. If you produce a minimal, standalone example which I can copy and paste I will test here.

            1 Reply Last reply
            0
            • A Offline
              A Offline
              adrien-lsh
              wrote on last edited by adrien-lsh
              #11

              @JonB
              Yes that's what is happening. I am using PySide6 and here is an example:

              from PySide6.QtCore import QObject, QPointF, Signal
              from PySide6.QtGui import QPen, Qt
              from PySide6.QtWidgets import QApplication, QGraphicsItem, QGraphicsView, QGraphicsScene, QGraphicsLineItem
              
              
              class GraphicsView(QGraphicsView):
                  def __init__(self, parent=None):
                      super().__init__(parent)
                      scene = QGraphicsScene()
                      self.line = CroppingLine(0, 0, 100, 100)
                      scene.addItem(self.line)
                      self.setScene(scene)
              
              
              class CroppingLine(QGraphicsLineItem, QObject):
                  moved = Signal(object, QPointF)
              
                  def __init__(self, x1: float, y1: float, x2: float, y2: float):
                      super().__init__(x1, y1, x2, y2)
                      self.setPen(QPen(Qt.GlobalColor.blue, 3))
                      self.setFlags(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
              
                  def mouseMoveEvent(self, event):
                      super().mouseMoveEvent(event)
                      self.moved.emit(self, self.scenePos())
              
              if __name__ == '__main__':
                  import sys
                  app = QApplication(sys.argv)
                  window = GraphicsView()
                  window.show()
                  sys.exit(app.exec())
              

              About the swap of the superclasses, I dont think it would work because the super().__init__() would not call QGraphicsLineItem init function but QObject's.

              JonBJ 1 Reply Last reply
              0
              • A adrien-lsh has marked this topic as unsolved on
              • A adrien-lsh

                @JonB
                Yes that's what is happening. I am using PySide6 and here is an example:

                from PySide6.QtCore import QObject, QPointF, Signal
                from PySide6.QtGui import QPen, Qt
                from PySide6.QtWidgets import QApplication, QGraphicsItem, QGraphicsView, QGraphicsScene, QGraphicsLineItem
                
                
                class GraphicsView(QGraphicsView):
                    def __init__(self, parent=None):
                        super().__init__(parent)
                        scene = QGraphicsScene()
                        self.line = CroppingLine(0, 0, 100, 100)
                        scene.addItem(self.line)
                        self.setScene(scene)
                
                
                class CroppingLine(QGraphicsLineItem, QObject):
                    moved = Signal(object, QPointF)
                
                    def __init__(self, x1: float, y1: float, x2: float, y2: float):
                        super().__init__(x1, y1, x2, y2)
                        self.setPen(QPen(Qt.GlobalColor.blue, 3))
                        self.setFlags(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
                
                    def mouseMoveEvent(self, event):
                        super().mouseMoveEvent(event)
                        self.moved.emit(self, self.scenePos())
                
                if __name__ == '__main__':
                    import sys
                    app = QApplication(sys.argv)
                    window = GraphicsView()
                    window.show()
                    sys.exit(app.exec())
                

                About the swap of the superclasses, I dont think it would work because the super().__init__() would not call QGraphicsLineItem init function but QObject's.

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

                @adrien-lsh
                Before you make me try this, I did ask you put QObject first, that is at least required using C++/moc so I'd like you to test it. As I said, you should look up how super() works in Python, I think you can call something like super(QGraphicsLineItem).__init__() (actually it might be super(QGraphicsLineItem, self).__init__()?) if you need to, but you are the Python programmer!

                A 1 Reply Last reply
                0
                • JonBJ JonB

                  @adrien-lsh
                  Before you make me try this, I did ask you put QObject first, that is at least required using C++/moc so I'd like you to test it. As I said, you should look up how super() works in Python, I think you can call something like super(QGraphicsLineItem).__init__() (actually it might be super(QGraphicsLineItem, self).__init__()?) if you need to, but you are the Python programmer!

                  A Offline
                  A Offline
                  adrien-lsh
                  wrote on last edited by
                  #13

                  @JonB
                  Nope it does not work with super(QGraphicsLineItem, self).__init__(...) because Python is trying to call the super class of QGraphicsLineItem which is QGraphicsItem and my class does not directly inherit from it so it doesnt work.

                  I did achieve the inheritance swap using super(QObject, self).__init__(...) tho and my line displays correctly but it still crashes :/

                  JonBJ 1 Reply Last reply
                  0
                  • A adrien-lsh

                    @JonB
                    Nope it does not work with super(QGraphicsLineItem, self).__init__(...) because Python is trying to call the super class of QGraphicsLineItem which is QGraphicsItem and my class does not directly inherit from it so it doesnt work.

                    I did achieve the inheritance swap using super(QObject, self).__init__(...) tho and my line displays correctly but it still crashes :/

                    JonBJ Online
                    JonBJ Online
                    JonB
                    wrote on last edited by
                    #14

                    @adrien-lsh
                    Since you seem to have provided a nice, standalone, complete example I can copy and paste --- unlike so many other people --- I will give it a play now....

                    A JonBJ 2 Replies Last reply
                    0
                    • JonBJ JonB

                      @adrien-lsh
                      Since you seem to have provided a nice, standalone, complete example I can copy and paste --- unlike so many other people --- I will give it a play now....

                      A Offline
                      A Offline
                      adrien-lsh
                      wrote on last edited by
                      #15

                      @JonB
                      Thanks! Let me know if you need any more information.

                      1 Reply Last reply
                      0
                      • JonBJ JonB

                        @adrien-lsh
                        Since you seem to have provided a nice, standalone, complete example I can copy and paste --- unlike so many other people --- I will give it a play now....

                        JonBJ Online
                        JonBJ Online
                        JonB
                        wrote on last edited by
                        #16

                        @JonB
                        Your code above, copied and pasted, works fine for me. Ubuntu 24.04, Qt 6.4.2, PySide6. Or at least I get an open window with a line in it. Could you be very specific about what you do to make it "crash"?

                        A 1 Reply Last reply
                        0
                        • JonBJ JonB

                          @JonB
                          Your code above, copied and pasted, works fine for me. Ubuntu 24.04, Qt 6.4.2, PySide6. Or at least I get an open window with a line in it. Could you be very specific about what you do to make it "crash"?

                          A Offline
                          A Offline
                          adrien-lsh
                          wrote on last edited by
                          #17

                          @JonB
                          Try to move the line.

                          JonBJ 1 Reply Last reply
                          0
                          • A adrien-lsh

                            @JonB
                            Try to move the line.

                            JonBJ Online
                            JonBJ Online
                            JonB
                            wrote on last edited by
                            #18

                            @adrien-lsh
                            Yeah, that's easier said than done! It's so thin, and I can't tell when I have actually grabbed it or not! Anyway I have reproed now, it does a SIGSEGV from

                            0x00007ffff711fc14 in PySide::SignalManager::emitSignal(QObject*, char const*, _object*) ()
                               from /home/jon/.venv/pyside6/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.7
                            (gdb) bt
                            #0  0x00007ffff711fc14 in PySide::SignalManager::emitSignal(QObject*, char const*, _object*) ()
                                at /home/jon/.venv/pyside6/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.7
                            

                            Looking into that now...

                            A 1 Reply Last reply
                            0
                            • JonBJ JonB

                              @adrien-lsh
                              Yeah, that's easier said than done! It's so thin, and I can't tell when I have actually grabbed it or not! Anyway I have reproed now, it does a SIGSEGV from

                              0x00007ffff711fc14 in PySide::SignalManager::emitSignal(QObject*, char const*, _object*) ()
                                 from /home/jon/.venv/pyside6/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.7
                              (gdb) bt
                              #0  0x00007ffff711fc14 in PySide::SignalManager::emitSignal(QObject*, char const*, _object*) ()
                                  at /home/jon/.venv/pyside6/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.7
                              

                              Looking into that now...

                              A Offline
                              A Offline
                              adrien-lsh
                              wrote on last edited by
                              #19

                              @JonB
                              Yeah I should've set a bigger width ^^. Thank you.

                              JonBJ 1 Reply Last reply
                              0
                              • A adrien-lsh

                                @JonB
                                Yeah I should've set a bigger width ^^. Thank you.

                                JonBJ Online
                                JonBJ Online
                                JonB
                                wrote on last edited by JonB
                                #20

                                @adrien-lsh
                                I think it is to do with the initialisation, requiring both inherited classes to be initialised. You were only doing so for the QGraphicsLineItem, not initialising the QObject. I find the following does work without crashing:

                                class CroppingLine(QObject, QGraphicsLineItem):
                                    moved = Signal(object, QPointF)
                                
                                    def __init__(self, x1: float, y1: float, x2: float, y2: float):
                                        #super(QGraphicsLineItem, self).__init__(x1, y1, x2, y2)
                                        QObject.__init__(self)
                                        QGraphicsLineItem.__init__(self, x1, y1, x2, y2)
                                

                                There may be other ways of doing this with super() and/or not swapping the inheritance order, I just know this works fine.

                                A 1 Reply Last reply
                                1
                                • A adrien-lsh has marked this topic as solved on
                                • JonBJ JonB

                                  @adrien-lsh
                                  I think it is to do with the initialisation, requiring both inherited classes to be initialised. You were only doing so for the QGraphicsLineItem, not initialising the QObject. I find the following does work without crashing:

                                  class CroppingLine(QObject, QGraphicsLineItem):
                                      moved = Signal(object, QPointF)
                                  
                                      def __init__(self, x1: float, y1: float, x2: float, y2: float):
                                          #super(QGraphicsLineItem, self).__init__(x1, y1, x2, y2)
                                          QObject.__init__(self)
                                          QGraphicsLineItem.__init__(self, x1, y1, x2, y2)
                                  

                                  There may be other ways of doing this with super() and/or not swapping the inheritance order, I just know this works fine.

                                  A Offline
                                  A Offline
                                  adrien-lsh
                                  wrote on last edited by
                                  #21

                                  @JonB
                                  Of course ! It never initialized the QObject so signals would never work.
                                  Thank you for your help !

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

                                    Hi,

                                    It's Python3, remove the class from your super calls. This should allow Python to do proper initialisation of the chain of classes (though sometimes it might fail for complex cases).

                                    [Edit: we are in such a complex case]

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

                                    JonBJ 1 Reply Last reply
                                    0
                                    • SGaistS SGaist

                                      Hi,

                                      It's Python3, remove the class from your super calls. This should allow Python to do proper initialisation of the chain of classes (though sometimes it might fail for complex cases).

                                      [Edit: we are in such a complex case]

                                      JonBJ Online
                                      JonBJ Online
                                      JonB
                                      wrote on last edited by JonB
                                      #23

                                      @SGaist
                                      But the OP started with just

                                      super().__init__(x1, y1, x2, y2)
                                      

                                      and, for whatever reason, that segments (later, on signal emit) because the QObject part has not been initialized, apparently. That is why I tried splitting it into two separate explicit initializations, which makes it work. So what exactly are you proposing?

                                      SGaistS 1 Reply Last reply
                                      0
                                      • JonBJ JonB

                                        @SGaist
                                        But the OP started with just

                                        super().__init__(x1, y1, x2, y2)
                                        

                                        and, for whatever reason, that segments (later, on signal emit) because the QObject part has not been initialized, apparently. That is why I tried splitting it into two separate explicit initializations, which makes it work. So what exactly are you proposing?

                                        SGaistS Offline
                                        SGaistS Offline
                                        SGaist
                                        Lifetime Qt Champion
                                        wrote on last edited by SGaist
                                        #24

                                        @JonB I misread the code !

                                        We are in the territory where your solution (using __init__) is the way to go. Multiple inheritance in Python is quite tricky...

                                        QObject expects an optional parent parameter which is not given here but it's not expecting the parameters for the QGraphicsLineItem constructor hence the failure. You can try to use the kwargs trick however it won't work either as it's not part of any of the method signature and thus can't work either.

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

                                        1 Reply Last reply
                                        0
                                        • N Offline
                                          N Offline
                                          Nlight
                                          wrote on last edited by Nlight
                                          #25
                                          This post is deleted!
                                          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