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
Forum Update on Monday, May 27th 2025

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.
  • N Offline
    N Offline
    Nlight
    wrote on 24 Feb 2025, 19:02 last edited by Nlight
    #3

    Actually you can implement your own Signal class, it's pretty trivial, here is a quick and dirty example :

    class Signal:
        def __init__(s):
            s._handlers_ = []
    
        def connect(s, func):
            if func not in s._handlers_:
                s._handlers_.append(func)
    
        def emit(s,*args,**kargs):
            for func in s._handlers_:
                if func(*args, **kargs):
                    break
    

    From the class that you want emit a non-existing signal, create an instance of the Signal class as an instance attribute.
    And when you want to emit, just call Signal instance emit() method.

    It's pretty convenient. However, it does require you sublass a QGraphicsItem, a QGraphicsLineItem in your case.

    J 1 Reply Last reply 25 Feb 2025, 08:00
    0
    • G Offline
      G Offline
      Gilboonet
      wrote on 24 Feb 2025, 19:33 last edited by
      #4

      Hello, I used signals that are emited from QGraphicsLineItems but not directly, by using their QGraphicsScene (indeed a subclassed one) that inherits QObject. Things like that :

      void PieceLigneItem::mousePressEvent (QGraphicsSceneMouseEvent *event) {
          qDebug() << this->ligne->id1 << this->ligne->id2;
          if (this->ligne->nb == 1) {
              emit sceneD->peutColorierFace(this->ligne->id1, this->ligne->id2);
          } else {
              emit sceneD->pieceEnleveFaces(this->ligne->id1, this->ligne->id2);
          }
      }
      
      void PieceLigneItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
      {
          QPen p = this->pen();
          p.setColor(Qt::yellow);
          emit sceneD->ligneHoverOn(this->ligne->id1, this->ligne->id2);
          setPen(p);
      }
      

      (sorry, I use C++, not Python)

      1 Reply Last reply
      0
      • N Nlight
        24 Feb 2025, 19:02

        Actually you can implement your own Signal class, it's pretty trivial, here is a quick and dirty example :

        class Signal:
            def __init__(s):
                s._handlers_ = []
        
            def connect(s, func):
                if func not in s._handlers_:
                    s._handlers_.append(func)
        
            def emit(s,*args,**kargs):
                for func in s._handlers_:
                    if func(*args, **kargs):
                        break
        

        From the class that you want emit a non-existing signal, create an instance of the Signal class as an instance attribute.
        And when you want to emit, just call Signal instance emit() method.

        It's pretty convenient. However, it does require you sublass a QGraphicsItem, a QGraphicsLineItem in your case.

        J Offline
        J Offline
        JonB
        wrote on 25 Feb 2025, 08:00 last edited by
        #5

        @Nlight said in Using Signals in QGraphicsItem:

        Actually you can implement your own Signal class, it's pretty trivial

        Your code is fine per se, but that is not using Qt signals at all. It lacks all sorts of stuff provided by Qt signals, it's just a queue a arbitrary functions to call. If you're going to subclass a QGraphicsItem you can just add QObject to inherit from and use Qt signals.

        1 Reply Last reply
        1
        • A Offline
          A Offline
          adrien-lsh
          wrote on 25 Feb 2025, 08:03 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 25 Feb 2025, 08:03
          • A Offline
            A Offline
            adrien-lsh
            wrote on 25 Feb 2025, 08:13 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 ?

            J 1 Reply Last reply 25 Feb 2025, 08:17
            0
            • A adrien-lsh
              25 Feb 2025, 08:13

              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 ?

              J Offline
              J Offline
              JonB
              wrote on 25 Feb 2025, 08:17 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 25 Feb 2025, 08:23 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

                J 1 Reply Last reply 25 Feb 2025, 08:38
                1
                • A adrien-lsh
                  25 Feb 2025, 08:23

                  @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

                  J Offline
                  J Offline
                  JonB
                  wrote on 25 Feb 2025, 08:38 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 25 Feb 2025, 09:04 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.

                    J 1 Reply Last reply 25 Feb 2025, 09:12
                    0
                    • A adrien-lsh has marked this topic as unsolved on 25 Feb 2025, 09:09
                    • A adrien-lsh
                      25 Feb 2025, 09:04

                      @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.

                      J Offline
                      J Offline
                      JonB
                      wrote on 25 Feb 2025, 09:12 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 25 Feb 2025, 09:23
                      0
                      • J JonB
                        25 Feb 2025, 09: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 Offline
                        A Offline
                        adrien-lsh
                        wrote on 25 Feb 2025, 09:23 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 :/

                        J 1 Reply Last reply 25 Feb 2025, 09:24
                        0
                        • A adrien-lsh
                          25 Feb 2025, 09:23

                          @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 :/

                          J Offline
                          J Offline
                          JonB
                          wrote on 25 Feb 2025, 09:24 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 J 2 Replies Last reply 25 Feb 2025, 09:31
                          0
                          • J JonB
                            25 Feb 2025, 09:24

                            @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 25 Feb 2025, 09:31 last edited by
                            #15

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

                            1 Reply Last reply
                            0
                            • J JonB
                              25 Feb 2025, 09:24

                              @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....

                              J Offline
                              J Offline
                              JonB
                              wrote on 25 Feb 2025, 09:31 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 25 Feb 2025, 09:32
                              0
                              • J JonB
                                25 Feb 2025, 09:31

                                @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 25 Feb 2025, 09:32 last edited by
                                #17

                                @JonB
                                Try to move the line.

                                J 1 Reply Last reply 25 Feb 2025, 09:35
                                0
                                • A adrien-lsh
                                  25 Feb 2025, 09:32

                                  @JonB
                                  Try to move the line.

                                  J Offline
                                  J Offline
                                  JonB
                                  wrote on 25 Feb 2025, 09:35 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 25 Feb 2025, 09:36
                                  0
                                  • J JonB
                                    25 Feb 2025, 09:35

                                    @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 25 Feb 2025, 09:36 last edited by
                                    #19

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

                                    J 1 Reply Last reply 25 Feb 2025, 09:50
                                    0
                                    • A adrien-lsh
                                      25 Feb 2025, 09:36

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

                                      J Offline
                                      J Offline
                                      JonB
                                      wrote on 25 Feb 2025, 09:50 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 25 Feb 2025, 10:03
                                      1
                                      • A adrien-lsh has marked this topic as solved on 25 Feb 2025, 10:03
                                      • J JonB
                                        25 Feb 2025, 09:50

                                        @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 25 Feb 2025, 10:03 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 25 Feb 2025, 10:23 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

                                          J 1 Reply Last reply 25 Feb 2025, 10:27
                                          0

                                          12/25

                                          25 Feb 2025, 09:12

                                          • Login

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