Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Best approach to displaying a picture for my purposes



  • I have never done anything picturey-graphicy like this, so I want to know what approach I should best take.

    I have a .jpeg file picture (a map, as it happens, but shouldn't matter). At present I just allow the user to open it via my OS's Image Viewer application, and that's fine. To give an idea, that scales it down to 22% to fit in a comfortable window, and that's what I'll want to do in my own window.

    Now I want to incorporate into my application. I will want to show it in a window such that I can map the user's mouse position on the pic to a logical coordinate, so I know where the mouse is in map coordinates. I do not intend to put any objects of my own onto it. The only thing I might want is to be able to draw a shape somewhere near the mouse to pick out a small map area.

    I can think of a few possibilities:

    1. QLabel with QPixmap.
    2. QLabel with HTML <img src=.
    3. Simple QWidget with the .jpg as a stylesheet backgroung-image: url().
    4. Some kind of direct QPainter and QImage to paint on a window-widget.
    5. Something with QGraphicsScene & QGraphicsPixmapItem.

    I have read through the following usefuls:

    The last one, in particular, seems to have replies suggesting most of these alternatives, but I'm not sure what conclusion to come to. The Qt ImageViewer example is quite a bit of code. I will need to scale-to-fit, but I don't think I'll need its zooming or scrolling as I will just want my pic always scaled to fit completely.

    My goal, as ever, is the least complicated with the least code which suffices for my needs. And I don't like doing it one way only to have to change later on to a different way :)

    So, which approach is best for me, where should I start from?



  • @J-Hilk , @ollarch , @JKSH , @SimonSchroeder
    Dear All,

    I hope nobody will be offended, but I am going for QGraphicsScene, @ollarch's recommendation and the one in the accepted stackoverflow post.

    I worry terribly about offending anyone, or looking like I don't heed expert advice! :( All of your suggestions/comments have been good. I just feel comfortable with this, and it will give me a chance to play with graphics stuff instead of widgets. I hope that if I eventually come back and say "this may not be the right choice" you won't just say "go away, told you so!" :-;



  • Hello @JonB, have you considered using QML? There are some easy ways of doing what you want to with it: https://doc.qt.io/qt-5/qml-qtquick-image.html
    I recommend using QML as a way of separating the UI logic with any other kind of logic your application may have. Also, the code is quite simple and you can create a widget for this and re-use it elsewhere in your application.


  • Moderators

    @JonB If you want to stay with c++, which I can understand and respect, I would go with option 4

    especially, if you plan to draw custom shapes on it later on



  • @rrlopez
    Thanks, but it is an existing widgets app I am adding to, no chance of QML! Nor, I have to say, any desire to do so -- personal!



  • @J-Hilk
    So #4 was https://stackoverflow.com/a/48783550/489865 from that stackoverflow

    void SomeWidget::paintEvent(QPaintEvent* event)
    {
        QPainter painter(this);
        QRect rect = event->rect();
        painter.drawImage(rect, image, rect);
    }
    

    In this case, where is my "scale to fit"? (While preserving aspect ratio.)


  • Moderators

    @JonB
    there's a build in functionality for that in drawImage

    Note: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
    

    For a more fancy scaling, including fit to aspect ratio . I would suggest overriding/listening to resizeEvent and scaling by hand to the new size constrains,



  • Hi,

    Use the QGraphicsView with a QGraphicsScene. The image can be displayed on a QGraphicsPixmapItem or a QGraphicsRectItem (setting the image to the item brush).
    To fit the image on the view just add the item and call the view to fit to this item. If the window can be resized you will have to override the resizeEvent of the view and call fit again.
    To get the mouse coordinates you have to override the QGraphicsScene::mouseMoveEvent and map the event position to the scene.
    This will get you the pixel coordinate. Knowing the map scale resolution you can convert it to world coordinates.

    Hope it helps.



  • @ollarch
    Yep this all makes sense.

    You guys are being kind :) But I kind of feel I'm going to end up with as many suggested "best" approaches as the ones I name and are in that stackoverflow post! I wish I knew who is "right" ;-) Maybe it doesn't matter which....


  • Moderators

    @JonB said in Best approach to displaying a picture for my purposes:

    I wish I knew who is "right" ;-) Maybe it doesn't matter which....

    In the first instance, the one who is "right" is the one that produces a reliable, functioning application.

    Once that is established, you can try some of the other approaches and see if they give you any improvements (e.g. better code readability/maintainability, better performance, etc.). If an approach is found with significant improvements and few drawbacks, that becomes the new "right" one.



  • For any solution you need a derived class if you want to calculate the mouse position. Basically, you need to override mouseMoveEvent and/or mousePressEvent.

    Let's have a quick look at the variants you suggested:

    1. QLabel with QPixmap.

    This is a good solution. However, by default QLabel will not scale the Pixmap for you. I recently had the problem and found a good solution here: https://stackoverflow.com/questions/8211982/qt-resizing-a-qlabel-containing-a-qpixmap-while-keeping-its-aspect-ratio. Still, you need to add code to a derived class to track the mouse.

    1. QLabel with HTML <img src=.

    I am not sure how much control over the size of the image you will have with this approach. It is not one of my favorites, as it adds some complexity by using HTML. Usually, I try to stay clear of any texts that need to be parsed during display as this is slower (even though I never encountered any speed problems with today's computers).

    1. Simple QWidget with the .jpg as a stylesheet backgroung-image: url().

    Here again I am trying to avoid stylesheets as long as possible. It's a similar reasoning as number 2.

    1. Some kind of direct QPainter and QImage to paint on a window-widget.

    As I said already, you need to derive anyway for mouse tracking. Also, as you can see the paint method is quite simple and short.

    1. Something with QGraphicsScene & QGraphicsPixmapItem.

    That sound awfully complicated for such a simple task. I don't recommend this approach as it introduces several layers of indirections.

    To sum it up: For a clean solution pick either 1. or 4. In the end it doesn't really matter as the two are quite similar. If done properly, the only major difference will be if you inherit from QWidget or QLabel.



  • Hi,

    First of all, using the QGraphicsView is not as complicated as you think. It can be done in less than an hour if its your first time using it.
    Second, all the other aproaches resize the image into a widget and when you try to obtain the pixel coordinates in the image you have to take into account that it have been scaled. So, as I said, QGraphicsScene is able to map the view coordinates to the item coordinates to get you the real pixel position.



  • @ollarch
    Ah! I was about to go for option #4, QPainter and QImage, from other's posts. However, you are persistent in holding your ground! I know I can resize, scale & multiply/divide for coordinates if I do widgets+mouse, but I rather like your

    QGraphicsScene is able to map the view coordinates to the item coordinates to get you the real pixel position

    as making Qt do the work for me on what I think will be the most common operation I will want to be dong.... :)

    What about what @J-Hilk wrote earlier about option #4/QWidget:

    especially, if you plan to draw custom shapes on it later on

    ? I will probably want to draw a square/hexagon/circle (of a fixed size, just the frame, see-through inside) as I move the mouse around which "snaps" to the nearest such area (calculated by me from coordinates) and is drawn on top of the map to show "where the nearest box for the mouse" is. Is this an issue in widget vs gfx scene/view?


  • Moderators

    @JonB I never used QGraphicsView before.
    It always seemed overkill for me 🤷‍♂️

    If it fits you better, use it!



  • Hi,

    Take a look at QGraphicsScene, specially methods like "addRect", "addLine", "addEllipse", "addPath", "addPolygon", and of course you can derive your own class from QGraphicsItem with your own shape.

    Of course that you can do this with option #4, but I think that this is easier, at least for me.



  • @J-Hilk , @ollarch , @JKSH , @SimonSchroeder
    Dear All,

    I hope nobody will be offended, but I am going for QGraphicsScene, @ollarch's recommendation and the one in the accepted stackoverflow post.

    I worry terribly about offending anyone, or looking like I don't heed expert advice! :( All of your suggestions/comments have been good. I just feel comfortable with this, and it will give me a chance to play with graphics stuff instead of widgets. I hope that if I eventually come back and say "this may not be the right choice" you won't just say "go away, told you so!" :-;


  • Moderators

    @JonB I'm sure none of us are offended (I'm certainly not). There were numerous options and you picked one based on features that you believe will be useful for your project. That is sound reasoning.

    I hope that if I eventually come back and say "this may not be the right choice" you won't just say "go away, told you so!" :-;

    The best way to learn a new tool's strengths and weaknesses is to use it for yourself. After this project, you'll have a much better understanding of QGraphicsScene. Then, you'll be better placed to determine how "right" it is for your project. That learning is a worthwhile pursuit in itself.

    Happy coding, and best of luck!


Log in to reply