qml绘图的三种方式
1,继承QQuickPaintedItem重写void paint(QPainter *painter);
#include "PaintedItem.h"
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QColor>
#include <QDebug>
PaintedItem::PaintedItem(QQuickItem *parent)
: QQuickPaintedItem(parent)
, m_element(0)
, m_bEnabled(true)
, m_bPressed(false)
, m_bMoved(false)
, m_pen(Qt::black)
{
setAcceptedMouseButtons(Qt::LeftButton);
}
PaintedItem::~PaintedItem()
{
purgePaintElements();
}
void PaintedItem::clear()
{
purgePaintElements();
update();
}
void PaintedItem::undo()
{
if(m_elements.size())
{
delete m_elements.takeLast();
update();
}
}
void PaintedItem::paint(QPainter *painter)
{
painter->setRenderHint(QPainter::Antialiasing);
int size = m_elements.size();
ElementGroup *element;
for(int i = 0; i < size; ++i)
{
element = m_elements.at(i);
painter->setPen(element->m_pen);
painter->drawLines(element->m_lines);
}
}
void PaintedItem::mousePressEvent(QMouseEvent *event)
{
m_bMoved = false;
if(!m_bEnabled || !(event->button() & acceptedMouseButtons()))
{
QQuickPaintedItem::mousePressEvent(event);
}
else
{
m_bPressed = true;
m_element = new ElementGroup(m_pen);
m_elements.append(m_element);
m_lastPoint = event->localPos();
event->setAccepted(true);
}
}
void PaintedItem::mouseMoveEvent(QMouseEvent *event)
{
if(!m_bEnabled || !m_bPressed || !m_element)
{
QQuickPaintedItem::mousePressEvent(event);
}
else
{
//qDebug() << "mouse move";
m_element->m_lines.append(QLineF(m_lastPoint, event->localPos()));
m_lastPoint = event->localPos();
update();
}
}
void PaintedItem::mouseReleaseEvent(QMouseEvent *event)
{
if(!m_element || !m_bEnabled || !(event->button() & acceptedMouseButtons()))
{
QQuickPaintedItem::mousePressEvent(event);
}
else
{
//qDebug() << "mouse released";
m_bPressed = false;
m_bMoved = false;
m_element->m_lines.append(QLineF(m_lastPoint, event->localPos()));
update();
}
}
void PaintedItem::purgePaintElements()
{
int size = m_elements.size();
if(size > 0)
{
for(int i = 0; i < size; ++i)
{
delete m_elements.at(i);
}
m_elements.clear();
}
m_element = 0;
}
效果如下:
2,继承QQuickItem重写QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);配合QSGNode实现:
#include "ordinateitem.h"
#include <QSGGeometryNode>
#include <QSGFlatColorMaterial>
#include <QDebug>
namespace UtAbCapb {
OrdinateItem::OrdinateItem()
{
setFlag(ItemHasContents, true);
this->init();
}
void OrdinateItem::init()
{
m_scale_vp = LeftVP;
m_line_width = 1;
m_line_color = "#C5AD63";
m_ruler_count = 35;
}
int OrdinateItem::scaleViewPostion()
{
return m_scale_vp;
}
void OrdinateItem::setScaleViewPostion(int vp)
{
m_scale_vp = vp;
}
int OrdinateItem::lineWidth()
{
return m_line_width;
}
void OrdinateItem::setLineWidth(int width)
{
m_line_width = width;
}
QString OrdinateItem::lineColor()
{
return m_line_color;
}
void OrdinateItem::setLineColor(QString color)
{
m_line_color = color;
}
int OrdinateItem::rulerTotal()
{
return m_ruler_count;
}
void OrdinateItem::setRulerTotal(int count)
{
if(count>=10 && count<120){
m_ruler_count = count;
update();
}
}
QSGNode *OrdinateItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
float max_x = (width()>30)? 20 : width();
float max_y = height();
float rulerUnit = (max_y-10)/m_ruler_count;
float scal_h = max_x;
float scal_m = max_x*0.8;
float scal_l = max_x*0.5;
int totalCount = m_ruler_count*2 + 4;
QSGGeometryNode *node = 0;
node = static_cast<QSGGeometryNode *>(oldNode);
QSGGeometry *geometry;
QSGFlatColorMaterial *material;
if(!node) {
node = new QSGGeometryNode;
geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), totalCount);
geometry->setDrawingMode(GL_LINES);
geometry->setLineWidth(m_line_width);
material = new QSGFlatColorMaterial;
material->setColor(QColor(m_line_color));
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry);
node->setMaterial(material);
node->setFlag(QSGNode::OwnsMaterial);
} else {
geometry = node->geometry();
material = static_cast<QSGFlatColorMaterial *>(node->material());
geometry->allocate(totalCount);
}
QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();
int max = (m_scale_vp == LeftVP)? max_x : 0;
vertices[0].set(max, 0);
vertices[1].set(max, max_y);
float x0=0;
float y0=max_y;
float x;
float y;
int cout =1;
for(int i=0;i<=m_ruler_count;i++){
int itype = (i%5==0 && i%10==0)? 0 :((i%5==0 && i%10!=0)? 1 : 2); //0:max,1:mid,2:min
switch (itype) {
case 0:
x0 = 0;
x = scal_h;
y = y0;
break;
case 1:
x0 = (m_scale_vp == LeftVP)? scal_h*0.2 : 0;
x = (m_scale_vp == LeftVP)? scal_h : scal_m;
y = y0;
break;
case 2:
x0 = (m_scale_vp == LeftVP)? scal_l : 0;
x = (m_scale_vp == LeftVP)? scal_h : scal_l;
y = y0;
break;
default:
break;
}
vertices[++cout].set(x0, y0);
vertices[++cout].set(x, y);
y0 = y0 - rulerUnit;
}
node->markDirty(QSGNode::DirtyGeometry);
return node;
}
}
3,Canvas
import QtQuick 2.1
import QtQuick.Window 2.1
import "qrc:/Canvas1/qml/RES/"
Window {
visible: true
width: imgBg.width*2
height: imgBg.height
title: qsTr("qmlPainterCanvas")
property var _listData:[0,50,0,70,10,0,-60,0,50,0,30,0,25,-80,0,20,0,70,0,20,0]
property var _list: new Array
property int marginY: 200
property int marginX: 100
property int spacing: 15
property int currentIndex: 0
property int maxLen: _listData.length
Component.onCompleted: {
}
Image{
id: imgBg
source: "qrc:/BGMain.png"
}
Item{
id: itemCanvas
anchors.fill: parent
transform: Rotation{
axis.x: 0
axis.y: 1
axis.z: 1
origin.x: 0
origin.y: itemCanvas.height/2
angle: 5
}
Canvas {
id: canvas
anchors.fill: parent
property real lastX: 0
property real lastY: 0
onPaint: {
//0,0 在左上角
var ctx = getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
//基线
ctx.lineWidth = 1.0
ctx.strokeStyle = "#bdfcff"
ctx.beginPath()
ctx.moveTo(marginX, canvas.height - marginY)
ctx.lineTo(300+marginX, canvas.height - marginY)
ctx.stroke()
ctx.lineWidth = 5.0
ctx.strokeStyle = "#bdfcff"
ctx.lineJoin = "miter" //miter, bevel, round
ctx.lineCap = "butt" //butt,round,square
ctx.beginPath()
ctx.shadowColor = "#bdfcff"
ctx.shadowBlur = 15
ctx.shadowOffsetX = -5
ctx.shadowOffsetY = -5
// console.log(_list.length)
for(var i=0; i<_list.length; i++){
var x1 = i*spacing + marginX + (maxLen-_list.length)*spacing
var y1 = canvas.height - _list[i] - marginY
if(i == 0){
ctx.moveTo(x1, y1)
}
else if(i == _list.length-1){
ctx.lineTo(x1, y1)
ctx.stroke()
}
else{
ctx.lineTo(x1, y1)
}
lastX = x1
lastY = y1
}
}
}
}
Timer{
id: timer
interval: 1000
running: true
repeat: true
onTriggered: {
addPoint(_listData[currentIndex])
currentIndex++
if(currentIndex>maxLen-1){
currentIndex = 0
}
}
}
function addPoint(num){
_list.push(num)
if(_list.length>maxLen){
_list.splice(0,1)
}
canvas.requestPaint()
}
Rectangle{
id:rec
x:imgBg.width
y:0
width:imgBg.width
height: imgBg.height
color: "gray"
Canvas{
x:0
y:0
id:canvas_two
width: imgBg.width
height: imgBg.height
property real lastX
property real lastY
contextType: "2d"
visible: true
onPaint: {//绘图事件的响应
context.lineWidth=1.0;//线的宽度
context.strokeStyle="red";//线的颜色
context.fillStyle="white";//填充颜色
context.beginPath();//开始
context.moveTo(lastX, lastY)//移动到指定位置
lastX = area.mouseX
lastY = area.mouseY
context.lineTo(lastX, lastY)//划线到指定位置
context.stroke();//背景执行
}
MouseArea {
id: area
anchors.fill: parent//屏蔽父窗口的点击事件
onPressed: {
canvas_two.lastX = mouseX//鼠标位置
canvas_two.lastY = mouseY
}
onPositionChanged: {//位置改变事件
canvas_two.requestPaint()//重绘
}
}
}
}
}