使用PythonTkinter开发GPGGA的坐标转换工具
- 需求
- 软件环境
- 安装环境
- Python2安装
- sandglass安装
- py2exe安装
- 实际功能
- 全部源码
- 运行效果图
- 要点总结
- 改进建议
需求
最近负责Cors系统售后工作的同事提出了一个需求,他们在做算法精度比对工作时,需要一个很方便的转换GPGGA到经纬度的工具,他在市面上没找到,需要我们帮忙开发一款,我简单了解了一下GPGGA,其实很简单,麻烦的但是如果将程序放到Web程序下,web程序需要向外网服务,而考虑的系统的安全性,不应该内部系统暴露到外网。最终我决定用Python开发一款C/S架构的工具,而看重Python的原因是:简单,代码量少,支持直接发布为exe程序,不需要安装运行环境。
软件环境
- Python 2.7.14(推荐没入坑的朋友还是要学习Python3,Python2要被放弃支持了,因为我之前学习、写工具用的都是Python2,相对比较熟悉,这里选用Python2进行开发)
- py2exe Python的exe打包工具
- sandglass 目前我用过最好用的时间包
安装环境
Python2安装
网上有大量的Python安装文档,这里不赘述了,提醒大家安装的时候一定要看一下系统环境是32位还是64位,再安装相应的程序
sandglass安装
安装好Python后,cmd运行命令pip install sandglass,自动安装就完成。
py2exe安装
下载路径:sourceforge下载路径这里再次提醒一下,一定要下载对应版本的py2exe,要和你的操作系统环境和Python版本对应起来,不然后续打包会报错,
比如:我的python版本是python2.7,操作系统是64位,我需要下载
py2exe-0.6.9.win64-py2.7.amd64.exe
实际功能
最终完成程序开发支持几个功能:
- 输入GGA转换为坐标
- 支持度显示和度分秒显示
- 支持文件批量导入,批量生成坐标,以文件形式导出
全部源码
全部源码如下:
#!/usr/local/bin/Python
# -*- coding: UTF-8 -*-
"""Displays the keysym for each KeyPress event as you type."""
import Tkinter as tk
import tkFileDialog
from sandglass import *
window = tk.Tk()
window.title('获取坐标工具')
window.geometry('400x300')
ggaVar = tk.StringVar()
latLngVar = tk.StringVar()
typeVar = tk.IntVar()
fileVar = tk.StringVar()
pathVar = tk.StringVar()
ggaText = tk.Entry(window,show=None,textvariable = ggaVar)
ggaText.pack(pady=20,padx = 20,fill="x")
latLngText = tk.Entry(window,show=None,textvariable = latLngVar)
latLngText.pack(pady = 10,padx = 20,fill = "x")
latLngText['state'] = 'readonly'
#度类型
DOC_TYPE = 0
#度分秒类型
DOC_MIN_SEC_TYPE = 1
NO_FILE = "NO_FILE"
def format_lat_lng():
try:
if pathVar.get() != NO_FILE:
loadFile(pathVar.get(),typeVar.get(),"./"+ben().strftime("%Y%m%d%H%M%S")+".txt")
return
if typeVar.get() == DOC_MIN_SEC_TYPE:
latLngVar.set(getLLDocMinSec(ggaVar.get()))
if typeVar.get() == DOC_TYPE:
latLngVar.set(getLLDoc(ggaVar.get()))
except Exception as e:
latLngVar.set("GPGGA异常:"+str(e))
def getLLDoc(gga):
splitMsg = gga.strip().split(",")
latStr = splitMsg[2]
latFlag = splitMsg[3]
lngStr = splitMsg[4]
lngFlag = splitMsg[5]
latInt = int(latStr[0:2])
latMin = float(latStr[2:-1])/60
lat = latInt + latMin
lat = lat if latFlag == "N" else -lat
lngInt = int(lngStr[0:3])
lngMin = float(lngStr[3:-1])/60
lng = lngInt + lngMin
lng = lng if lngFlag == "E" else -lng
return str(lat)+","+str(lng)
def getLLDocMinSec(gga):
splitMsg = gga.strip().split(",")
latStr = splitMsg[2]
latFlag = splitMsg[3]
lngStr = splitMsg[4]
lngFlag = splitMsg[5]
latDoc = latStr[0:2]
latDoc = latDoc if latFlag == "N" else ("-"+latDoc)
latMinList = latStr[2:-1].split(".")
latMin = latMinList[0]
latSec = float("0."+latMinList[1]) * 60
lat = "%s°%s′%s″"%(latDoc,latMin,latSec)
lngDoc = int(lngStr[0:3])
lngDoc = lngDoc if lngFlag == "E" else ("-"+lngDoc)
lngMinList = lngStr[3:-1].split(".")
lngMin = lngMinList[0]
lngSec = float("0." + lngMinList[1]) * 60
lng = "%s°%s′%s″"%(lngDoc,lngMin,lngSec)
return str(lat) + "," + str(lng)
def loadFile(path,curtype,writeFilePath):
with open(path, 'r') as file :
with open(writeFilePath, 'w') as wfile:
while 1:
wlines = []
lines = file.readlines(10000)
if not lines:
break
for line in lines:
result = "\n"
if curtype == DOC_TYPE:
try:
result = getLLDoc(line) + "\n"
except Exception as e:
print e
if curtype == DOC_MIN_SEC_TYPE:
try:
result = getLLDocMinSec(line) + "\n"
except Exception as e:
print e
wlines.append(result)
wfile.writelines(wlines)
def chageType():
print(typeVar.get())
docButton = tk.Radiobutton(window, text="度", value=DOC_TYPE, command=chageType, variable=typeVar)
docMinSecButton = tk.Radiobutton(window, text="度分秒", value=DOC_MIN_SEC_TYPE, command=chageType, variable=typeVar)
docButton.pack()
docMinSecButton.pack()
typeVar.set(DOC_TYPE)
fileVar.set(u"您没有选择任何文件")
pathVar.set(NO_FILE)
lb = tk.Label(window,textvariable = fileVar)
lb.pack(padx = 10,pady = 10)
def uploadFile():
filename = tkFileDialog.askopenfilename()
if filename != "":
#lb.config(text = u"您选择的文件是:" + filename)
fileVar.set(u"您选择的文件是:" + filename)
pathVar.set(filename)
def clearUploadFile():
fileVar.set(u"您没有选择任何文件")
pathVar.set(NO_FILE)
b2 = tk.Button(window,text = "上传文件",width=15,height = 2,command = uploadFile)
b2.pack(side='left',padx = 10)
b1 = tk.Button(window,text='获取坐标',width=15,
height=2,command=format_lat_lng)
b1.pack(side='right',padx = 10)
b3 = tk.Button(window,text = "清除文件",width=15,height = 2,command = clearUploadFile)
b3.pack(side="left",padx = 10)
window.mainloop()
运行效果图
要点总结
下面开始要点总结:
- Tkinter使用了类似数据绑定的功能进行更新,如:
ggaVar = tk.StringVar()
ggaText = tk.Entry(window,show=None,textvariable = ggaVar)
上面文本框的内容通过ggaVar这个变量进行关联,监控ggaVar可以方便的了解到文本框的内容变更,同时也可以通过ggaVar.set()函数对文本框内的内容进行修改。
2. Tkinter的组件如果显示,必须要条用pack函数,同时pack函数可以对布局产生影响
3. 注意Tkinter包的引入,网上很多程序Tkinter包引入时是tkinter小写,python2.7在使用时Tkinter包已经改成首字母大写
4. 文件路径获取组件使用tkFileDialog不在Tkinter包内,需要单独引用
5. StringVar中set为None,再获取时获取的字符串“None”,而不是None对象
改进建议
整体来说,代码写的非常的丑