add data collect.

This commit is contained in:
luocai
2024-08-21 09:26:06 +08:00
parent 5adb0d783d
commit 6289b66ac5
23 changed files with 746 additions and 109 deletions

View File

@ -0,0 +1,6 @@
import QtQuick
import QtQuick.Controls
Popup {
}

366
qml/DeviceView.qml Normal file
View File

@ -0,0 +1,366 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import AntiClipSettings
Item {
id: root
property alias enabled: shieldedRow.enabled
property int dargWidth: 12
property color openDoorAreaColor: "green"
property var openDoorAreaPoints: []
property int openDoorAreaWay: 0
property color shieldedAreaColor: "yellow"
property var shieldedAreaPoints: []
property bool shieldedAreaEnabled: false
property color antiClipAreaColor: "blue"
property var antiClipAreaPoints: []
property bool antiClipAreaEnabled: false
Item {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: controlBar.top
Image {
id: image
anchors.centerIn: parent
cache: false
fillMode: Image.PreserveAspectFit
source: "image://videoframe/"
property real aspectRatio: 16 / 9
width: Math.min(parent.width, parent.height * aspectRatio)
height: width / aspectRatio
enabled: root.enabled
Canvas {
id: canvas
anchors.fill: parent
onPaint: {
var ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
if(!root.enabled)return
if(openDoorAreaWay == DeviceConnection.FullArea){
ctx.strokeStyle = openDoorAreaColor
ctx.lineWidth = 8
ctx.strokeRect(0,0, canvas.width,
canvas.height)
} else if ((openDoorAreaWay>=DeviceConnection.Quadrangle) &&(openDoorAreaPoints.length > 0)) {
ctx.strokeStyle = openDoorAreaColor
ctx.lineWidth = 2
ctx.beginPath()
let point = scaledPoint(openDoorAreaPoints[0],
width, height)
ctx.moveTo(point.x, point.y)
for (var i = 1; i < openDoorAreaPoints.length; i++) {
point = scaledPoint(openDoorAreaPoints[i],
width, height)
ctx.lineTo(point.x, point.y)
}
ctx.closePath()
ctx.stroke()
}
if (antiClipAreaEnabled && (antiClipAreaPoints.length > 0)) {
ctx.strokeStyle = antiClipAreaColor
ctx.lineWidth = 2
ctx.beginPath()
let point = scaledPoint(antiClipAreaPoints[0],
width, height)
ctx.moveTo(point.x, point.y)
for (var i = 1; i < antiClipAreaPoints.length; i++) {
point = scaledPoint(antiClipAreaPoints[i],
width, height)
ctx.lineTo(point.x, point.y)
}
ctx.closePath()
ctx.stroke()
}
if (shieldedAreaEnabled &&(shieldedAreaPoints.length > 0)) {
ctx.lineWidth = 2
ctx.strokeStyle = shieldedAreaColor
let point0 = scaledPoint(shieldedAreaPoints[0],
width, height)
let point1 = scaledPoint(shieldedAreaPoints[1],
width, height)
let point2 = scaledPoint(shieldedAreaPoints[2],
width, height)
let point3 = scaledPoint(shieldedAreaPoints[3],
width, height)
ctx.strokeRect(point0.x, point0.y, point1.x - point0.x,
point1.y - point0.y)
ctx.strokeRect(point2.x, point2.y, point3.x - point2.x,
point3.y - point2.y)
}
}
}
Repeater {
id: repeater
visible: openDoorAreaWay>=DeviceConnection.Quadrangle
model: openDoorAreaPoints
delegate: Rectangle {
width: dargWidth
height: dargWidth
visible: root.enabled &&(openDoorAreaWay>=DeviceConnection.Quadrangle)
color: openDoorAreaColor
x: scaledPoint(modelData, canvas.width,
canvas.height).x - width / 2
y: scaledPoint(modelData, canvas.width,
canvas.height).y - height / 2
}
}
Repeater {
id: shieldedAreaRepeater
model: shieldedAreaPoints
visible: shieldedAreaEnabled
delegate: Rectangle {
width: dargWidth
height: dargWidth
visible: root.enabled && shieldedAreaEnabled
color: shieldedAreaColor
x: scaledPoint(modelData, canvas.width,
canvas.height).x - width / 2
y: scaledPoint(modelData, canvas.width,
canvas.height).y - height / 2
}
}
Repeater {
id: antiAreaRepeater
visible: antiClipAreaEnabled
model: antiClipAreaPoints
delegate: Rectangle {
visible: root.enabled && antiClipAreaEnabled
width: dargWidth
height: dargWidth
color: antiClipAreaColor
x: scaledPoint(modelData, canvas.width,
canvas.height).x - width / 2
y: scaledPoint(modelData, canvas.width,
canvas.height).y - height / 2
}
}
MouseArea {
anchors.fill: parent
enabled: root.enabled
property int draggedOpenDoorAreaPointIndex: -1
property int draggedShieldedAreaPointIndex: -1
property int draggedAntiAreaPointIndex: -1
onPressed: mouse => {
if(openDoorAreaWay == DeviceConnection.Quadrangle){
for (var i = 0; i < openDoorAreaPoints.length; i++) {
let point = scaledPoint(
openDoorAreaPoints[i], canvas.width,
canvas.height)
if (isInside(mouse.x, mouse.y, point)) {
draggedOpenDoorAreaPointIndex = i
break
}
}
}
if (draggedOpenDoorAreaPointIndex >= 0)
return
if(shieldedAreaEnabled){
for (let i = 0; i < shieldedAreaPoints.length; i++) {
let point = scaledPoint(
shieldedAreaPoints[i], canvas.width,
canvas.height)
if (isInside(mouse.x, mouse.y, point)) {
draggedShieldedAreaPointIndex = i
break
}
}
}
if (draggedShieldedAreaPointIndex >= 0)
return
if(antiClipAreaEnabled){
for (let i = 0; i < antiClipAreaPoints.length; i++) {
let point = scaledPoint(
antiClipAreaPoints[i], canvas.width,
canvas.height)
if (isInside(mouse.x, mouse.y, point)) {
draggedAntiAreaPointIndex = i
break
}
}
}
}
onReleased: {
if (draggedOpenDoorAreaPointIndex >= 0) {
App.updateOpenDoorAreaPoints(openDoorAreaPoints)
draggedOpenDoorAreaPointIndex = -1
}
if (draggedShieldedAreaPointIndex >= 0) {
App.updateShieldedAreaPoints(shieldedAreaPoints)
draggedShieldedAreaPointIndex = -1
}
if (draggedAntiAreaPointIndex >= 0) {
App.updateAntiClipAreaPoints(antiClipAreaPoints)
draggedAntiAreaPointIndex = -1
}
}
onPositionChanged: mouse => {
if ((mouse.x < 0) || (mouse.x > canvas.width) || (mouse.y < 0) || (mouse.y > canvas.height)) return
if (draggedOpenDoorAreaPointIndex >= 0) {
openDoorAreaPoints[draggedOpenDoorAreaPointIndex]
= standardPoint(Qt.point(mouse.x, mouse.y), canvas.width, canvas.height)
canvas.requestPaint()
repeater.model = openDoorAreaPoints
} else if (draggedShieldedAreaPointIndex >= 0) {
shieldedAreaPoints[draggedShieldedAreaPointIndex]
= standardPoint(Qt.point(mouse.x,
mouse.y),
canvas.width,
canvas.height)
canvas.requestPaint()
shieldedAreaRepeater.model = shieldedAreaPoints
} else if (draggedAntiAreaPointIndex >= 0) {
antiClipAreaPoints[draggedAntiAreaPointIndex]
= standardPoint(Qt.point(mouse.x,
mouse.y),
canvas.width,
canvas.height)
canvas.requestPaint()
antiAreaRepeater.model = antiClipAreaPoints
}
}
function isInside(x, y, point) {
let edge = dargWidth / 2
return x >= point.x - edge && x <= point.x + edge
&& y >= point.y - edge && y <= point.y + edge
}
}
}
}
Grid {
id: controlBar
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
columns: 2
spacing: 10
Text {text: qsTr("开门区域: ")}
Row {
enabled: root.enabled
RadioButton {
text: "关闭"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Diabled
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.Diabled
}
}
RadioButton {
text: "全区域"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.FullArea
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.FullArea
}
}
RadioButton {
text: "四边形"
checked: App.currentOpenDoorAreaWay ==DeviceConnection.Quadrangle
onToggled:{
App.currentOpenDoorAreaWay =DeviceConnection.Quadrangle
}
}
}
Text {text: qsTr("防夹区域: ")}
Row {
enabled: root.enabled
RadioButton {
text: "关闭"
checked: !App.currentAntiClipAreaEnabled
onToggled: {
App.currentAntiClipAreaEnabled=false
}
}
RadioButton {
text: "四边形"
checked: App.currentAntiClipAreaEnabled
onToggled: {
App.currentAntiClipAreaEnabled=true
}
}
}
Text {text: qsTr("屏蔽区域: ")}
Row {
id: shieldedRow
RadioButton {
checked: !shieldedAreaEnabled
text: "关闭"
onToggled: {
App.currentShieldedAreaEnabled = false
}
}
RadioButton {
checked: shieldedAreaEnabled
text: "开启"
onToggled: {
App.currentShieldedAreaEnabled = true
}
}
}
}
// 转换为显示画点
function scaledPoint(point, width, height) {
let x = point.x * width / App.DeviceWidth
let y = point.y * height / App.DeviceHeight
return Qt.point(x, y)
}
// 转换为设备画点(640x360)
function standardPoint(point, width, height) {
let x = point.x * App.DeviceWidth / width
let y = point.y * App.DeviceHeight / height
return Qt.point(x, y)
}
onEnabledChanged: {
canvas.requestPaint()
if(!enabled){
image.source = "image://videoframe/black"
}
}
Connections {
target: App
function onNewVideoFrame() {
image.source = ""
image.source = "image://videoframe/"
}
function onCurrentOpenDoorAreaPointsChanged() {
canvas.requestPaint()
repeater.model = openDoorAreaPoints
}
function onCurrentShieldedAreaPointsChanged() {
shieldedAreaRepeater.model = shieldedAreaPoints
canvas.requestPaint()
}
function onCurrentAntiClipAreaPointsChanged() {
antiAreaRepeater.model = antiClipAreaPoints
canvas.requestPaint()
}
function onCurrentOpenDoorAreaWayChanged(){
canvas.requestPaint()
}
function onCurrentShieldedAreaEnabledChanged(){
canvas.requestPaint()
}
function onCurrentAntiClipAreaEnabledChanged(){
canvas.requestPaint()
}
}
}

