Tkinter打包exe报错问题和 Tkinter在子线程中无法更新GUI的解决办法之一

文章讲述了如何处理Tkinter程序在PyCharmIDEA通过pyinstaller打包成exe后遇到的TclError,以及如何通过子线程在GUI更新中避免错误。提到将Tix包放在同一路径或与Python可执行文件合并,同时介绍了如何在子线程中控制主线程的GUI更新以确保正确运行。
摘要由CSDN通过智能技术生成

问题描述:

提示:使用Tkinter写的程序通过pycharm IDEA的pyinstaller 打包exe,执行之后报错
报错内容如下:

Traceback (most recent call last):
  File "peakcan.py", line 2096, in <module>
  File "tkinter\tix.py", line 214, in __init__
_tkinter.TclError: can't find package Tix

解决方案:

将tix放到相同路径下即可正常运行。
也可以将二者通过WinRAR等工具合并在这里插入图片描述
原因我们可以根据它的报错行进行查找,File “tkinter\tix.py”, line 214, in init
索引进去的话我们可以看到他的路径是本地索引路径,因此打包后就找不到tix包。

tix包的位置在哪里
首先我们要找到编译器python 打开tcl文件夹,文件Tix就在里面。在这里插入图片描述


问题描述

提示:通过pycharm IDEA使用Tkinter写的程序,当我们在子线程对gui进行更新的时候会出现错误,那何种方法可以让他通过子线程来操控gui呢

解决方案:

提示:这里填写该问题的具体解决方案:

我的解决方案为在子线程中判断当前状态,在主线程中创建计时器作响应,并在程序的工作开始与结束正确打开和结束计时器,节省资源,保证软件正确运行。

介绍:我们通过子线程对这些变量进行修改,再通过主线程中的函数做相应的gui更新。

#这里是更新的函数 通过root.after递归进行循环
#self.timer_running的意义是 当我们执行我们要的操作之后,可以将这个定时器关掉。
   def timer(self):
        self.gui_fresh()  
        if self.timer_running:
            root.after(1000, self.timer)
#这只是一个例子,子线程中的标识赋值后,通过定时器判断更新gui
    def gui_fresh(self):
        if self.erase_fin == 1:
            if self.error_1 == 1 or self.error_2 == 1:
                self.IncludeTextMessage("Once the radar is powered back on, click 'Start' quickly")
                self.timer_running = 0
            elif self.error_1 == 2 or self.error_2 == 2:
                self.IncludeTextMessage("Disconnect the radar first, restart the software/initialization and re-power the radar")
                self.timer_running = 0
            else:
                self.IncludeTextMessage("Erasing is complete")
                self.IncludeTextMessage("The firmware is being updated, please be patient...")
                self.erase_fin = 0

        if self.trans1_fin == 1:
            self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(30, self.finsh, self.dur))
            self.trans1_fin = 0

        if self.trans2_fin == 1:
            self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(60, self.finsh, self.dur))
            self.trans2_fin = 0

        if self.trans3_fin == 1:
            self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(100, self.finsh, self.dur))
            self.trans3_fin = 0

        if self.trans4_fin == 1:
            self.IncludeTextMessage("Sending complete!")
            self.trans4_fin = 0
            self.timer_running = 0

不过需要注意的是,要注意好时间问题,比如下面我对时间的处理

首先这是子线程的定义

         erase = threading.Thread(target=self.erasing)
         erase.start()
         transmit = threading.Thread(target=self.transmiting)
         transmit.start()

