示例#1
0
class App(Tk):  #the main class for the main window
    def __init__(self):
        Tk.__init__(self)

        # window properties
        self.title(string="Screen Recorder")
        self.iconbitmap("icon.ico")
        self.resizable(width=False, height=False)

        ffmpegAvailable = False
        for item in os.listdir():
            if item == "ffmpeg.exe":
                ffmpegAvailable = True
                break
        if not ffmpegAvailable:
            self.withdraw()
            if messagebox.askyesno(
                    "FFmpeg Not Found",
                    "ffmpeg.exe could not be found in screen recorder's directory. Do you want to be redirected to the ffmpeg download website?"
            ):
                webbrowser.open_new_tab("https://ffmpeg.zeranoe.com/builds/")
            exit()
        self.cmdGen = cmdGen(
        )  # create a command generator object to store settings

        # file name
        label1 = Label(self, text="File Name:")
        label1.grid(row=0, column=0, sticky="")
        self.entry1 = Entry(self)
        self.entry1.grid(row=0, column=1, sticky="ew")

        # ensure the existance of the "ScreenCaptures" directory
        try:
            os.mkdir("ScreenCaptures")
        except FileExistsError:
            pass
        os.chdir("ScreenCaptures")

        # find a default file name that is currently available.
        defaultFile = "ScreenCapture.mp4"
        available = False
        fileNum = 0
        while available == False:
            hasMatch = False
            for item in os.listdir():
                if item == defaultFile:
                    hasMatch = True
                    break
            if not hasMatch:
                available = True
            else:
                fileNum += 1
                defaultFile = "ScreenCapture" + str(fileNum) + ".mp4"
        os.chdir("..")
        self.entry1.insert(END, defaultFile)

        # radio buttons determine what to record
        self.what = StringVar()
        self.what.set("desktop")
        self.radio2 = Radiobutton(self,
                                  text="record the window with the title of: ",
                                  variable=self.what,
                                  value="title",
                                  command=self.enDis1)
        self.radio1 = Radiobutton(self,
                                  text="record the entire desktop",
                                  variable=self.what,
                                  value="desktop",
                                  command=self.enDis)
        self.radio1.grid(row=1, column=0, sticky="w")
        self.radio2.grid(row=2, column=0, sticky="w")
        self.entry2 = Entry(self, state=DISABLED)
        self.entry2.grid(row=2, column=1, sticky="ew")

        # initialize webcam
        self.webcamdevices = Webcam.listCam()
        self.webcamrecorder = Webcam.capturer("")

        # "record from webcam" checkbox
        self.rcchecked = IntVar()
        self.recordcam = Checkbutton(self,
                                     text="Record from webcam",
                                     command=self.checkboxChanged,
                                     variable=self.rcchecked)
        self.recordcam.grid(row=3, column=0)

        # a drop-down allowing you to select the webcam device from the available directshow capture devices
        self.devicename = StringVar(self)
        if self.webcamdevices:
            self.devicename.set(self.webcamdevices[0])
            self.deviceselector = OptionMenu(self, self.devicename,
                                             *self.webcamdevices)
            self.deviceselector.config(state=DISABLED)
            self.deviceselector.grid(row=3, column=1)
        else:
            self.devicename.set("NO DEVICES AVAILABLE")
            self.recordcam.config(state=DISABLED)
            self.deviceselector = OptionMenu(self, self.devicename,
                                             "NO DEVICES AVAILABLE")
            self.deviceselector.config(state=DISABLED)
            self.deviceselector.grid(row=3, column=1)

        self.opButton = Button(self,
                               text="⚙ Additional Options...",
                               command=self.openSettings)
        self.opButton.grid(row=4, column=1, sticky='e')

        # the "start recording" button
        self.startButton = Button(self,
                                  text="⏺ Start Recording",
                                  command=self.startRecord)
        self.startButton.grid(row=5, column=0, columnspan=2)

        # some variables
        self.recording = False  # are we recording?
        self.proc = None  # the popen object for ffmpeg (during screenrecord)
        self.recorder = recordFile.recorder(
        )  # the "recorder" object for audio (see recordFile.py)
        self.mergeProcess = None  # the popen object for ffmpeg (while merging video and audio files)

        # start the ffmpeg monitoring callback
        self.pollClosed()

    def openSettings(self):
        self.settings = settingsWin(self, self.cmdGen, self.recorder)

    def pollClosed(self):
        """callback that repeats itself every 100ms. Automatically determines if ffmpeg is still running."""
        if self.recording:
            if self.proc.poll() != None:
                self.startRecord()
                messagebox.showerror(
                    "ffmpeg error", "ffmpeg has stopped working. ERROR: \n" +
                    str(self.proc.stderr.read()).replace('\\r\\n', '\n'))
            if self.recorder.error:
                self.startRecord()
        if self.mergeProcess and self.recording == False:
            if self.mergeProcess.poll() != None:
                self.startButton.config(text="⏺ Start Recording", state=NORMAL)
                self.title(string="Screen Recorder")
        self.after(100, self.pollClosed)

    def enDis(self):
        """Called when the "desktop" radio button is pressed"""
        self.entry2.config(state=DISABLED)
        # self.what.set("desktop")

    def enDis1(self):
        """Called when the "window title" radio button is pressed"""
        self.entry2.config(state=NORMAL)
        # self.what.set("title")

    def checkboxChanged(self):
        """Called when the "record webcam" checkbox is checked or unchecked."""
        #self.rcchecked = not self.rcchecked
        if self.rcchecked.get():
            self.deviceselector.config(state=NORMAL)
        else:
            self.deviceselector.config(state=DISABLED)

    def startRecord(self):
        """toggles recording. Will start conversion subprocess on recording completion"""
        if self.recording == False:
            # change the window
            self.title(string="Screen Recorder (Recording...)")
            self.startButton.config(text="⏹️ Stop Recording")
            self.filename = self.entry1.get()

            # disable interface
            self.entry1.config(state=DISABLED)
            self.radio1.config(state=DISABLED)
            self.radio2.config(state=DISABLED)
            self.deviceselector.config(state=DISABLED)
            self.opButton.config(state=DISABLED)
            if self.what.get() == "title":
                self.entry2.config(state=DISABLED)

            # ensure the existence of the "tmp" directory
            try:
                os.mkdir("tmp")
            except FileExistsError:
                pass

            # start screen recording process
            self.recording = True
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE

            # self.cmdGen.setFps(60)
            # self.cmdGen.setEncode('nvenc_h264') # CPU: mpeg4 // NVIDIA: h264_nvenc // AMD: no.
            self.cmdGen.setSource(self.what.get() == "title",
                                  self.entry2.get())
            command = self.cmdGen.getCmd("tmp/tmp.mkv")
            self.proc = subprocess.Popen(args=command,
                                         startupinfo=startupinfo,
                                         stderr=subprocess.PIPE)

            # start audio recording
            self.recorder.record("tmp/tmp.wav")

            # start webcam recording, if checked
            self.recordcam.config(state=DISABLED)
            if self.rcchecked.get() and self.webcamdevices:
                self.webcamrecorder.setDevice(str(self.devicename.get()))
                self.webcamrecorder.startCapture("tmp/webcamtmp.mkv")

            # minimize the window to get it out of the way of the recording
            self.iconify()
        elif self.recording == True:
            self.deiconify()
            defaultFile = self.filename

            # re-enable interface
            self.entry1.config(state=NORMAL)
            self.radio1.config(state=NORMAL)
            self.radio2.config(state=NORMAL)
            self.opButton.config(state=NORMAL)
            if self.webcamdevices:
                self.recordcam.config(state=NORMAL)
                if self.rcchecked.get():
                    self.deviceselector.config(state=NORMAL)
            if self.what.get() == "title":
                self.entry2.config(state=NORMAL)

            available = False
            fileNum = 0

            # stop all recording processes
            self.recording = False
            self.proc.terminate()
            self.recorder.stop_recording()
            if self.rcchecked.get() and self.webcamdevices:
                self.webcamrecorder.stopCapture()
            try:
                os.mkdir("ScreenCaptures")
            except FileExistsError:
                pass

            # change the window title and button text to reflect the current process
            self.title(string="Screen Recorder (converting...)")
            self.startButton.config(
                text="converting your previous recording, please wait...",
                state=DISABLED)

            # start the video conversion process
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            startupinfo.wShowWindow = subprocess.SW_HIDE
            self.cmdGen.config(audList=self.recorder.devices)
            command = self.cmdGen.getCvtCmd("ScreenCaptures/" + self.filename)
            if not self.recorder.error:
                self.mergeProcess = subprocess.Popen(args=command,
                                                     startupinfo=startupinfo)

            # if self.rcchecked.get():
            #     self.mergeProcess = subprocess.Popen(args= ["ffmpeg","-i",'tmp/tmp.mkv','-i','tmp/tmp.wav','-i','tmp/webcamtmp.mkv','-filter_complex','[2:v] scale=640:-1 [inner]; [0:0][inner] overlay=0:0 [out]',"-shortest",'-map','[out]','-y',"ScreenCaptures/"+self.filename])
            # else:
            #     self.mergeProcess = subprocess.Popen(args= ["ffmpeg","-i",'tmp/tmp.mkv','-i','tmp/tmp.wav',"-shortest",'-y',"ScreenCaptures/"+self.filename], startupinfo=startupinfo)

            # change the screen capture name to something that is not taken
            os.chdir("ScreenCaptures")
            while True:
                matches = 0
                for item in os.listdir():
                    if item == defaultFile:
                        matches += 1
                if matches == 0:
                    self.entry1.delete(0, END)
                    self.entry1.insert(END, defaultFile)
                    break
                else:
                    fileNum += 1
                    file = self.filename.split(".")
                    defaultFile = file[0].rstrip("1234567890") + str(
                        fileNum) + "." + file[1]

            os.chdir("../")
