QCustomPlot QML



  • Hello,
    I was trying to integrate a qml program that can represent math expressions. I saw that there were a library for that goal called QCustomPlot and I also saw a example of how can I integrate it with QML: https://www.qcustomplot.com/index.php/support/forum/172

    However when I run the code I have the following error:
    QWidget: Cannot create a QWidget without QApplication

    This is my code:

    .pro

    QT += quick
    CONFIG += c++11
    QT += script
    QT += printsupport
    QT += widgets
    # The following define makes your compiler emit warnings if you use
    # any Qt feature that has been marked deprecated (the exact warnings
    # depend on your compiler). Refer to the documentation for the
    # deprecated API to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
            calculadorafunciones.cpp \
            customplotitem.cpp \
            main.cpp \
            qcustomplot.cpp
    
    RESOURCES += qml.qrc
    
    # Additional import path used to resolve QML modules in Qt Creator's code model
    QML_IMPORT_PATH =
    
    # Additional import path used to resolve QML modules just for Qt Quick Designer
    QML_DESIGNER_IMPORT_PATH =
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    HEADERS += \
        calculadorafunciones.h \
        customplotitem.h \
        qcustomplot.h
    

    main.cpp (There are two comments for two librery because I tried with different options but any of them worked)

    //#include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "exprtk/exprtk.hpp"
    #include <QQmlContext>
    #include "calculadorafunciones.h"
    #include "customplotitem.h"
    #include <QtWidgets/QApplication>
    //#include <QApplication>
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
    
        qmlRegisterType<CalculadoraFunciones>("mi.calculadora", 1, 0,"MyCalculadora");
        qmlRegisterType<CustomPlotItem>("CustomPlot", 1, 0, "CustomPlotItem");
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    
    

    customplotitem.h

    #pragma once
    
    #include <QtQuick>
    #include "qcustomplot.h"
    class QCustomPlot;
    
    class CustomPlotItem : public QQuickPaintedItem
    {
        Q_OBJECT
    
    public:
        CustomPlotItem( QQuickItem* parent = 0 );
        virtual ~CustomPlotItem();
    
        void paint( QPainter* painter );
    
        Q_INVOKABLE void initCustomPlot();
    
    protected:
        void routeMouseEvents( QMouseEvent* event );
    
        virtual void mousePressEvent( QMouseEvent* event );
        virtual void mouseReleaseEvent( QMouseEvent* event );
        virtual void mouseMoveEvent( QMouseEvent* event );
        virtual void mouseDoubleClickEvent( QMouseEvent* event );
    
        void setupQuadraticDemo( QCustomPlot* customPlot );
    
    private:
        QCustomPlot*         m_CustomPlot;
    
    private slots:
        void graphClicked( QCPAbstractPlottable* plottable );
        void onCustomReplot();
        void updateCustomPlotSize();
    
    };
    
    

    customplotitem.cpp

    #include "CustomPlotItem.h"
    
    #include <QDebug>
    
    CustomPlotItem::CustomPlotItem( QQuickItem* parent ) : QQuickPaintedItem( parent )
        , m_CustomPlot( nullptr )
    {
        setFlag( QQuickItem::ItemHasContents, true );
        // setRenderTarget(QQuickPaintedItem::FramebufferObject);
        // setAcceptHoverEvents(true);
        setAcceptedMouseButtons( Qt::AllButtons );
    
        connect( this, &QQuickPaintedItem::widthChanged, this, &CustomPlotItem::updateCustomPlotSize );
        connect( this, &QQuickPaintedItem::heightChanged, this, &CustomPlotItem::updateCustomPlotSize );
    }
    
    CustomPlotItem::~CustomPlotItem()
    {
        delete m_CustomPlot;
        m_CustomPlot = nullptr;
    }
    
    void CustomPlotItem::initCustomPlot()
    {
        m_CustomPlot = new QCustomPlot();
    
        updateCustomPlotSize();
    
        setupQuadraticDemo( m_CustomPlot );
    
        connect( m_CustomPlot, &QCustomPlot::afterReplot, this, &CustomPlotItem::onCustomReplot );
    
        m_CustomPlot->replot();
    }
    
    
    void CustomPlotItem::paint( QPainter* painter )
    {
        if (m_CustomPlot)
        {
            QPixmap    picture( boundingRect().size().toSize() );
            QCPPainter qcpPainter( &picture );
    
            //m_CustomPlot->replot();
            m_CustomPlot->toPainter( &qcpPainter );
    
            painter->drawPixmap( QPoint(), picture );
        }
    }
    
    void CustomPlotItem::mousePressEvent( QMouseEvent* event )
    {
        qDebug() << Q_FUNC_INFO;
        routeMouseEvents( event );
    }
    
    void CustomPlotItem::mouseReleaseEvent( QMouseEvent* event )
    {
        qDebug() << Q_FUNC_INFO;
        routeMouseEvents( event );
    }
    
    void CustomPlotItem::mouseMoveEvent( QMouseEvent* event )
    {
        routeMouseEvents( event );
    }
    
    void CustomPlotItem::mouseDoubleClickEvent( QMouseEvent* event )
    {
        qDebug() << Q_FUNC_INFO;
        routeMouseEvents( event );
    }
    
    void CustomPlotItem::graphClicked( QCPAbstractPlottable* plottable )
    {
        qDebug() << Q_FUNC_INFO << QString( "Clicked on graph '%1 " ).arg( plottable->name() );
    }
    
    void CustomPlotItem::routeMouseEvents( QMouseEvent* event )
    {
        if (m_CustomPlot)
        {
            QMouseEvent* newEvent = new QMouseEvent( event->type(), event->localPos(), event->button(), event->buttons(), event->modifiers() );
            //QCoreApplication::sendEvent( m_CustomPlot, newEvent );
            QCoreApplication::postEvent( m_CustomPlot, newEvent );
        }
    }
    
    void CustomPlotItem::updateCustomPlotSize()
    {
        if (m_CustomPlot)
        {
            m_CustomPlot->setGeometry( 0, 0, width(), height() );
        }
    }
    
    void CustomPlotItem::onCustomReplot()
    {
        qDebug() << Q_FUNC_INFO;
        update();
    }
    
    void CustomPlotItem::setupQuadraticDemo( QCustomPlot* customPlot )
    {
        // make top right axes clones of bottom left axes:
        QCPAxisRect* axisRect = customPlot->axisRect();
    
        // generate some data:
        QVector<double> x( 101 ), y( 101 );   // initialize with entries 0..100
        QVector<double> lx( 101 ), ly( 101 ); // initialize with entries 0..100
        for (int i = 0; i < 101; ++i)
        {
            x[i] = i / 50.0 - 1;              // x goes from -1 to 1
            y[i] = x[i] * x[i];               // let's plot a quadratic function
    
            lx[i] = i / 50.0 - 1;             //
            ly[i] = lx[i];                    // linear
        }
        // create graph and assign data to it:
        customPlot->addGraph();
        customPlot->graph( 0 )->setPen( QPen( Qt::red ) );
    
        customPlot->graph( 0 )->setData( x, y );
    
        customPlot->addGraph();
        customPlot->graph( 1 )->setPen( QPen( Qt::magenta ) );
    
        customPlot->graph( 1 )->setData( lx, ly );
    
        // give the axes some labels:
        customPlot->xAxis->setLabel( "x" );
        customPlot->yAxis->setLabel( "y" );
        // set axes ranges, so we see all data:
        customPlot->xAxis->setRange( -1, 1 );
        customPlot->yAxis->setRange( -1, 1 );
    
        customPlot ->setInteractions( QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectPlottables );
        connect( customPlot, SIGNAL( plottableClick( QCPAbstractPlottable*, QMouseEvent* ) ), this, SLOT( graphClicked( QCPAbstractPlottable* ) ) );
    
    

    Does anyone know what is wrong?
    Thanks for the help


  • Qt Champions 2019

    @Dooham said in QCustomPlot QML:

    QWidget: Cannot create a QWidget without QApplication

    Do you have any static QWidget derived instances in your app somewhere?
    Also, did you try with QApplication instead of QGuiApplication?
    From https://doc.qt.io/qt-5/qguiapplication.html
    "For QWidget based Qt applications, use QApplication instead, as it provides some functionality needed for creating QWidget instances."



  • @jsulm In my Qml file I have some buttons and a textField. This is the file qml:

    import QtQuick 2.12
    import QtQuick.Controls 2.5
    import mi.calculadora 1.0
    import CustomPlot 1.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
        MyCalculadora{
            id: miCalculadora
        }
        Row{
            Button{
                text: "Raiz"
                onClicked: {
                    inputExpresion.text= inputExpresion.text+" sqrt("
    
                }
            }
            Button{
                text: "Logaritmo"
                onClicked: {
                    inputExpresion.text= inputExpresion.text+" log("
    
                }
            }
            Button{
                text: "Coseno"
                onClicked: {
                    inputExpresion.text= inputExpresion.text+" cos("
    
                }
            }
            Button{
                text: "Seno"
                onClicked: {
                    inputExpresion.text= inputExpresion.text+" sin("
    
                }
            }
            Button{
                text: "Tangente"
                onClicked: {
                    inputExpresion.text= inputExpresion.text+" tan("
    
                }
            }
            Button{
                text: "Limpiar"
                onClicked: {
                    inputExpresion.text= ""
    
                }
            }
        }
        Column{
            anchors.centerIn: parent
    
            TextField{
                id: inputExpresion
                width:150
                text: ""
                focus: true
                selectByMouse: true
                inputMethodHints: Qt.ImhDigitsOnly
                //validator: DoubleValidator{notation: DoubleValidator.StandardNotation}
    
                //onEditingFinished: {cuadriculaItem.parametrosCuad[1]=Funciones.deStringADouble(inputParam1.text)}
    
    
            }
    
    
            Button{
                id: miBoton
                text: "Pulsar Aqui"
                onClicked: {
                    miCalculadora.evaluarFuncion(inputExpresion.text)
                }
            }
    
            CustomPlotItem{
            id:plot
            height: 100
            width: 100
            Component.onCompleted: plot.initCustomPlot();
            }
        }
    }
    
    

    Yes, I tried with QApplication instead of QGuiApplication.


  • Qt Champions 2019

    @Dooham What about stativ QWidget instances?



  • @jsulm I think I dont have any of them.



  • @jsulm ok I found out the solution. I had to change the engine for a QQuickView in the main.cpp. But is there any method to create a new kind if widget un qml and insert It like I can maje with a button ?


Log in to reply