为模拟GPS数据给到AIS模块,随手写了这么个工具,顺便复习下快、准、狠,开发效率极高的pyqt(亲测稳定性也OK,QT本一家,所以关键的还是思路)
开发环境(IDE自然是pycharm):
python-2.7.9.amd64 + PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64 + pywin32-216.win-amd64-py2.7 + pyserial-3.4 + py2exe-0.6.9.win64-py2.7.amd64
效果图:
源码地址:https://github.com/avalonLZ/PyQT_GIS
逻辑部分Code如下:
# -*- coding: utf-8 -*-
import sys
import time
from gis_form import *
from PyQt4 import QtCore, QtGui
import serial
import serial.tools.list_ports
#$GNGGA,033723.000,2308.9503,N,11325.9527,E,6,06,4.1,30.6,M,0.0,M,,*40
#$GNRMC,033723.000,A,2308.9503,N,11325.9527,E,999.00,103.94,261017,,,E*72
#GIS信息校验
def GIS_Check(temstr):
checksum = 0
for i in temstr:
checksum = checksum ^ ord(str(i))#注意需要一个str
return checksum
#串口扫描,返回存在的COM口
def serial_ports(open_com = None):
ports = []
port_list = list(serial.tools.list_ports.comports())
for i in port_list:
ports.append(str(i.device))
return ports
class Thread_SendData(QtCore.QThread):
def __init__(self, temstr = '', parent=None, obj = None):
super(Thread_SendData, self).__init__(parent)
self.temstr = temstr
self.serial = obj.ser
self.interval = obj.return_interval()
self.display = obj.return_ui_display()
self.nostop = 1
def run(self):
while self.nostop:#while结束线程也就退出了
self.serial.write(str(self.temstr))
self.display.append(str(self.temstr))
self.display.currentFont()
time.sleep(int(self.interval))
def senddata_stop(self):#若写为私有函数则主线程中的sin无法绑定此函数(无法绑定到不同类的私有函数上)
self.nostop = 0
old_port = []#保证不一致刷新com口数量
class Thread_ScanCom(QtCore.QThread):
sinOut = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(Thread_ScanCom, self).__init__(parent)
self.new_port = []
def run(self):
while 1:
old_port = self.new_port
self.new_port = serial_ports()
if self.new_port != old_port:
self.sinOut.emit(self.new_port)#发送信号到主线程
class MainWindow(QtGui.QWidget):
sin2senddatastop = QtCore.pyqtSignal()#类变量,可由类名直接调用,也可由实例调用。一个线程只能绑定一个信号量
ser = serial.Serial()
def __init__(self,parent=None):
QtGui.QWidget.__init__(self,parent)
self.__ui = Ui_Windows()
self.__ui.setupUi(self)
self.__param_init()
self.__solt_init()
# 创建线程扫描com变化
self.thread_scancom = Thread_ScanCom()
self.thread_scancom.sinOut.connect(self.__scancom)
self.thread_scancom.start()
def __click_start(self):
if self.__ui.comboBox.currentText() == '' or str(self.__ui.serial.currentText()) == '':
QtGui.QMessageBox.warning(self, u"错误" ,u"串口或波特率错误,请检查")
return
self.__ui_disable(self.__ui.start)
self.__ui_disable(self.__ui.clean)
self.__serial_config(serial = self.ser, port = str(self.__ui.serial.currentText()),
baudrate = int(self.__ui.comboBox.currentText()))
#若已经打开,关闭前将无法再次打开,此后的程序不再执行
self.ser.open()
self.__gis_fill()
#创建线程按1秒间隔发送gis信息
self.__thread_senddata = Thread_SendData(temstr = self.gga + '\r\n' + self.rmc + '\r\n', obj = self)
self.sin2senddatastop.connect(self.__thread_senddata.senddata_stop) # 绑定信号
self.__thread_senddata.start()
def __click_end(self):
self.__ui_enable(self.__ui.start)
self.__ui_enable(self.__ui.clean)
self.sin2senddatastop.emit()
self.ser.close()
def __click_cleandisplay(self):
self.__ui.display.clear()
def __click_about(self):
QtGui.QMessageBox.about(self, u"关于", u"0183协议生成器\r\n从指定串口输出0183协议数据\r\n"
u" by:lz")
def __scancom(self, com_list):
self.__ui.serial.clear()
self.__ui.serial.addItems(com_list)
def __param_init(self):
self.gga1 = "$GNGGA,033723.000,"
self.latitudenum = "2308.9503" # 纬度
self.gga2 = ",N,"
self.longitudenum = "11325.9527" # 经度
self.gga3 = ",E,6,06,4.1,30.6,M,0.0,M,,*"
self.ggachecknum = "0"
self.gga = ""
self.rmc1 = "$GNRMC,033723.000,A,"
self.rmc2 = ",N,"
self.rmc3 = ",E,"
self.speednum = "999.00"
self.rmc4 = ",103.94,261017,,,E*"
self.rmcchecknum = "0"
self.rmc = ""
self.interval = ""
def __solt_init(self):
self.connect(self.__ui.start, QtCore.SIGNAL("clicked()"), self.__click_start)
self.connect(self.__ui.end, QtCore.SIGNAL("clicked()"), self.__click_end)
self.connect(self.__ui.clean, QtCore.SIGNAL("clicked()"), self.__click_cleandisplay)
self.connect(self.__ui.about, QtCore.SIGNAL("clicked()"), self.__click_about)
def __serial_config(self, serial = None, port = None, baudrate = None, bytesize = 8, stopbits = 1, parity = 'N'):
serial.port = port
serial.baudrate = baudrate
serial.bytesize = bytesize
serial.stopbits = stopbits
serial.parity = parity
def __gis_fill(self):
self.longitudenum = self.__ui.longutide.text()
self.latitudenum = self.__ui.latitude.text()
self.speednum = self.__ui.speed.text()
self.gga = self.gga1 + self.latitudenum + self.gga2 + self.longitudenum + self.gga3
self.ggachecknum = GIS_Check(self.gga)
self.gga += hex(self.ggachecknum)[2:]
self.rmc = self.rmc1 + self.latitudenum + self.rmc2 + self.longitudenum + self.rmc3 + self.speednum + self.rmc4
self.rmcchecknum = GIS_Check(self.rmc)
self.rmc += hex(self.rmcchecknum)[2:]
self.interval = self.__ui.interval.text()
def __ui_disable(self, obj = None):
obj.setDisabled(True)
def __ui_enable(self, obj = None):
obj.setDisabled(False)
def return_ui_display(self):
return self.__ui.display
def return_interval(self):
return self.interval
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp=MainWindow()
#窗口最大化按键无效
myapp.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint)
#锁定窗口大小
myapp.setFixedSize(myapp.width(), myapp.height())
myapp.show()