效果
可以用鼠标拖动曲线上的采样点来编辑曲线。
默认情况下只能在Y方向上编译。可以通过修改dragableDirection: DragableChart.DragableDirect.Veritcal 让点可以全向拖动
代码文件
- 仓库
https://gitee.com/deng-gang/QMLTestProjects
这是一些测试项目的集合 - 文件目录
QT512/10-6/10-6-1/mycharts/DragableChart.qml
代码
import QtQuick 2.0
import QtCharts 2.3
ChartView{
property var points_X:[1.51,1.57,2.0,2.55]
property var points_Y: [2.51,3.57,4.0,4.55]
id: myChart
anchors.fill: parent
legend.visible: false
antialiasing: true
// 为了使用枚举,必须把这个ChartView放到一个独立的qml文件里
enum DragableDirect{
Both, //0
Veritcal, // 1
Horizontal // 2
}
// line curve
LineSeries{id: line}
property point selectedPointInChart
ScatterSeries{
id: points
onHovered:{
var global_position
//global_position = myChart.mapToGlobal(point.x,point.y)
global_position = myChart.mapToPosition(point,points)
selectedHandler.x = global_position.x - selectedHandler.width / 2
selectedHandler.y = global_position.y - selectedHandler.height / 2
selectedPointInChart = point
//console.log(global_position)
// 在鼠标移入的时候显示selectedPointer
// 当selectedPointer 被显示后,焦点转换到 selectedPointer 上,这时会收到一个 hovered事件,且 state 是 false
// 因此鼠标移出,消除selectedPointer的动作要由 selectedPointer onHovered 事件去处理,如果在points 里删除 selectedPointer,会导致 qmlscence crash
if (state === true){
//console.log("hovered in : x:" + point.x + " y:" + point.y)
selectedHandler.state = "HOVERED"
//selectedPointer.clear()
//selectedPointer.append(point.x,point.y)
}else{
//console.log("hovered out : x:" + point.x + " y:" + point.y)
// importent!!!! Can not clear selectedPointer here!
//selectedPointer.clear()
}
}
Connections{
target: selectedHandler
onDataModified:{
var newPoint
newPoint = myChart.mapToValue(Qt.point(newX, newY),points)
//console.log("myChart.onDataModified: x:" + newX + " y:" + newY + " new value:" + newPoint)
points.replace(selectedPointInChart.x,selectedPointInChart.y,newPoint.x,newPoint.y)
line.replace(selectedPointInChart.x,selectedPointInChart.y,newPoint.x,newPoint.y)
}
}
}
Item{
id: selectedHandler;
width: 20; height:20
visible: false
property real xCenter: x+width/2
property real yCenter: y+height/2
property int dragableDirection: DragableChart.DragableDirect.Veritcal
signal posChange(int xOffset, int yOffset)
onPosChange: {
if(dragableDirection === DragableChart.DragableDirect.Both){
x += xOffset;y += yOffset
}else if(dragableDirection === DragableChart.DragableDirect.Veritcal){
y += yOffset
}else if(dragableDirection === DragableChart.DragableDirect.Horizontal){
x += xOffset
}
}
signal dataModified(real newX, real newY);
onDataModified: {
//console.log("newX:"+newX + " newY:" + newY)
}
state: "HIDE"
states: [
State{
name:"HIDE"
PropertyChanges{target: selectedHandler; opacity:0.8 }
PropertyChanges{target: selectedHandler; visible:false}
},
State {
name: "HOVERED"
PropertyChanges {target: selectedHandler; opacity:0.5 }
PropertyChanges {target: selectedHandler; visible:true}
},
State{
name: "SELECTED"
PropertyChanges{target: selectedHandler; opacity:0.8 }
PropertyChanges{target: selectedHandler; visible:true}
},
State{
name: "MODIFING"
PropertyChanges{target: selectedHandler; opacity:0.9 }
PropertyChanges{target: selectedHandler; visible:true}
},
State{
name: "MODIFIED"
PropertyChanges{target: selectedHandler; opacity:1.0 }
PropertyChanges{target: selectedHandler; visible:true}
}
]
onStateChanged: {
//console.log("onStateChanged : ", state)
// 当数据修改完成,转入"MODIFIED"状态时,发送signal,
// 外面的chart需要根据这个signal更新曲线
if(state === "MODIFIED"){
dataModified(xCenter,yCenter);
}
}
Rectangle{
anchors.fill: parent
color: "red"
radius: width/2
}
MouseArea{
anchors.fill: parent
hoverEnabled: true // 必须设置为true 才能接受hover事件
property int lastX: 0 // mouseX 是当前光标与root中心点的偏移量,在拖动的过程中要保持光标和root中心的偏移量不变
property int lastY: 0
onExited: {
if(selectedHandler.state != "MODIFING"){ // sometimes move too fast
selectedHandler.state = "HIDE"
//console.log("onExited")
}
}
onPressed: {
selectPoint(mouseX,mouseY)
}
onReleased: {
if(selectedHandler.state === "MODIFING"){
selectedHandler.state = "MODIFIED"
}
}
onPositionChanged: {
if (selectedHandler.state === "SELECTED" || selectedHandler.state === "MODIFING") {
selectedHandler.posChange(mouseX - lastX, mouseY - lastY)
if(selectedHandler.state === "SELECTED" ){
selectedHandler.state = "MODIFING"
}
}
}
function selectPoint(mouseX,mouseY){
if (selectedHandler.state === "HOVERED" || selectedHandler.state === "MODIFIED"){
selectedHandler.state = "SELECTED"
lastX = mouseX;
lastY = mouseY;
}
}
}
}
Component.onCompleted: {
var index
//console.log("points_X:"+ points_X.length)
for(index = 0;index < points_X.length;index++){
line.append(points_X[index],points_Y[index])
points.append(points_X[index],points_Y[index])
//console.log("append : "+ points_X[index],points_Y[index])
}
myChart.axisX().max = points_X[points_X.length-1] * 1.2
myChart.axisY().max = points_Y[points_Y.length-1] * 1.2
}
}