我有一个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感到不舒服。
感谢您的帮助。
答案 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(已注册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
- 来电,我们不会打电话。
更改大小将产生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