2021-01-29 973. K Closest Points to Origin

该博客介绍了如何解决计算机科学中的一个问题:在给定一组平面上的点和一个整数K的情况下,找出离原点最近的K个点。通过实现一个Java解决方案,博主展示了如何利用排序和比较器来有效地找到这K个点,时间复杂度为O(n log n)。示例展示了在不同输入情况下如何得到正确答案,并强调了答案的唯一性(除了顺序外)。

973. K Closest Points to Origin

Difficulty: Medium

Related Topics: Divide and Conquer, Heap, Sort

We have a list of points on the plane. Find the K closest points to the origin (0, 0).

(Here, the distance between two points on a plane is the Euclidean distance.)

You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:

Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation: 
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].

Example 2:

Input: points = [[3,3],[5,-1],[-2,4]], K = 2
Output: [[3,3],[-2,4]]
(The answer [[-2,4],[3,3]] would also be accepted.)

Note:

  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000
Solution

Language: Java

Key: Another way to use divide and conquer to reach only O(n) time complexity

class Solution {
    public int[][] kClosest(int[][] points, int K) {
        List<Point> result = new ArrayList<>();
        int[][] res = new int[K][2];
        Comparator<Point> comp = new Comparator<>() {
            public int compare(Point a, Point b) {
                return a.distance() - b.distance();
            }
        };
        for (int i = 0; i < points.length; i ++) {
            result.add(new Point(points[i][0], points[i][1]));
        }
        Collections.sort(result, comp);
        for (int i = 0; i < K; i++) {
            res[i][0] = result.get(i).x;
            res[i][1] =result.get(i).y;
        }
        return res;
    }
    
}class Point {
    int x;
    int y;
    
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int distance() {
        return (x * x + y * y);
    }
}
内容概要:本文设计了一种基于PLC的全自动洗衣机控制系统内容概要:本文设计了一种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔和过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及和柔和、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能和、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识和梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制类项目开发参考一定PLC基础知识。; 阅读和梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中类似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件和MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
根据上面的解释,修改下面的qml,并给出完整的代码//DataLogShow.qml import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import CsvLogger 1.0 import QtCharts 2.15 Item { // 基准分辨率(设计稿尺寸) property real baseWidth: 1024 property real baseHeight: 600 // 动态计算缩放比例 property real scaleX: width / baseWidth property real scaleY: height / baseHeight property real unifiedScale: Math.max(Math.min(scaleX, scaleY),1) property string mountPath: "" property string curFileName: "" // 文件列表模型 property ListModel fileListModel: ListModel {} CsvLogger { id: csvLogger } CustomVirKeyboard { id: keyboard x: (parent.width - width) / 2 y: Math.max(0, parent.height - height - 20) onAccepted: (text) => { if (target) target.text = text keyVisible = false } } MouseArea { anchors.fill: parent propagateComposedEvents: true onClicked: function(mouse) { var keyboardPos = mapToItem(keyboard, mouse.x, mouse.y) var isOnKeyboard = keyboardPos.x >= 0 && keyboardPos.y >= 0 && keyboardPos.x <= keyboard.width && keyboardPos.y <= keyboard.height var isOnTarget = false if (keyboard.target) { var targetPos = mapToItem(keyboard.target, mouse.x, mouse.y) isOnTarget = targetPos.x >= 0 && targetPos.y >= 0 && targetPos.x <= keyboard.target.width && targetPos.y <= keyboard.target.height } if (!isOnKeyboard && !isOnTarget) keyboard.keyVisible = false else keyboard.keyVisible = true mouse.accepted = false } } Connections { target: csvLogger function onDownloadFile(status, err) { if (status) { usbCompletePopup.labText = "文件已拷贝到" + err; usbCompletePopup.open() } else { usbErrorPopup.labelText = err usbErrorPopup.open() } } function onFilesInfoCompleted(filefullData, fileMaxminData) { var chartData = { channelData: filefullData, channelMaxmin: fileMaxminData } chartPopup.chartData = chartData chartPopup.open() } } function loadCsvFiles() { var csvFiles = csvLogger.getCsvFiles(); fileListModel.clear(); for (var i = 0; i < csvFiles.length; i++) { var fileInfo = csvLogger.getCvsFileInfo(csvFiles[i]); if (!fileInfo.isEmpty && fileInfo.startTime !== "") { fileListModel.append({ filePath: fileInfo.fullName, fileName: fileInfo.fileName, startTime: fileInfo.startTime, endTime: fileInfo.endTime, fileSize: fileInfo.fileSize, lineNumber: fileListModel.count + 1 }); } } } function handleDownloadRequest(fileName) { csvLogger.copyFile(fileName) } function handleRenameFile(filePath, newName) { csvLogger.renameFile(filePath, newName) } function analyzeCsvFile(filePath) { console.log("[analyzeCsvFile] 开始分析文件:", filePath) csvLogger.readChannelDataFromFile(filePath) } Popup { id: chartPopup width: 800 height: 500 anchors.centerIn: parent closePolicy: Popup.CloseOnEscape modal: true property bool isLarge: false property bool isTable: false property var chartData: ({}) property var channelDataList: [] property var channelDataMinMax: [] property bool hasValidData: false property real chartLeftMargin: 60 property real chartRightMargin: 20 property real chartTopMargin: 40 property real chartBottomMargin: 40 property int horizontalGridLines: 6 background: Rectangle { anchors.fill: parent color: "#212529" radius: 5 border.color: "#555555" border.width: 1 } onChartDataChanged: { if (chartData.channelData && chartData.channelMaxmin) { channelDataList = chartData.channelData channelDataMinMax = chartData.channelMaxmin validateData() Qt.callLater(chartView.updateChart) } } function validateData() { var valid = (channelDataList.length > 0 && channelDataMinMax.length > 0 && channelDataList.length === channelDataMinMax.length) hasValidData = valid } function getSeriesColor(index) { const colors = [ "#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFA500", "#800080", "#008000", "#000080", "#808000", "#800000", "#008080", "#9370DB", "#20B2AA", "#1E90FF" ] return colors[index % colors.length] } Row { id: changeAera anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter spacing: 10 Button { id: curveButton text: "曲线视图" width: 120 height: 40 background: Rectangle { color: parent.pressed ? "#404040" : (parent.hovered ? "#353535" : "#4169E1") radius: 4 } onClicked: { chartPopup.isTable = false } contentItem: Text { text: parent.text color: "white" font.pixelSize: 16 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Button { id: tableButton text: "数据表格" width: 120 height: 40 background: Rectangle { color: parent.pressed ? "#404040" : (parent.hovered ? "#353535" : "#4169E1") radius: 4 } onClicked: { chartPopup.isTable = true } contentItem: Text { text: parent.text color: "white" font.pixelSize: 16 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } Button { text: "关闭" width: 100 height: 40 background: Rectangle { color: parent.pressed ? "#404040" : (parent.hovered ? "#353535" : "#4169E1") radius: 4 } onClicked: { chartPopup.close() } contentItem: Text { text: parent.text color: "white" font.pixelSize: 16 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } } } //显示区域 Rectangle { id: dataAera width: parent.width - 20 height: parent.height - changeAera.height - 20 color: "#191919" anchors { top: changeAera.bottom left: parent.left margins: 10 } ChartView { id: chartView width: parent.width - 120 height: parent.height anchors.left: parent.left anchors.top: parent.top visible: !chartPopup.isTable antialiasing: true backgroundColor: "#000000" legend.visible: false animationOptions: ChartView.NoAnimation property real yAxisMin: -5 property real yAxisMax: 105 // 变换控制属性 property real zoomFactor: 1.0 property point panOffset: Qt.point(0, 0) property real zoomStep: 0.01 property real panStep: 30 property int animationDuration: 300 property real xZoomFactor: 1.0 property real zoomInFactor: 1.05 property real zoomOutFactor: 0.95 // 交互式图例和垂直线 Rectangle { id: verticalLine width: 1 height: parent.height - chartPopup.chartTopMargin - chartPopup.chartBottomMargin color: "white" visible: false z: 10 x: chartPopup.chartLeftMargin y: chartPopup.chartTopMargin property real currentX: 0 property var closestPoints: ({}) } Rectangle { id: legendContainer width: 200 height: Math.min((chartPopup.channelDataList.length + 1) * 18 , chartView.height - 20) color: "#333333" border.color: "#555555" border.width: 1 radius: 5 visible: false z: 10 anchors.top: parent.top anchors.topMargin: 30 Column { anchors.fill: parent anchors.margins: 2 spacing: 2 Text { id: timeLabel width: parent.width color: "white" font { pixelSize: 14; bold: true } horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight } Rectangle { width: parent.width height: 1 color: "#555555" } Repeater { model: Object.keys(verticalLine.closestPoints) Row { spacing: 3 Rectangle { width: 14 height: 14 radius: 7 color: chartPopup.getSeriesColor(parseInt(modelData)) //border.color: "white" //border.width: 2 } Row { spacing: 2 Text { text: chartPopup.channelDataList[modelData].channelName color: "white" font.pixelSize: 12 } Text { text: verticalLine.closestPoints[modelData].value.toFixed(2) color: "#AAAAAA" font.pixelSize: 12 } } } } } } Repeater { model: Object.keys(verticalLine.closestPoints) Rectangle { id: pointMarker width: 10 height: 10 radius: 5 color: chartPopup.getSeriesColor(parseInt(modelData)) visible: verticalLine.visible x: { var closestPoint = verticalLine.closestPoints[modelData]; if (!closestPoint) return 0; var seriesIndex = parseInt(modelData); var series = chartView.seriesAt(seriesIndex); if (!series || series.count === 0) return 0; var point = Qt.point( closestPoint.x, closestPoint.y ); var pos = chartView.mapToPosition(point, series); return pos.x - width / 2; } y: { var closestPoint = verticalLine.closestPoints[modelData]; if (!closestPoint) return 0; var seriesIndex = parseInt(modelData); var series = chartView.seriesAt(seriesIndex); if (!series || series.count === 0) return 0; var point = Qt.point( closestPoint.x, closest.y ); var pos = chartView.mapToPosition(point, series); return pos.y - height / 2; // 中心对齐 } } } MouseArea { anchors.fill: parent hoverEnabled: true propagateComposedEvents: true onPositionChanged: function(mouse) { if (!chartPopup.hasValidData) return; verticalLine.currentX = mouse.x; verticalLine.x = mouse.x; verticalLine.visible = true; var timeRange = axisX.max.getTime() - axisX.min.getTime(); var relX = (mouse.x - chartPopup.chartLeftMargin) / (width - chartPopup.chartLeftMargin - chartPopup.chartRightMargin); var currentTime = axisX.min.getTime() + relX * timeRange; timeLabel.text = Qt.formatDateTime(new Date(currentTime), "yyyy-MM-dd hh:mm:ss.zzz"); var closestPoints = {}; for (var i = 0; i < chartPopup.channelDataList.length; i++) { var channel = chartPopup.channelDataList[i]; var range = chartPopup.channelDataMinMax[i]; if (!channel.points || !range) continue; var closestPoint = findClosestPoint(channel.points, currentTime); if (closestPoint) { closestPoints[i] = { x: closestPoint.timestamp, y: ((closestPoint.value - range.minValue) / (range.maxValue - range.minValue)) * 100, value: closestPoint.value }; } } verticalLine.closestPoints = closestPoints; updateLegendPosition(mouse.x); } /* onPositionChanged: function(mouse) { if (!chartPopup.hasValidData) return; // 更新垂直线位置 verticalLine.currentX = mouse.x; verticalLine.x = mouse.x; verticalLine.visible = true; // 将鼠标坐标转换为图表值 var mouseValue = chartView.mapToValue(Qt.point(mouse.x, 0)); var currentTime = mouseValue.x; // 更新图例时间显示 timeLabel.text = Qt.formatDateTime(new Date(currentTime), "yyyy-MM-dd hh:mm:ss.zzz"); // 查找每条曲线上最近的点 var closestPoints = {}; var seriesList = chartView.series(); for (var i = 0; i < seriesList.length; i++) { var series = seriesList[i]; var closestPoint = findClosestPoint(series, currentTime); if (closestPoint) { closestPoints[i] = closestPoint; } } verticalLine.closestPoints = closestPoints; updateLegendPosition(mouse.x); } */ onExited: { verticalLine.visible = false; legendContainer.visible = false; } onPressed: function(mouse) { mouse.accepted = false; } onReleased: function(mouse) { mouse.accepted = false; } function findClosestPoint(points, targetTime) { if (!points || points.length === 0) return null; var low = 0; var high = points.length - 1; var closest = null; var minDiff = Infinity; while (low <= high) { var mid = Math.floor((low + high) / 2); var point = points[mid]; var diff = Math.abs(point.timestamp - targetTime); if (diff < minDiff) { minDiff = diff; closest = point; } if (point.timestamp < targetTime) { low = mid + 1; } else { high = mid - 1; } } return closest; } // 更新图例位置 function updateLegendPosition(mouseX) { legendContainer.visible = true; if (mouseX < width / 2) { legendContainer.anchors.left = undefined; legendContainer.anchors.right = parent.right; legendContainer.anchors.rightMargin = 10; } else { legendContainer.anchors.right = undefined; legendContainer.anchors.left = parent.left; legendContainer.anchors.leftMargin = 10; } } } transform: [ Scale { id: scaleTransform origin.x: width/2 origin.y: height/2 xScale: chartView.zoomFactor yScale: chartView.zoomFactor }, Translate { id: translateTransform x: chartView.panOffset.x y: chartView.panOffset.y } ] Behavior on xZoomFactor { NumberAnimation { duration: chartView.animationDuration easing.type: Easing.InOutQuad } } Behavior on panOffset { PropertyAnimation { duration: chartView.animationDuration easing.type: Easing.InOutQuad } } function resetView() { zoomFactor = 1.0 panOffset = Qt.point(0, 0) if (chartPopup.channelDataMinMax.length > 0) { var range = chartPopup.channelDataMinMax[0] axisX.min = new Date(range.minTimestamp) axisX.max = new Date(range.maxTimestamp) axisY.min = chartView.yAxisMin axisY.max = chartView.yAxisMax } } function msToDateTime(ms) { return new Date(ms) } function formatFullDateTimeWithMs(timestamp) { if (!timestamp) return "N/A" var date = new Date(timestamp) return Qt.formatDateTime(date, "yyyy-MM-dd hh:mm:ss.zzz") } function xZoomIn() { xZoomFactor = Math.max(0.05, xZoomFactor - zoomStep) updateXAxisRange() } function xZoomOut() { xZoomFactor = Math.min(10.0, xZoomFactor + zoomStep) updateXAxisRange() } function updateXAxisRange() { if (!axisX || chartPopup.channelDataMinMax.length === 0) return var centerTimeMs = (axisX.max.getTime() + axisX.min.getTime()) / 2 var totalRangeMs = chartPopup.channelDataMinMax[0].maxTimestamp - chartPopup.channelDataMinMax[0].minTimestamp var visibleRangeMs = totalRangeMs * xZoomFactor axisX.min = msToDateTime(centerTimeMs - visibleRangeMs/2) axisX.max = msToDateTime(centerTimeMs + visibleRangeMs/2) } function adjustXAxisRange(pixelDelta) { if (!axisX) return var timeRangeMs = axisX.max.getTime() - axisX.min.getTime() var msPerPixel = timeRangeMs / width var msDelta = pixelDelta * msPerPixel var newMinMs = axisX.min.getTime() + msDelta var newMaxMs = axisX.max.getTime() + msDelta if (chartPopup.channelDataMinMax.length > 0) { var dataMinMs = chartPopup.channelDataMinMax[0].minTimestamp var dataMaxMs = chartPopup.channelDataMinMax[0].maxTimestamp if (newMinMs < dataMinMs) { newMinMs = dataMinMs newMaxMs = newMinMs + timeRangeMs } if (newMaxMs > dataMaxMs) { newMaxMs = dataMaxMs newMinMs = newMaxMs - timeRangeMs } } axisX.min = msToDateTime(newMinMs) axisX.max = msToDateTime(newMaxMs) } function updateChart() { removeAllSeries() if (!chartPopup.hasValidData) return for (var i = 0; i < chartPopup.channelDataList.length; i++) { var channel = chartPopup.channelDataList[i] var range = chartPopup.channelDataMinMax[i] if (!channel.points || !range) continue var series = createSeries(ChartView.SeriesTypeLine, channel.channelName || `通道 ${i+1}`, axisX, axisY) series.color = chartPopup.getSeriesColor(i) series.width = 2 axisX.min = new Date(range.minTimestamp) axisX.max = new Date(range.maxTimestamp) //var maxPoints = 2000 //var step = Math.max(1, Math.floor(channel.points.length / maxPoints)) //var step = for (var j = 0; j < channel.points.length; j++) { var point = channel.points[j] if (typeof point.value === "number") { var xValue = point.timestamp var yValue = ((point.value - range.minValue) / (range.maxValue - range.minValue)) * 100 series.append(xValue, yValue) } } } } // 设置X轴 DateTimeAxis { id: axisX format: "hh:mm:ss.zzz" gridVisible: true labelsBrush: Qt.rgba(1, 1, 1, 1) gridLineColor: Qt.rgba(1, 1, 1, 0.1) tickCount: 5 //onMinChanged: console.log("X轴最小值更新:", chartView.formatFullDateTimeWithMs(axisX.min)) //onMaxChanged: console.log("X轴最大值更新:", chartView.formatFullDateTimeWithMs(axisX.max)) } // 设置Y轴(百分比) ValueAxis { id: axisY min: chartView.yAxisMin max: chartView.yAxisMax titleText: "百分比(%)" titleBrush: Qt.rgba(1, 1, 1, 1) labelsBrush: Qt.rgba(1, 1, 1, 1) gridLineColor: Qt.rgba(1, 1, 1, 0.1) tickCount: chartPopup.horizontalGridLines minorTickCount: 0 } MultiPointTouchArea { anchors.fill: parent minimumTouchPoints: 1 maximumTouchPoints: 2 //property real lastX1: 0 //property real lastX2: 0 //property real baseRange: 0 property point touchPoint1 property point touchPoint2 property real initialDistance: 0 property real initialZoom: 1.0 property real initialXZoom: 1.0 property bool isZoomingX: false onPressed: (touchPoints) => { if (touchPoints.length === 1) { touchPoint1 = Qt.point(touchPoints[0].x, touchPoints[0].y) } else if (touchPoints.length === 2) { touchPoint1 = Qt.point(touchPoints[0].x, touchPoints[0].y) touchPoint2 = Qt.point(touchPoints[1].x, touchPoints[1].y) initialDistance = Math.sqrt( Math.pow(touchPoint1.x - touchPoint2.x, 2) + Math.pow(touchPoint1.y - touchPoint2.y, 2) ) var angle = Math.atan2( Math.abs(touchPoint1.y - touchPoint2.y), Math.abs(touchPoint1.x - touchPoint2.x) ) * (180/Math.PI) isZoomingX = (angle < 30) if (isZoomingX) { initialXZoom = xZoomFactor } else { initialZoom = zoomFactor } } } onUpdated: (touchPoints) => { // 单指拖动 - 平移 if (touchPoints.length === 1) { var dx = touchPoints[0].x - touchPoint1.x chartView.adjustXAxisRange(-dx * 0.5) touchPoint1 = Qt.point(touchPoints[0].x, touchPoints[0].y) } // 双指缩放 else if (touchPoints.length === 2) { var currentDistance = Math.sqrt( Math.pow(touchPoints[0].x - touchPoints[1].x, 2) + Math.pow(touchPoints[0].y - touchPoints[1].y, 2) ) if (isZoomingX) { xZoomFactor = initialXZoom * (currentDistance / initialDistance) } else { zoomFactor = initialZoom * (currentDistance / initialDistance) } } } onReleased: (touchPoints) => { // 单击处理(可选) if (touchPoints.length === 1 && !touchPoint1.pressed) { // 可以添加单击事件处理 } } } } Column { id: imagesAera width: 100 height: 175 anchors.right: parent.right anchors.rightMargin: 10 anchors.top: parent.top anchors.topMargin: 10 spacing: 5 Row { width: parent.width spacing: 5 Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: zoomInImg source: "qrc:/images/zoomIn.svg" width: 36 height: 36 anchors.centerIn: parent cache: true MouseArea { anchors.fill: parent onClicked: { chartView.zoom(chartView.zoomInFactor) } } } } Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: zoomOutImg source: "qrc:/images/zoomOut.svg" width: 36 * scaleX height: 36 * scaleY cache: true anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: { chartView.zoom(chartView.zoomOutFactor) } } } } } Row { spacing: 5 Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: moveLeftImg source: "qrc:/images/moveRight.svg" width: 36 * scaleX height: 36 * scaleY rotation: 180 cache: true anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: chartView.scrollLeft(10) } } } Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: moveRightImg source: "qrc:/images/moveRight.svg" width: 36 * scaleX height: 36 * scaleY cache: true anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: chartView.scrollRight(10) } } } } Row { width: parent.width spacing: 5 Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: xZoomInImg source: "qrc:/images/xZoomIn.svg" width: 36 * scaleX height: 36 * scaleY cache: true anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: chartView.xZoomIn() } } } Rectangle { width: 40 height: 40 color: "#333333" radius: 4 border.color: "#555555" border.width: 1 Image { id: xZoomOutImg source: "qrc:/images/xZoomOut.svg" width: 36 * scaleX height: 36 * scaleY cache: true anchors.centerIn: parent MouseArea { anchors.fill: parent onClicked: chartView.xZoomOut() } } } } Button { id: resetButton text: "X-Y复位" width: 85 height: 40 background: Rectangle { color: "#1296db" radius: 4 } onClicked: { chartView.resetView() //chartView.zoomReset() } contentItem: Text { text: parent.text color: "white" font.pixelSize: 16 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter anchors.fill: parent } } } } Component { id: chartPage Rectangle { color: "#2E2E2E" anchors.fill: parent Text { text: "📊 图表/表格页面" color: "white" font.pixelSize: 18 anchors.centerIn: parent } } } } Component.onCompleted: { loadCsvFiles(); } // 背景层 Rectangle { id: background anchors.fill: parent color: "#000000" } // 顶部菜单栏 Rectangle { id: menuBar height: 50 * scaleY anchors { top: parent.top left: parent.left right: parent.right } color: "#212529" Image { id: homeButton source: "qrc:/images/backHomePage.svg" width: 36 * scaleX height: 36 * scaleY anchors { top: parent.top topMargin: 7 * scaleY left: parent.left leftMargin: 20 * scaleX } cache: true MouseArea { anchors.fill: parent onClicked: { mainLoader.source = "qml/StoragePage.qml" } } } Text { width: 60 * scaleX height: 40 * scaleY color: "#ffffffff" text: "监测记录" font { family: "TOPRIE-WR-YaHei" pixelSize: 28 * unifiedScale } anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } Image { id: imageLayout source: "qrc:/images/layout.svg" width: 30 * scaleX height: 30 * scaleY anchors { top: parent.top topMargin: 10 * scaleY right: parent.right rightMargin: 20 * scaleX } cache: true MouseArea { anchors.fill: parent onClicked: { mainLoader.source = "qml/DataLogShowList.qml" } } } } // 主内容区 Rectangle { id: contentArea width: 984 * scaleX height: 521 * scaleY color: "transparent" anchors { top: menuBar.bottom bottom: parent.bottom left: parent.left right: parent.right rightMargin: 20 * scaleX topMargin: 14 * scaleY leftMargin: 20 * scaleX bottomMargin: 15 * scaleY } // 数据表格 Flickable { id: flickable anchors.fill: parent contentWidth: parent.width contentHeight: dataTable.height clip: true boundsBehavior: Flickable.StopAtBounds flickableDirection: Flickable.VerticalFlick Column { id: dataTable width: parent.width anchors { top: parent.top topMargin: 10 * scaleY } spacing: 20 * scaleY Repeater { model: fileListModel delegate: MonitorRecordItem { id: recordDelegate width: parent.width startTime: model.startTime endTime: model.endTime lineNumber: model.lineNumber customName: model.fileName fileSize: model.fileSize filePath: model.filePath vkeyboard: keyboard onDownloadRequested: handleDownloadRequest onAnalyzeRequested: analyzeCsvFile onRenameRequested: handleRenameFile } } } } } Popup { //导出完成提示 id: usbCompletePopup width: parent.width * 0.6 height: 120 anchors.centerIn: parent closePolicy: Popup.NoAutoClose background: Rectangle { color: "#212529" radius: 5 border.color: "#555555" border.width: 1 } property string labText: "" Column { width: parent.width * 0.8 anchors.horizontalCenter: parent.horizontalCenter spacing: 20 Label { width: parent.width text: usbCompletePopup.labText font.pixelSize: 20 color: "white" wrapMode: Text.WordWrap horizontalAlignment: Text.AlignHCenter } Label { width: parent.width text: "下载成功!" font.pixelSize: 22 color: "green" horizontalAlignment: Text.AlignHCenter } } Timer { id: closeTimer interval: 1500 running: usbCompletePopup.visible onTriggered: { usbCompletePopup.close() } } onOpened: closeTimer.restart() } Popup { //导出失败提示 id: usbErrorPopup width: parent.width * 0.6 height: 100 anchors.centerIn: parent closePolicy: Popup.NoAutoClose background: Rectangle { color: "#212529" radius: 5 border.color: "#555555" border.width: 1 } property string labelText: "" Label { anchors.centerIn: parent text: usbErrorPopup.labelText font.pixelSize: 22 color: "red" } Timer { id: errorTimer interval: 2000 running: usbErrorPopup.visible onTriggered: { usbErrorPopup.close() } } onOpened: errorTimer.restart() } }
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值