6.2KML转Excel插件
本插件的核心功能是解析kml中的点、线、面要素,并根据配置输出要素的名称、坐标、类型、描述信息等为Excel文件。 解决快速获取gis矢量文件要素名称的问题,如需要在报告里面罗列所有消防设施的编号,通过该功能可以快速获取。
通过本插件可了解到:
- 熟悉使用ttkbootstrap库构建bootstrap风格界面的过程(比tkinter要美观很多)
- 熟悉矢量图层的加载及要素遍历过程
- 熟悉logging模块的日志输出调试过程(可直接打印对象)
- 熟悉使用openpyxl库写入excel文件的过程
插件界面:
转换结果:
源码及示例数据下载地址: 图新地球PythonAPI-KML转Excel示例插件
注:示例代码并不是完整的插件,需要按照开发环境的构建流程,安装对应的依赖包。
6.1 ttkbootstrap库界面构建
- 界面主要涉及窗体(TK)、标签(Label)、输入框(Entry)、按钮(Button)、多行文本框(Frame+ScrolledText)、复选框(CheckButton)6个控件。
- 布局采用了最简单的绝对定位
6.2 读取KML文件
- 加载图层,获取Layer对象
- 根据Layer对象获取Marker列表、polyline列表、polygon列表
- 遍历Marker列表、polyline列表、polygon列表获取TXGeoMarker、TXGeoPolyline、TXGeoPolygon对象
- 根据TXGeoMarker、TXGeoPolyline、TXGeoPolygon对象获取坐标、坐标集、名称、描述信息等
6.3 写入要素信息到Excel
- 核心使用openpyxl用于构建workbook、worksheet,
- 按行写入单元格内容。
- 保存Excel文件
6.4 具体代码如下:
python
from TXEarthAPI import *
'''
# 引入界面库(tkinter的美化版)
可在pycharm的依赖包中直接安装
也可通过如下命令行进行安装
如果按照python时默认勾选了安装tkinter,则无需安装tk
pip install tk -i https://mirrors.aliyun.com/pypi/simple
pip install ttkbootstrap -i https://mirrors.aliyun.com/pypi/simple
'''
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from tkinter import filedialog
from tkinter import messagebox
##滚动文本框
from ttkbootstrap.scrolled import ScrolledText
'''
日志输出库,可作为调试的重要方法,可通过命令行单独安装
pip install openpyxl -i https://mirrors.aliyun.com/pypi/simple
'''
import logging
import os
'''
# excel表格内容编辑库,可在pycharm的依赖包中直接安装,也可通过命令安装
pip install openpyxl -i https://mirrors.aliyun.com/pypi/simple
'''
import openpyxl
# 程序入口
def run(app):
'''
# 配置日志输出的模板:时间-文件名称[line:行号]-日志级别:消息
# 示例:2023-08-28 15:15:51,532 - main.py[line:13] - INFO: 开始执行run方法
日志的文件名称,如果不是绝对路径,相对路径是相对于图新地球的exe文件的
'''
logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s',
filename='kml2excellog.txt', level=logging.INFO)
# 在插件入口的run函数里面开始进行日志输出
logging.info('开始执行run方法')
# 初始化球对象
global globe
globe = TXGlobeControl(app)
# 初始化界面对话框
init_dialog()
# 选择kml文件,并获取文件的体积
def select_kml_file():
logging.info('开始执行select_kml_file方法')
global kml_file_path
# 调用系统选择文件对话框,选择一个kml文件,获取kml文件的路径
kml_file_path = filedialog.askopenfilename(
title="选择kml文件",
filetypes=(("kml文件", "*.kml | *.kmz"),)
)
if kml_file_path == "":
logging.info('取消选择文件')
return
reset_everything()
# 把选择的文件路径的名称,展示到输入框内
url_value.set(kml_file_path)
# 加载数据,并获取数据的基本信息,展示出来
kml_info = "你选择的文件【 "
kml_file_name = os.path.basename(kml_file_path)
# 获取文件体积,并自动转换体积单位为M或者kb
kml_file_size = os.path.getsize(kml_file_path) / 1024
kml_file_size_unit = "kb"
if kml_file_size > 1024:
kml_file_size = kml_file_size / 1024
kml_file_size_unit = "M"
# 体积大小保留一位小数
kml_file_size = round(kml_file_size, 1)
kml_info = kml_info + kml_file_name + "】体积" + str(kml_file_size) + kml_file_size_unit + "\n"
scrolledtext_kml_info.delete(1.0, "end")
scrolledtext_kml_info.insert("end", kml_info)
logging.info('获取文件体积,并显示到标签上:' + kml_info)
button_excel_to_kml.config(state="normal")
return
def export_kml_to_excel():
logging.info('开始执行export_kml_to_excel方法')
# 添加图层到地球,并获取要素的数量
global current_layer
current_layer = globe.AddLayer(kml_file_path)
logging.info('添加图层current_layer:' + str(current_layer))
try:
# 从layer对象(图层)获取要素(点、线、面)列表
marker_list = current_layer.GetMarkers()
polyline_list = current_layer.GetPolylines()
polygon_list = current_layer.GetPolygons()
parse_feautre_info = '要素个数:marker对象' + str(len(marker_list)) + "个,polyline对象" + str(
len(polyline_list)) + "个,polygon对象" + str(len(polygon_list)) + "个"
scrolledtext_kml_info.insert("end", parse_feautre_info)
logging.info(parse_feautre_info)
if len(marker_list) < 1 and len(polyline_list) < 1 and len(polygon_list) < 1:
logging.info('无可导出要素,取消导出')
messagebox.showwarning("提醒", "无可导出要素,取消导出")
return
# 选择excel文件的保存位置
excel_file_path = filedialog.asksaveasfilename(
title="选择Excel文件保存的名称",
filetypes=(("Excel文件", "*.xlsx"),),
defaultextension='.xlsx'
)
if excel_file_path == "":
logging.info('用户取消导出')
return
workbook = openpyxl.Workbook()
worksheet = workbook.active
worksheet.title = "kml转excel成果"
first_row = ["名称"]
if checkbutton_type_filed_var.get() == 1:
first_row.append("要素类型")
if checkbutton_pos_filed_var.get() == 1:
first_row.append("坐标值")
if checkbutton_desc_filed_var.get() == 1:
first_row.append("描述信息")
# 写表头
worksheet.append(first_row)
# 获取要素的名称、类别、坐标、描述等信息,并写入到excel
if len(marker_list) > 0:
current_index = 0
while current_index < len(marker_list):
current_marker: TXGeoMarker = marker_list[current_index]
logging.info(TXGeoMarker)
# 要素名称
current_row = [current_marker.GetName()]
# 要素类型
if checkbutton_type_filed_var.get() == 1:
current_row.append("点")
# 要素坐标
if checkbutton_pos_filed_var.get() == 1:
marker_pos = current_marker.GetPosition()
marker_pos_str = str(marker_pos.x) + ","+str(marker_pos.y) + "," + str(marker_pos.z)
current_row.append(marker_pos_str)
# 要素描述信息
if checkbutton_desc_filed_var.get() == 1:
current_row.append(current_marker.GetDescription())
current_index = current_index + 1
worksheet.append(current_row)
if len(polyline_list) > 0:
current_polyline_index = 0
while current_polyline_index < len(polyline_list):
current_polyline: TXGeoPolyline = polyline_list[current_polyline_index]
logging.info(current_polyline)
# 要素名称
current_row = [current_polyline.GetName()]
# 要素类型
if checkbutton_type_filed_var.get() == 1:
current_row.append("线")
# 要素坐标
if checkbutton_pos_filed_var.get() == 1:
polyline_pos = current_polyline.GetPoints()
# polyline_pos
logging.info("坐标个数:" + str(len(polyline_pos)))
point_num = 0
polyline_pos_str = ""
while point_num < len(polyline_pos):
polyline_pos_str = " " + str(polyline_pos[point_num].x) + ","+str(polyline_pos[point_num].y) + "," + str(polyline_pos[point_num].z)
point_num = point_num + 1
logging.info(polyline_pos_str)
current_row.append(polyline_pos_str)
# 要素描述信息
if checkbutton_desc_filed_var.get() == 1:
current_row.append(current_polyline.GetDescription())
current_polyline_index = current_polyline_index + 1
worksheet.append(current_row)
if len(polygon_list) > 0:
current_polygon_index = 0
while current_polygon_index < len(polygon_list):
current_polygon: TXGeoPolygon = polyline_list[current_polygon_index]
logging.info(current_polygon)
# 要素名称
current_row = [current_polygon.GetName()]
# 要素类型
if checkbutton_type_filed_var.get() == 1:
current_row.append("面")
# 要素坐标
if checkbutton_pos_filed_var.get() == 1:
polygon_pos = current_polygon.GetPoints()
# polyline_pos
logging.info("坐标个数:" + str(len(polygon_pos)))
point_num = 0
polygon_pos_str = ""
while point_num < len(polygon_pos):
polygon_pos_str = " " + str(polygon_pos[point_num].x) + ","+str(polygon_pos[point_num].y) + "," + str(polygon_pos[point_num].z)
point_num = point_num + 1
logging.info(polygon_pos_str)
current_row.append(polygon_pos_str)
# 要素描述信息
if checkbutton_desc_filed_var.get() == 1:
current_row.append(current_polygon.GetDescription())
current_polygon_index = current_polygon_index + 1
worksheet.append(current_row)
workbook.save(excel_file_path)
workbook.close()
messagebox.showwarning("提醒", "数据已导出完成")
except Exception as e:
logging.info("获取要素列表错误:" + str(e))
return ""
def reset_everything():
'''
重置界面,恢复到插件启动状态
'''
logging.info('开始执行reset_everything方法')
url_value.set("请选择kml文件,此处显示其路径")
scrolledtext_kml_info.delete(1.0, "end")
button_excel_to_kml.config(state="disabled")
try:
logging.info('尝试删除图层')
globe.RemoveLayer(current_layer)
except Exception as e:
logging.info("删除图层错误:" + str(e))
return ""
# 对话框界面对象定义
top = ttk.Window()
style = ttk.Style()
style.theme_use("cerculean")
# 修改窗口标题
top.title("KML转Excel")
# 修改窗口大小
top.geometry("800x600")
top.resizable(width=False, height=False)
left_padding = 20
top_padding = 20
# 选择kml文件标签
label_select_kml_file = ttk.Label(top, text="选择kml文件")
label_select_kml_file.place(x=left_padding, y=top_padding + 5)
# 显示路径的文本输入框
url_value = ttk.StringVar(value="请选择kml文件,此处显示其路径")
entry_url = ttk.Entry(top, state="disabled", textvariable=url_value)
entry_url.place(x=left_padding + 100, y=top_padding, width=550)
# 选择kml文件的按钮
button_select_kml_file = ttk.Button(top, text="...", command=select_kml_file, bootstyle=SUCCESS)
button_select_kml_file.place(x=700, y=top_padding, width=50)
# 一个信息标签用来显示kml文件的基本信息
frame_kml_info = ttk.Frame(top)
frame_kml_info.place(x=400, y=60, width=380, height=450)
text_content_frame_kml_info = '此处将显示kml文件的基本信息'
scrolledtext_kml_info = ScrolledText(frame_kml_info, padding=5, height=10, autohide=True)
scrolledtext_kml_info.pack(fill=BOTH, expand=YES)
scrolledtext_kml_info.insert(END, text_content_frame_kml_info)
# 选择要导出的字段复选框
combobox_y_pos = 30
combobox_step = 60
label_select_field = ttk.Label(top, text="请选择要导出的字段")
label_select_field.place(x=left_padding, y=combobox_y_pos + combobox_step)
# 名称字段
checkbutton_name_filed_var = ttk.IntVar()
checkbutton_name_filed_var.set(1)
checkbutton_name_filed = ttk.Checkbutton(top, text="要素名称", onvalue=1, offvalue=0,
variable=checkbutton_name_filed_var, state="disabled")
checkbutton_name_filed.place(x=left_padding, y=combobox_y_pos + combobox_step * 2)
# 类型字段
checkbutton_type_filed_var = ttk.IntVar()
checkbutton_type_filed_var.set(1)
checkbutton_type_filed = ttk.Checkbutton(top, text="要素类型", onvalue=1, offvalue=0,
variable=checkbutton_type_filed_var)
checkbutton_type_filed.place(x=left_padding, y=combobox_y_pos + combobox_step * 3)
# 坐标字段
checkbutton_pos_filed_var = ttk.IntVar()
checkbutton_pos_filed_var.set(1)
checkbutton_pos_filed = ttk.Checkbutton(top, text="坐标值(坐标串)", onvalue=1, offvalue=0,
variable=checkbutton_pos_filed_var)
checkbutton_pos_filed.place(x=left_padding, y=combobox_y_pos + combobox_step * 4)
# 描述字段
checkbutton_desc_filed_var = ttk.IntVar()
checkbutton_desc_filed_var.set(1)
checkbutton_desc_filed = ttk.Checkbutton(top, text="描述信息", onvalue=1, offvalue=0,
variable=checkbutton_desc_filed_var)
checkbutton_desc_filed.place(x=left_padding, y=combobox_y_pos + combobox_step * 5)
# 导出按钮及取消导出按钮
button_excel_to_kml = ttk.Button(top, text='导出', command=export_kml_to_excel, state="disabled")
button_reset = ttk.Button(top, text='重置', command=reset_everything, bootstyle="light")
button_reset.place(x=660, y=540, width=120, height=50)
button_excel_to_kml.place(x=530, y=540, width=120, height=50)
# 初始化对话框,构建界面要素
def init_dialog():
# 进入消息循环
top.mainloop()
# init_dialog()