通过Pyqt做的一个小软件,主要功能是显示飞行器当前的状态如“机身海拔高度”、“机身坐标”、“偏航角”等,绘制出飞机当前所处区域高程地图。飞机机头朝向随航行方向变化。
软件效果如下图所示,地图窗口显示地形等高线彩色图,在地图中间位置是飞机,飞机始终位于地图的中心位置,地图随时间位置变化改变显示区域。
右侧显示飞机各时刻的数据信息,并实时更新。
(1)地图区域的等高线彩色图进行绘制的任务,通过自定义一个派生于QLabel
类的MapLabel
类实现,重写MapLabel
类的paintEvent
函数,进行相关的绘图操作,如绘制“圆”、“线段”、“扇形”、“红色飞机”等元素;
(2)在Widget
类中开一个QThread
子线程用于实时模拟飞机的运行轨迹,通过time.time()
获取系统时间,并利用系统时间激励飞机运行轨迹的更新;
(3)将QThread
子线程中飞机的各个参数与MapLabel
、Menu
(即右侧显示数据的Widget
)中的槽函数进行绑定,用QTimer
定时更新显示画面;
首先需要定义一个Plane类,用于确定地图中间位置的红色小飞机的相关信息。
其中需要定义一个self.plane_rotated
用于记录旋转后的飞机的图像。
成员函数主要用于对该类各属性的赋值操作。
MapLabel类的属性主要有一个self.map
用于存放QImage
格式地图数据,self.plane
存放Plane
对象,self.timer
设置了一个定时器用于定时触发QLabel
类的update
函数,以调用paintEvent
函数重绘各种图案。
# 自定义飞机类
class Plane:
def __init__(self):
# 当前飞机图像
self.icon = QImage('./2.png')
# 飞机当前像素点位置(由经纬度转换过来)、速度、偏航角、高度等信息
self.location_x = 3000
self.location_y = 1000
self.velocity = 0
self.yaw = 0
self.altitude = 3000
# 旋转后的飞机图像
self.plane_rotated = QImage()
# 旋转角度(红色飞机根据航向旋转机头朝向)
self.transform = QTransform()
def set_location(self, present_point):
self.location_x = present_point.x()
self.location_y = present_point.y()
def set_yaw(self, yaw):
self.yaw = yaw + 90
def set_rotated_plane(self):
self.transform.rotate(self.yaw)
self.plane_rotated = self.icon.transformed(self.transform)
self.transform.rotate(-self.yaw)
def set_velocity(self, velocity):
self.velocity = velocity
def set_altitude(self, altitude):
self.altitude = altitude
# 自定义QLabel类(地图)
class MapLabel(QLabel):
def __init__(self, parent=None):
super(MapLabel, self).__init__(parent)
# 地图、指北针等图片资源
self.map = QImage('./3.png')
self.northIco = QImage('./4.png')
# 创建飞机对象
self.plane = Plane()
# 绘图更新
self.t = 0 # 用于画旋转线段的计数器
self.timer = QTimer()
self.timer.timeout.connect(self.update) # 触发paintEvent
self.timer.start(10)
def paintEvent(self, event):
self.t += 1
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
# 将地图的QRect(self.plane.location_x, self.plane.location_y, 600, 600)区域绘制到QLabel的QRect(0, 0, 600, 600)区域中去
painter.drawImage(QRect(0, 0, 600, 600), self.map,
QRect(self.plane.location_x, self.plane.location_y, 600, 600))
painter.drawImage(QPoint(500, 40), self.northIco)
# 画圆
painter.setPen(QPen(QColor(255, 0, 0), 3)) # 后面参数3为线条的粗细
painter.drawEllipse(QPoint(300, 300), 200, 200)
# 画线段(旋转线段)
painter.setPen(QPen(QColor(135, 0, 0), 3))
painter.drawLine(QPoint(300, 300), QPoint(300 + 200 * math.cos(self.t/100),
300 + 200 * math.sin(self.t/100)))
# 画扇形
painter.setPen(QPen(QColor(255, 135, 2), 3))
painter.drawPie(QRect(QPoint(50, 50), QPoint(550, 550)), -(self.plane.yaw - 55)*16, 70*16)
# 设置偏航角及旋转后的飞机图片
self.plane.set_rotated_plane()
# 画红色飞机
painter.drawImage(QPoint(300 - self.plane.plane_rotated.width() / 2,
300 - self.plane.plane_rotated.height() / 2), self.plane.plane_rotated)
在最外层的Widget
类中实现基于时间的激励条件,这里的PlaneInfo
类是继承于QThread
类,在Widget
类中实例化该类后,执行其start()
函数,就可以运行run()
中的相关操作。
# 运动参数,是关于t的函数,应由外部激励决定,此处为模拟
class PlaneInfo(QThread):
send_position = pyqtSignal(QPoint)
send_yaw = pyqtSignal(float)
send_velocity = pyqtSignal(int)
def __init__(self):
super(PlaneInfo, self).__init__()
self.start_time = time.time()
self.end_time = 0
self.during_time = 0
self.x = 1000
self.y = 1000
self.yaw = 0
self.velocity = 0
def run(self):
while True:
# time.sleep(0.01)
self.end_time = time.time()
print(self.end_time)
print(int(round(self.end_time * 1000)))
self.during_time = self.end_time - self.start_time
# x,y关于t的参数方程
self.x = 100 * self.during_time + 1000
self.y = 2 * self.during_time * self.during_time + 1000
self.yaw = math.atan(0.02 * self.during_time) * 1800 / 3.1415926
# print(self.yaw)
self.velocity = 4 * self.during_time * self.during_time + 0
self.send_position.emit(QPoint(self.x, self.y))
self.send_yaw.emit(float(self.yaw))
self.send_velocity.emit(int(self.velocity))
本案例中涉及到的所有代码、工程文件等,到此处https://download.csdn.net/download/wang_chao118/87031348下载。