QML学习笔记(二)-纯qml画图实现canvas画板-鼠标画图
作者: 狐狸家的鱼
Github: 八至
版权声明:如需转载请获取授权和联系作者
用纯qml实现canvas画板功能,用鼠标进行画图,可以画直线,画圆,画矩形,画弧线。
由于canvas画图会有延迟和卡顿,建议还是结合c++实现画图功能。
以下gif效果都没有录进鼠标
1.鼠标点击画图-无预览路径(两点实现)

贴上代码和注释:
property real startX
property real startY
property real stopX
property real stopY
property color color: colorTools.paintColor
property var paintType: ["line","rect","circle","curve"]//自定义绘制类型
property var clickPoint: []//多边形画图的存点数组 未实现
property int clickNum: 0//鼠标点击 Row{
id:colorTools//颜色提取工具
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 8 }
property color paintColor: "#33b5e5"//设置初始画笔颜色
spacing: 4;
// Repeater{//四个colorSquare
// model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"]//modelData 颜色数据
// ColorSquare{
// id:red;
// color: modelData;
// active: parent.paintColor == color//当选中一个colorSquare时,当前画笔颜色为选中的颜色
// onClicked: {
// parent.paintColor = color
// } // }
// }
Button {
text: "Clear"
onClicked: {
canvas.clear()
}
}
Button{
text: "line";
onClicked: { paintType = "line";
//canvas.requestPaint();
} }
Button{
text: "rect"
onClicked: {
paintType = "rect";
// canvas.requestPaint();
}
}
Button{
text: "circle"
onClicked: {
paintType = "circle";
// canvas.requestPaint();
}
}
Button{
text: "curve"
onClicked: {
paintType = "curve";
// canvas.requestPaint();
}
}
}
Rectangle{
anchors.fill: canvas
border.color: "#666"
border.width: 4; }
Canvas{
id:canvas;
anchors{
left: parent.left;
right:parent.right;
top:colorTools.bottom;
bottom: parent.bottom;
margins: 8
}
//鼠标点击坐标位置 function clear() {
var ctx = getContext("2d");
ctx.reset();
canvas.requestPaint();
}
onPaint: {
var ctx = getContext("2d")
ctx.lineWidtn = 5
ctx.strokeStyle = canvas.color;//轮廓颜色
//ctx.fillStyle = canvas.color;//填充颜色
ctx.beginPath()
if(paintType === "line"){
ctx.moveTo(startX,startY)
startX = area.mouseX;
startY = area.mouseY;
ctx.lineTo(stopX,stopY)
stopX = area.mouseX;
stopY = area.mouseY; }
if(paintType === "rect"){
//ctx.fillRect(startX,startY,stopX-startX,stopY-startY)//填充类型
//ctx.clearRect(0,0,width,height)
ctx.strokeRect(startX,startY,stopX-startX,stopY-startY)//非填充
}
if(paintType === "circle"){
ctx.arc(startX,startY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)),0,360,false)
}
if(paintType === "curve"){
ctx.arcTo(startX,startY,stopX,stopY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)))
} // ctx.fill();//完成填充
ctx.stroke()
}
MouseArea{
id:area;
anchors.fill: parent;
onClicked: {//存点 遍历
//clickPoint.push({"x":mouseX,"y":mouseY})//多边形绘制存点 多边形未实现
clickNum++;
for(var i = 0;i<clickPoint.length;i++){
var point = clickPoint[i]; } if(clickNum == 1){
startX = mouseX;
startY = mouseY;
}
if(clickNum == 2){
clickNum = 0;
stopX = mouseX;
stopY = mouseY;
canvas.requestPaint();
} }
} }
}
2.鼠标按压拖动绘图-无预览路径(鼠标释放完成绘制)
代码和注释:

