使用pythonw运行Arduino监控脚本时出现窗口闪烁问题
问题:pythonw运行监控脚本时反复弹出窗口,无报错日志
用Arduino+Python做了简易电脑监控屏,正常运行没问题,但想实现开机无窗口启动,改用pythonw.exe或.pyw后缀运行时,会有窗口弹出,还每隔2-3秒反复开闭。用普通python.exe运行则完全正常,日志文件始终为空。
原代码
import serial import psutil import GPUtil import time from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume from ctypes import cast, POINTER from comtypes import CLSCTX_ALL from PIL import Image import pystray import threading import logging logging.basicConfig(filename='C:\\Users\\natha\\Documents\\GitHub\\arduino-serial-monitor\\log.txt', level=logging.ERROR) try: run = True display = True devices = AudioUtilities.GetSpeakers() interface = devices.Activate( IAudioEndpointVolume._iid_, CLSCTX_ALL, None) volume = cast(interface, POINTER(IAudioEndpointVolume)) ser = serial.Serial('COM4', 9600, timeout=1) def create_menu(): return pystray.Menu( pystray.MenuItem('Quit', on_quit_callback), pystray.MenuItem('Reboot', on_reboot_callback), pystray.MenuItem(lambda text: 'Display Off' if display else 'Display On', on_display_off_callback) ) def on_quit_callback(icon, item): global run icon.stop() ser.write('SHUTDOWN\n'.encode()) run = False def on_display_off_callback(icon, item): global display display = False if display else True def on_reboot_callback(icon, item): ser.write('REBOOT\n'.encode()) image = Image.open('C:\\Users\\natha\\Documents\\GitHub\\arduino-serial-monitor\\icon.png') icon = pystray.Icon('System Monitor', image, 'System Monitor', menu=create_menu()) icon_thread = threading.Thread(target=icon.run) icon_thread.start() time.sleep(2) # Wait for 2 seconds to give the Arduino time to get ready while run: gpus = GPUtil.getGPUs() gpu = gpus[0] cpu_usage = max(psutil.cpu_percent(interval=1, percpu=True)) memory = psutil.virtual_memory() memory_usage = memory.percent memory_usage_raw = round(memory.used / (1024 ** 3), 2) memory_total = round(memory.total / (1024 ** 3)) gpu_usage = round(gpu.load * 100) gpu_temp = gpu.temperature timePrint = time.strftime('%H:%M', time.localtime()) volumePercent = round(volume.GetMasterVolumeLevelScalar() * 100) if ser.is_open: if display: ser.write(f'INFO:CPU:{cpu_usage},MEM_RAW:{memory_usage_raw},MEM_TOTAL:{memory_total},GPU:{gpu_usage},TEMP:{gpu_temp},TIME:{timePrint},VOL:{volumePercent}\n'.encode()) else: ser.write('DISPLAY_OFF\n'.encode()) else: print('Serial port is not open') #if ser.in_waiting > 0: # try: # # except UnicodeDecodeError: # pass # Ignore the error time.sleep(0.5) # Wait for 0.5 second before sending the next set of data except Exception as e: logging.exception(e)
解决办法
1. 替换GPUtil模块,避免控制台窗口泄露
GPUtil在pythonw环境下会调用控制台窗口,导致反复弹出。改用nvidia-smi命令直接获取GPU信息:
# 替换原GPUtil相关代码 import subprocess def get_gpu_data(): try: # 调用nvidia-smi获取GPU使用率和温度,强制不创建窗口 output = subprocess.check_output( ["nvidia-smi", "--query-gpu=utilization.gpu,temperature.gpu", "--format=csv,noheader,nounits"], creationflags=subprocess.CREATE_NO_WINDOW ) gpu_util, gpu_temp = output.decode().strip().split(', ') return int(gpu_util), int(gpu_temp) except Exception as e: logging.exception("获取GPU信息失败") return 0, 0
然后在循环中替换原GPU相关代码:
# 替换原gpus = GPUtil.getGPUs()及以下行 gpu_usage, gpu_temp = get_gpu_data()
2. 强制隐藏控制台窗口
在代码最开头添加以下代码,确保所有可能的控制台窗口被隐藏:
import ctypes # 隐藏当前控制台窗口 ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)
3. 修复线程异常捕获
原代码无法捕获托盘图标线程中的异常,修改线程启动逻辑:
def run_tray_icon(): try: icon.run() except Exception as e: logging.exception("托盘图标线程出错") icon_thread = threading.Thread(target=run_tray_icon) icon_thread.start()
同时把logging.basicConfig移到代码最开头,确保日志初始化优先:
import logging logging.basicConfig(filename='C:\\Users\\natha\\Documents\\GitHub\\arduino-serial-monitor\\log.txt', level=logging.ERROR)
4. 优化串口操作
在退出回调中添加串口关闭逻辑,避免资源泄漏:
def on_quit_callback(icon, item): global run icon.stop() ser.write('SHUTDOWN\n'.encode()) ser.close() # 关闭串口 run = False
内容的提问来源于stack exchange,提问作者Sarxzer11
相关产品推荐
相关产品推荐