12
qml/IconButton.qml Normal file
View File

@ -0,0 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
Button {
property alias source: image.source
background: Item {
Image {
id:image
anchors.centerIn: parent
}
}
}

177
qml/Main.qml Normal file
View File

@ -0,0 +1,177 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import AntiClipSettings
ApplicationWindow {
id: window
width: 1000
height: 640
visible: true
title: qsTr("Hello World")
header: ToolBar {
RowLayout {
anchors.fill: parent
Button {
text: "搜索设备"
onClicked: {
deviceList.currentIndex = -1
App.startSearchDevice()
}
}
Text {
text: `: ${deviceList.count}`
}
Text {
Layout.alignment: Qt.AlignRight
Layout.preferredWidth: 400
text: deviceList.currentIndex
>= 0 ? `: ${App.devices.get(
deviceList.currentIndex).softwareVersion}` : ""
}
}
}
ListView {
id: deviceList
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 420
clip: true
model: App.devices
delegate: Rectangle {
width: deviceList.width
height: 40
color: ListView.isCurrentItem ? "#aaddff" : (index % 2 == 0 ? "#ffffff" : "#eeeeee")
Row {
anchors.fill: parent
spacing: 10
Text {
anchors.verticalCenter: parent.verticalCenter
text: deviceId
}
Item {}
Text {
anchors.verticalCenter: parent.verticalCenter
text: ip
}
Rectangle {
anchors.verticalCenter: parent.verticalCenter
color: onlineStatus ? "green" : "black"
width: 10
height: 10
radius: 5
}
}
MouseArea {
anchors.fill: parent
onClicked: {
deviceList.currentIndex = index
}
onDoubleClicked: {
networkPopup.open()
}
}
}
onCurrentIndexChanged: {
// deviceVersion.text = App.devices.get(deviceList.currentIndex).softwareVersion;
App.connectToDevice(deviceList.currentIndex)
}
ProgressBar {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
visible: App.devices.isSearching
from: 0
to: 100
value: App.devices.searchProgress
height: 25
}
}
DeviceView {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: deviceList.right
anchors.right: parent.right
enabled: deviceList.currentIndex>=0
openDoorAreaWay: App.currentOpenDoorAreaWay
openDoorAreaPoints: App.currentOpenDoorAreaPoints
shieldedAreaEnabled: App.currentShieldedAreaEnabled
shieldedAreaPoints: App.currentShieldedAreaPoints
antiClipAreaEnabled: App.currentAntiClipAreaEnabled
antiClipAreaPoints: App.currentAntiClipAreaPoints
}
NetworkSettingPopup {
id: networkPopup
visible: false
width: 500
height: 240
}
OtaPopup {
id: otaPopup
}
FolderDialog {
id: folderDialog
onAccepted: {
App.collector.path = folderDialog.selectedFolder
App.collector.start(App.devices.get(deviceList.currentIndex).ip)
}
}
footer: RowLayout {
width: parent.width
Item {}
Button {
text: App.collector.enabled ? "停止采集" : "数据采集"
onClicked: {
if (App.collector.enabled) {
App.collector.stop()
} else {
if (deviceList.currentIndex < 0) {
showMessageDialog(2, "数据采集", "请先选择设备")
return
}
if (App.collector.path.length <= 0) {
folderDialog.open()
} else {
App.collector.start(App.devices.get(
deviceList.currentIndex).ip)
}
}
}
}
Item {}
Button {
text: "升级"
onClicked: {
if (deviceList.currentIndex < 0) {
showMessageDialog(2, "OTA升级", "请选选择设备")
return
}
otaPopup.open()
}
}
Item {}
spacing: (parent.width - (2 * 100)) / 3
}
function showMessageDialog(type, title, message) {
let component = Qt.createComponent("MessageDialog.qml")
if (component.status === Component.Ready) {
let dialog = component.createObject(window, {
"type": type,
"height": 200,
"titleText": title,
"text": message
})
dialog.open()
}
}
}

