3.可视化:
在项目树底层新建一个Dialog,命名为VisualFrame。在该窗口中添加一个wxBoxSizer后添加两行,把第一行改为横行排列,依次添加wxStaticText和wxComboBox(在Common下)、wxButton,并分别把两个wxStaticText的标签改为测点类型、测点位置:
注意这里是连续三个wxComboBox,依次改名为m_comboBoxyb,m_comboBoxrd,m_comboBoxwd(截图有误)。
在第二行中添加wxPanel(中央组件Containers-wxPanel),并将姓名改为m_zxt:
在wxPanel中再新加一行,后在该行中新建一个Customcontrol(Additional-Customcontrol),并将其名字修改为m_figurecanvas:
在该组件属性的construction中书写语句:
# 创建了一个Matplotlib的Figure实例,表示一个图形
# figsize=(11.3, 7.9) 指定了图形的大小为11.3英寸宽,7.9英寸高。
# dpi=72 指定了图形的分辨率为72点每英寸。
# facecolor='#FFFFFF' 设置了图形的背景色为白色(使用十六进制颜色表示法,#FFFFFF表示白色)。
self.m_figure = matplotlib.figure.Figure(figsize=(11.3, 7.9),dpi=72,facecolor='#FFFFFF')
# 创建了一个Matplotlib的FigureCanvas实例,用于将Figure实例渲染到界面上。具体来说:
# self.m_zxt 是画布的父窗口,表示画布被嵌入到哪个窗口中。这里可能是一个窗口对象的引用。
# -1 是画布的标识符,通常用于在窗口中识别画布。
# self.m_figure 是之前创建的Figure实例,表示该画布与哪个图形相关联。
self.m_figurecanvas = FigureCanvas(self.m_zxt, -1, self.m_figure)
在include中书写语句:
import matplotlib
'''
指定了Matplotlib的渲染后端为"WXAgg"。Matplotlib支持多种后端,
用于在不同的图形用户界面(GUI)工具包中显示图形。
"WXAgg"表示使用wxPython工具包的Agg渲染后端,
其中Agg是Anti-Grain Geometry的缩写,是一个高质量的图形渲染引擎。
'''
matplotlib.use("WXAgg")
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
点击测点类型后面那个下拉选项框,在其属性框中点击choices最后的三个点,添加选项:
点击New item,然后在里面输入以下内容,
点击ok关闭窗口,就可以看到下拉选项框变成了这样
同理在后面三个选项框中分别添加以下内容:
在第二个选项框的属性中找到hidden并勾选,就可以隐藏掉这个选项框,第三个选项框同理进行隐藏,最后隐藏的只剩第一个:
给确认键添加一个事件:evt_ok,记得F8生成代码
至此我们前端的绘图面板就设置好了,接下来我们到后端进行数据读取及绘图。
现在就是重复每次新设计一个界面就要做的工作,继承这个界面并写入自己的方法,正常的,先重写__init__方法:
class VisualFrame(CSDNtext01.VisualFrame):
def __init__(self,parent):
CSDNtext01.VisualFrame.__init__(self,parent)
# 绘制图形在panel中所占的位置,其中四个参数表示图像距离左右上下的距离
self.axes = self.m_figure.add_axes([0.05, 0.15, 0.92, 0.8])
self.parent = parent
# 窗口最大化
self.Maximize()
这个__init__方法重写略有不同,因为需要调整画板的位置,所以多了几行。
现在就开始画图吧。因为我们的窗口支持多次点击。根据选择不同多次生成图像,所以我们得需要一个清除上一个图像的函数吧:
def __clear(self):
try:
'''# 再次画图前必须调用该命令清空原来的图形'''
self.axes.clear()
self.m_figure.set_canvas(self.m_figurecanvas)
self.__updateplot()
self.m_figurecanvas.draw()
except:
pass
清除了之后,得有个更新图像的函数吧:
def __updateplot(self):
'''修改图形的任何属性后都必须使用self.__updateplot()更新GUI界面'''
try:
self.m_figurecanvas.draw()
except:
pass
最重要的,图怎么画出来的(里面备注都写的蛮清楚的,不懂得自己搜一下吧):
def __draw(self):
x_datas = []
y_datas = []
conn = Connection(
host="localhost",
port=3306,
user="root",
password="123456",
db="Csdn_text01"
)
cursor = conn.cursor()
yb = cursor.execute("select *from yb_db")
yb_data = cursor.fetchall()
# print(yb_data)
time_data = []
for i in yb_data:
time_data.append(i[0])
# print(time_data)
x = time_data
# self.axes.plot(x,y1)
# self.m_panel1.Layout()
if self.m_comboBox1.GetValue() == "应变":
type1 = "yb_db"
type2 = self.m_comboBoxyb.GetValue()
if self.m_comboBox1.GetValue() == "扰度":
type1 = "rd_db"
type2 = self.m_comboBoxrd.GetValue()
if self.m_comboBox1.GetValue() == "温度":
type1 = "wd_db"
type2 = self.m_comboBoxwd.GetValue()
# 这里在写的时候用%s占位符搞半天不行,用字符串格式化(.format)就好了:
cursor.execute("select {} from {}".format(type2, type1))
y = cursor.fetchall()
# 清除上一次生成的折线图
self.__clear()
# 用来显示坐标轴网格的函数
self.axes.grid()
# 这里是设置了中文字体,没有这一步可能会导致中文无法显示
plt.rcParams['font.sans-serif'] = ['Simhei']
# 设置标题及字号,其中使用了GetValue获取到第一个选项框的内容,比如获取到应变,这里生成的标题就是“应变 数据曲线”
self.axes.set_title('%s 数据曲线' % self.m_comboBox1.GetValue(), size=32)
# 这个madtes是import matplotlib.dates as mdates
# 定义横坐标轴显示的格式
self.axes.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d '
'%H:%M:%S'))
# 设置x轴的主要刻度定位器为自动日期定位器。根据x轴数据的范围自动选择合适的日期刻度间隔,使得x轴上的日期刻度更加合理和易读
self.axes.xaxis.set_major_locator(mdates.AutoDateLocator())
# x轴标签
self.axes.set_xlabel('时间', size=18)
# y轴标签,使用到了GetValue,同理,可变化
self.axes.set_ylabel('测点:%s' % self.m_comboBox1.GetValue(), size=18)
self.m_figure.autofmt_xdate() # x轴日期时间自动旋转
# 让 Matplotlib 自动调整x和y轴的范围,以适应数据的范围
self.axes.set_xlim(auto=True)
self.axes.set_ylim(auto=True)
'''x 和 y 是日期和相应的数值。
'-' 表示使用实线连接数据点。
c='#00FF00' 设置线的颜色为绿色。
linewidth=1 设置线的宽度为1。'''
p, = self.axes.plot_date(x, y, '-', c='#00FF00',
linewidth=1)
'''
[p] 表示传递包含绘制对象的列表。
loc='best' 表示自动选择最佳的位置放置图例。
shadow=True 表示在图例中添加阴影效果。
fontsize=12 设置图例字体的大小为12。
'''
self.axes.legend([p], [self.m_comboBox1.GetValue()], loc='best', shadow=True, fontsize=12)
# 更新图像
self.__updateplot()
编写evt_ok方法把这些函数连接起来:
def evt_ok(self, event):
if self.m_comboBox1.CurrentSelection == -1:
return
self.__draw()
event.Skip()
在实际测试中我们会发现,在选择应变之后,后面的选项框是n1-n9,但是选择了扰度和温度时,后面的选项框仍然是n1-n9,我们多做的两个选项框未显示出来,因为缺少了这么一个东西:
def checkChoice(self, event):
# print(self.m_comboBox1.GetValue())
if self.m_comboBox1.GetValue() == '应变':
self.m_comboBoxyb.Show()
self.m_comboBoxrd.Hide()
self.m_comboBoxwd.Hide()
self.Layout()
if self.m_comboBox1.GetValue() == '扰度':
self.m_comboBoxyb.Hide()
self.m_comboBoxrd.Show()
self.m_comboBoxwd.Hide()
self.Layout()
if self.m_comboBox1.GetValue() == '温度':
self.m_comboBoxyb.Hide()
self.m_comboBoxrd.Hide()
self.m_comboBoxwd.Show()
self.Layout()
self.Layout()
这个方法实现了当类型选择框结果不同时,显示不同的下属选择框。
注意:修改后需要self.layout()重新排列窗口,否则布局会乱。
测试发现绘制出的图总是首尾相连,进到数据库看了一眼发现是多次载入同一份excel数据。重复存储,导致一份数据的结尾和另一份数据的开头连接起来了。而我们在每次运行程序都要载入一次表格,所以我们需要编写一个函数用于检查数据库中是否有数据,如果有就把数据库清空,并在程序正常退出时清空数据库。
进入到db.py,在MyConnection下新建一个方法:
def del_db(self):
conn=Connection(
host='localhost',
port=3306,
user='root',
password='123456',
db='Csdn_text01'
)
cursor=conn.cursor()
cursor.execute("delete from yb_db")
cursor.execute("delete from rd_db")
cursor.execute("delete from wd_db")
conn.commit()
cursor.close()
conn.close()
一定记得commit,以及连接数据库用完数据后,执行close。
我们给实现检测数据库是否有数据这个功能起个名字,叫系统自检,是不是一下就高大上了,在Login类中编写一个函数:
def evt_sysselftest(self, event):
conn = Connection(
host='localhost',
port=3306,
user='root',
password='123456',
db='Csdn_text01'
)
cursor = conn.cursor()
cursor.execute('select count(*) from yb_db ')
result_yb1 = cursor.fetchone()
result_yb = result_yb1[0]
# print(result_yb)
cursor.execute('select count(*) from rd_db ')
result_rd1 = cursor.fetchone()
result_rd = result_rd1[0]
cursor.execute('select count(*) from wd_db ')
result_wd1 = cursor.fetchone()
result_wd = result_wd1[0]
if result_yb != 0 or result_rd != 0 or result_wd != 0:
wx.MessageBox("上次程序未正常退出,请点击OK等待程序修复", "错误信息")
# 程序退出时自动清空数据库
db.MyConnection.del_db(self)
wx.MessageBox("程序已修复", "提示信息")
else:
wx.MessageBox("系统正常,请继续使用", "提示信息")
self.Close()
然后在登录成功后(调用数据库之前)调用这个方法:
self.evt_sysselftest()
再次跑一下代码,可以发现没有问题了。