下面是第一个子线程的操作

    def erasing(self):
        print("ok1")
        output_lock.acquire()
        print("ok1")
        try:
            print("ok2")
            result = self.ReadMessageFD() if self.m_IsFD else self.ReadMessage()
            st = time.perf_counter()
            while result != PCAN_ERROR_OK:
                result = self.ReadMessageFD() if self.m_IsFD else self.ReadMessage()
                if time.perf_counter() - st >= 5:
                    self.error_1 = 1
                    break
            if time.perf_counter() - st <= 0.15:
                self.error_1 = 2
            result = self.ReadMessageFD() if self.m_IsFD else self.ReadMessage()
            print("ok2")
            st = time.perf_counter()
            while result != PCAN_ERROR_OK:
                result = self.ReadMessageFD() if self.m_IsFD else self.ReadMessage()
                if time.perf_counter() - st >= 7:
                    self.error_2 = 1
                    break
            if time.perf_counter() - st <= 0.12:
                self.error_2 = 2
            # self.IncludeTextMessage("Erasing is complete")
            print("ok3")
        finally:
            # ?????
            if self.error_2 == 0 and self.error_1 == 0:
                self.error_ok = 1
            else:
                self.error_ok = 0
            self.erase_fin = 1
            output_lock.release()

下面是第二个子线程的操作,注意在一开始进行了14秒的休眠,这是因为这个应用的实际意义就是更新一个固件在雷达上,所以需要确保擦除完成,再进行写入,还要添加一些限制如果擦除失败则不进行,并且关闭定时器,这些都需要根据自己的需求去修改。

 def transmiting(self):
        time.sleep(14)
        output_lock.acquire()
        print(self.error_ok)
        if self.error_ok == 1:
            try:
                prt = 0
                self.last_time = 0
                start_time = time.perf_counter()
                for i in range(self.num_of_packets):
                    for j in range(10):
                        start_index = (i * 10 + j) * 8
                        end_index = min(((i * 10 + j) + 1) * 8, self.data_len)
                        data_len_this_packet = end_index - start_index
                        data_array_this_packet = self.ubyte_array(*self.data_array[start_index:end_index])
                        CANMsg = TPCANMsg()
                        CANMsg.ID = int("29E", 16)
                        CANMsg.LEN = int(data_len_this_packet)
                        CANMsg.MSGTYPE = PCAN_MESSAGE_STANDARD
                        for k in range(CANMsg.LEN):
                            CANMsg.DATA[k] = int(hex(data_array_this_packet[k]), 16)
                        while 1:
                            if time.perf_counter() - self.last_time > 0.0004:
                                break
                        stsResult = self.m_objPCANBasic.Write(self.m_PcanHandle, CANMsg)
                        self.last_time = time.perf_counter()
                        if stsResult != PCAN_ERROR_OK:
                            break
                        if end_index == self.data_len:
                            break
                    progress = end_index / self.data_len * 100
                    self.finsh = "\u2593" * int(progress // 2)
                    self.dur = time.perf_counter() - start_time
                    if 30 <= progress <= 31 and prt == 0:
                        prt += 1
                        # self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(progress, finsh, dur))
                        self.trans1_fin = 1
                    if 60 <= progress <= 61 and prt == 1:
                        prt += 1
                        # self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(progress, finsh, dur))
                        self.trans2_fin = 1
                    if progress == 100:
                        # self.IncludeTextMessage("\rProgress: {:^3.0f}%[{}]{:.2f}s\n".format(progress, finsh, dur))
                        self.trans3_fin = 1

                        break
                time.sleep(0.5)
                CANMsg = TPCANMsg()
                CANMsg.ID = int("29E", 16)
                CANMsg.LEN = int(8)
                CANMsg.MSGTYPE = PCAN_MESSAGE_STANDARD
                text = "02 01 03 04 55 66 77 88"
                numbers = text.split(" ")
                int_numbers = [int(num) for num in numbers]
                data = self.ubyte_array(*int_numbers)
                for z in range(8):
                    CANMsg.DATA[z] = int(hex(data[z]), 16)
                self.m_objPCANBasic.Write(self.m_PcanHandle, CANMsg)
                # self.IncludeTextMessage("Sending complete!")
                self.trans4_fin = 1
                self.__m_iCount = 1
            finally:
                # ?????

                output_lock.release()
        else:
            output_lock.release()
  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值