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. Exact correct size needed
Forum Updated to NodeBB v4.3 + New Features

Exact correct size needed

Scheduled Pinned Locked Moved Solved General and Desktop
33 Posts 7 Posters 5.0k Views 3 Watching
  • 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 ollarch

    Hi,

    The view is the one that takes care of the display part. What it does is show the scene with the indicated transformations. So, let the view do its job.
    The view is not resizing, it only paints the scene and does not modify the scene. So, as I told you, the pixmap is still the same, what have changed is where are you looking it.

    Think on a CAD software. The schematic have to keep the units regardless of the zoom applied or the rotation of the view. You can rotate the view, zoom it, ... but when you ask the view to map the mouse position into scene coordinates, this coordinates will still be the same pixel position.

    Start with points 1 and 2. When you have it working, do the point 3. Finally point 4.
    When you finish all this steps, call "rotate(90)" on your view and see what happens (what you see and the mouse positions).

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

    @ollarch
    Thank you. I will save what I have now and rewrite your way tomorrow, and report back :)

    1 Reply Last reply
    0
    • O ollarch

      Hi,

      The view is the one that takes care of the display part. What it does is show the scene with the indicated transformations. So, let the view do its job.
      The view is not resizing, it only paints the scene and does not modify the scene. So, as I told you, the pixmap is still the same, what have changed is where are you looking it.

      Think on a CAD software. The schematic have to keep the units regardless of the zoom applied or the rotation of the view. You can rotate the view, zoom it, ... but when you ask the view to map the mouse position into scene coordinates, this coordinates will still be the same pixel position.

      Start with points 1 and 2. When you have it working, do the point 3. Finally point 4.
      When you finish all this steps, call "rotate(90)" on your view and see what happens (what you see and the mouse positions).

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

      @ollarch
      Firstly, I do understand what you are saying/your approach. I had been expecting to have to take the current scaling into account and do my own conversion of mouse coords to scene/pixmap coords. I agree that your way means the QGraphicsView will do this for me, and that makes me a happy bunny :)

      I followed your instructions above exactly. It almost worked, but there is a little wrinkle!

      When the window is first shown the pixmap is "small", does not fit whole area --- even though I had fitToView() in the constructor (where I add the pixmap) and a resizeEvent is generated. Once I then start interactive window resizing it jumps to correct, full size, and maintains that from then on correctly.

      [Also your way I did not have to put in any "magic" - 2 on sizes, it never caused scrollbars to appear (even when I still had them allowed), so no need for "small pixel adjustment, which is an added plus point :) ]

      I tried "everything" (I'm pretty thorough!) but nothing remedied this. So on a hunch I put in a showEvent() override to do the fitToView() there, and sure enough that, and only that, made it also be correct when first shown.

      The essentials of my now-working code are:

      void MapWindow::setupUi()
      {
          // as per https://doc.qt.io/qt-5/qgraphicsview.html#fitInView
          // since we intend to always call `QGraphicsView::fitToView()` in `resizeEvent()`
          // we explicitly disable scrollbars to *ensure* no infinite recursion
          view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
          view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
          // create the map as a `QGraphicsPixmapItem`
          // `pixmapMap` will be fitted tightly in view in `showEvent()`/`resizeEvent()`
          this->pixmapMap = new QGraphicsPixmapItem(*pixmapOriginalMap);
          scene->addItem(pixmapMap);
      }
      
      /*virtual*/ void MapWindow::showEvent(QShowEvent *showEvent) /*override*/
      {
          // call the base method
          QWidget::showEvent(showEvent);
      
          view->fitInView(pixmapMap, Qt::KeepAspectRatio);
      }
      
      /*virtual*/ void MapWindow::resizeEvent(QResizeEvent *event) /*override*/
      {
          // call the base method
          QWidget::resizeEvent(event);
      
          view->fitInView(pixmapMap, Qt::KeepAspectRatio);
      }
      

      [I am unsure about the need to call QWidget::showEvent/resizeEvent() base class, and where, in my overrides. Some examples do, some don't. With/without, or moving/before after the fitInView() call, all make no difference.]

      I don't know whether you have any comment/alternative suggestion about this need to do fitView() in showEvent(), but I couldn't get it to work first time without?

      O 1 Reply Last reply
      1
      • JonBJ JonB

        @ollarch
        Firstly, I do understand what you are saying/your approach. I had been expecting to have to take the current scaling into account and do my own conversion of mouse coords to scene/pixmap coords. I agree that your way means the QGraphicsView will do this for me, and that makes me a happy bunny :)

        I followed your instructions above exactly. It almost worked, but there is a little wrinkle!

        When the window is first shown the pixmap is "small", does not fit whole area --- even though I had fitToView() in the constructor (where I add the pixmap) and a resizeEvent is generated. Once I then start interactive window resizing it jumps to correct, full size, and maintains that from then on correctly.

        [Also your way I did not have to put in any "magic" - 2 on sizes, it never caused scrollbars to appear (even when I still had them allowed), so no need for "small pixel adjustment, which is an added plus point :) ]

        I tried "everything" (I'm pretty thorough!) but nothing remedied this. So on a hunch I put in a showEvent() override to do the fitToView() there, and sure enough that, and only that, made it also be correct when first shown.

        The essentials of my now-working code are:

        void MapWindow::setupUi()
        {
            // as per https://doc.qt.io/qt-5/qgraphicsview.html#fitInView
            // since we intend to always call `QGraphicsView::fitToView()` in `resizeEvent()`
            // we explicitly disable scrollbars to *ensure* no infinite recursion
            view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
            view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
            // create the map as a `QGraphicsPixmapItem`
            // `pixmapMap` will be fitted tightly in view in `showEvent()`/`resizeEvent()`
            this->pixmapMap = new QGraphicsPixmapItem(*pixmapOriginalMap);
            scene->addItem(pixmapMap);
        }
        
        /*virtual*/ void MapWindow::showEvent(QShowEvent *showEvent) /*override*/
        {
            // call the base method
            QWidget::showEvent(showEvent);
        
            view->fitInView(pixmapMap, Qt::KeepAspectRatio);
        }
        
        /*virtual*/ void MapWindow::resizeEvent(QResizeEvent *event) /*override*/
        {
            // call the base method
            QWidget::resizeEvent(event);
        
            view->fitInView(pixmapMap, Qt::KeepAspectRatio);
        }
        

        [I am unsure about the need to call QWidget::showEvent/resizeEvent() base class, and where, in my overrides. Some examples do, some don't. With/without, or moving/before after the fitInView() call, all make no difference.]

        I don't know whether you have any comment/alternative suggestion about this need to do fitView() in showEvent(), but I couldn't get it to work first time without?

        O Offline
        O Offline
        ollarch
        wrote on last edited by
        #14

        @JonB said in Exact correct size needed:

        When the window is first shown the pixmap is "small", does not fit whole area

        This is because when the widget constructor is executed, the widget size is not the "final" widget size. After the constructor is called you call "show" and then it calculates the size of the ui elements.

        [I am unsure about the need to call QWidget::showEvent/resizeEvent() base class

        You don't need to call it.

        Can you check the values on the debugger of "event->s" and "event->olds" ? The first one is the new size and the last is the old size.

        A workarround for this could be to use a "QTimer::singleshot(100,this,&YourWindowClass::fitMyPixmapToView)" into constructor.
        , but I have not need to use it.

        JonBJ 1 Reply Last reply
        0
        • O ollarch

          @JonB said in Exact correct size needed:

          When the window is first shown the pixmap is "small", does not fit whole area

          This is because when the widget constructor is executed, the widget size is not the "final" widget size. After the constructor is called you call "show" and then it calculates the size of the ui elements.

          [I am unsure about the need to call QWidget::showEvent/resizeEvent() base class

          You don't need to call it.

          Can you check the values on the debugger of "event->s" and "event->olds" ? The first one is the new size and the last is the old size.

          A workarround for this could be to use a "QTimer::singleshot(100,this,&YourWindowClass::fitMyPixmapToView)" into constructor.
          , but I have not need to use it.

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

          @ollarch said in Exact correct size needed:

          This is because when the widget constructor is executed, the widget size is not the "final" widget size.

          Yep, I do realize this :)

          After the constructor is called you call "show" and then it calculates the size of the ui elements.

          It doesn't matter when I call show(), I find I have to do the "fit" in showEvent(), i.e. when it's actually shown.

          Can you check the values on the debugger of "event->s" and "event->olds" ? The first one is the new size and the last is the old size.

          I did that right from the start. In the very first resizeEvent() the old size is always (-1, -1), while the (new) size is always the correct, big one. This is still the case even after I have fitted in showEvent(). So, it looks like I get the first resizeEvent() before the showEvent(), and at that point fitting doesn't work in resizeEvent() but it does in showEvent().

          12:33:20: Debugging starts
          resizeEvent QSize(-1, -1) QSize(1492, 772)
          showEvent
          // now start dragging
          resizeEvent QSize(1492, 772) QSize(1491, 772)
          resizeEvent QSize(1491, 772) QSize(1490, 772)
          resizeEvent QSize(1490, 772) QSize(1490, 771)
          ...
          

          A workarround for this could be to use a "QTimer::singleshot(100,this,&YourWindowClass::fitMyPixmapToView)" into constructor.

          Indeed I could have done that. But since it works via showEvent() I'm happy.

          What else can I say? :)

          1 Reply Last reply
          0
          • O Offline
            O Offline
            ollarch
            wrote on last edited by
            #16

            Hi, I just found that I use to call "showMaximized" on "main.cpp" instead of "show" to make the application full screen.
            I've tested with calling "show" and yes, it does not fit the item to the view the first time.

            I don't like too much this solution but you can use this

            QTimer::singleShot(50, this, SLOT(fit()));
            

            Define "fit" method as slot.

            JonBJ 1 Reply Last reply
            0
            • O ollarch

              Hi, I just found that I use to call "showMaximized" on "main.cpp" instead of "show" to make the application full screen.
              I've tested with calling "show" and yes, it does not fit the item to the view the first time.

              I don't like too much this solution but you can use this

              QTimer::singleShot(50, this, SLOT(fit()));
              

              Define "fit" method as slot.

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

              @ollarch
              Thanks, it sounds like (if I understand correctly) you are saying you find the same issue as me first time? Though I haven't seen this commented on elsewhere.

              As I said earlier, I have no problem with rectifying via your QTimer, but since I have rectified via showEvent() (as per my code) why are you not satisfied with that approach. any reason?

              I have moved on now to mouseworks, and am happy with my coordinates :)

              1 Reply Last reply
              0
              • O Offline
                O Offline
                ollarch
                wrote on last edited by ollarch
                #18

                As I said earlier, I have no problem with rectifying via your QTimer, but since I have rectified via showEvent() (as per my code) why are you not satisfied with that approach. any reason?

                No, I have any problem and I'm satisfied that it works.

                I have moved on now to mouseworks, and am happy with my coordinates :)

                Now you can try to rotate the view 45 degrees and you will see that when you map the view coordinates to scene coordinates you still have the correct pixel coordinate.

                JonBJ 1 Reply Last reply
                0
                • O ollarch

                  As I said earlier, I have no problem with rectifying via your QTimer, but since I have rectified via showEvent() (as per my code) why are you not satisfied with that approach. any reason?

                  No, I have any problem and I'm satisfied that it works.

                  I have moved on now to mouseworks, and am happy with my coordinates :)

                  Now you can try to rotate the view 45 degrees and you will see that when you map the view coordinates to scene coordinates you still have the correct pixel coordinate.

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

                  @ollarch
                  Indeed, though rotation is not something I will want to do, but I take your point.

                  Overall I am very happy with the approach you stuck with and made me adopt for my situation. As I said, I thought I was going to have to do my own coordinate transformation arithmetic taking into account my current scale/zoom setting etc. I am much happier that all I have to do is call Qt's already-written mapToScene() to do it for me, and everything makes logical, "purist" sense to me.

                  So thank you for sticking to your guns and recommending the approach I was really looking for!

                  O 1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    sainivedant41
                    wrote on last edited by sainivedant41
                    #20

                    Thanks for the clarification. mobdro

                    1 Reply Last reply
                    0
                    • JonBJ JonB

                      @ollarch
                      Indeed, though rotation is not something I will want to do, but I take your point.

                      Overall I am very happy with the approach you stuck with and made me adopt for my situation. As I said, I thought I was going to have to do my own coordinate transformation arithmetic taking into account my current scale/zoom setting etc. I am much happier that all I have to do is call Qt's already-written mapToScene() to do it for me, and everything makes logical, "purist" sense to me.

                      So thank you for sticking to your guns and recommending the approach I was really looking for!

                      O Offline
                      O Offline
                      ollarch
                      wrote on last edited by
                      #21

                      Overall I am very happy with the approach you stuck with and made me adopt for my situation. As I said, I thought I was going to have to do my own coordinate transformation arithmetic taking into account my current scale/zoom setting etc. I am much happier that all I have to do is call Qt's already-written mapToScene() to do it for me, and everything makes logical, "purist" sense to me.

                      I'd rather not reinvent the wheel.

                      So thank you for sticking to your guns and recommending the approach I was really looking for!

                      I'm happy. ;)

                      JonBJ 1 Reply Last reply
                      0
                      • O ollarch

                        Overall I am very happy with the approach you stuck with and made me adopt for my situation. As I said, I thought I was going to have to do my own coordinate transformation arithmetic taking into account my current scale/zoom setting etc. I am much happier that all I have to do is call Qt's already-written mapToScene() to do it for me, and everything makes logical, "purist" sense to me.

                        I'd rather not reinvent the wheel.

                        So thank you for sticking to your guns and recommending the approach I was really looking for!

                        I'm happy. ;)

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

                        @ollarch
                        Hi @ollarch , hope you're around and see this question (or anyone else who knows!)....

                        I am moving onto my requirement to draw a shape on the view to follow the mouse. It will be see-through but with a frame, so that user can see where on map the mouse is.

                        For now I will do that via a QAbstractGraphicsShapeItem on the QGrapcicsScene, because that's the only way I know how to do it; plus it will use scene coordinates, which is easy.

                        However, I am aware this is not "correct". There should be no permanent object on the scene for this. And, for example, although I do not have multiple views onto the scene, if I did it would show up in all views. Which is not correct. This shape is a temporary object which belongs/should be shown only in the view where the mouse is moved, not on the scene shared across views.

                        The "correct" thing to is to draw this on the GraphicsView only (with necessary coordinate calculations, but that's not the point). I came across QRubberBand which looks like the sort of thing which should be used (and I think that can be put on the view only). But unfortunately for me that only allows a line or a rectangle, and I will want a circle or a hexagon for my usage.

                        So.... what is the right way to do this, please? :)

                        EDIT
                        I have now come across, say, https://www.qtcentre.org/threads/4479-Adding-Rectangular-overlay-on-graphics-view [from 2006!], which is asking just my kind of question:

                        To simplify my problem, lets assume that we have two different graphics views. Both of these views have the same scene applied to it. When the user clicks on a specific point in the first graphics view I want to draw a rectangle related to the point she clicked, but I want it to only be visible in that graphics view.

                        I think this ends up saying to use QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect) to achieve this. Is that the route I should be following? [And if it is I shall have further questions! Because the principle there is not good enough as-is for following the mouse and redrawing when it moves.]

                        UPDATE
                        Now that I am beginning to understand what facilities the graphics scene/view offer. I am now sailing along, using the foreground layer of the view via QGraphicsView::drawForeground() to draw my mouse-follow-shape, calling scene()->invalidate(QRectF(), QGraphicsScene::ForegroundLayer); to cause it to redraw from mouseMoveEvent(). I think I have got this right!

                        Which now makes me think: maybe I should be drawing the map on which all this happens via QGraphicsScene::drawBackground() instead of in a QGraphicsPixmapItem() on the scene? For one thing, I believe the scene's background layer is cached for speed by default, which sounds good for an unchanging map background?

                        1 Reply Last reply
                        0
                        • O Offline
                          O Offline
                          ollarch
                          wrote on last edited by
                          #23

                          So you want to display a rect only on the first view? You could create two scenes and two views and add only the rect into the first one. If the second view is some kind of "only selected view" you can take the rect position and size to crop the image and set it to the QGraphicsPixmapItem on the second scene.

                          JonBJ 1 Reply Last reply
                          0
                          • O ollarch

                            So you want to display a rect only on the first view? You could create two scenes and two views and add only the rect into the first one. If the second view is some kind of "only selected view" you can take the rect position and size to crop the image and set it to the QGraphicsPixmapItem on the second scene.

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

                            @ollarch said in Exact correct size needed:
                            Hi @ollarch. Your post has just crossed with the latest UPDATE I have typed into my post above!

                            So you want to display a rect only on the first view? You could create two scenes and two views and add only the rect into the first one.

                            Nooo, I don't think so! 2 scenes?! Just for a shape on a view?

                            I'm pretty sure now that I understand a bit more that what I am doing via QGraphicsView::drawForeground() is the correct, cheapest way to draw a temporary foreground shape --- which is not an object on the scene --- to follow the mouse.

                            You can see there that I am getting so excited now that I understand layers --- background -> any graphics objects -> foreground --- plus the fact that QGraphicsView draws its own layers, QGraphicsView::drawForeground

                            Reimplement this function to provide a custom foreground for this view.

                            The default implementation fills rect using the view's foregroundBrush. If no such brush is defined (the default), the scene's drawForeground() function is called instead.

                            So I now think I ought best move the map pixmap out from being a graphics object and into the scene's background layer instead. I am enjoying this as I begin to understand :)

                            1 Reply Last reply
                            0
                            • O Offline
                              O Offline
                              ollarch
                              wrote on last edited by
                              #25

                              If I understand it. When the mouse enters the view you want to display a rect (or circle) centered to the mouse position?

                              JonBJ 1 Reply Last reply
                              0
                              • O ollarch

                                If I understand it. When the mouse enters the view you want to display a rect (or circle) centered to the mouse position?

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

                                @ollarch
                                Yes. (Only a touch more complex than that: it has to map to nearest rect/circle/shape where the map is notionally divided into a grid of distinctly-located shapes, rather than continuous, and "snap" to there. But that is a detail.) And this shape must only be drawn on the view where the mouse is being moved; it does not belong to the scene, and if there were multiple views it must not appear in views other than the one with the mouse move. That's why it has to be view-based, not scene-based.

                                But I am already at this point now, I have achieved what I need, using QGraphicsView::drawForeground() :)

                                1 Reply Last reply
                                0
                                • O Offline
                                  O Offline
                                  ollarch
                                  wrote on last edited by
                                  #27

                                  Hi,

                                  Do you have a second view, for what?

                                  JonBJ 1 Reply Last reply
                                  0
                                  • O ollarch

                                    Hi,

                                    Do you have a second view, for what?

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

                                    @ollarch
                                    As I wrote earlier, presently I do not, but there is no reason I should not introduce one at a later date. One could have multiple views onto the same scene, so that user could see different areas of map in different windows (views) if desired.

                                    At which point I would only want the foreground shape following the user's mouse to appear in the one view where he is currently moving the mouse, not any other views (even if they happened to observe the same area of the scene as the current mouse view window).

                                    This is why the shape should be drawn in QGraphicsView::drawForeground(), which is local to one view, not either in QGraphicsScene::drawForeground() nor via placing a QGraphicsItem on the scene (both of these would show the shape in all views observing that area of the scene, which I do not want.)

                                    As I say, I have this working well now :)

                                    1 Reply Last reply
                                    0
                                    • O Offline
                                      O Offline
                                      ollarch
                                      wrote on last edited by
                                      #29

                                      I was only thinking on a another way to to this.

                                      JonBJ 1 Reply Last reply
                                      1
                                      • O ollarch

                                        I was only thinking on a another way to to this.

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

                                        @ollarch
                                        :) No problem. You have really helpful getting me going on gfx scene + view.

                                        I am finding that QGraphicsView::drawForeground() is the best way to draw a temporary shape on (the top of) the given view (only). I came across that somewhere (but can't remember where) as the suggested way to achieve this best.

                                        1 Reply Last reply
                                        0
                                        • O Offline
                                          O Offline
                                          ollarch
                                          wrote on last edited by
                                          #31

                                          Happy to help.
                                          ;D

                                          1 Reply Last reply
                                          1

                                          • Login

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