property real startX
property real startY
property real stopX
property real stopY
property color color: colorTools.paintColor
property var paintType: ["line","rect","circle","curve"]
property var clickPoint: []
property int clickNum: 0
Row{
id:colorTools//颜色提取工具
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 8
}
property color paintColor: "#33b5e5"//设置初始画笔颜色
spacing: 4;
// Repeater{//四个colorSquare
// model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"]//modelData 颜色数据
// ColorSquare{
// id:red;
// color: modelData;
// active: parent.paintColor == color//当选中一个colorSquare时,当前画笔颜色为选中的颜色
// onClicked: {
// parent.paintColor = color
// }
// }
// }
Button {
text: "Clear"
onClicked: {
canvas.clear()
}
}
Button{
text: "line";
onClicked: {
paintType = "line";
//canvas.requestPaint();
}
}
Button{
text: "rect"
onClicked: {
paintType = "rect";
// canvas.requestPaint();
}
}
Button{
text: "circle"
onClicked: {
paintType = "circle";
// canvas.requestPaint();
}
}
Button{
text: "curve"
onClicked: {
paintType = "curve";
// canvas.requestPaint();
}
}
}
Rectangle{
anchors.fill: canvas
border.color: "#666"
border.width: 4;
}
Canvas{
id:canvas;
anchors{
left: parent.left;
right:parent.right;
top:colorTools.bottom;
bottom: parent.bottom;
margins: 8
}
//鼠标点击坐标位置
function clear() {//此清除有问题
var ctx = getContext("2d");
ctx.reset();
canvas.requestPaint();
}
onPaint: {
var ctx = getContext("2d")
ctx.lineWidtn = 10
ctx.strokeStyle = canvas.color;
// ctx.fillStyle = canvas.color;//若想要填充的 此不注释
ctx.beginPath()
if(paintType === "line"){
ctx.moveTo(startX,startY)
startX = area.mouseX;
startY = area.mouseY;
ctx.lineTo(stopX,stopY)
stopX = area.mouseX;
stopY = area.mouseY;
}
if(paintType === "rect"){
//ctx.fillRect(startX,startY,stopX-startX,stopY-startY)//填充类型
//ctx.clearRect(0,0,width,height)
ctx.strokeRect(startX,startY,stopX-startX,stopY-startY)//非填充
}
if(paintType === "circle"){
ctx.arc(startX,startY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)),0,360,false)
}
if(paintType === "curve"){//未实现
ctx.arcTo(startX,startY,stopX,stopY,Math.sqrt(Math.pow((stopX-startX),2)+Math.pow((stopY-startY),2)))
}
//ctx.fill();
ctx.stroke()
}
MouseArea{
id:area;
anchors.fill: parent;
// onClicked: {//存点 遍历
// clickPoint.push({"x":mouseX,"y":mouseY})
// clickNum++;
// for(var i = 0;i<clickPoint.length;i++){
// var point = clickPoint[i];
// }
// if(clickNum == 1){
// startX = mouseX;
// startY = mouseY;
// }
// if(clickNum == 2){
// clickNum = 0;
// stopX = mouseX;
// stopY = mouseY;
// canvas.requestPaint();
// }
// }
onPressed: {
startX = mouseX;
startY = mouseY;
}
onMouseXChanged: {
stopX = mouseX;
}
onMouseYChanged: {
stopY = mouseY;
}
onReleased: {
canvas.requestPaint()//重绘
}
// onPositionChanged: {
// canvas.requestPaint()//重绘 这句话不注释 会有预览路径 但是临时区没有清理 需要在cpp中进行清除
// }
}
}
3.鼠标按压拖动绘制-有预览路径
因为想要绘制的过程中有预览路径,需要在cpp中实现清理临时区域,因为如果不清理 ,画直线的时候没问题,但是在画矩形圆的时候会出现如下情况:

