|
|
|
|
@ -25,7 +25,7 @@
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include "mapbridge.h"
|
|
|
|
|
|
|
|
|
|
MapPage::MapPage(QWidget *parent) : QWidget(parent),
|
|
|
|
|
MapPage::MapPage(QWidget *parent) : QWidget(parent),
|
|
|
|
|
mapArea_(nullptr),
|
|
|
|
|
heightCombo_(nullptr),
|
|
|
|
|
downloadMapBtn_(nullptr),
|
|
|
|
|
@ -77,7 +77,7 @@ void MapPage::setupUI() {
|
|
|
|
|
mainLayout->setSpacing(8);
|
|
|
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
auto* title = new QLabel("地图监控");
|
|
|
|
|
auto* title = new QLabel("路径监控");
|
|
|
|
|
title->setProperty("class", "section");
|
|
|
|
|
mainLayout->addWidget(title);
|
|
|
|
|
|
|
|
|
|
@ -240,7 +240,7 @@ void MapPage::setupMapArea() {
|
|
|
|
|
window.map.setZoom(15); // 更高缩放级别以显示街道
|
|
|
|
|
console.log("GPS定位成功: 经度 " + position.lng + ", 纬度 " + position.lat + ", 精度 " + result.accuracy);
|
|
|
|
|
|
|
|
|
|
// 添加 GPS 定位成功标记 (蓝色)
|
|
|
|
|
// 添加定位成功标记 (蓝色)
|
|
|
|
|
var marker = new AMap.Marker({
|
|
|
|
|
position: lnglat,
|
|
|
|
|
title: 'GPS Position',
|
|
|
|
|
@ -249,7 +249,7 @@ void MapPage::setupMapArea() {
|
|
|
|
|
});
|
|
|
|
|
marker.setMap(window.map);
|
|
|
|
|
|
|
|
|
|
// 添加 GPS 信息窗口
|
|
|
|
|
// 添加定位信息窗口
|
|
|
|
|
var infoContent = '<div>GPS定位成功<br>经度: ' + position.lng + '<br>纬度: ' + position.lat;
|
|
|
|
|
if (result.accuracy) infoContent += '<br>精度: ' + result.accuracy + '米';
|
|
|
|
|
if (result.info) infoContent += '<br>信息: ' + result.info;
|
|
|
|
|
@ -299,26 +299,6 @@ void MapPage::setupMapArea() {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 辅助函数:使用默认位置
|
|
|
|
|
function useDefaultPosition() {
|
|
|
|
|
var defaultPos = new AMap.LngLat(116.397428, 39.90923);
|
|
|
|
|
window.map.setCenter(defaultPos);
|
|
|
|
|
window.map.setZoom(10);
|
|
|
|
|
|
|
|
|
|
var marker = new AMap.Marker({
|
|
|
|
|
position: defaultPos,
|
|
|
|
|
title: '默认位置',
|
|
|
|
|
content: '<div style="background:#FF9800; color:white; padding:4px 8px; border-radius:50%%; font-size:12px;">默认位置</div>'
|
|
|
|
|
});
|
|
|
|
|
marker.setMap(window.map);
|
|
|
|
|
|
|
|
|
|
var infoWindow = new AMap.InfoWindow({
|
|
|
|
|
content: '<div>使用默认位置<br>经度: 116.397428<br>纬度: 39.90923</div>',
|
|
|
|
|
offset: new AMap.Pixel(0, -30)
|
|
|
|
|
});
|
|
|
|
|
infoWindow.open(window.map, defaultPos);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
@ -386,11 +366,15 @@ QWidget* MapPage::createControlBarWidget() {
|
|
|
|
|
connect(areaCoverageBtn_, &QPushButton::clicked, this, &MapPage::onAreaCoverageClicked);
|
|
|
|
|
layout->addWidget(areaCoverageBtn_);
|
|
|
|
|
|
|
|
|
|
// Clear path button moved to PathPlanningDialog
|
|
|
|
|
|
|
|
|
|
return bar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef INCLUDE_AREA_SEARCH
|
|
|
|
|
void MapPage::onAreaSearchClicked() {
|
|
|
|
|
searchDialog_->exec();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void MapPage::enableGeolocation() {
|
|
|
|
|
if (mapView_) {
|
|
|
|
|
QWebEngineSettings* settings = mapView_->settings();
|
|
|
|
|
@ -514,398 +498,3 @@ void MapPage::clearPathOverlays() {
|
|
|
|
|
console.log('Map not available for clearing');
|
|
|
|
|
}
|
|
|
|
|
)").arg(pathOverlayId_, startMarkerId_, endMarkerId_);
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
qDebug() << "路径覆盖物清除完成";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::visualizeCoveragePath(const QString& pathData) {
|
|
|
|
|
QString js = QString(R"(
|
|
|
|
|
if (window.map) {
|
|
|
|
|
var pathCoords = JSON.parse("%1");
|
|
|
|
|
console.log('Visualizing coverage path with ' + pathCoords.length + ' points');
|
|
|
|
|
|
|
|
|
|
// Remove existing coverage overlay if any
|
|
|
|
|
if (window.%2) {
|
|
|
|
|
window.map.remove(window.%2);
|
|
|
|
|
window.%2 = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create new polyline for coverage path (green, dashed)
|
|
|
|
|
var polyline = new AMap.Polyline({
|
|
|
|
|
path: pathCoords,
|
|
|
|
|
strokeColor: "#4CAF50",
|
|
|
|
|
strokeOpacity: 0.8,
|
|
|
|
|
strokeWeight: 4,
|
|
|
|
|
strokeStyle: "dashed",
|
|
|
|
|
strokeDasharray: [8, 4],
|
|
|
|
|
zIndex: 2
|
|
|
|
|
});
|
|
|
|
|
polyline.setMap(window.map);
|
|
|
|
|
window.%2 = polyline;
|
|
|
|
|
|
|
|
|
|
// Clear existing coverage intermediates
|
|
|
|
|
if (!window.coverageIntermediates) {
|
|
|
|
|
window.coverageIntermediates = [];
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < window.coverageIntermediates.length; i++) {
|
|
|
|
|
if (window.coverageIntermediates[i]) {
|
|
|
|
|
window.map.remove(window.coverageIntermediates[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
window.coverageIntermediates = [];
|
|
|
|
|
|
|
|
|
|
// Add intermediate markers for coverage points
|
|
|
|
|
for (var i = 0; i < pathCoords.length; i += 5) { // Every 5th point for visibility
|
|
|
|
|
var marker = new AMap.Marker({
|
|
|
|
|
position: pathCoords[i],
|
|
|
|
|
content: '<div style="background:#4CAF50; color:white; padding:2px 6px; border-radius:50%%; font-size:10px; font-weight:bold;">C' + (i/5 + 1) + '</div>',
|
|
|
|
|
zIndex: 15
|
|
|
|
|
});
|
|
|
|
|
marker.setMap(window.map);
|
|
|
|
|
window.coverageIntermediates.push(marker);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fit view
|
|
|
|
|
var allOverlays = [polyline].concat(window.coverageIntermediates);
|
|
|
|
|
if (allOverlays.length > 0) {
|
|
|
|
|
window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Coverage path visualization completed');
|
|
|
|
|
}
|
|
|
|
|
)").arg(pathData, coverageOverlayId_);
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
currentCoveragePathData_ = pathData;
|
|
|
|
|
qDebug() << "区域覆盖路径可视化完成";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::clearCoverageOverlays() {
|
|
|
|
|
QString js = QString(R"(
|
|
|
|
|
if (window.map) {
|
|
|
|
|
console.log('Clearing all coverage overlays...');
|
|
|
|
|
|
|
|
|
|
// Remove coverage polyline
|
|
|
|
|
if (window.%1) {
|
|
|
|
|
window.map.remove(window.%1);
|
|
|
|
|
window.%1 = null;
|
|
|
|
|
console.log('Removed coverage polyline');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove area overlay if exists
|
|
|
|
|
if (window.%2) {
|
|
|
|
|
window.map.remove(window.%2);
|
|
|
|
|
window.%2 = null;
|
|
|
|
|
console.log('Removed area overlay');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear coverage intermediates
|
|
|
|
|
if (!window.coverageIntermediates) {
|
|
|
|
|
window.coverageIntermediates = [];
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < window.coverageIntermediates.length; i++) {
|
|
|
|
|
if (window.coverageIntermediates[i]) {
|
|
|
|
|
window.map.remove(window.coverageIntermediates[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
window.coverageIntermediates = [];
|
|
|
|
|
|
|
|
|
|
console.log('All coverage overlays cleared successfully');
|
|
|
|
|
} else {
|
|
|
|
|
console.log('Map not available for clearing');
|
|
|
|
|
}
|
|
|
|
|
)").arg(coverageOverlayId_, areaOverlayId_);
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
qDebug() << "区域覆盖覆盖物清除完成";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double MapPage::parseLng(const QString& coord) const {
|
|
|
|
|
// Handle both "[lng, lat]" and "lng, lat"
|
|
|
|
|
QRegExp rx("^\\s*\\[?\\s*([\\d.-]+)\\s*,");
|
|
|
|
|
if (rx.indexIn(coord) != -1) {
|
|
|
|
|
return rx.cap(1).toDouble();
|
|
|
|
|
}
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double MapPage::parseLat(const QString& coord) const {
|
|
|
|
|
// Handle both "[lng, lat]" and "lng, lat"
|
|
|
|
|
QRegExp rx(",\\s*([\\d.-]+)\\s*\\]?\\s*$");
|
|
|
|
|
if (rx.indexIn(coord) != -1) {
|
|
|
|
|
return rx.cap(1).toDouble();
|
|
|
|
|
}
|
|
|
|
|
return 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::showMarker(double lng, double lat, const QString& label, const QString& color, int index) {
|
|
|
|
|
QString markerId = (index == 0) ? startMarkerId_ : endMarkerId_;
|
|
|
|
|
QString js = QString(R"(
|
|
|
|
|
if (window.map) {
|
|
|
|
|
// Only remove if it's a different position
|
|
|
|
|
if (window.%1 && (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) {
|
|
|
|
|
window.map.remove(window.%1);
|
|
|
|
|
}
|
|
|
|
|
if (!window.%1 || (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) {
|
|
|
|
|
var marker = new AMap.Marker({
|
|
|
|
|
position: new AMap.LngLat(%2, %3),
|
|
|
|
|
content: '<div style="background:%4; color:white; padding:2px 6px; border-radius:50%%; font-size:12px;">%5</div>',
|
|
|
|
|
zIndex: 100 + (%6 === 0 ? 10 : 5) // Start marker gets higher z-index
|
|
|
|
|
});
|
|
|
|
|
marker.setMap(window.map);
|
|
|
|
|
window.%1 = marker;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)").arg(markerId, QString::number(lng), QString::number(lat), color, label, QString::number(index));
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::addClickListener() {
|
|
|
|
|
QString js = R"(
|
|
|
|
|
console.log('Adding click listener...');
|
|
|
|
|
function addListener() {
|
|
|
|
|
if (window.map && window.bridge && window.mapReady) {
|
|
|
|
|
// Remove existing listener if any
|
|
|
|
|
if (window.clickListener) {
|
|
|
|
|
window.clickListener.remove();
|
|
|
|
|
console.log('Removed existing listener');
|
|
|
|
|
}
|
|
|
|
|
window.clickListener = window.map.on('click', function(e) {
|
|
|
|
|
console.log('Map clicked at: ' + e.lnglat.getLng() + ', ' + e.lnglat.getLat());
|
|
|
|
|
window.bridge.onClick(e.lnglat.getLng(), e.lnglat.getLat());
|
|
|
|
|
});
|
|
|
|
|
console.log('Click listener added successfully');
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (addListener()) {
|
|
|
|
|
// Already ready
|
|
|
|
|
} else {
|
|
|
|
|
console.log('Map or bridge not ready - polling...');
|
|
|
|
|
var attempts = 0;
|
|
|
|
|
var maxAttempts = 100; // 10 seconds at 100ms intervals
|
|
|
|
|
var interval = setInterval(function() {
|
|
|
|
|
attempts++;
|
|
|
|
|
if (addListener()) {
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
} else if (attempts >= maxAttempts) {
|
|
|
|
|
clearInterval(interval);
|
|
|
|
|
console.error('Failed to add listener after ' + maxAttempts + ' attempts');
|
|
|
|
|
}
|
|
|
|
|
}, 100);
|
|
|
|
|
}
|
|
|
|
|
)";
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::removeClickListener() {
|
|
|
|
|
QString js = R"(
|
|
|
|
|
if (window.clickListener) {
|
|
|
|
|
window.clickListener.remove();
|
|
|
|
|
window.clickListener = null;
|
|
|
|
|
}
|
|
|
|
|
)";
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::visualizePath(const QString& pathData) {
|
|
|
|
|
QString js = QString(R"(
|
|
|
|
|
if (window.map) {
|
|
|
|
|
var pathCoords = JSON.parse("%1");
|
|
|
|
|
console.log('Visualizing path with ' + pathCoords.length + ' points');
|
|
|
|
|
|
|
|
|
|
// Remove existing path overlay if any
|
|
|
|
|
if (window.%2) {
|
|
|
|
|
window.map.remove(window.%2);
|
|
|
|
|
window.%2 = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create new polyline
|
|
|
|
|
var polyline = new AMap.Polyline({
|
|
|
|
|
path: pathCoords,
|
|
|
|
|
strokeColor: "#3366FF",
|
|
|
|
|
strokeOpacity: 1,
|
|
|
|
|
strokeWeight: 5,
|
|
|
|
|
strokeStyle: "solid",
|
|
|
|
|
strokeDasharray: [10, 5],
|
|
|
|
|
zIndex: 1
|
|
|
|
|
});
|
|
|
|
|
polyline.setMap(window.map);
|
|
|
|
|
window.%2 = polyline;
|
|
|
|
|
|
|
|
|
|
// Clear existing intermediate markers
|
|
|
|
|
if (!window.intermediates) {
|
|
|
|
|
window.intermediates = [];
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < window.intermediates.length; i++) {
|
|
|
|
|
if (window.intermediates[i]) {
|
|
|
|
|
window.map.remove(window.intermediates[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
window.intermediates = [];
|
|
|
|
|
|
|
|
|
|
// Add intermediate markers (excluding start and end)
|
|
|
|
|
for (var i = 1; i < pathCoords.length - 1; i++) {
|
|
|
|
|
var marker = new AMap.Marker({
|
|
|
|
|
position: pathCoords[i],
|
|
|
|
|
content: '<div style="background:#9C27B0; color:white; padding:2px 6px; border-radius:50%%; font-size:12px; font-weight:bold;">' + (i + 1) + '</div>',
|
|
|
|
|
zIndex: 10
|
|
|
|
|
});
|
|
|
|
|
marker.setMap(window.map);
|
|
|
|
|
window.intermediates.push(marker);
|
|
|
|
|
console.log('Added intermediate marker ' + (i + 1) + ' at: ' + pathCoords[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fit view to show all elements
|
|
|
|
|
var allOverlays = [];
|
|
|
|
|
if (window.startMarker) allOverlays.push(window.startMarker);
|
|
|
|
|
if (window.endMarker) allOverlays.push(window.endMarker);
|
|
|
|
|
allOverlays.push(polyline);
|
|
|
|
|
allOverlays = allOverlays.concat(window.intermediates);
|
|
|
|
|
|
|
|
|
|
if (allOverlays.length > 0) {
|
|
|
|
|
window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('Path visualization completed with ' + window.intermediates.length + ' intermediate points');
|
|
|
|
|
}
|
|
|
|
|
)").arg(pathData, pathOverlayId_);
|
|
|
|
|
runMapJavaScript(js);
|
|
|
|
|
qDebug() << "路径可视化完成";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MapPage::onPageLoaded(bool ok) {
|
|
|
|
|
if (ok) {
|
|
|
|
|
qDebug() << "Page loaded successfully";
|
|
|
|
|
|
|
|
|
|
// Ensure bridge is properly registered with WebChannel
|
|
|
|
|
if (channel_ && bridge_) {
|
|
|
|
|
channel_->registerObject("bridge", bridge_);
|
|
|
|
|
qDebug() << "Bridge registered with WebChannel";
|
|
|
|
|
|
|
|
|
|
// Check readiness after a short delay
|
|
|
|
|
QTimer::singleShot(500, this, [this]() {
|
|
|
|
|
runMapJavaScript("console.log('Readiness check: mapReady=' + !!window.mapReady + ', bridge exists=' + !!window.bridge);");
|
|
|
|
|
// 如果地图已就绪且bridge可用,添加点击监听器(JS侧会处理)
|
|
|
|
|
runMapJavaScript("if (window.mapReady && window.bridge) { addClickListener(); } else { console.log('Waiting for map and bridge to be ready...'); }");
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "ERROR: Channel or bridge is null!";
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "Page load failed";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Implement ThreatAreaDialog methods
|
|
|
|
|
ThreatAreaDialog::ThreatAreaDialog(QWidget *parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), drawingPoints_() {
|
|
|
|
|
setWindowTitle("设置威胁区域");
|
|
|
|
|
setMinimumSize(600, 500);
|
|
|
|
|
auto* layout = new QVBoxLayout(this);
|
|
|
|
|
layout->setSpacing(15);
|
|
|
|
|
layout->setContentsMargins(20, 20, 20, 20);
|
|
|
|
|
|
|
|
|
|
// 威胁区域基本信息组
|
|
|
|
|
auto* basicGroup = new QGroupBox("基本信息");
|
|
|
|
|
basicGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }");
|
|
|
|
|
auto* basicLayout = new QGridLayout(basicGroup);
|
|
|
|
|
basicLayout->setSpacing(10);
|
|
|
|
|
|
|
|
|
|
// 威胁类型
|
|
|
|
|
basicLayout->addWidget(new QLabel("威胁类型:"), 0, 0);
|
|
|
|
|
typeCombo_ = new QComboBox();
|
|
|
|
|
typeCombo_->addItems({"导弹威胁", "雷达干扰", "防空火力", "禁飞区域", "其他"});
|
|
|
|
|
typeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }");
|
|
|
|
|
basicLayout->addWidget(typeCombo_, 0, 1);
|
|
|
|
|
|
|
|
|
|
// 威胁等级
|
|
|
|
|
basicLayout->addWidget(new QLabel("威胁等级:"), 0, 2);
|
|
|
|
|
levelCombo_ = new QComboBox();
|
|
|
|
|
levelCombo_->addItems({"高", "中", "低"});
|
|
|
|
|
levelCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }");
|
|
|
|
|
basicLayout->addWidget(levelCombo_, 0, 3);
|
|
|
|
|
|
|
|
|
|
layout->addWidget(basicGroup);
|
|
|
|
|
|
|
|
|
|
// 添加形状选择
|
|
|
|
|
basicLayout->addWidget(new QLabel("形状:"), 1, 0);
|
|
|
|
|
shapeCombo_ = new QComboBox();
|
|
|
|
|
shapeCombo_->addItems({"圆形", "矩形"});
|
|
|
|
|
shapeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }");
|
|
|
|
|
connect(shapeCombo_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThreatAreaDialog::onShapeChanged);
|
|
|
|
|
basicLayout->addWidget(shapeCombo_, 1, 1);
|
|
|
|
|
|
|
|
|
|
// 添加颜色选择(假设用于 overlay 颜色)
|
|
|
|
|
basicLayout->addWidget(new QLabel("颜色:"), 1, 2);
|
|
|
|
|
colorCombo_ = new QComboBox();
|
|
|
|
|
colorCombo_->addItems({"红色", "黄色", "蓝色"});
|
|
|
|
|
basicLayout->addWidget(colorCombo_, 1, 3);
|
|
|
|
|
|
|
|
|
|
layout->addWidget(basicGroup);
|
|
|
|
|
|
|
|
|
|
// 时间设置组 (保持不变)
|
|
|
|
|
auto* timeGroup = new QGroupBox("威胁区域存在时间");
|
|
|
|
|
timeGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }");
|
|
|
|
|
auto* timeLayout = new QVBoxLayout(timeGroup);
|
|
|
|
|
|
|
|
|
|
// 开始时间
|
|
|
|
|
auto* startTimeLayout = new QHBoxLayout();
|
|
|
|
|
startTimeLayout->addWidget(new QLabel("开始时间:"));
|
|
|
|
|
startTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime());
|
|
|
|
|
startTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss");
|
|
|
|
|
startTimeEdit_->setCalendarPopup(true);
|
|
|
|
|
startTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }");
|
|
|
|
|
startTimeLayout->addWidget(startTimeEdit_);
|
|
|
|
|
startTimeLayout->addStretch();
|
|
|
|
|
timeLayout->addLayout(startTimeLayout);
|
|
|
|
|
|
|
|
|
|
// 结束时间
|
|
|
|
|
auto* endTimeLayout = new QHBoxLayout();
|
|
|
|
|
endTimeLayout->addWidget(new QLabel("结束时间:"));
|
|
|
|
|
endTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime().addSecs(3600)); // 默认1小时后
|
|
|
|
|
endTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss");
|
|
|
|
|
endTimeEdit_->setCalendarPopup(true);
|
|
|
|
|
endTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }");
|
|
|
|
|
endTimeLayout->addWidget(endTimeEdit_);
|
|
|
|
|
endTimeLayout->addStretch();
|
|
|
|
|
timeLayout->addLayout(endTimeLayout);
|
|
|
|
|
|
|
|
|
|
layout->addWidget(timeGroup);
|
|
|
|
|
|
|
|
|
|
// 动态输入 widget
|
|
|
|
|
circleInputWidget_ = new QWidget();
|
|
|
|
|
auto* circleLayout = new QFormLayout(circleInputWidget_);
|
|
|
|
|
centerLngInput_ = new QLineEdit();
|
|
|
|
|
centerLngInput_->setPlaceholderText("中心经度");
|
|
|
|
|
circleLayout->addRow("中心经度:", centerLngInput_);
|
|
|
|
|
centerLatInput_ = new QLineEdit();
|
|
|
|
|
centerLatInput_->setPlaceholderText("中心纬度");
|
|
|
|
|
circleLayout->addRow("中心纬度:", centerLatInput_);
|
|
|
|
|
radiusInput_ = new QLineEdit();
|
|
|
|
|
radiusInput_->setPlaceholderText("半径 (米)");
|
|
|
|
|
circleLayout->addRow("半径 (米):", radiusInput_);
|
|
|
|
|
layout->addWidget(circleInputWidget_);
|
|
|
|
|
|
|
|
|
|
rectangleInputWidget_ = new QWidget();
|
|
|
|
|
auto* rectLayout = new QVBoxLayout(rectangleInputWidget_);
|
|
|
|
|
rectPointsTable_ = new QTableWidget(4, 2);
|
|
|
|
|
rectPointsTable_->setHorizontalHeaderLabels({"经度", "纬度"});
|
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
|
rectPointsTable_->setItem(i, 0, new QTableWidgetItem(""));
|
|
|
|
|
rectPointsTable_->setItem(i, 1, new QTableWidgetItem(""));
|
|
|
|
|
}
|
|
|
|
|
rectLayout->addWidget(rectPointsTable_);
|
|
|
|
|
layout->addWidget(rectangleInputWidget_);
|
|
|
|
|
rectangleInputWidget_->setVisible(false);
|
|
|
|
|
|
|
|
|
|
// 按钮 (保持 drawOnMapBtn_ 等)
|
|
|
|
|
auto* buttonLayout = new QHBoxLayout();
|
|
|
|
|
buttonLayout->addStretch();
|
|
|
|
|
|
|
|
|
|
drawOnMapBtn_ = new QPushButton("在地图上绘制");
|
|
|
|
|
drawOnMapBtn_->setStyleSheet("QPushButton { padding: 8px 20px; background: #4CAF50; color: white; border-radius: 4px; }");
|
|
|
|
|
connect(drawOnMapBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::startDrawingThreatArea);
|
|
|
|
|
buttonLayout->addWidget(drawOnMapBtn_);
|
|
|
|
|
|
|
|
|
|
auto* addBtn = new QPushButton("添加区域");
|
|
|
|
|
addBtn->setProperty("primary", true);
|
|
|
|
|
addBtn->setStyleSheet("QPushButton { padding: 8px 20px; background: #2196f3; color: white
|
|
|
|
|
|