Search code examples
qtqpainterqpen

qt - instantiate a drawing with QPainter


So I drew a circle with QPainter.

My Question is: who can I save that circle in a variable so I can work with it ? I want to make an animation with the circle.

QPainter painter(this);
painter.setPen(dottedPen);
painter.drawEllipse(QRect(160,260,80,80));

Solution

  • You can implement your own class for Ellipse with all property you need. And then set QPropertyAnimation for any of your property. Here is a small example. Ellipse class (with 4 custom properties):

    class Ellipse : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
        Q_PROPERTY(QPoint center READ center WRITE setCenter NOTIFY centerChanged)
        Q_PROPERTY(int radiusX READ radiusX WRITE setRadiusX NOTIFY radiusXChanged)
        Q_PROPERTY(int radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged)
    public:
        explicit Ellipse(QObject *parent = 0);
    
        void setWidgetToPaint(QWidget* widget);
    
        void paint();
    
        void setVisible(const bool visible);
        bool visible() const;
    
        void setCenter(const QPoint& center);
        const QPoint& center() const;
    
        void setRadiusX(const int rx);
        int radiusX() const;
    
        void setRadiusY(const int ry);
        int radiusY() const;
    
    signals:
        void centerChanged();
        void radiusXChanged();
        void radiusYChanged();
        void visibleChanged();
    
    public slots:
    
    private:
        QPointer<QWidget> m_widgetToPaint;
        bool m_isVisible;
        QPoint m_center;
        int m_rx;
        int m_ry;
    };
    
    Ellipse::Ellipse(QObject *parent) :
        QObject(parent),
        m_widgetToPaint(nullptr),
        m_isVisible(false),
        m_rx(1),
        m_ry(1)
    {
    }
    
    void Ellipse::setWidgetToPaint(QWidget *widget)
    {
        m_widgetToPaint = widget;
        if (widget)
        {
            connect(this, SIGNAL(visibleChanged()), m_widgetToPaint.data(), SLOT(repaint()));
            connect(this, SIGNAL(centerChanged()), m_widgetToPaint.data(), SLOT(repaint()));
            connect(this, SIGNAL(radiusXChanged()), m_widgetToPaint.data(), SLOT(repaint()));
            connect(this, SIGNAL(radiusYChanged()), m_widgetToPaint.data(), SLOT(repaint()));
        }
    }
    
    void Ellipse::paint()
    {
        if(!m_widgetToPaint)
        {
            return;
        }
    
        if (!m_isVisible)
        {
            return;
        }
    
        QPainter painter(m_widgetToPaint);
        painter.drawEllipse(m_center, m_rx, m_ry);
    }
    
    void Ellipse::setCenter(const QPoint &center)
    {
        bool needNotify = m_center != center;
        m_center = center;
        if (needNotify)
        {
            emit centerChanged();
        }
    }
    
    const QPoint & Ellipse::center() const
    {
        return m_center;
    }
    
    void Ellipse::setRadiusX(const int rx)
    {
        bool needNotify = m_rx != rx;
        m_rx = rx;
        if (needNotify)
        {
            emit radiusXChanged();
        }
    }
    
    int Ellipse::radiusX() const
    {
        return m_rx;
    }
    
    void Ellipse::setRadiusY(const int ry)
    {
        bool needNotify = m_ry != ry;
        m_ry = ry;
        if (needNotify)
        {
            emit radiusYChanged();
        }
    }
    
    int Ellipse::radiusY() const
    {
        return m_ry;
    }
    
    void Ellipse::setVisible(const bool visible)
    {
        bool needNotify = m_isVisible != visible;
        m_isVisible = visible;
        if (needNotify)
        {
            emit visibleChanged();
        }
    }
    
    bool Ellipse::visible() const
    {
        return m_isVisible;
    }
    

    And now create an instance of ellipse inside your widget. And reimplement paintEvent your widget

    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    protected:
        void paintEvent(QPaintEvent *event);
    
    private slots:
        void on_pushButton_clicked();
    
        void on_pushButton_2_clicked();
    
    private:
        Ui::MainWindow *ui;
        Ellipse m_ellipse;
    };
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        m_ellipse.setWidgetToPaint(this);
    }
    
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        QMainWindow::paintEvent(event);
        m_ellipse.paint();
    }
    

    To make ellipse visible now just set visible=true

    void MainWindow::on_pushButton_clicked()
    {
        m_ellipse.setVisible(true);
        m_ellipse.setCenter(QPoint(30, 30));
        m_ellipse.setRadiusX(25);
        m_ellipse.setRadiusY(15);
    }
    

    Also now you are avaliable to set any animation for custom properties. Here is example for center property

    void MainWindow::on_pushButton_2_clicked()
    {
        QPropertyAnimation *animationCenter = new QPropertyAnimation(&m_ellipse, "center", this);
        animationCenter->setStartValue(QPoint(30, 30));
        animationCenter->setEndValue(QPoint(100, 100));
        animationCenter->setDuration(3000);
        animationCenter->start(QAbstractAnimation::DeleteWhenStopped);
    }