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

Fit MouseArea to QuickPaintedItem with changing size and adding a scrollbar?



  • Hello,

    I have an existing C++ Class painting a QImage in QML.
    This class in general works fine but it lacks some features I would like to implement.
    As I just started with QML I have no clue how to reach my goal.

    I expect nobody to provide a full working solution!
    Still it would be very appreciated ;-)
    Just some hints would be very nice!

    Status quo:
    Images are shown in QML without problems.
    Everytime the paint event is called the QImage to be drawn is one line bigger (line feed camera).
    So the image expands into one dimension by time.
    It starts at the bottom of the screen and old lines move up as new ones are added at the bottom.

    I now would like to achieve the following:

    1. The image grows from top to bottom.
    2. There shall be a MouseArea on the image giving me the original image pixel coordinates.
    3. If the image gets larger than the screen a scroll bar shall be added.
    4. (Addition: If possible the image should be zoomable with the mouse wheel and even then the MouseArea should deliver the original image pixel coordinates)

    So to begin with how can I make the paint event drawing the image at the top of the screen adding new lines also at the top so that the image moves down?

    And how can I set the MouseArea to the real size of the image?

    Thank you very much!

    imageviewer.h

    #ifndef QIMAGEVIEWER_H
    #define QIMAGEVIEWER_H
    
    #include <QQuickItem>
    #include <QQuickPaintedItem>
    #include <QImage>
    #include <QPainter>
    
    class QImageViewer : public QQuickPaintedItem
    {
        Q_OBJECT
    public:
        QImageViewer(QQuickItem *parent = Q_NULLPTR);
        Q_INVOKABLE void setImage(const QImage &img);
    private:
        QImage currentImage;
        void paint(QPainter *painter);
    };
    
    #endif // QIMAGEVIEWER_H
    
    

    imageviewer.cpp

    #include "qimageviewer.h"
    QImageViewer::QImageViewer(QQuickItem *parent)
        : QQuickPaintedItem(parent)
    {
    }
    void QImageViewer::setImage(const QImage &img)
    {
        currentImage = img.copy(); // perform a copy
        update(); //Calls paint function
    }
    void QImageViewer::paint(QPainter *painter)
    {
        QSizeF scaled = QSizeF(currentImage.width(),
                               currentImage.height()).scaled(boundingRect().size(), Qt::KeepAspectRatio);
        QRect centerRect(qAbs(scaled.width() - width()) / 1.0f,
                         qAbs(scaled.height() - height()) / 1.0f,
                         scaled.width(),
                         scaled.height());
        painter->drawImage(centerRect, currentImage);
    }
    
    

    qml:

    Connections {
            target: source;
            onImageProcessed: {
                imgViewer.setImage(image);
            }
    
    
        ImageViewer
        {
            id: imgViewer
            width: 1024
            height: 500
            anchors.centerIn: parent
            //anchors.fill: parent
    
            MouseArea {
                anchors.fill: parent //Wrong size!
                onClicked: console.log("Clicked")
            }
        }
    


  • Why don't you just use the Qml Image Type?

    As I understand your use case right, it's perfectly fine for this.

    For example:

    import QtQuick 2.10
    import QtQuick.Controls 2.3
    
    ApplicationWindow {
      id: root
      width: 1200; height: 600
      visible: true
    
      Image {
        id: image
        height: 200
        width: 200
        anchors.centerIn: parent
        source: "pathToImage"
        //transform: Scale { id: imageScale; origin.x: image.width/2 ; origin.y: image.height/2; yScale: 1}
      }
    
      Timer {
        interval: 500; running: true; repeat: true
        //onTriggered: { imageScale.yScale += 0.1 }
        onTriggered: { image.height += 15}
      }
    }
    

    This will Scale you Image on the y-axis. You can either do it by acessesing the Scale Transform or simply change the height. I suppose last one it fitting better your use case as you only want it to get scaled in one direction.

    1. Only a point of anchoring you Image in the right way in my example. You will figure it out, it's only one small change.
    2. Don't understand what you exactly want? One simple solution would be to just save them in the beginning. I am sure there are other solutions, but therefore you have to explain this more in detail (to somebody not having much knowlege about images)
    3. Put the Image into a Flickable and configure as you desire. Just read the docs, I am sure you will find a way
    4. This is just scaling the Image from the center in every direction. You can either use the Scale transform or just the scale property (which is not so powerful, but good enough for this task)


  • Thank you very much for your answer!

    Actually an Image Object does not work well for me, because internally I use cv::Mat and it is more like a video with changing dimensions, what I would like to show.

    The refresh of the image calling a C++ method is really convenient and I also cannot easily provide a source URL of the image.

    I just added properties for the width and height of the "centerRect" in the imageviewer class.
    So I now can fit my MouseArea to the correct size.

    From here on I think I can make the rest on my own with your suggestions :-)


Log in to reply