cpp中如何画,可以参考这篇博文:https://blog.csdn.net/foruok/article/details/32698603
第三种方法可以在qml中有预览路径的同时也清理临时图区,只不过只能存在一个图元,也就是画了直线之后画圆,直线就会消失。所以还是建议结合c++中的QQuickPaintedItem方法等进行清理临时图区。这个链接有三个实例提供参考 https://www.aliyun.com/jiaocheng/173346.html ,上面那个链接就是对第一个实例的解释
以下代码我做了临时图元的简单清理,但是画线段的时候由于清理了,所以画不出来了,所以还是建议看博客结合cpp
通过gif可以看到录制把临时图元都看到了,但是在实际绘制的时候却看不到的,
QML学习笔记(二)-纯qml画图实现canvas画板-鼠标画图的更多相关文章
- qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)
原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...
- QML学习笔记(六)- 简单计时器和定时器
做一个简单的qml计时器和定时器,左键触发计时,右键触发定时 GitHub:八至 作者:狐狸家的鱼 本文链接:QML学习笔记(六)- 简单计时器和定时器 左键点击按钮,触发计时器,中键可以暂停计时,同 ...
- QML学习笔记(五)— 做一个简单的待做事项列表
做一个简单的QML待做事项列表,能够动态添加和删除和编辑数据 GitHub:八至 作者:狐狸家的鱼 本文链接:QML学习笔记(五)— 做一个待做事项列表 主要用到QML:ListView 效果 全部代 ...
- 纯JS实现KeyboardNav(学习笔记)二
纯JS实现KeyboardNav(学习笔记)二 这篇博客只是自己的学习笔记,供日后复习所用,没有经过精心排版,也没有按逻辑编写 这篇主要是添加css,优化js编写逻辑和代码排版 GitHub项目源码 ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
随机推荐
- MyBatis映射文件2(不支持自增的数据库解决方案/参数处理[单参、多参、命名参数])
针对Oracle不支持自增的解决方案 Oracle不支持自增,但是它使用序列来模拟自增,每次插入数据的主键是从序列中拿到的值,那么如何获取这个值呢? <insert id="addEm ...
- python之路--装饰器
二 .通用装饰器的写法 python里面的动态代理. 存在的意义: 在不破坏原有的函数和原有函数的调用基础上,给函数添加新的功能 def wrapper(fn): # fn是目标函数. def inn ...
- 集合转数组的toArray()和toArray(T[] a)方法
参考:集合转数组的toArray()和toArray(T[] a)方法 1.ArrayList的toArray ArrayList提供了一个将List转为数组的一个非常方便的方法toArray.toA ...
- C-Lodop提示“有窗口已打开,先关闭它(持续如此请刷新页面)!”
c-lodop显示“有窗口已打开,先关闭它(持续如此时请刷新页面)!”如果连续执行多个预览语句等导致的,可以预先判断一下,并可以自定义修改窗口已打开的提示,该默认提示的位置如本博客的下图http:// ...
- linux利用CMakeLists编译cuda程序
文件目录: cudaTest |--utils.cu |--utils.h |--squaresum.cu |--squaresum.h |--test.cpp |--CMakeLists.txt 编 ...
- poj-2337(欧拉回路输出)
题意:给你n个字符串,每个字符串可以和另一个字符串连接的前提是,前一个字符串的尾字符等于后一个字符串的首字符,问你存不存在欧拉通路并输出 解题思路:基本标准流程,建图:把一个字符串可以看作一条首字符指 ...
- java基础1之基本数据类型
java的数据类型 整数型(byte.short.int.long) 编程过程中,默认是int类型.long类型的字面值后面需要加上L或l PS:java底层,byte.short是按照32位计算的. ...
- Lisp小程序,大作用,不该放弃!
从听说autolisp到现在已经20年了, 学了一点点, 可惜中间没能坚持下来, 放弃了! 今天在画图, 图纸是从revit转成dwg的, 其中有些文本的朝向是错误的, 如果手工旋转很是费事, ...
- POI Excel 单元格内容类型判断并取值
个人用到的 String birthdayVal = null; ...
- BZOJ5210 最大连通子块和 【树链剖分】【堆】【动态DP】
题目分析: 解决了上次提到的<切树游戏>后,这道题就是一道模板题. 注意我们需要用堆维护子重链的最大值.这样不会使得复杂度变坏,因为每个重链我们只考虑一个点. 时间复杂度$O(nlog^2 ...