108
qml/MessageDialog.qml Normal file
View File

@ -0,0 +1,108 @@
import QtQuick
import QtQuick.Controls
Dialog {
id: control
width: 320
parent: Overlay.overlay
anchors.centerIn: Overlay.overlay
modal: true
property alias titleText: titleLabel.text
property alias text: textLabel.text
property alias textFontSize: textLabel.font.pixelSize
property int type: MessageDialog.Type.Successful
closePolicy: Popup.CloseOnEscap | Popup.NoAutoClose
background: Rectangle {
radius: 8
}
enum Type {
Ok,
Successful,
Warning,
Failed
}
IconButton {
anchors.right: parent.right
anchors.rightMargin: 7
anchors.top: parent.top
anchors.topMargin: 10
source: "../resources/popup_close.svg"
onClicked: control.close()
}
Image {
id: image
width: 18
height: 18
anchors.left: parent.left
anchors.leftMargin: 30
anchors.top: parent.top
anchors.topMargin: 40
source: "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
}
Text {
id: titleLabel
anchors.left: parent.left
anchors.leftMargin: 60
anchors.top: parent.top
anchors.topMargin: 40
font.family: control.font.family
font.pixelSize: 16
color: "#0A1F44"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Text {
id: textLabel
anchors.left: parent.left
anchors.leftMargin: 60
anchors.right: parent.right
anchors.rightMargin: 40
anchors.top: parent.top
anchors.topMargin: 76
font.family: control.font.family
font.pixelSize: 14
color: "#53627C"
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
}
Button {
id: cancelButton
width: 72
height: 26
anchors.right: parent.right
anchors.rightMargin: 15
anchors.bottom: parent.bottom
anchors.bottomMargin: 15
font.family: control.font.family
text: "关闭"
font.pixelSize: 14
contentItem: Text {
text: parent.text
font: parent.font
color: parent.down ? "#FFFFFF" : "#53627C"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
border.color: "#E1E4E8"
border.width: 1
color: parent.down ? "#F25959" : "#FFFFFF"
radius: 2
}
onClicked: control.reject()
}
onTypeChanged: {
if (type === MessageDialog.Type.Successful || type === MessageDialog.Type.Ok) {
image.source = "qrc:/qt/qml/AntiClipSettings/resources/successfull.svg"
} else if (type === MessageDialog.Type.Warning) {
image.source = "qrc:/qt/qml/AntiClipSettings/resources/warning.svg"
} else if(type === MessageDialog.Type.Failed){
// image.source = "qrc:/AntiClipSettings/resources/prompt_delete.svg"
}
}
}

117
qml/NetworkSettingPopup.qml Normal file
View File

@ -0,0 +1,117 @@
import QtQuick
import QtQuick.Controls
import AntiClipSettings
Popup {
id: root
parent: Overlay.overlay
anchors.centerIn: Overlay.overlay
Rectangle {
width: parent.width
height: parent.height
color: "white"
border.color: "lightgray"
radius: 10
Column {
anchors.centerIn: parent
spacing: 10
padding: 20
Row {
spacing: 10
Text {
text: "模式"
font.pointSize: 14
width: 100
}
RadioButton {
id: dhcpMode
text: "DHCP"
checked: App.currentNetworkInfomation.dhcp
}
RadioButton {
id: staticMode
text: "静态IP"
checked: !App.currentNetworkInfomation.dhcp
}
}
Row {
spacing: 5
Text {
text: "设备IP"
font.pointSize: 14
width: 100
}
TextField {
id: ipInput
width: 350
height: 30
text: App.currentNetworkInfomation.ip
}
}
Row {
spacing: 5
Text {
width: 100
text: "子网掩码"
font.pointSize: 14
}
TextField {
id: netmaskInput
width: 350
height: 30
text: App.currentNetworkInfomation.netmask
}
}
Row {
spacing: 5
Row {
spacing: 5
Text {
text: "设备网关"
font.pointSize: 14
width: 100
}
}
TextField {
id: gatewayInput
width: 350
height: 30
text: App.currentNetworkInfomation.gateway
}
}
Row {
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
Button {
text: "保存"
onClicked: {
App.updateNetworkInfomation(dhcpMode.checked,ipInput.text,netmaskInput.text,gatewayInput.text);
networkPopup.close()
}
}
Button {
text: "取消"
onClicked: root.close()
}
}
}
}
}

113
qml/OtaPopup.qml Normal file
View File

@ -0,0 +1,113 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import AntiClipSettings
Popup {
id: root
parent: Overlay.overlay
anchors.centerIn: Overlay.overlay
width: 540
height: 260
modal: true
focus: true
closePolicy: Popup.CloseOnEscape
property var onClose
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
RowLayout {
Layout.alignment: Qt.AlignRight
Button {
text: "关闭"
onClicked: root.close()
}
}
RowLayout {
spacing: 10
TextField {
id: otaFile
Layout.fillWidth: true
placeholderText: "请选择升级文件或将文件拖入工具中"
}
Button {
text: "选择"
onClicked: fileDialog.open()
}
}
RowLayout {
spacing: 10
ProgressBar {
id: progressBar
Layout.fillWidth: true
from: 0
to: 100
value: 0.0
}
Text {
id: progressText
text: "0%"
verticalAlignment: Text.AlignVCenter
}
}
RowLayout {
Text {
id: otaMessage
text: "请选择升级文件,点击开始按钮升级模组"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
Layout.fillWidth: true
}
Button {
text: "开始"
Layout.alignment: Qt.AlignRight
onClicked: {
otaMessage.color = "black"
App.upgradeDevice(otaFile.text)
}
}
}
}
onClosed: {
if (onClose)
onClose()
}
FileDialog {
id: fileDialog
nameFilters: ["OTA文件 (*.bin)"]
currentFolder: StandardPaths.standardLocations(
StandardPaths.DesktopLocation)[0]
onAccepted: {
var fileUrl = fileDialog.selectedFile.toString()
var localFilePath = fileUrl.startsWith(
"file:///") ? fileUrl.substring(8) : fileUrl
otaFile.text = localFilePath
}
}
Connections {
target: App
function onCurrentDeviceOtaProgressChanged (status, progress, message) {
progressBar.value = progress
progressText.text = `${progress}%`
if(progress>=100){
otaMessage.text = "OTA升级完成"
otaMessage.color = "green"
}else {
otaMessage.text = message
}
}
}
}

55
qml/StatusTip.qml Normal file
View File

@ -0,0 +1,55 @@
import QtQuick
import QtQuick.Controls
Popup{
id: control
property alias text: textItem.text
property alias icon: image.source
property alias color: back.color
property string borderColor
x: (parent.width-200)/2
y: 40
width: 200
height: 32
font.pixelSize: 16
contentItem: Row{
leftPadding: 4
spacing: 9.6
Image {
id: image
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: textItem
anchors.verticalCenter: parent.verticalCenter
text: control.text
font: control.font
color: "#666666"
}
}
background: Rectangle {
id:back
anchors.fill: parent
color: "#EBF8ED"
radius: 3.2
border.width: 1
border.color: control.borderColor
layer.enabled: true
}
Timer {
id: timer
repeat: false
onTriggered: control.visible=false
}
function show(text,timeout){
control.text = text
timer.interval = timeout
timer.restart();
control.visible=true
}
}