c++ - QQuickPaintedItem 的 Paint 方法未调用

标签 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 不满意。

感谢您的帮助。

最佳答案

我认为这个最小的例子可以重现您的问题:

//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";
}

//ma​​in.qml(将 MyPaintedItem 注册为 PaintItem)

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 调用,我们不调用它。

更改大小将产生绘制调用:

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)的大小。它仅实例化它们。

  • Repeater委托(delegate)是一个Loader。如果没有设置显式大小,则 Loader 会根据其内容调整其大小。那么它加载什么?可能是您的 XPlotXY.qml 没有设置大小。因此 Loader 和绘图最终的大小为 0

关于c++ - QQuickPaintedItem 的 Paint 方法未调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46827603/

相关文章:

c++ - QComboBox动态项目列表

c++ - BlackBerry 10 开发中的 .pro 文件

qt - 逻辑值不依赖于实际值(M325)

c++ - qt 和 ffmpeg - 未定义引用

c++ - 如何轻松应用Crypto++哈希函数?

c++ - 在 Qml 场景下使用 OpenGL 渲染时出现奇怪的错误

javascript - Qml 属性钩子(Hook)

c++ - 将 QObject 类公开到 qml 时,在 Qt 中管理内存的正确方法?

c++ - OnMousePress 脚本在 UE4 中不起作用

c++ - 模板类返回类型?这是怎么写的?