Files
ArcGis_Py/tools/ui/tabs/export_map_tab.py
2026-04-22 12:27:49 +08:00

385 lines
15 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
导出地图选项卡模块
"""
import os
import arcpy
import traceback
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QLabel,
QLineEdit, QPushButton, QCheckBox, QFileDialog, QMessageBox)
from PyQt6.QtCore import pyqtSignal
from ..components.file_list_group import FileListGroup
from ..runners.script_runner import ScriptRunner
class ExportMapTab(QWidget):
"""导出地图选项卡"""
# 定义日志信号,用于将日志消息传递给主窗口
log_signal = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.main_window = parent
self.setupUi()
self.load_settings()
def setupUi(self):
"""设置界面"""
# 主布局
self.main_layout = QVBoxLayout(self)
# 参数区域
self.form_layout = QFormLayout()
# 区县名称
self.county_name_edit = QLineEdit()
self.form_layout.addRow("区县名称:", self.county_name_edit)
# 配置文件
config_layout = QHBoxLayout()
self.config_file_edit = QLineEdit()
self.config_file_edit.setEnabled(False)
config_layout.addWidget(self.config_file_edit)
# self.config_file_browse = QPushButton("浏览...")
# self.config_file_browse.clicked.connect(self.on_browse_config_file)
# config_layout.addWidget(self.config_file_browse)
self.form_layout.addRow("配置文件:", config_layout)
# 模板文件
self.template_aprx_file_edit = QLineEdit()
self.template_path_browse = QPushButton("浏览...")
self.template_path_browse.clicked.connect(self.on_browse_template_path)
template_layout = QHBoxLayout()
template_layout.addWidget(self.template_aprx_file_edit)
template_layout.addWidget(self.template_path_browse)
self.form_layout.addRow("模板文件:", template_layout)
# 数据源路径
self.data_source_path_edit = QLineEdit()
self.data_source_path_browse = QPushButton("浏览...")
self.data_source_path_browse.clicked.connect(self.on_browse_data_source_path)
data_source_layout = QHBoxLayout()
data_source_layout.addWidget(self.data_source_path_edit)
data_source_layout.addWidget(self.data_source_path_browse)
self.form_layout.addRow("数据源路径:", data_source_layout)
# 符号系统路径
self.symbol_path_edit = QLineEdit()
self.symbol_path_browse = QPushButton("浏览...")
self.symbol_path_browse.clicked.connect(self.on_browse_symbol_path)
symbol_layout = QHBoxLayout()
symbol_layout.addWidget(self.symbol_path_edit)
symbol_layout.addWidget(self.symbol_path_browse)
self.form_layout.addRow("符号系统路径:", symbol_layout)
# 统计表格图片路径
self.pic_path_edit = QLineEdit()
self.pic_path_browse = QPushButton("浏览...")
self.pic_path_browse.clicked.connect(self.on_browse_pic_path)
pic_layout = QHBoxLayout()
pic_layout.addWidget(self.pic_path_edit)
pic_layout.addWidget(self.pic_path_browse)
self.form_layout.addRow("面积统计图片路径:", pic_layout)
# 输出路径
self.output_path_edit = QLineEdit()
self.output_path_browse = QPushButton("浏览...")
self.output_path_browse.clicked.connect(self.on_browse_output_path)
output_layout = QHBoxLayout()
output_layout.addWidget(self.output_path_edit)
output_layout.addWidget(self.output_path_browse)
self.form_layout.addRow("输出路径:", output_layout)
# 文件列表布局
self.file_list_group = FileListGroup(self, "选择要导出的要素类:")
self.file_list_group.load_files.connect(self.on_load_polygon)
# 选项区域
options_layout = QVBoxLayout()
# 强制重新生成选项
self.force_regenerate_check = QCheckBox("强制重新生成工程文件")
options_layout.addWidget(self.force_regenerate_check)
# 添加到主布局
self.main_layout.addLayout(self.form_layout)
self.main_layout.addWidget(self.file_list_group)
self.main_layout.addLayout(options_layout)
# 导出按钮
self.export_button = QPushButton("导出地图")
self.export_button.clicked.connect(self.on_export_map)
self.main_layout.addWidget(self.export_button)
# 状态标签
self.status_label = QLabel("状态: 就绪")
self.main_layout.addWidget(self.status_label)
def on_browse_config_file(self):
"""浏览配置文件"""
initial_dir = ""
if os.path.exists(self.config_file_edit.text()):
initial_dir = self.config_file_edit.text()
file_path, _ = QFileDialog.getOpenFileName(self, "选择配置文件", initial_dir, "JSON文件 (*.json);;所有文件 (*.*)")
if file_path:
self.config_file_edit.setText(file_path)
def on_browse_template_path(self):
"""浏览模板文件"""
initial_dir = ""
if os.path.exists(self.template_aprx_file_edit.text()):
initial_dir = self.template_aprx_file_edit.text()
file_path, _ = QFileDialog.getOpenFileName(self, "选择模板文件", initial_dir, "ArcGIS Pro工程文件 (*.aprx)")
if file_path:
self.template_aprx_file_edit.setText(file_path)
def on_browse_data_source_path(self):
"""浏览数据源路径"""
initial_dir = ""
if os.path.exists(self.data_source_path_edit.text()):
initial_dir = os.path.dirname(self.data_source_path_edit.text())
folder_path = QFileDialog.getExistingDirectory(self, "选择数据源文件夹", initial_dir)
if folder_path and folder_path.endswith(".gdb"):
self.data_source_path_edit.setText(folder_path)
# 自动加载图层列表
self.on_load_polygon()
else:
QMessageBox.warning(self, "错误", "请选择GDB的数据源。")
def on_browse_symbol_path(self):
"""浏览符号系统路径"""
initial_dir = ""
if os.path.exists(self.symbol_path_edit.text()):
initial_dir = os.path.dirname(self.symbol_path_edit.text())
folder_path = QFileDialog.getExistingDirectory(self, "选择符号系统文件夹", initial_dir)
if folder_path:
self.symbol_path_edit.setText(folder_path)
def on_browse_pic_path(self):
"""浏览符号系统路径"""
initial_dir = ""
if os.path.exists(self.pic_path_edit.text()):
initial_dir = os.path.dirname(self.pic_path_edit.text())
folder_path = QFileDialog.getExistingDirectory(self, "选择符号系统文件夹", initial_dir)
if folder_path:
self.pic_path_edit.setText(folder_path)
def on_browse_output_path(self):
"""浏览输出路径"""
initial_dir = ""
if os.path.exists(self.output_path_edit.text()):
initial_dir = os.path.dirname(self.output_path_edit.text())
folder_path = QFileDialog.getExistingDirectory(self, "选择输出文件夹", initial_dir)
if folder_path.endswith(".gdb"):
QMessageBox.warning(self, "警告", "请选择有效的输出路径")
return
self.output_path_edit.setText(folder_path)
def on_load_polygon(self):
"""加载图层列表"""
try:
data_source_paths = self.data_source_path_edit.text()
# 清空列表
self.file_list_group.file_list.clear()
# 添加图层
if arcpy.Exists(data_source_paths):
arcpy.env.workspace = data_source_paths
for polygon in arcpy.ListFeatureClasses(feature_type="Polygon"):
self.file_list_group.file_list.addItem(polygon)
self.log_message(f"已加载 {self.file_list_group.file_list.count()} 个图层")
except Exception as e:
self.log_error(f"加载图层列表失败: {str(e)}")
traceback.print_exc()
def get_selected_polygon(self):
"""获取选中的图层列表"""
selected_items = self.file_list_group.file_list.selectedItems()
return [item.text() for item in selected_items]
def on_export_map(self):
"""导出地图按钮点击事件"""
try:
# 验证并获取参数
params = self.validate_and_params()
if not params:
return
polygon_list = params.get('polygon_list')
# 清空日志
self.log_message("开始导出工程文件...")
self.log_message(f"选中的图层: {polygon_list}")
# 创建导出线程
self.runner = ScriptRunner()
self.runner.task_log.connect(self.on_script_log)
self.runner.task_error.connect(self.log_error)
self.runner.task_finished.connect(self.on_script_finished)
# 禁用导出按钮
self.export_button.setEnabled(False)
self.status_label.setText("状态: 正在导出...")
# 运行导出脚本(使用外部窗口)
# print(params)
self.runner.run_export_map(params)
except Exception as e:
self.log_error(f"导出准备过程出错: {str(e)}")
traceback.print_exc()
def log_message(self, message):
"""添加日志消息"""
# 如果父窗口存在,使用父窗口的日志功能
if self.main_window and hasattr(self.main_window, 'log_signal'):
self.main_window.log_signal.emit(message)
else:
# 否则发射自己的信号
self.log_signal.emit(message)
def log_error(self, message):
"""添加错误日志"""
self.log_message(f"错误: {message}")
def on_script_log(self, task_id, message):
"""脚本输出日志"""
self.log_message(f"{task_id}: {message}")
def on_script_finished(self, task_id:str, success:bool, message:str):
"""导出完成事件处理"""
# 恢复导出按钮
self.export_button.setEnabled(True)
if success:
self.status_label.setText("状态: 导出完成")
QMessageBox.information(self, "成功", "地图导出完成!")
else:
self.status_label.setText("状态: 导出失败")
QMessageBox.warning(self, "失败", "地图导出过程中出现错误,请查看日志详情")
def validate_and_params(self):
# 获取输入参数
county_name = self.county_name_edit.text().strip()
if not county_name:
QMessageBox.warning(self, "错误", "请输入区县名称")
return
# 获取面要素列表
polygon_list = self.get_selected_polygon()
if not polygon_list:
QMessageBox.warning(self, "错误", "请选择至少一个要素")
return
# 获取配置文件
config_file = self.config_file_edit.text()
if not os.path.exists(config_file):
QMessageBox.warning(self, "错误", "配置文件不存在")
return
# 获取模板文件
template_aprx_file = self.template_aprx_file_edit.text()
if not os.path.exists(template_aprx_file):
QMessageBox.warning(self, "错误", "模板文件不存在")
return
# 获取输出路径
output_path = self.output_path_edit.text()
if not output_path:
QMessageBox.warning(self, "错误", "请选择输出路径")
return
# 获取数据源路径
data_source_path = self.data_source_path_edit.text()
if not os.path.exists(data_source_path) and not data_source_path.endswith(".gdb"):
QMessageBox.warning(self, "错误", "请确认是否是有效数据源")
return
# 获取符号系统路径
symbol_path = self.symbol_path_edit.text()
if not os.path.exists(symbol_path):
QMessageBox.warning(self, "错误", "符号系统路径不存在")
return
# 获取图片源路径
pic_path = self.pic_path_edit.text()
if not os.path.exists(pic_path):
QMessageBox.warning(self, "错误", "符号系统路径不存在")
return
# 是否强制重新生成
force_regenerate = self.force_regenerate_check.isChecked()
# 准备参数
return {
'config_file': config_file,
'county_name': county_name,
'polygon_list': polygon_list,
'template_aprx_file': template_aprx_file,
'output_path': output_path,
'data_source_path': data_source_path,
'symbol_path': symbol_path,
'force_regenerate': force_regenerate,
'pic_path': pic_path
}
def load_settings(self):
"""从主窗口加载设置"""
try:
if not self.main_window or not hasattr(self.main_window, 'settings'):
return
settings = self.main_window.settings
if 'export_map_settings' in settings:
paths = settings['export_map_settings']
# 直接使用get方法设置默认值
self.config_file_edit.setText(paths.get("config_file", ""))
self.county_name_edit.setText(paths.get("county_name", ""))
self.template_aprx_file_edit.setText(paths.get("template_aprx_file", ""))
self.output_path_edit.setText(paths.get("output_path", ""))
self.data_source_path_edit.setText(paths.get("data_source_path", ""))
self.symbol_path_edit.setText(paths.get("symbol_path", ""))
self.pic_path_edit.setText(paths.get("pic_path", ""))
except Exception as e:
self.log_error(f"加载设置失败: {str(e)}")
def get_settings(self):
"""获取当前设置,供主窗口保存使用"""
return {
'config_file': self.config_file_edit.text(),
'county_name': self.county_name_edit.text(),
'template_aprx_file': self.template_aprx_file_edit.text(),
'output_path': self.output_path_edit.text(),
'data_source_path': self.data_source_path_edit.text(),
'symbol_path': self.symbol_path_edit.text(),
'pic_path': self.pic_path_edit.text()
}
def update_config_file(self, config_file):
self.config_file_edit.setText(config_file)