From de7d73aa50d02a99ab1e25313379da16ac1b8139 Mon Sep 17 00:00:00 2001 From: esea_info Date: Fri, 14 Apr 2023 10:38:01 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=97=E5=87=BALw=20Rs=E5=86=8D=E4=BF=9D?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataplot.py | 237 ++++++++++++++++++++++++++++++++++++ handheld.py | 134 +++++++++++--------- mypanel.py | 96 +++++++++++++++ mythread.py | 126 +++++++++++++++++++ retrieve.yml | 2 + uiconfig/ui_plot_setting.py | 100 +++++++++++++++ yiwinframe.py | 179 ++++++++++++++++----------- 7 files changed, 746 insertions(+), 128 deletions(-) create mode 100644 dataplot.py create mode 100644 mythread.py create mode 100644 uiconfig/ui_plot_setting.py diff --git a/dataplot.py b/dataplot.py new file mode 100644 index 0000000..8b95949 --- /dev/null +++ b/dataplot.py @@ -0,0 +1,237 @@ +# import numpy as np + +from pathlib import Path + + +class DataPlot(): + ''' + 从文件读取数据,出来成待显示数据 + ''' + + # def __init__(self, mypanel, ): + def __init__(self, ): + # self.mypanel = mypanel + # self.__eventManager = eventManger + # self.dataSaveFile = DATA_FNAME_WITHOUT_WATER + # self.axes_title = "Water Attenuation Coefficient" + # self.axes_xlabel = "Wavelength (nm)" + # self.axes_ylabel = "Attenuation Coefficient m(-1)" + # self.axes_title = "Attenuation Coefficient Demo" + self.demo_time = '' + self.demo_wl = [] # 纯水 + self.demo_data = [] # 纯水 + + self.wavelength = None + self.data_one = None + self.data_multi = None + # self.mode = "one" # multi + # self.begin_line = None + # self.line_interval = None + self.fpath :Path = Path() + self.total_lines = 0 + self.token = ";" + # self.MPL = myPanel.MPL_Panel(self) # 调用自己建立的 panel 类 + # self.Figure = self.MPL.Figure + # self.axes = self.MPL.axes + # self.FigureCanvas = self.MPL.FigureCanvas + def set_file_path( self, fpath:Path ): + self.fpath = fpath + pass + + def set_wavelength(self): + pass + + # def set_mode(self, mode ="one"): + # self.mode = mode + # pass + + def set_token(self, token =";"): + self.token = token + pass + + def set_begin_line( self, lineno = 0 ): + self.begin_line = lineno + pass + + def set_line_interval( self, line_interval = 0 ): + self.line_interval = line_interval + pass + + def get_total_lines( self, ): + ''' 大文件 ''' + count = 0 + thefile = open( self.fpath, 'rb') + while True: + buffer = thefile.read(8192*1024) + if not buffer: + break + count += buffer.count(b'\n') + self.total_lines = count + 1 + + def get_wavelength_from_file( self, ): + tmp = self.get_first_line() + self.wavelength = tmp.split(self.token)[1:] + pass + + def get_reverse_x_lineno( self, x ): + line = self.__get_reverse_x_lineno(x) + line = line.split(self.token) + return line[0], line[1:] + pass + + def get_multi_by_x_m_n( self, x,m,n ): + # res_time = [] + # res_lines = [] + lines = self.__get_reverse_x_m_n_line(x,m,n) + # print(f'+++++ {lines}') + # for i in range(len(lines)): + # ln = + # res_time.append( lines[i] [0] ) + # res_lines.append( lines[i][1:] ) + # return res_time, res_lines + return lines + pass + + def __get_reverse_x_lineno(self, x): + """ + 获得倒数第x行 + """ + try: + # filesize = os.path.getsize(self.fpath) + filesize = self.fpath.stat().st_size + if filesize == 0: + return None + else: + with open(self.fpath, 'rb') as fp: # to use seek from end, must use mode 'rb' + offset = -8 # initialize offset + while -offset < filesize: # offset cannot exceed file size + fp.seek(offset, 2) # read # offset chars from eof(represent by number '2') + lines = fp.readlines() # read from fp to eof + if len(lines) >= x+1: # if contains at least 2 lines + return lines[-1*x] # then last line is totally included + else: + offset *= 2 # enlarge offset + fp.seek(0) + lines = fp.readlines() + if len(lines) < x: + raise Exception("行数有误,请重试") + return lines[-1*x] + except FileNotFoundError: + print(self.fpath.name + ' not found!') + return None + + def __get_reverse_x_m_n_line(self, x, m=1, n=1): + """ + 获得倒数第x行, 间隔m行, 共取n个行 + """ + print(f'__get_reverse_x_m_n_line {x} {self.fpath}') + min_lines = x + m*n + res_lines = [] + try: + # filesize = os.path.getsize(self.fpath) + filesize = self.fpath.stat().st_size + if filesize == 0: + return None + else: + with open(self.fpath, 'rb') as fp: # to use seek from end, must use mode 'rb'x + offset = -8 # initialize offset + while -offset < filesize: # offset cannot exceed file size + fp.seek( offset, 2 ) # read # offset chars from eof(represent by number '2') + lines = fp.readlines() # read from fp to eof + if len(lines) >= min_lines+1 : + for i in range(n): + res_lines.append( lines[-1*(x+m*i)].decode()) + return res_lines + else: + offset *= 2 # enlarge offset + fp.seek( 0 ) + lines = fp.readlines( ) + if len(lines) < min_lines: + raise Exception("行数有误,请重试") + for i in range(n): + res_lines.append( lines[-1*(x+m*i)].decode()) + return res_lines + print(res_lines) + except FileNotFoundError: + print(self.fpath.name + ' not found!') + return None + + def get_first_line(self, ): + firstline = '' + with open(self.fpath, 'rb') as fp: # to use seek from end, must use mode 'rb'x + firstline = fp.readline() + return firstline.decode() + + def get_last_line(self,filename:Path): + """ + 获得最后一行 + :param filename: file name + :return: last line or None for empty file + """ + try: + filesize = filename.stat().st_size + if filesize == 0: + return None + else: + with open(filename, 'rb') as fp: # to use seek from end, must use mode 'rb' + offset = -8 # initialize offset + while -offset < filesize: # offset cannot exceed file size + fp.seek(offset, 2) # read # offset chars from eof(represent by number '2') + lines = fp.readlines() # read from fp to eof + if len(lines) >= 2: # if contains at least 2 lines + return lines[-1] # then last line is totally included + else: + offset *= 2 # enlarge offset + fp.seek(0) + lines = fp.readlines() + return lines[-1] + except FileNotFoundError: + print(filename + ' not found!') + return None + + def tail(file, taillines=500, return_str=True, avg_line_length=None): + """ + 大文件的尾行,小文件会导致报错 + taillines : 读取尾部多少行 + avg_line_length:每行字符平均数, + return_str:返回类型,默认为字符串,False为列表。 + offset:每次循环相对文件末尾指针偏移数 + f.tell() 当前指针位置 + f.seek(a,b) a 偏移量, b:0 1 2 ,文件头 当前位置 文件尾部 + """ + with open(file, errors='ignore') as f: + if not avg_line_length: + f.seek(0, 2) + f.seek(f.tell() - 3000) + avg_line_length = int(3000 / len(f.readlines())) + 10 + f.seek(0, 2) + end_pointer = f.tell() + offset = taillines * avg_line_length + if offset > end_pointer: + f.seek(0, 0) + lines = f.readlines()[-taillines:] + return "".join(lines) if return_str else lines + offset_init = offset + i = 1 + while len(f.readlines()) < taillines: + location = f.tell() - offset + f.seek(location) + i += 1 + offset = i * offset_init + if f.tell() - offset < 0: + f.seek(0, 0) + break + else: + f.seek(end_pointer - offset) + lines = f.readlines() + if len(lines) >= taillines: + lines = lines[-taillines:] + + return "".join(lines) if return_str else lines + + +if __name__ == "__main__": + d = DataPlot() + + + \ No newline at end of file diff --git a/handheld.py b/handheld.py index e3845ef..ce9cc8d 100644 --- a/handheld.py +++ b/handheld.py @@ -15,6 +15,7 @@ import locale import struct import numpy as np from pathlib import PurePath,Path +from pubsub import pub from myconfig import CURRENT_DIR,DATA_DIR,OUTPUT_DIR,NEWLINE,ROWFACTOR,SAVE_EXT_NAME,TOKEN from myconfig import DeviceType,RamsesSURFACE,RamsesAWRAMS,RamsesPROFILE from tools.mylogger import log @@ -413,6 +414,12 @@ class HandHeld(object): if self.device_type == DeviceType.PROFILE.name: self.device_enum = RamsesPROFILE + def __set_msg(self, flag, d): + self.msg = {} + self.msg.update( {"flag":flag} ) + self.msg.update( {"data":d} ) + pass + def getDataFileList(self, ): self.hhp.getDataFileList() self.filelist = self.hhp.getFilelist() @@ -457,6 +464,8 @@ class HandHeld(object): log.error( "处理传感器文件" + self.sensor_path_fname.name + "出现错误",__name__,"dealAllMeasurements") raise MyException( "处理传感器文件" + self.sensor_path_fname.name + "出现错误" ) pass + self.__set_msg('notice', '处理文件完成') + pub.sendMessage('update' , msg=self.msg) log.info(f"Finished !! ", __name__, "dealAllMeasurements") return True,self.error_result pass @@ -464,7 +473,7 @@ class HandHeld(object): def dealOneHandheldMeasurement(self, fpath:Path): '''handheld一次测量包含多组数据''' # 调用handheldbuf 处理,将一组数据提交出来 - log.info(f" 手持一个文件,多组测量数据", __name__, "dealOneHandheldMeasurement") + log.info(f" 处理一个文件,多组测量数据", __name__, "dealOneHandheldMeasurement") if len(self.filelist)<1: pass @@ -519,49 +528,49 @@ class HandHeld(object): self.__do_sensor_dict_interpo() # 选择追加保存, 一个Lsky 可能多组文件,只能单独保存为 Lsky Esky ..Rs - self.appendSave() - # self.checkAndSaveData( ) - # self.getLwRsAndSave() - # path_info_txt = self.output_path.joinpath( "info.txt" ) - # self.save_dict_to_file( self.info_dict, path_info_txt ) - - def dealOneGroup(self, ): - # 分组,并获得平均值, 255个未插值结果 (依据 measurement_interval measurement_repeat) - self.output_path = OUTPUT_DIR - self.getAvg( self.intensity_before_avg ) - - # 插值 - self.real_wavelength = self.getWavelenthDict() - self.__do_sensor_dict_interpo() - - self.ymdhms = "20"+ str(self.info_dict['year']) + '_' \ - + str(self.info_dict['month']) + '_' \ - + str(self.info_dict['day']) + '_' \ - + str(self.info_dict['hour']) + '_' \ - + str(self.info_dict['minute']) + '_' \ - + str(self.info_dict['second']) + # self.appendSave() + self.getLwRs() + self.checkAndSaveData( ) + path_info_txt = self.output_path.joinpath( "info.txt" ) + self.save_dict_to_file( self.info_dict, path_info_txt ) + + # def dealOneGroup(self, ): + # # 分组,并获得平均值, 255个未插值结果 (依据 measurement_interval measurement_repeat) + # self.output_path = OUTPUT_DIR + # self.getAvg( self.intensity_before_avg ) + + # # 插值 + # self.real_wavelength = self.getWavelenthDict() + # self.__do_sensor_dict_interpo() + + # self.ymdhms = "20"+ str(self.info_dict['year']) + '_' \ + # + str(self.info_dict['month']) + '_' \ + # + str(self.info_dict['day']) + '_' \ + # + str(self.info_dict['hour']) + '_' \ + # + str(self.info_dict['minute']) + '_' \ + # + str(self.info_dict['second']) - self.output_path = self.output_path.joinpath( self.ymdhms ) - self.appendSave() - # self.checkAndSaveData( ) - # self.getLwRsAndSave() - # path_info_txt = self.output_path.joinpath( "info.txt" ) - # self.save_dict_to_file( self.info_dict, path_info_txt ) - - def dealOneMeasurement(self, fpath:Path): - '''handheld一次测量包含多组数据''' - # 调用handheldbuf 处理,将一组数据提交出来 - log.info(f"dealOneMeasurement: 一组测量数据", __name__, "dealOneMeasurement") - if len(self.filelist)<1: - pass - - # 当前文件名 - self.current_filepath = fpath - self.current_measure_time = self.hhp.getCurrentMeasureTimeFromPath(fpath) # ?? - self.hhb.readFile2Buf(fpath) - self.decode_sensor_buf() - self.real_wavelength = self.getWavelenthDict() - self.dealOneGroup() + # self.output_path = self.output_path.joinpath( self.ymdhms ) + # self.appendSave() + # # self.checkAndSaveData( ) + # # self.getLwRsAndSave() + # # path_info_txt = self.output_path.joinpath( "info.txt" ) + # # self.save_dict_to_file( self.info_dict, path_info_txt ) + + # def dealOneMeasurement(self, fpath:Path): + # '''handheld一次测量包含多组数据''' + # # 调用handheldbuf 处理,将一组数据提交出来 + # log.info(f"dealOneMeasurement: 一组测量数据", __name__, "dealOneMeasurement") + # if len(self.filelist)<1: + # pass + + # # 当前文件名 + # self.current_filepath = fpath + # self.current_measure_time = self.hhp.getCurrentMeasureTimeFromPath(fpath) # ?? + # self.hhb.readFile2Buf(fpath) + # self.decode_sensor_buf() + # self.real_wavelength = self.getWavelenthDict() + # self.dealOneGroup() def decode_sensor_buf(self,) : @@ -685,11 +694,15 @@ class HandHeld(object): self.newFileByFunc( self.device_enum(1).name ) self.newFileByFunc( self.device_enum(2).name ) self.newFileByFunc( self.device_enum(3).name ) + self.newFileByFunc( self.device_enum(4).name ) + self.newFileByFunc( self.device_enum(5).name ) pass self.appendFileByFunc( self.device_enum(1).name ) self.appendFileByFunc( self.device_enum(2).name ) self.appendFileByFunc( self.device_enum(3).name ) + self.appendFileByFunc( self.device_enum(4).name ) + self.appendFileByFunc( self.device_enum(5).name ) def newFileByFunc(self, func:str) -> None: self.mydir.newFileIfNot( func+SAVE_EXT_NAME) @@ -713,26 +726,37 @@ class HandHeld(object): def clearRes(self, ) -> None: self.res = { } - - def getLwRsAndSave(self, ) -> bool: + + def getLwRs(self, ) -> bool: """ 并计算Lw Rs并保存 """ Lw = self.res["Lwater"] - ROWFACTOR * self.res["Lsky"] - self.res.update({ "Lw" : Lw }) + self.res.update({ self.device_enum(4).name : Lw }) Rs = self.res["Lw"] / self.res["Esky"] - self.res.update({ "Rs" : Rs }) - self.mydir.setBaseDir(self.output_path) #基路径 + self.res.update({ self.device_enum(5).name : Rs }) + + return True + + # def getLwRsAndSave(self, ) -> bool: + # """ + # 并计算Lw Rs并保存 + # """ + # Lw = self.res["Lwater"] - ROWFACTOR * self.res["Lsky"] + # self.res.update({ "Lw" : Lw }) + # Rs = self.res["Lw"] / self.res["Esky"] + # self.res.update({ "Rs" : Rs }) + # self.mydir.setBaseDir(self.output_path) #基路径 - # 保存 + # # 保存 - if self.current_group_num == 0: - self.newFileByFunc( "Lw" ) - self.newFileByFunc( "Rs" ) - pass + # if self.current_group_num == 0: + # self.newFileByFunc( "Lw" ) + # self.newFileByFunc( "Rs" ) + # pass - self.appendFileByFunc( "Lw" ) - self.appendFileByFunc( "Rs" ) + # self.appendFileByFunc( "Lw" ) + # self.appendFileByFunc( "Rs" ) return True diff --git a/mypanel.py b/mypanel.py index 8c0db77..fc005f6 100644 --- a/mypanel.py +++ b/mypanel.py @@ -1,4 +1,100 @@ import wx +import numpy as np +from enum import Enum +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas #FigureCanvasWxAgg +# from matplotlib.backends.backend_wx import NavigationToolbar2Wx as NavigationToolbar # FIgure 导航 +from matplotlib.figure import Figure + +class LineColor(Enum): + RED = 0 + ORANGE = 1 + YELLOW = 2 + GREEN = 3 + CYAN = 4 + BLUE = 5 + PURPLE = 6 + + +class Plot(wx.Panel): + ''' + # 需要在 Frame 实例化一个实例 + # 改变需要对实例化后的进行操作 + ''' + ''' + Matplotlib Panel 单独拿出来画图 + 可以 __do_layout + 可以 __add_widgets + 可以 button事件 + 可以鼠标事件 + ''' + def __init__(self,parent): + ''' + * panel 初始化后的样子 + ''' + super(Plot,self).__init__(parent) + # 本地化语言 + self.locale = wx.Locale(wx.LANGUAGE_CHINESE_SIMPLIFIED) + + self.Figure = Figure(figsize=(4,3)) # 4,3 为英寸 + self.axes = self.Figure.add_axes([0.1,0.1,0.8,0.8],facecolor="lightgray") # 坐标系起始位置 + self.FigureCanvas = FigureCanvas(self,-1,self.Figure) + + #继承鼠标移动显示鼠标处坐标的事件 + # self.FigureCanvas.mpl_connect('motion_notify_event',self.MPLOnMouseMove) + + # self.NavigationToolbar = NavigationToolbar(self.FigureCanvas) + + # self.StaticText = wx.StaticText(self,-1,label=u'坐标信息') + + # self.SubBoxSizer = wx.BoxSizer(wx.HORIZONTAL) + # self.SubBoxSizer.Add(self.NavigationToolbar,proportion =0, border = 2,flag = wx.ALL | wx.EXPAND) + # self.SubBoxSizer.Add(self.StaticText,proportion =-1, border = 2,flag = wx.ALL | wx.EXPAND) + + self.TopBoxSizer = wx.BoxSizer(wx.VERTICAL) + # self.TopBoxSizer.Add(self.SubBoxSizer,proportion =-1, border = 2,flag = wx.ALL | wx.EXPAND) + self.TopBoxSizer.Add(self.FigureCanvas,proportion =-10, border = 2,flag = wx.ALL | wx.EXPAND) + + self.SetSizer(self.TopBoxSizer) + + self.purewater_legend = (" Rs" + ,"Wavelength (nm)" + ," Rs " ) + + self.measure_legend = (" Rs" + ,"Wavelength (nm)" + ," Rs" ) + + def set_axes_title(self,title): + self.axes.set_title(title) + + def set_axes_xlabel(self,x): + self.axes.set_xlabel(x) + + def set_axes_ylable(self,y): + self.axes.set_ylabel(y) + + def set_title_x_y(self,title, x, y): + self.axes.set_title(title) + self.axes.set_xlabel(x) + self.axes.set_ylabel(y) + + def plot_one( self, time_, wavelength:np.ndarray, data:np.ndarray, color="green" ): + self.axes.plot(wavelength, data, color=color, linewidth=0.5 , label=time_ ) + self.axes.legend( ) + self.axes.grid( True ) + self.FigureCanvas.draw() + + + def plot_multi( self, tm, wavelength:np.ndarray, data:np.ndarray ): + len_ = len(data) + for i in range(len_): + self.axes.plot(wavelength, data[i], color=LineColor(i).name.lower(), linewidth=0.5 , label=tm[i] ) + self.axes.legend( ) + self.axes.grid(True) + self.FigureCanvas.draw() + + def clear_past( self, ): + self.axes.clear() class MyPanel(wx.Panel): """docstring for MyPanel.""" diff --git a/mythread.py b/mythread.py new file mode 100644 index 0000000..b2ba0e1 --- /dev/null +++ b/mythread.py @@ -0,0 +1,126 @@ +import threading +import time + +class Mythead(threading.Thread): + '''线程守护''' + def __init__(self ): + super(Mythead, self).__init__() + pass + + def set_task(self, func, *args): + self.func = func + self.args = args + + def run(self): + # print(f" --- {len(self.args)}") + if len(self.args) > 0: + self.func(self.args) + else: + self.func( ) + +class Multithread(threading.Thread): + ''' + 多线程 + 子线程.join() -> ( 设置在start之后, 等所有阻塞线程运行完, 再运行主线程 ) + 子线程.setDaemon(True) -> 设置子线程A为守护线程, 主线程所在的进程内所有非守护线程统统运行完毕, + 无论子线程A有没有结束, 程序都结束 + Method: + + ''' + def __init__(self): + super(Multithread, self).__init__() + self.__tasks = [] + self.act = [] + # self.__block = False + pass + + # def set_task( self, tasks ): + # self.__tasks = tasks + + def add_task(self, func, daemon=False, join=True,args=()): + tmp_dict = {} + tmp_dict.update( {"func" : func}) + if daemon == True: + tmp_dict.update( {"daemon" : True}) + else: + tmp_dict.update( {"daemon" : False}) + if join == True: + tmp_dict.update( {"join" : True}) + else: + tmp_dict.update( {"join" : False}) + if args == (): + tmp_dict.update( {"args" : ()}) + else: + tmp_dict.update( {"args" : args}) + self.__tasks.append( tmp_dict ) + + def remove_tasks(self, ): + self.__tasks = [] + self.act = [] + + def add_task_2_act(self, task): + t = threading.Thread( target = task['func'], args = task['args'] ) + self.act.append(t) + t.start() + + def execute_one_act(self,i): + if self.__tasks[i]['join']: + self.act[i].join() # 子线程阻塞完毕再运行主线程 + pass + + def prepare_tasks(self): + self.act = [] + for task in self.__tasks: + self.add_task_2_act(task) + + def execute_tasks(self): + try: + for i in range( len(self.act) ): + self.execute_one_act( i ) + pass + except Exception as e: + print(e) + + def prepare_tasks(self): + self.act = [] + for task in self.__tasks: + t = threading.Thread( target = task['func'], args = task['args'] ) + self.act.append(t) + t.start() + + def simultaneously_execute_tasks(self): + self.prepare_tasks() + self.execute_tasks() + + def sequently_execute_tasks(self): + for task in self.__tasks: + t = threading.Thread( target = task['func'], args = task['args'] ) + t.start() + t.join() + + + def t1(self): + print("thread1...") + time.sleep(10) + print("thread1... after sleep...") + + def t2(self): + print("thread2...") + time.sleep(5) + print("thread2... after sleep...") + + def t3(self): + print("thread3...") + time.sleep(3) + print("thread3... after sleep...") + +if __name__ == '__main__': + mt = Multithread() + mt.add_task(mt.t1) + mt.add_task(mt.t2) + mt.add_task(mt.t3) + # mt.prepare_tasks() # 线程同步运行 + # mt.execute_tasks() + # mt.simultaneously_execute_tasks() + mt.sequently_execute_tasks() + diff --git a/retrieve.yml b/retrieve.yml index ba0f0ee..5e22497 100644 --- a/retrieve.yml +++ b/retrieve.yml @@ -1,3 +1,5 @@ +LineBegin: 1 +LineInterval: 1 beginWL: 350 endWL: 950 interval: 1 diff --git a/uiconfig/ui_plot_setting.py b/uiconfig/ui_plot_setting.py new file mode 100644 index 0000000..dee0670 --- /dev/null +++ b/uiconfig/ui_plot_setting.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +import wx +# from configobj import ConfigObj +from myconfig import MyConfig +from myconfig import YAML_FILE_NAME + +class UI_Plot_Setting(wx.Dialog): + """ + @description : 绘图 配置 + """ + def __init__(self, parent, id): + # 串口页面配置 + super(UI_Plot_Setting, self).__init__( parent ,id = id ) + self.config = MyConfig() + self.InitUI() + self.SetSize((400, 400)) + self.SetTitle(" 绘图 序列号 ") + + def InitUI(self): + self.config_yml = self.config.read_rtv_yaml() + + self.panel = wx.Panel(self) + self.vbox = wx.BoxSizer(wx.VERTICAL) + + self.sb = wx.StaticBox(self.panel, label='指定绘图设置 ') + self.sbs = wx.StaticBoxSizer(self.sb, orient=wx.VERTICAL) + + self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText1 = wx.StaticText(self.panel, label='起始行号 ',size=(60, -1), style=wx.ALIGN_CENTRE_VERTICAL ) + self.textCtrl1 = wx.TextCtrl(self.panel, value="",size=(250,25) ) + tmp = self.get_str_from_config( "LineBegin" ) + if tmp is not None: + self.textCtrl1.SetValue(tmp) + self.hbox1.Add(self.staticText1, flag=wx.TOP|wx.LEFT, border=5) + self.hbox1.Add(self.textCtrl1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.hbox1, flag=wx.TOP|wx.LEFT, border= 5) + + self.hbox2 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText2 = wx.StaticText(self.panel, label='间隔行号: ' ,size=(60, -1)) + # self.staticText2_1 = wx.StaticText(self.panel, label='分钟 ' ,size=(60, -1)) + self.textCtrl2 = wx.TextCtrl(self.panel, value="",size=(250,25)) + tmp = self.get_str_from_config( "LineInterval" ) + if tmp is not None: + self.textCtrl2.SetValue(tmp) + self.hbox2.Add(self.staticText2, flag=wx.TOP|wx.LEFT, border=5) + self.hbox2.Add(self.textCtrl2,flag=wx.TOP|wx.LEFT, border=5) + # self.hbox2.Add(self.staticText2_1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.hbox2, flag=wx.TOP|wx.LEFT, border=5) + + self.panel.SetSizer(self.sbs) + + self.hbox_0 = wx.BoxSizer(wx.HORIZONTAL) + self.okButton = wx.Button(self, label=u'保存配置') + self.closeButton = wx.Button(self, label='Close') + self.hbox_0.Add(self.okButton) + self.hbox_0.Add(self.closeButton, flag = wx.LEFT, border=5) + + # 添加 vbox 到panel + self.vbox.Add(self.panel, proportion=1, + flag=wx.ALL | wx.EXPAND, border=5) + + self.vbox.Add(self.hbox_0, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) + + self.SetSizer(self.vbox) + + self.okButton.Bind(wx.EVT_BUTTON, self.OnSave) + self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose) + + def get_str_from_config( self, key ): + return str(self.config_yml[key]) + pass + + def set_config_by_key_val( self, key, val ): + # print(f" {key} current type {type( self.config_yml[section][key] )}") + if type( self.config_yml [key] ) == int: + self.config_yml [key] = int(val) + elif type( self.config_yml [key] ) == float: + self.config_yml [key] = float(val) + else: + self.config_yml[key] = val + pass + + + def saveData(self, e): + pass + + def OnClose(self, e): + + self.Destroy() + + def OnSave(self, e): + success = True + # 赋值字典,写入文件 + self.set_config_by_key_val( "LineBegin",self.textCtrl1.GetValue( )) + self.set_config_by_key_val( "LineInterval",self.textCtrl2.GetValue( )) + self.config.write_rtv_yaml(self.config_yml) + del self.config + if success: + self.EndModal(wx.ID_OK) \ No newline at end of file diff --git a/yiwinframe.py b/yiwinframe.py index 4921838..ffef5f6 100644 --- a/yiwinframe.py +++ b/yiwinframe.py @@ -2,20 +2,23 @@ import wx import os import time import threading -from pathlib import * -# from configobj import ConfigObj +from pathlib import PurePath,Path +from pubsub import pub + from listctrl import Listctrl -from mypanel import MyPanel +from mypanel import MyPanel,Plot,LineColor from uiconfig.uisensor import UISensor # from uiconfig.uilogging import UILogging from uiconfig.uiabout import About from uiconfig.uihelp import Help +from uiconfig.ui_plot_setting import UI_Plot_Setting from myconfig import TOKEN,DeviceType,YAML_FILE_NAME,RETRIEVE_CFG_FILE -from myconfig import MyConfig +from myconfig import MyConfig,RamsesFunc +from mythread import Mythead from configuration import Configuration from handheld import HandHeld,HandHeldBuf @@ -28,6 +31,12 @@ ID_MEASURE = 1 ID_SENSOR_SETTING = 11 ID_LOGGING_SETTING = 12 ID_CAL_INFO = 13 +ID_DISPLAY_PARA = 14 + +ID_PLOT_LAST = 15 +ID_PLOT_LAST_7 = 16 +ID_PLOT_7 = 17 +ID_PLOT_SETTING = 18 ID_HELP = 21 ID_ABOUT = 22 @@ -66,7 +75,12 @@ class YiwinFrame(wx.Frame): self.BoxSizer.Add( self.mypanel, proportion =-10, border = 0, flag = wx.ALL | wx.EXPAND) self.static_text = self.mypanel.staticText1 # 隐藏 等待show - self.mypanel.Show() + self.mypanel.Hide() + + self.plotpanel = Plot( self ) # 调用自己建立的 Listctrl panel 类 + self.BoxSizer.Add( self.plotpanel, proportion =-10, border = 0, flag = wx.ALL | wx.EXPAND) + self.plotpanel.set_title_x_y(*self.plotpanel.purewater_legend) + self.plotpanel.Show() self.statusBar = self.CreateStatusBar() # 创建状态栏 self.statusBar.SetFieldsCount(2) # 状态栏分成3个区域 @@ -81,8 +95,8 @@ class YiwinFrame(wx.Frame): log.info(f"system init....",__name__, "__init__") self.mycfg = MyConfig() self.hh = HandHeld() - - # self.hhb = HandHeldBuf() + self.mythread = Mythead() + pub.subscribe( self.updateDisplay, "update") pass @@ -98,10 +112,20 @@ class YiwinFrame(wx.Frame): settingMenu.Append(ID_CAL_INFO, u'&获取标定信息', ' ') settingMenu.AppendSeparator() settingMenu.Append(ID_MEASURE, u'&处理数据', ' ') - # settingMenu.AppendSeparator() - # settingMenu.Append(ID_LOGGING_SETTING, u'&采集设置', ' ') + settingMenu.AppendSeparator() + settingMenu.Append(ID_LOGGING_SETTING, u'&采集设置', ' ') self.menubar.Append(settingMenu, u'&系统 ') + plotMenu = wx.Menu() + plotMenu.Append(ID_PLOT_LAST, u'&最后一条', '...') + plotMenu.AppendSeparator() + plotMenu.Append(ID_PLOT_LAST_7, u'&最后七条', ' ') + plotMenu.AppendSeparator() + plotMenu.Append(ID_PLOT_7, u'&指定七条', ' ') + plotMenu.AppendSeparator() + plotMenu.Append(ID_PLOT_SETTING, u'&指定设置', ' ') + self.menubar.Append(plotMenu, u'&绘图 ') + aboutMenu = wx.Menu() aboutMenu.Append(ID_HELP, u'&帮助', 'help...') aboutMenu.AppendSeparator() @@ -126,6 +150,11 @@ class YiwinFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.OnDealData, id=ID_MEASURE) # self.Bind(wx.EVT_MENU, self.OnLoggingSetting, id=ID_LOGGING_SETTING) + self.Bind(wx.EVT_MENU, self.OnPlotLast, id=ID_PLOT_LAST ) + self.Bind(wx.EVT_MENU, self.OnPlotLast7, id=ID_PLOT_LAST_7 ) + self.Bind(wx.EVT_MENU, self.OnPlot7, id=ID_PLOT_7) + self.Bind(wx.EVT_MENU, self.OnPlotSetting, id=ID_PLOT_SETTING) + self.Bind(wx.EVT_MENU, self.OnHelpConfig, id=ID_HELP) self.Bind(wx.EVT_MENU, self.OnAboutConfig, id=ID_ABOUT) pass @@ -135,6 +164,36 @@ class YiwinFrame(wx.Frame): self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) #绑定一个定时器事件 pass + def updateDisplay(self, msg): + log.warning(f" updateDisplay 。。 {msg['data']}") + if msg['flag'] == "notice": + self.__update_notice(msg['data']) + pass + if msg['flag'] == "data": + # log.info(f" ... update .{msg['data']}........... " ) + self.__update_data(msg['data']) + pass + pass + + def __update_notice(self,msg): + log.info(f" .......{msg}... ",__name__,'__update_notice') + self.alterStatus_0( msg) + self.popDialog( msg ) + pass + + def __update_data(self,data ): + log.info(f" .......... ",__name__,'__update_data') + self.plotpanel.set_axes_title( data['tm']) + res = data['res'] + x = self.hh.wavelength.tolist() + length = len(data) + self.plotpanel.clear_past() + for display in RamsesFunc: + self.plotpanel.plot_one(display.name, x, res[display.name],color= LineColor(display.value).name ) + pass + pass + + def OnStart( self, event ): log.info(f"OnStart....interval: {self.interval} min, port: {self.port}") # self.m = SerialThread() @@ -181,11 +240,20 @@ class YiwinFrame(wx.Frame): MyException( f"System Configuration is empty." ) pass - if self.hh.dealAllMeasurements( ): - self.onNotify("正在处理数据" ) - self.statusBar.SetStatusText(u" 数据处理完成......", 0) - self.onNotify("处理数据已经结束" ) - pass + # 处理数据 + self.alterStatus_0(" 正在处理数据...." ) + try: + self.mythread.set_task( self.hh.dealAllMeasurements ) + self.mythread.start() + except Exception as e: + log.error(e) + pass + + # if self.hh.dealAllMeasurements( ): + # self.onNotify("正在处理数据" ) + # self.statusBar.SetStatusText(u" 数据处理完成......", 0) + # self.onNotify("处理数据已经结束" ) + # pass def OnCalInfo(self,e): '''依据传感器获取标定文件信息''' @@ -235,7 +303,29 @@ class YiwinFrame(wx.Frame): def popDialog(self, msg, msg_type=u"错误提示"): with wx.MessageDialog( self, msg, msg_type, wx.OK )as dlg: dlg.ShowModal() - + + def OnPlotLast(self,e): + pass + + def OnPlotLast7(self,e): + pass + + def OnPlot7(self,e): + pass + + + def OnPlotSetting(self,e): + with UI_Plot_Setting( + self, + -1 ) as Dialog_Sensor_Setting: + Dialog_Sensor_Setting.CenterOnParent() + resultLog = Dialog_Sensor_Setting.ShowModal() + + if resultLog == wx.ID_OK: + log.info( " Plot config dialog confirm, call back " ) + self.__read_config() + pass + def OnSensorSetting(self,e): with UISensor( self, @@ -277,61 +367,4 @@ class YiwinFrame(wx.Frame): self.Close() - -# class SerialThread(threading.Thread): -# """进度条类 """ -# def __init__(self, parent): -# """ -# :param parent: 主线程UI -# """ -# super(SerialThread, self).__init__() # 继承 -# self.parent = parent -# # log.info(f"SerialThread ... {self.parent.kh}") -# self.start() -# self.join() -# # self.setDaemon(True) # 设置为守护线程, 即子线程是守护进程,主线程结束子线程也随之结束。 - - -# def stop(self): -# self.parent.kh.disconnect() -# log.info(" Serial stop.... ") -# pass - - # def run(self): - # log.info(" Serial run.... ") - # wx.CallAfter(self.parent.OnRcv) - - # wx.CallAfter(self.parent.update_process_bar, count) # 调用parent的函数 - # wx.CallAfter(self.parent.close_process_bar) # destroy进度条 - - # def OnSerialThreadStart(self): - # self.m = SerialThread(self) - # pass - - # def OnSerialThreadStop(self): - # self.m.stop() - # pass - - # def OnDisplaySave(self): - # ''' - # 保存数据 self.result - # ''' - # log.info(f"OnDisplaySave ....") - # # self.m = SerialThread(self) - # # self.kh.flush() - # self.OnSerialThreadStart() - - - # def OnRcv( self ): - # log.info(f"OnRcv....") - # self.kh.setPort(self.port) - # if not self.OnDetectPort: - # MyException(f"Can not find port : {self.port}") - # log.info(f"{self.port} ok!") - # # if not self.kh: - # # self.kh = KH3000(self.port) - # # self.result = self.kh.OneMeasure() - # log.info( f"OnRcv success {self.result}", __class__.__name__ ) - # self.OnSave() - # self.OnDisplay() - # pass \ No newline at end of file + \ No newline at end of file