示例#2
0
class Assist_Serial_Port():
    def __init__(self):
        self.BTL = [110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, 115200, 128000, 256000]  # 波特率下拉列表框内容
        self.JYW = ['NONE', 'ODD', 'EVEN', 'MARK', 'SPACE']  # 校验位下拉列表框内容
        self.SJW = [5, 6, 7, 8]  # 数据位下拉列表内容
        self.TZW = [1, 1.5, 2]  # 停止位下拉列表内容
        self.CKXX = self.read_serial_info()
        self.PZMC = ['串口号','波特率','校验位','数据位','停止位']
        self.serial_res_hex_bzw = False  # 接收数据框内容显示hex标志位
        self.serial_sen_hex_bzw = False  # 发送数据框内容显示hex标志位
        self.radiobutton_sen_ascii_click_count = 1  # 设置发送ASCII单选框点击次数为0
        self.radiobutton_sen_hex_click_count = 0  # 设置发送HEX单选框点击次数为0

        self.root = Tk(className='串口调试助手')  # 创建一个主窗体,并命名为‘串口调试助手’
        self.root.protocol('WM_DELETE_WINDOW',self.close_window)  # 实现点击窗口关闭按钮,调用self.close_window方法,关闭已经打开的串口,销毁窗口
        self.root.geometry('630x580')  # 设置窗体大小
        self.root.minsize(width=630, height=435)  # 这两句语言限制窗口不能随意变化
        self.root.maxsize(width=630, height=435)

        self.lf = LabelFrame(self.root, text='串口设置')  # 创建标签容器,并且命名为‘串口设置’
        self.lf.grid(padx=8, pady=10,ipadx=3, ipady=5,row=1,column=1,sticky='n')  # 设置标签容器在窗口中的位置

        self.text_res_con = LabelFrame(master=self.root,text='接收设置')  # 创建标签容器,并命名为接收设置
        self.text_res_con.grid(row=1,column=1,sticky='s')  # 设置标签容器在窗口中的位置

        self.text_sen_con = LabelFrame(master=self.root,text='发送设置')  # 创建标签容器,并命名为接收设置
        self.text_sen_con.grid(padx=8, pady=10,row=2,column=1,sticky='nesw')  # 设置标签容器在窗口中的位置

        self.data_rec = LabelFrame(self.root, text='数据日志')  # 创建标签容器,并且命名为‘数据日志’
        self.data_rec.grid(ipadx=3, ipady=5,row=1, column=2, sticky='e')  # 设置标签容器在窗口中的位置

        self.y_scroll = Scrollbar(self.data_rec)  # 创建接收文本框的Y轴下拉框
        self.y_scroll.pack(side=RIGHT,fill=Y)  # 确定位置

        self.result_text = Text(master=self.data_rec,height=22,width=66,yscrollcommand=self.y_scroll.set) # 创建一个多文本组件,用来显示接收的串口信息,并且配置关联滚轴
        self.result_text.pack(side=RIGHT,fill=Y)  # 设置多文本组件在窗口中的位置
        self.y_scroll.config(command=self.result_text.yview)  # 让文本框和滚轴关联起来

        self.data_sen = LabelFrame(self.root, text='数据发送')  # 创建标签容器,并且命名为‘数据日志’
        self.data_sen.grid(ipadx=3, ipady=5,row=2, column=2, sticky='w')  # 设置标签容器在窗口中的位置

        self.send_text = Text(master=self.data_sen,height=6,width=60)  # 创建一个发送文本框
        self.send_text.grid(row=1,column=1,sticky='n')  # 设置标签容器在窗口中的位置

        self.button_send = Button(self.data_sen,text='发送消息',command=self.button_send_serial_click,width=7)  # 创建一个发送文本框
        self.button_send.grid(row=1,column=2,sticky='NSEW')  # 设置串口打开按钮的位置

    '''关闭串口工具窗口触发的函数'''
    def close_window(self):
        ans = messagebox.askyesno('警告',message='确定关闭窗口?')
        print(ans,'ans')
        if ans:
            try:
                self.thd.stop()  # 停止读取串口线程
                '''确保串口会被关掉,修复关掉串口立马更改波特率,显示错误的问题'''
                while self.ser.isOpen():
                    self.ser.close()  # 将串口实例关闭
            except:
                print('关闭窗口')
            self.root.destroy()
        else:
            return

    '''创建串口配置框架'''
    def serial_config_frame(self):
        for temp in enumerate(self.PZMC):
            '''生成标签组'''
            label_name = Label(self.lf, text=temp[1])  # 创建串口标签
            label_name.grid(padx=5,pady=6,column=1,row=temp[0] + 1)   # 设置标签在标签容器中的位置

            '''生成下拉列表框组'''
            if temp[0] == 0:
                self.combobox0 = Combobox(master=self.lf, values=self.CKXX, width=6, height=3,state='readonly')  # 创建下拉列表框
                self.combobox0.current(0)  # 设置下拉列表当前选中项
                self.combobox0.grid(column=2, row=1, sticky='e')  # 设置下拉列表框在标签容器中的位置
                self.combobox0.bind('<Button-1>',self.update_serial_info)
            elif temp[0] == 1:
                self.combobox1 = Combobox(master=self.lf, values=self.BTL, width=6, height=3,state='readonly')  # 创建下拉列表框
                self.combobox1.current(6)   # 设置下拉列表当前选中项
                self.combobox1.grid(column=2, row=2, sticky='e')  # 设置下拉列表框在标签容器中的位置
            elif temp[0] == 2:
                self.combobox2 = Combobox(master=self.lf, values=self.JYW, width=6, height=3,state='readonly')  # 创建下拉列表框
                self.combobox2.current(0)   # 设置下拉列表当前选中项
                self.combobox2.grid(column=2, row=3, sticky='e')  # 设置下拉列表框在标签容器中的位置
            elif temp[0] == 3:
                self.combobox3 = Combobox(master=self.lf, values=self.SJW, width=6, height=3,state='readonly')  # 创建下拉列表框
                self.combobox3.current(3)   # 设置下拉列表当前选中项
                self.combobox3.grid(column=2, row=4, sticky='e')  # 设置下拉列表框在标签容器中的位置
            else:
                self.combobox4 = Combobox(master=self.lf, values=self.TZW, width=6, height=3,state='readonly')  # 创建下拉列表框
                self.combobox4.current(0)   # 设置下拉列表当前选中项
                self.combobox4.grid(column=2, row=5, sticky='e')  # 设置下拉列表框在标签容器中的位置

        self.button_open_serial = Button(self.lf,text='打开串口',command=self.button_open_serial_click)  # 创建串口打开按钮
        self.button_open_serial.grid(row=6,columnspan=5,sticky='s')  # 设置串口打开按钮的位置

    '''串口单击按钮函数'''
    def button_open_serial_click(self):
        if self.button_open_serial['text'] == '打开串口':
            '''下面的try...except...else操作确定当串口被占用报错后,无法在重新打开串口'''
            try:
                self.open_serial_and_config()  # 打开串口
                self.thd = Thread_myself(target=self.serial_read_content)  # 新建线程对象,并且传入串口对象
                self.thd.start()  # 启动串口助手
            except Exception:
                self.button_open_serial['text'] = '打开串口'
                self.result_text.config(state=NORMAL)
                self.result_text.tag_config('text_error_tag', foreground='red')  # 设置插入文本样式
                self.result_text.insert('end','\r\n无法打开串口,请检查串口连接或者是否被占用...\r\n','text_error_tag')
                self.result_text.config(state=DISABLED)
                self.result_text.see(END)  # 文本框总是显示最新内容
            else:
                self.button_open_serial['text'] = '关闭串口'
                self.combobox0.config(state='disabled')  # 打开之后将所有下拉列表框禁用防止误操作
                self.combobox1.config(state='disabled')
                self.combobox2.config(state='disabled')
                self.combobox3.config(state='disabled')
                self.combobox4.config(state='disabled')
        else:
            self.button_open_serial['text'] = '打开串口'
            self.combobox0.config(state='readonly')
            self.combobox1.config(state='readonly')
            self.combobox2.config(state='readonly')
            self.combobox3.config(state='readonly')
            self.combobox4.config(state='readonly')
            try:
                self.thd.stop()  # 停止读取串口线程
                '''确保串口会被关掉,修复关掉串口立马更改波特率,显示错误的问题'''
                while self.ser.isOpen():
                    self.ser.close()  # 将串口实例关闭
            except:
                print('无聊')

    '''打开串口并配置'''
    def open_serial_and_config(self,timeout=5):
        if self.combobox2.get() == 'NONE':  # 判断校验位方式
            parity = 'N'
        elif self.combobox2.get() == 'ODD':
            parity = 'O'
        elif self.combobox2.get() == 'EVEN':
            parity = 'E'
        elif self.combobox2.get() == 'MARK':
            parity = 'M'
        else:
            parity = 'S'

        if self.combobox3.get() == '5':  # 判断数据然后配数据位
            bytesize = 5
        elif self.combobox3.get() == '6':
            bytesize = 6
        elif self.combobox3.get() == '7':
            bytesize = 7
        else:
            bytesize = 8

        if self.combobox4.get() == '1':  # 判断串口停止位
            stopbits = 1
        elif self.combobox4.get() == '1.5':
            stopbits = 1.5
        else:
            stopbits = 2

        '''创建一个串口实例'''
        self.ser = Serial(port=self.combobox0.get(),baudrate=self.combobox1.get(),parity=parity,bytesize=bytesize,stopbits=stopbits,timeout=timeout)
        self.ser.set_buffer_size(rx_size=4096)  # 设置输入缓存去为4096个字节
        self.ser.flushInput()  # 将输入缓存去清空
        print('波特率为%s' %self.ser.baudrate)

    '''读取设备串口信息,并返回串口列表'''
    def read_serial_info(self):
        serial_info = [temp.__getitem__(0) for temp in list_ports.comports()]
        print(serial_info)
        if serial_info:
            return serial_info
        else:
            serial_info = ['No Port!']
            return serial_info

    '''当下拉框被选中时更新串口列表信息'''
    def update_serial_info(self,*args):
        self.combobox0['values'] = self.read_serial_info()

    '''将发送文本框中的内容发送出去'''
    def button_send_serial_click(self):
        '''if逻辑是判断串口有没有打开,如果打开在发送数据,如果没有打开提示打开串口'''
        if self.button_open_serial['text']  == '打开串口':
            messagebox.showwarning('警告','请先打开串口!')
        else:
            try:
                '''判断发送的内容是HEX还是ASCII,根据方式的不同发送方式也不同'''
                if self.serial_sen_hex_bzw:  # HEX方式发送
                    content = self.send_text.get(1.0, 'end').strip()
                    self.ser.write(bytes.fromhex(content))  # HEX方式发送串口数据
                else:  # ASCII方式发送
                    content = self.send_text.get(1.0, 'end').strip().encode().hex()
                    self.ser.write(bytes.fromhex(content))  # ASCII方式发送串口数据
                if content.encode() == b'':
                    messagebox.showwarning('警告', '发送内容不能为空...')
            except Exception:
                messagebox.showerror('错误','请先打开串口...')

    '''串口接收设置'''
    def text_res_config(self):
        '''创建单选框ASCII并配置单选框'''
        self.radiobutton_res_variable = IntVar()  # 设置单选框variable变量,作用是规定value的数值类型
        self.radiobutton_res_dx_acci = Radiobutton(master=self.text_res_con)
        self.radiobutton_res_dx_acci.config(
            text = 'ASCII',  # 单选框名字
            variable = self.radiobutton_res_variable,  # 设置数值类型
            value = 1,  # 设置value数值,同一组单选框中数值必须不一样
            command = self.res_ascii_set  # 绑定单选框单击之后调用的函数
        )
        '''创建单选框HEX并配置单选框'''
        self.radiobutton_res_dx_hex = Radiobutton(master=self.text_res_con)
        self.radiobutton_res_dx_hex.config(
            text = 'HEX',  # 单选框名字
            variable = self.radiobutton_res_variable,  # 设置数值类型
            value = 2,  # 设置value数值,同一组单选框中数值必须不一样
            command = self.res_hex_set   # 绑定单选框单击之后调用的函数
        )
        self.radiobutton_res_variable.set(1)  # 设置那个单选框初始的时候为选中状态
        self.radiobutton_res_dx_acci.grid(padx=5,row=1, column=1, sticky='w')  # 封装ASCII单选框
        self.radiobutton_res_dx_hex.grid(padx=5,row=1,column=2,sticky='e')  # 封装HEX单选框
        self.button_clear_res = Button(master=self.text_res_con,text='清空接收',command=lambda:self.clear_text(self.result_text))  # 添加清空接手区按键
        self.button_clear_res.grid(row=2,sticky='s',columnspan=5,pady=7)  # 将清空按键打包

    '''串口发送设置'''
    def text_sen_config(self):
        '''创建单选框ASCII并配置单选框'''
        self.radiobutton_sen_variable = IntVar()  # 设置单选框variable变量,作用是规定value的数值类型
        self.button_sen_dx_acci = Radiobutton(master=self.text_sen_con)
        self.button_sen_dx_acci.config(
            text = 'ASCII',  # 单选框名字
            variable = self.radiobutton_sen_variable,  # 设置数值类型
            value = 1,  # 设置value数值,同一组单选框中数值必须不一样
            command = self.sen_ascii_set  # 绑定单选框单击之后调用的函数
        )
        '''创建单选框HEX并配置单选框'''
        self.button_sen_dx_hex = Radiobutton(master=self.text_sen_con)
        self.button_sen_dx_hex.config(
            text = 'HEX',  # 单选框名字
            variable = self.radiobutton_sen_variable,  # 设置数值类型
            value = 2,  # 设置value数值,同一组单选框中数值必须不一样
            command = self.sen_hex_set   # 绑定单选框单击之后调用的函数
        )
        self.radiobutton_sen_variable.set(1)  # 设置那个单选框初始的时候为选中状态
        self.button_sen_dx_acci.grid(padx=5,row=1, column=1, sticky='w')  # 封装ASCII单选框
        self.button_sen_dx_hex.grid(padx=5,row=1,column=2,sticky='e')  # 封装HEX单选框
        self.button_sen_clear_res = Button(master=self.text_sen_con,text='清空发送',command=lambda:self.clear_text(self.send_text))  # 添加清空接手区按键
        self.button_sen_clear_res.grid(row=2,sticky='s',columnspan=5,pady=7)  # 将清空按键打包

    '''清空文本空间内容'''
    def clear_text(self,object):
        print('清除')
        object.config(state=NORMAL)  # 设置text对象可以操作
        object.delete(1.0,'end')  # 清空text对象内容
        # object.config(state=DISABLED)  # 设置text对象不可用

    '''设置接收框ASCII转换标志位'''
    def res_ascii_set(self):
        self.serial_res_hex_bzw = False

    '''设置接收框HEX转换标志位'''
    def res_hex_set(self):
        self.serial_res_hex_bzw = True

    '''将发送文本框中的内容以ASCII方式显示'''
    def sen_ascii_set(self):
        self.radiobutton_sen_hex_click_count = 0  # 清零
        self.radiobutton_sen_ascii_click_count += 1  # 单击一次次数+1
        self.serial_sen_hex_bzw = False  # 设置HEX标志位为False
        if not self.serial_sen_hex_bzw and self.radiobutton_sen_ascii_click_count == 1:
            self.send_text.unbind('<Key>')
            self.send_text.unbind('<BackSpace>')
            self.send_text.unbind('<Control--V>')
            self.send_text.unbind('<Control--v>')
            self.send_text.unbind('<Control--C>')
            self.send_text.unbind('<Control--c>')
            self.send_text.config(state=NORMAL)
            send_content = self.send_text.get(1.0,'end').strip()  # 读取输入文本框中的内容
            send_content = ''.join(send_content.split())  # 将16进制的文本去掉空格
            '''实现输入的数据个数不是偶数时,对不成对的数据用0进行补位'''
            if len(send_content) % 2 == 0:
                send_content = [send_content[x * 2:x * 2 + 2] for x in range(len(send_content)//2)]  # 将内容分成2个字符的数组,如:['01','02']
            else:
                temp = send_content
                send_content = [send_content[x * 2:x * 2 + 2] for x in range(len(send_content) // 2)]
                send_content.append(temp[-1].zfill(2))  # 在最后一位前面补0
                send_content = ''.join(send_content)
                send_content = [send_content[x * 2:x * 2 + 2] for x in range(len(send_content) // 2)]  # 将内容分成2个字符的数组,如:['01','02']
                print(send_content, 'send_content')
            send_content = ''.join([chr(int(x,16)) for x in send_content])  # 将上面的数组中的每个元素转换成ASCII格式
            self.clear_text(self.send_text)  # 清空输入文本框内容
            self.send_text.insert('end',send_content.encode())  # 将转换好的内容插入到文本框中

    '''将发送文本框中的内容以HEX方式显示'''
    def sen_hex_set(self):
        self.radiobutton_sen_ascii_click_count = 0  # 清零
        self.radiobutton_sen_hex_click_count += 1  # 单击一次次数+1
        self.serial_sen_hex_bzw = True  # 设置HEX标志位为True
        if self.serial_sen_hex_bzw and self.radiobutton_sen_hex_click_count == 1:
            self.send_text.bind('<Key>',self.key_callback)
            self.send_text.bind('<BackSpace>',self.key_backspace_control_v_callback)
            self.send_text.bind('<Control--V>',self.key_backspace_control_v_callback)
            self.send_text.bind('<Control--v>', self.key_backspace_control_v_callback)
            self.send_text.bind('<Control--C>',self.key_backspace_control_v_callback)
            self.send_text.bind('<Control--c>', self.key_backspace_control_v_callback)
            send_content = self.send_text.get(1.0, 'end').strip()  # 读取输入文本框中的内容
            # send_content = ''.join(send_content.split())  # 将16进制的文本去掉空格
            send_content = send_content.encode().hex()  # 将输入框中的内容转换成16进制

            send_content = ''.join([send_content[x * 2:x * 2 + 2] for x in range(len(send_content) // 2)])  # 转换成16进制的数据进行格式化
            print(send_content, '+++++++++++++++')
            self.clear_text(self.send_text)  # 清空原来的输入框内容
            self.send_text.insert('end', send_content.encode().upper())  # 将转换好的内容插入到文本框中

    '''backspace、control-v、control-c键盘事件回调函数'''
    def key_backspace_control_v_callback(self,event):
        self.send_text.config(state=NORMAL)

    '''发送框绑定键盘事件回调函数'''
    def key_callback(self,event):
        if event.char not in 'abcdefABCDEF0123456789 ':
            self.send_text.config(state=DISABLED)
        else:
            self.send_text.config(state=NORMAL)

    '''类方法:读取串口内容'''
    def serial_read_content(self):
        try:
            '''判断显示方式,self.serial_hex_bzw = True时为16进制显示,self.serial_hex_bzw=False时为ascii显示'''
            if self.serial_res_hex_bzw:
                time_str = time.strftime('[%Y-%m-%d %H:%M:%S]') + '-->HEX\r\n'
                data_res_sum = self.ser.inWaiting()  # 读取输入缓存中有多少个字节数据
                if data_res_sum:
                    text_content = self.ser.read(data_res_sum).hex()  # 将缓存中的数据读取出来
                    text_content = ' '.join([text_content[x*2:x*2+2] for x in range(len(text_content)//2)]).upper()  # 转换成16进制的数据进行格式化,带空格
                    print(text_content,'转换格式之后的文本')
            else:
                time_str = time.strftime('[%Y-%m-%d %H:%M:%S]') + '-->ASCII\r\n'
                data_res_sum = self.ser.inWaiting()  # 读取输入缓存中有多少个字节数据
                if data_res_sum:
                    text_content = self.ser.read(data_res_sum).decode(encoding='utf-8',
                                                                           errors='replace')  # 将缓存中的数据读取出来
                    print('---------------------{}'.format(data_res_sum), text_content)
            time.sleep(0.5)
            if text_content:
                # print('sssssss')
                self.result_text.config(state=NORMAL)  # 打开文本框输入
                self.result_text.tag_config('text_head_tag', foreground='blue')  # 设置插入文本样式
                self.result_text.tag_config('text_tag',foreground='green')  # 设置插入文本样式
                self.result_text.insert('end','\r\n' + time_str + '\r\n','text_head_tag')  # 在文本框中插入数据
                self.result_text.insert('end',text_content + '\r\n','text_tag')  # 在文本框中插入数据
                self.result_text.config(state=DISABLED)  # 禁止文本框输入
                self.result_text.see(END)  # 文本框总是显示最新内容
                text_content = ''
        except Exception:
            print('F**k you!')

    '''运行软件'''
    def run(self):
        self.serial_config_frame()
        self.text_res_config()
        self.text_sen_config()
        self.root.mainloop()