QQuickPaintedItem的Paint方法没有被调用

时间:2017-10-19 10:14:40

标签: c++ qt qml

我有一个C ++ QQuickPaintedItem,我想在QML中实现。 但是,从不调用paint()方法。

这是我的代码:

CPlotXY.h

#ifndef CPLOTXY_H
#define CPLOTXY_H

#include <QQuickPaintedItem>
#include <lib/qcustomplot-source/qcustomplot.h>
#include <QQuickView>

class CPlotXY : public QQuickPaintedItem
{
    Q_OBJECT
    public:
        CPlotXY(QQuickItem* parent = 0);
        virtual ~CPlotXY();

        void paint(QPainter* painter);

        Q_INVOKABLE void init();

    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* Q_CustomPlot );

    private:
        QCustomPlot*         Q_CustomPlot;

    private slots:
        void graphClicked( QCPAbstractPlottable* plottable );
        void onCustomReplot();
        void updateCustomPlotSize();

};

#endif // CPLOTXY_H

CPlotXY.cpp

#include "CPlotXY.h"

CPlotXY::CPlotXY( QQuickItem* parent ) : QQuickPaintedItem( parent ), Q_CustomPlot( nullptr )
{
    setFlag( QQuickItem::ItemHasContents, true );
    setAcceptedMouseButtons( Qt::AllButtons );
    connect( this, &QQuickPaintedItem::widthChanged, this, &CPlotXY::updateCustomPlotSize );
    connect( this, &QQuickPaintedItem::heightChanged, this, &CPlotXY::updateCustomPlotSize );
}

CPlotXY::~CPlotXY()
{
    delete Q_CustomPlot;
    Q_CustomPlot = nullptr;
}

void CPlotXY::init()
{
    Q_CustomPlot = new QCustomPlot();

    updateCustomPlotSize();

    setupQuadraticDemo( Q_CustomPlot );

    connect( Q_CustomPlot, &QCustomPlot::afterReplot, this, &CPlotXY::onCustomReplot );

    Q_CustomPlot->replot();

}


void CPlotXY::paint(QPainter* painter)
{
    qDebug() << "@####";
    if (Q_CustomPlot)
    {
        QPixmap    Q_PixMap( boundingRect().size().toSize() );
        QCPPainter Q_CPPainter( &Q_PixMap );

        Q_CustomPlot->toPainter(&Q_CPPainter);

        painter->drawPixmap(QPoint(), Q_PixMap);
    }
}

void CPlotXY::mousePressEvent( QMouseEvent* Q_Event )
{
    qDebug() << Q_FUNC_INFO;
    routeMouseEvents( Q_Event );
}

void CPlotXY::mouseReleaseEvent( QMouseEvent* Q_Event )
{
    qDebug() << Q_FUNC_INFO;
    routeMouseEvents( Q_Event );
}

void CPlotXY::mouseMoveEvent( QMouseEvent* Q_Event )
{
    routeMouseEvents( Q_Event );
}

void CPlotXY::mouseDoubleClickEvent( QMouseEvent* Q_Event )
{
    qDebug() << Q_FUNC_INFO;
    routeMouseEvents( Q_Event );
}

void CPlotXY::graphClicked( QCPAbstractPlottable* Q_Plottable )
{
    qDebug() << Q_FUNC_INFO << QString( "Clicked on graph '%1 " ).arg( Q_Plottable->name() );
}

void CPlotXY::routeMouseEvents( QMouseEvent* Q_Event )
{
    if (Q_CustomPlot)
    {
        QMouseEvent* Q_NewEvent = new QMouseEvent( Q_Event->type(), Q_Event->localPos(), Q_Event->button(), Q_Event->buttons(), Q_Event->modifiers() );
        //QCoreApplication::sendEvent( m_CustomPlot, newEvent );
        QCoreApplication::postEvent( Q_CustomPlot, Q_NewEvent );
    }
}

void CPlotXY::updateCustomPlotSize()
{
    if (Q_CustomPlot)
    {
        Q_CustomPlot->setGeometry( 0, 0, width(), height() );
    }
}

void CPlotXY::onCustomReplot()
{
    qDebug() << Q_FUNC_INFO;
    update();
}

void CPlotXY::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 )->setSelectedPen( QPen( Qt::blue, 2 ) );
    customPlot->graph( 0 )->setData( x, y );

    customPlot->addGraph();
    customPlot->graph( 1 )->setPen( QPen( Qt::magenta ) );
    //customPlot->graph( 1 )->setSelectedPen( QPen( Qt::blue, 2 ) );
    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* ) ) );
}

XPlotXY.qml

import QtQuick 2.0
import CPlotXY 1.0

Item {
    CPlotXY {
        id: customPlot
        anchors.fill: parent
        Component.onCompleted: init()
    }
}

最后这是我实例化的时候:

Repeater {
    id: widgetRepeater
    model: pageModel
    anchors.fill: parent
    delegate: Loader {



        property int modelX: model.XPos
        property int modelY: model.YPos
        //property int modelWidth: model.width
        //property int modelHeight: model.height

        active: true;
        asynchronous: true
        //anchors.centerIn:  parent
        source: "%1.qml".arg(model.Type)
    }
}

调用CPlotXY的init()函数并创建对象,但从不调用paint()方法。 我知道解决方案很明显,但我对QQuickPaintedItem感到不舒服。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

我认为这个最小的例子会重现你的问题:

// mypainteditem.h

#ifndef MYPAINTEDITEM_H
#define MYPAINTEDITEM_H

#include <QObject>
#include <QQuickPaintedItem>

class MyPaintedItem : public QQuickPaintedItem
{
    Q_OBJECT
public:
    MyPaintedItem(QQuickItem* parent = nullptr);


    void paint(QPainter* painter);
};

#endif // MYPAINTEDITEM_H

// mypainteditem.cpp

#include "mypainteditem.h"
#include <QDebug>

MyPaintedItem::MyPaintedItem(QQuickItem* parent)
    : QQuickPaintedItem(parent)
{

}


void MyPaintedItem::paint(QPainter *painter)
{
    qDebug() << "Paint called";
}

// main.qml(已注册MyPaintedItemPaintItem

import QtQuick 2.7
import QtQuick.Window 2.1
import PaintItem 1.0

Window {
    id:rootWindow
    visible: true
    width: 800
    height: 600
    title: qsTr("Test")

    PaintItem {
    }
}

如您所见:未调用paint - 方法。问题是:我们没有PaintItem的大小,因此它是不可见的。为了避免不必要的paint - 来电,我们不会打电话。

更改大小将产生paint-call:

import QtQuick 2.7
import QtQuick.Window 2.1
import PaintItem 1.0

Window {
    id:rootWindow
    visible: true
    width: 800
    height: 600
    title: qsTr("Test")

    PaintItem {
        id: pi
        height: width
    }

    Timer {
        interval: 2000 // Set some dimensions after 2 seconds will produce the paint call.
        onTriggered: pi.width = 100;
        running: true
    }
}

如果问题可能出现,为什么您的图表大小为0 ...

  • 在您的文件XPlotXY.qml中,您(由于某些原因)将您的情节包装在Item中,使情节填充Item

  • main.qml中,您创建了一个填充窗口的Repeater。但Repeater并未调整其代理人的大小。它只是实例化它们。

  • delegate的{​​{1}}为Repeater。如果没有设置明确的大小,Loader会根据其内容调整其大小。那它加载了什么?可能是您的Loader没有设置大小。因此XPlotXY.qml和地图最终的大小为Loader