Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. itemChange() problem

itemChange() problem

Scheduled Pinned Locked Moved Unsolved General and Desktop
pyqtitemchange
12 Posts 5 Posters 6.7k 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.
  • O Offline
    O Offline
    Oatmeal
    wrote on 20 Nov 2017, 09:34 last edited by Oatmeal
    #1

    I am using pyqt and Python 3. I want to prevent a QGraphicsRectItem to cross the horizontal axis (y=0) in a QGraphicsScene when dragged with the mouse. I am using the following code (employing height() because the rectangle is in the upper half of the screen). See below a full example of the code.

    ######################################################

    import sys
    from PyQt4.QtCore import Qt, QPointF
    from PyQt4.QtGui import QGraphicsRectItem, QGraphicsLineItem, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem
    
    class MyRect(QGraphicsRectItem):
        def __init__(self, w, h):
            super().__init__(0, 0, w, h)
            self.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.setFlag(QGraphicsItem.ItemIsSelectable, True)
            self.setFlag(QGraphicsItem.ItemIsFocusable, True)
            self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
    
        def itemChange(self, change, value):
            if change == QGraphicsItem.ItemPositionChange:
                if self.y() + self.rect().height() > 0:
                    return QPointF(self.x(), -self.rect().height())
            return value
    
    def main():
        # Set up the framework.
        app = QApplication(sys.argv)
        gr_view = QGraphicsView()
        scene = QGraphicsScene()
        scene.setSceneRect(-100, -100, 200, 200)
        gr_view.setScene(scene)
    
        # Add an x-axis
        x_axis = QGraphicsLineItem(-100, 0, 100, 0)
        scene.addItem(x_axis)
    
        # Add the restrained rect.
        rect = MyRect(50, 50)
        rect.setPos(-25, -100) # <--- not clear to me why I have to do this twice to get the 
        rect.setPos(-25, -100) # item positioned. I know it has to do with my itemChanged above...
        scene.addItem(rect)
    
        gr_view.fitInView(0, 0, 200, 200, Qt.KeepAspectRatio)    
        gr_view.show()
        sys.exit(app.exec_())
    
    if __name__ == '__main__':
        main()
    

    ##################################################

    In principle this is working, but when I drag the mouse below the horizontal axis (y=0), the rectangle flickers and jumps back and forth between the mouse position and its restrained position in the upper hemiplane. So it looks like the drag first moves it to the mouse cursor, and only then the position is adjusted retroactively. I would like the adjustment to happen before the item is moved (visibly) at all. What is the recommended approach to do this right?

    Using mouseMoveEvent towards the same end works very well, by the way. It's just that this fails when I select a group of items, because then the action only applies to the item under the mouse cursor.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 20 Nov 2017, 21:20 last edited by
      #2

      Hi and welcome to devnet,

      Not a direct answer but did you took a look at the Colliding Mice Example ? It shows a way to do collision detection.

      Hope it helps

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

      O 1 Reply Last reply 21 Nov 2017, 10:26
      0
      • S SGaist
        20 Nov 2017, 21:20

        Hi and welcome to devnet,

        Not a direct answer but did you took a look at the Colliding Mice Example ? It shows a way to do collision detection.

        Hope it helps

        O Offline
        O Offline
        Oatmeal
        wrote on 21 Nov 2017, 10:26 last edited by
        #3

        @SGaist
        SGaist, thank you for the interesting example, but it didn't get me any further in answering the question what I'm doing wrong in my itemChange() approach above. The colliding mice don't make use of itemChange().

        J 1 Reply Last reply 21 Nov 2017, 10:56
        0
        • O Oatmeal
          21 Nov 2017, 10:26

          @SGaist
          SGaist, thank you for the interesting example, but it didn't get me any further in answering the question what I'm doing wrong in my itemChange() approach above. The colliding mice don't make use of itemChange().

          J Offline
          J Offline
          JonB
          wrote on 21 Nov 2017, 10:56 last edited by JonB
          #4

          @Oatmeal
          Please bear in mind that I know nothing about QGraphicsScene, but....

          Clearly from what you say you observe it's "too late" by the time the itemChange event handler is called --- I presume Qt has already moved the item, and returning a new position works but causes a flicker-move-redraw. Correct?

          If so, it seems to me you'll need to handle the situation earlier, before the undesired move has happened. Can you instead intercept/handle the "drag" event, calculate the fact that it would move the rectangle to an undesired position, and deal with there? (Assumes that comes before the item is actually moved.)

          Else you'll have to handle it at the MouseMoveEvent stage. And I think https://stackoverflow.com/a/13102984/489865 might give you enough idea to alter for what you need? Also perhaps look at https://stackoverflow.com/a/4161542/489865 ?

          O 1 Reply Last reply 22 Nov 2017, 07:21
          0
          • A Offline
            A Offline
            Asperamanca
            wrote on 21 Nov 2017, 12:53 last edited by
            #5

            I do something similar (although in C++), and it works for me. The only difference I see between our approaches is that, instead of directly returning the corrected value, I call the base class itemChange method with it.

            1 Reply Last reply
            1
            • J JonB
              21 Nov 2017, 10:56

              @Oatmeal
              Please bear in mind that I know nothing about QGraphicsScene, but....

              Clearly from what you say you observe it's "too late" by the time the itemChange event handler is called --- I presume Qt has already moved the item, and returning a new position works but causes a flicker-move-redraw. Correct?

              If so, it seems to me you'll need to handle the situation earlier, before the undesired move has happened. Can you instead intercept/handle the "drag" event, calculate the fact that it would move the rectangle to an undesired position, and deal with there? (Assumes that comes before the item is actually moved.)

              Else you'll have to handle it at the MouseMoveEvent stage. And I think https://stackoverflow.com/a/13102984/489865 might give you enough idea to alter for what you need? Also perhaps look at https://stackoverflow.com/a/4161542/489865 ?

              O Offline
              O Offline
              Oatmeal
              wrote on 22 Nov 2017, 07:21 last edited by
              #6

              @JNBarchan
              Thanks for your suggestions. Yes, you are correct. And yes, I would like to handle the situation before the actual move has happened. And it does work like a charm when I handle the mouseEvent. The problem with that, though, is that when I select two items and drag them, mouseEvent() is only called for the one that actually is under the mouse cursor. So that one gets constrained, but the other one still can happily move wherever it wants.

              I took this this restraining method from the QT documentation (http://doc.qt.io/qt-4.8/qgraphicsitem.html#itemChange). I'm now wondering if it has something to do with the fact that I'm using Python, because it is inherently slower than C++.

              J 1 Reply Last reply 22 Nov 2017, 08:12
              0
              • O Oatmeal
                22 Nov 2017, 07:21

                @JNBarchan
                Thanks for your suggestions. Yes, you are correct. And yes, I would like to handle the situation before the actual move has happened. And it does work like a charm when I handle the mouseEvent. The problem with that, though, is that when I select two items and drag them, mouseEvent() is only called for the one that actually is under the mouse cursor. So that one gets constrained, but the other one still can happily move wherever it wants.

                I took this this restraining method from the QT documentation (http://doc.qt.io/qt-4.8/qgraphicsitem.html#itemChange). I'm now wondering if it has something to do with the fact that I'm using Python, because it is inherently slower than C++.

                J Offline
                J Offline
                JonB
                wrote on 22 Nov 2017, 08:12 last edited by
                #7

                @Oatmeal
                Although I don't know what your exact code is, I should be most surprised if it were any noticeably slower than the corresponding C++. Python is not bad at speed, but in any case a few lines of code at the Python side is neither here nor there: the time will be spent in the Qt code it calls/is called from in a UI context.

                O 1 Reply Last reply 27 Nov 2017, 07:10
                0
                • J JonB
                  22 Nov 2017, 08:12

                  @Oatmeal
                  Although I don't know what your exact code is, I should be most surprised if it were any noticeably slower than the corresponding C++. Python is not bad at speed, but in any case a few lines of code at the Python side is neither here nor there: the time will be spent in the Qt code it calls/is called from in a UI context.

                  O Offline
                  O Offline
                  Oatmeal
                  wrote on 27 Nov 2017, 07:10 last edited by
                  #8

                  @JNBarchan
                  I posted my exact code at the beginning (between the lines of hash tags), but I admit I didn't do a good job at getting the web page to display it well.

                  J 1 Reply Last reply 27 Nov 2017, 07:57
                  0
                  • O Oatmeal
                    27 Nov 2017, 07:10

                    @JNBarchan
                    I posted my exact code at the beginning (between the lines of hash tags), but I admit I didn't do a good job at getting the web page to display it well.

                    J Offline
                    J Offline
                    JonB
                    wrote on 27 Nov 2017, 07:57 last edited by JonB
                    #9

                    @Oatmeal

                    but I admit I didn't do a good job at getting the web page to display it well.

                    :) When posting a block of code here, use the </> "toolbar" button to cause to surround the whole code. It puts in:
                    ```
                    (triple-backtick) markers on a line of their own at the start & end of the whole block, and does not rely on you indenting each line with spaces!

                    O 1 Reply Last reply 27 Nov 2017, 09:53
                    0
                    • J JonB
                      27 Nov 2017, 07:57

                      @Oatmeal

                      but I admit I didn't do a good job at getting the web page to display it well.

                      :) When posting a block of code here, use the </> "toolbar" button to cause to surround the whole code. It puts in:
                      ```
                      (triple-backtick) markers on a line of their own at the start & end of the whole block, and does not rely on you indenting each line with spaces!

                      O Offline
                      O Offline
                      Oatmeal
                      wrote on 27 Nov 2017, 09:53 last edited by
                      #10

                      @JNBarchan
                      Thanks. I edited my post to make the code look prettier.

                      1 Reply Last reply
                      1
                      • O Offline
                        O Offline
                        Oatmeal
                        wrote on 29 Nov 2017, 09:38 last edited by
                        #11

                        Come on, guys, I wouldn't have thought that I have discovered an unsolvable problem with Qt or that I am trying to do something so far out of the ordinary. I'm sure that if somebody versed in Qt threw the above code in an editor and ran it, they would find out in the blink of an eye what I am doing wrong.

                        S 1 Reply Last reply 5 Sept 2018, 16:54
                        0
                        • O Oatmeal
                          29 Nov 2017, 09:38

                          Come on, guys, I wouldn't have thought that I have discovered an unsolvable problem with Qt or that I am trying to do something so far out of the ordinary. I'm sure that if somebody versed in Qt threw the above code in an editor and ran it, they would find out in the blink of an eye what I am doing wrong.

                          S Offline
                          S Offline
                          selimnar
                          wrote on 5 Sept 2018, 16:54 last edited by
                          #12

                          @Oatmeal I guess you already solved your issue since 9 months passed but I experienced same issue today and solved it eventually so I want to share it anyway. Instead of using below code
                          self.setFlag(QGraphicsItem.ItemIsMovable, True)
                          self.setFlag(QGraphicsItem.ItemIsSelectable, True)
                          self.setFlag(QGraphicsItem.ItemIsFocusable, True)
                          self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
                          using below code did the trick for me
                          setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsMovable | QGraphicsItem.ItemIsFocusable | QGraphicsItem::ItemSendsGeometryChanges);

                          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