自研windows版conky(桌面系统监控面板)

代码如下:

import tkinter as tk
import psutil
import ctypes
import ctypes.wintypes
import time
import platform
import winreg
import subprocess
import json
import os
import threading
import sys
from PIL import Image
from pystray import Icon, Menu, MenuItem

# ===================== Windows常量 =====================
WS_EX_LAYERED = 0x00080000
WS_EX_TRANSPARENT = 0x0020
WS_EX_NOACTIVATE = 0x08000000
GWL_EXSTYLE = -20
HWND_BOTTOM = 1
SWP_NOACTIVATE = 0x0010
SWP_NOMOVE = 0x0001
SWP_NOSIZE = 0x0002

EXIT_FLAG = threading.Event()
DATA_LOCK = threading.Lock()
shared_data = {
    "cpu_pct": 0.0,
    "mem_pct": 0.0,
    "gpu_load": 0.0,
    "gpu_name": "未知显卡",
    "disks": [],
    "upload": 0.0,
    "download": 0.0,
    "up_time_str": "",
    "top_cpu_proc": [],
    "top_mem_proc": []
}

def load_config():
    default_cfg = {
        "panel_width": 315,    # 默认改成315
        "refresh_interval": 4000,
        "max_proc_name_len": 24,
        "bar_width": 180,
        "bar_height": 12,
        "alert_threshold": 80,
        "bg_color": "#1a1a22",
        "txt_label": "#b8c2cc",
        "txt_value": "#72e0a0",
        "bar_normal_color": "#40aa70",
        "bar_warn_color": "#dd4444",
        "net_color": "#ffdd77",
        "blacklist": ["system idle process", "svchost.exe"],
        "disk_ignore": ["Z:", "Y:"],
        "win_x": -1,
        "win_y": 0
    }
    path = "config.json"
    if os.path.exists(path):
        try:
            with open(path, "r", encoding="utf-8") as f:
                cfg = json.load(f)
            for k, v in default_cfg.items():
                if k not in cfg:
                    cfg[k] = v
            return cfg
        except Exception:
            return default_cfg
    return default_cfg

def save_config(cfg):
    path = "config.json"
    try:
        with open(path, "w", encoding="utf-8") as f:
            json.dump(cfg, f, indent=4, ensure_ascii=False)
    except Exception:
        pass

CONFIG = load_config()

def check_single_instance():
    MUTEX_NAME = "Global\\FloatSysMonitorMutex_20260922"
    mutex = ctypes.windll.kernel32.CreateMutexW(None, False, MUTEX_NAME)
    if ctypes.windll.kernel32.GetLastError() == 183:
        ctypes.windll.kernel32.CloseHandle(mutex)
        return False
    return True

# ========== 显卡读取:新增注册表方案(专门适配老Intel核显) ==========
def get_gpu_name_from_registry():
    try:
        base_key = r"SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}"
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_key)
        subkey_count = winreg.QueryInfoKey(key)[0]
        filter_keywords = ["OrayIdd", "RDP", "Mirror", "Remote Display"]
        gpu_names = []
        for i in range(subkey_count):
            try:
                sub_name = winreg.EnumKey(key, i)
                if sub_name.startswith("000"):
                    sub = winreg.OpenKey(key, sub_name)
                    try:
                        dev_name = winreg.QueryValueEx(sub, "DriverDesc")[0].strip()
                        if dev_name and not any(kw.lower() in dev_name.lower() for kw in filter_keywords):
                            gpu_names.append(dev_name)
                    except:
                        pass
                    winreg.CloseKey(sub)
            except:
                continue
        winreg.CloseKey(key)
        gpu_names = list(dict.fromkeys(gpu_names))
        if gpu_names:
            return " | ".join(gpu_names)
    except Exception:
        pass
    return ""

def get_gpu_name_powershell():
    cmds = [
        r'powershell -Command "Get-CimInstance Win32_VideoController | Select-Object -ExpandProperty Name"',
        r'powershell -Command "Get-WmiObject Win32_VideoController | Select-Object -ExpandProperty Name"'
    ]
    filter_keywords = ["OrayIdd", "RDP", "Mirror", "Remote Display"]
    for cmd in cmds:
        try:
            ret = subprocess.check_output(cmd, shell=True, encoding="utf-8", timeout=3)
            lines = []
            for name in ret.splitlines():
                name = name.strip()
                if not name:
                    continue
                if any(kw.lower() in name.lower() for kw in filter_keywords):
                    continue
                lines.append(name)
            lines = list(dict.fromkeys(lines))
            if lines:
                return " | ".join(lines)
        except Exception:
            continue
    return ""

def get_final_gpu_name():
    # 优先级:注册表 > PowerShell,删掉LHM读取显卡名称(老核显LHM经常读不出名字)
    n = get_gpu_name_from_registry()
    if n:
        return n
    n = get_gpu_name_powershell()
    if n:
        return n
    return "未知显卡"

# ========== GPU负载依然走LHM(如果你不需要GPU占用,可以后续去掉) ==========
clr = None
Computer = None
HardwareType = None
SensorType = None
hw_computer = None
try:
    import pythonnet
    clr = pythonnet.load("LibreHardwareMonitorLib")
    from LibreHardwareMonitor.Hardware import Computer, HardwareType, SensorType
    hw_computer = Computer()
    hw_computer.CPUEnabled = False
    hw_computer.GPUEnabled = True
    hw_computer.HDDEnabled = False
    hw_computer.Open()
except Exception:
    pass

def read_gpu_load():
    gpu_load = 0.0
    if not hw_computer:
        return 0.0
    try:
        hw_computer.Accept(None)
        for hw in hw_computer.Hardware:
            hw.Update()
            if hw.HardwareType in (HardwareType.GpuNvidia, HardwareType.GpuAmd, HardwareType.GpuIntel):
                for s in hw.Sensors:
                    if s.SensorType == SensorType.Load and s.Value is not None:
                        gpu_load = float(s.Value)
                        return gpu_load
    except Exception:
        pass
    return 0.0

def get_cpu_full_name():
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
        cpu_name = winreg.QueryValueEx(key, "ProcessorNameString")[0].strip()
        winreg.CloseKey(key)
        if "CPU" in cpu_name:
            cpu_name = cpu_name.split("CPU")[0].strip()
        return cpu_name
    except Exception:
        return platform.processor()

def get_all_local_disks():
    disks = []
    ignore = [d.upper() for d in CONFIG["disk_ignore"]]
    try:
        parts = psutil.disk_partitions(all=False)
        for p in parts:
            mp = p.mountpoint
            if mp.upper() in ignore:
                continue
            try:
                usage = psutil.disk_usage(mp)
                disks.append({
                    "letter": mp,
                    "percent": usage.percent,
                    "total_gb": round(usage.total / (1024**3), 2)
                })
            except Exception as e:
                continue
    except Exception:
        pass
    return disks

def truncate_name(name: str, max_len: int):
    if len(name) > max_len:
        return name[:max_len - 1] + "…"
    return name

def set_full_mouse_transparent(hwnd):
    style = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
    new_style = style | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE
    ctypes.windll.user32.SetWindowLongW(hwnd, GWL_EXSTYLE, new_style)

def get_progman_hwnd():
    return ctypes.windll.user32.FindWindowW("Progman", None)

def force_desktop_bottom(hwnd):
    progman = get_progman_hwnd()
    if progman:
        ctypes.windll.user32.SetWindowPos(
            hwnd, progman,
            0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
        )
    else:
        ctypes.windll.user32.SetWindowPos(
            hwnd, HWND_BOTTOM,
            0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
        )

def get_top_cpu_processes(count=12):
    proc_list = []
    bl = [x.lower() for x in CONFIG["blacklist"]]
    try:
        for p in psutil.process_iter(["name", "cpu_percent"]):
            try:
                pname = p.info["name"].lower()
                if pname in bl:
                    continue
                proc_list.append(p.info)
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue
        proc_list.sort(key=lambda x: x["cpu_percent"], reverse=True)
        return proc_list[:count]
    except Exception:
        return []

def get_top_mem_processes(count=12):
    proc_list = []
    bl = [x.lower() for x in CONFIG["blacklist"]]
    try:
        for p in psutil.process_iter(["name", "memory_info"]):
            try:
                mem_mb = p.info["memory_info"].rss / 1024 / 1024
                pname = p.info["name"].lower()
                if pname in bl:
                    continue
                proc_list.append({"name": p.info["name"], "mem_mb": mem_mb})
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue
        proc_list.sort(key=lambda x: x["mem_mb"], reverse=True)
        return proc_list[:count]
    except Exception:
        return []

def data_collector(net_last):
    interval = CONFIG["refresh_interval"] / 1000.0
    gpu_static_name = get_final_gpu_name()
    while not EXIT_FLAG.is_set():
        net_now = psutil.net_io_counters()
        now_time = time.time()
        delta_time = now_time - net_last["t"]
        upload, download = 0.0, 0.0
        if delta_time > 0.3:
            upload = (net_now.bytes_sent - net_last["sent"]) / delta_time / 1024 / 1024
            download = (net_now.bytes_recv - net_last["recv"]) / delta_time / 1024 / 1024
        net_last["sent"] = net_now.bytes_sent
        net_last["recv"] = net_now.bytes_recv
        net_last["t"] = now_time

        boot_stamp = psutil.boot_time()
        up_seconds = time.time() - boot_stamp
        up_h = int(up_seconds // 3600)
        up_m = int((up_seconds % 3600) // 60)
        up_s = int(up_seconds % 60)
        up_time_str = f"{up_h:02d}:{up_m:02d}:{up_s:02d}"

        cpu_pct = psutil.cpu_percent(None)
        mem = psutil.virtual_memory()
        mem_pct = mem.percent
        disks = get_all_local_disks()
        gpu_load = read_gpu_load()

        top_cpu = get_top_cpu_processes(CONFIG["top_cpu_count"])
        top_mem = get_top_mem_processes(CONFIG["top_mem_count"])
        with DATA_LOCK:
            shared_data["cpu_pct"] = cpu_pct
            shared_data["mem_pct"] = mem_pct
            shared_data["gpu_load"] = gpu_load
            shared_data["gpu_name"] = gpu_static_name
            shared_data["disks"] = disks
            shared_data["upload"] = upload
            shared_data["download"] = download
            shared_data["up_time_str"] = up_time_str
            shared_data["top_cpu_proc"] = top_cpu
            shared_data["top_mem_proc"] = top_mem
        time.sleep(interval)

class FloatSysMonitor:
    def __init__(self, root):
        self.root = root
        self.root.title("桌面硬件监控面板")
        self.root.overrideredirect(True)
        self.root.attributes("-alpha", 0.88)
        self.cfg = CONFIG
        panel_w = self.cfg["panel_width"]
        screen_w = self.root.winfo_screenwidth()
        screen_h = self.root.winfo_screenheight()

        if self.cfg["win_x"] < 0:
            x = screen_w - panel_w
            y = 0
        else:
            x = self.cfg["win_x"]
            y = self.cfg["win_y"]
        self.root.geometry(f"{panel_w}x{screen_h}+{x}+{y}")
        self.bg_color = self.cfg["bg_color"]
        self.txt_label = self.cfg["txt_label"]
        self.txt_value = self.cfg["txt_value"]
        self.root.configure(bg=self.bg_color)
        self.window_visible = True

        self.os_info = f"{platform.system()} {platform.release()}"
        self.cpu_full_name = get_cpu_full_name()
        self.mem_total_gb = round(psutil.virtual_memory().total / (1024 ** 3), 2)

        main_frame = tk.Frame(root, bg=self.bg_color)
        main_frame.pack(padx=8, pady=8, fill=tk.BOTH, expand=True)
        top_banner = tk.Frame(main_frame, bg=self.bg_color)
        top_banner.pack(fill=tk.X, pady=(0,4))
        logo_canvas = tk.Canvas(top_banner, width=28, height=28, bg=self.bg_color, highlightthickness=0)
        logo_canvas.grid(row=0, column=0)
        s = 12
        logo_canvas.create_rectangle(0, 0, s, s, fill="#f25022")
        logo_canvas.create_rectangle(s, 0, s * 2, s, fill="#7fba00")
        logo_canvas.create_rectangle(0, s, s, s * 2, fill="#00a4ef")
        logo_canvas.create_rectangle(s, s, s * 2, s * 2, fill="#ffb900")
        tk.Label(
            top_banner,
            text=CONFIG["name"],
            bg=self.bg_color,
            fg="#ffffff",
            font=("微软雅黑", 11, "bold")
        ).grid(row=0, column=1, padx=4)
        top_banner.grid_columnconfigure(1, weight=1)
        tk.Frame(main_frame, height=1, bg="#444455").pack(fill=tk.X, pady=4)

        self.info_label = tk.Label(
            main_frame, bg=self.bg_color, fg=self.txt_label,
            font=("微软雅黑",9), justify="left", anchor="nw"
        )
        self.info_label.pack(anchor="nw")
        tk.Frame(main_frame, height=1, bg="#444455").pack(fill=tk.X, pady=4)

        # ========= 统一进度条父框架,CPU/内存/GPU/磁盘全部放在这里,自动对齐 =========
        self.bar_frame = tk.Frame(main_frame, bg=self.bg_color)
        self.bar_frame.pack(fill=tk.X)
        self.bar_frame.grid_columnconfigure(0, weight=0)
        self.bar_frame.grid_columnconfigure(1, weight=0)
        self.bar_frame.grid_columnconfigure(2, weight=0)

        self.bar_w = self.cfg["bar_width"]
        self.bar_h = self.cfg["bar_height"]
        self.threshold = self.cfg["alert_threshold"]
        self.bar_normal = self.cfg["bar_normal_color"]
        self.bar_warn = self.cfg["bar_warn_color"]

        # CPU
        tk.Label(self.bar_frame, text="CPU", bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 10)).grid(row=0, column=0, sticky="w")
        self.cpu_bar = tk.Canvas(self.bar_frame, width=self.bar_w, height=self.bar_h, bg="#2c2c38", highlightthickness=0)
        self.cpu_bar.grid(row=0, column=1, padx=6)
        self.cpu_fill = self.cpu_bar.create_rectangle(0, 0, 0, self.bar_h, fill=self.bar_normal)
        self.cpu_text = tk.Label(self.bar_frame, text="0%", bg=self.bg_color, fg=self.txt_value, font=("微软雅黑", 10))
        self.cpu_text.grid(row=0, column=2)

        # 内存
        tk.Label(self.bar_frame, text="内存", bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 10)).grid(row=1, column=0, sticky="w", pady=3)
        self.mem_bar = tk.Canvas(self.bar_frame, width=self.bar_w, height=self.bar_h, bg="#2c2c38", highlightthickness=0)
        self.mem_bar.grid(row=1, column=1, padx=6)
        self.mem_fill = self.mem_bar.create_rectangle(0, 0, 0, self.bar_h, fill=self.bar_normal)
        self.mem_text = tk.Label(self.bar_frame, text="0%", bg=self.bg_color, fg=self.txt_value, font=("微软雅黑", 10))
        self.mem_text.grid(row=1, column=2)

        # GPU占用
        tk.Label(self.bar_frame, text="GPU", bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 10)).grid(row=2, column=0, sticky="w", pady=3)
        self.gpu_bar = tk.Canvas(self.bar_frame, width=self.bar_w, height=self.bar_h, bg="#2c2c38", highlightthickness=0)
        self.gpu_bar.grid(row=2, column=1, padx=6)
        self.gpu_fill = self.gpu_bar.create_rectangle(0,0,0,self.bar_h, fill=self.bar_normal)
        self.gpu_text = tk.Label(self.bar_frame, text="0%", bg=self.bg_color, fg=self.txt_value, font=("微软雅黑", 10))
        self.gpu_text.grid(row=2, column=2)

        # 磁盘行,和上面在同一个grid里,自动对齐
        self.disk_start_row = 3
        tk.Frame(main_frame, height=1, bg="#444455").pack(fill=tk.X, pady=4)

        self.net_label = tk.Label(main_frame, text="网络 ↑0MB/s ↓0MB/s", bg=self.bg_color, fg=self.cfg["net_color"], font=("微软雅黑", 10))
        self.net_label.pack(anchor="nw")
        tk.Frame(main_frame, height=1, bg="#444455").pack(fill=tk.X, pady=4)

        tk.Label(main_frame, text="CPU占用排行", bg=self.bg_color, fg="#ffffff", font=("微软雅黑", 10, "bold")).pack(anchor="nw")
        self.cpu_proc_label = tk.Label(main_frame, text="加载中...", bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 8), justify="left")
        self.cpu_proc_label.pack(anchor="nw")
        tk.Frame(main_frame, height=1, bg="#444455").pack(fill=tk.X, pady=4)
        tk.Label(main_frame, text="内存占用排行", bg=self.bg_color, fg="#ffffff", font=("微软雅黑", 10, "bold")).pack(anchor="nw")
        self.mem_proc_label = tk.Label(main_frame, text="加载中...", bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 8), justify="left")
        self.mem_proc_label.pack(anchor="nw")

        self.root.update_idletasks()
        self.hwnd = ctypes.windll.user32.GetParent(self.root.winfo_id())
        set_full_mouse_transparent(self.hwnd)
        self.root.bind("<Map>", lambda e: force_desktop_bottom(self.hwnd))
        force_desktop_bottom(self.hwnd)

        net_init = psutil.net_io_counters()
        net_last_data = {"sent": net_init.bytes_sent, "recv": net_init.bytes_recv, "t": time.time()}
        collector_thread = threading.Thread(target=data_collector, args=(net_last_data,), daemon=True)
        collector_thread.start()

        self.tray_icon = None
        self.init_tray()
        self.render_ui()

    def init_tray(self):
        try:
            image = Image.open("icon.png")
        except Exception:
            image = Image.new("RGB", (64, 64), (26, 26, 34))
        menu = Menu(
            MenuItem("显示/隐藏面板", self.on_tray_toggle),
            MenuItem("退出", self.on_tray_exit)
        )
        self.tray_icon = Icon("SysMonitor", image, title="系统监控", menu=menu)
        tray_thread = threading.Thread(target=self.tray_icon.run, daemon=True)
        tray_thread.start()

    def on_tray_toggle(self):
        self.root.after(0, self.toggle_window)

    def toggle_window(self):
        if self.window_visible:
            self.root.withdraw()
            self.window_visible = False
        else:
            self.root.deiconify()
            self.window_visible = True
            force_desktop_bottom(self.hwnd)

    def on_tray_exit(self):
        self.root.after(0, self.quit_app)

    def quit_app(self):
        x = self.root.winfo_x()
        y = self.root.winfo_y()
        self.cfg["win_x"] = x
        self.cfg["win_y"] = y
        save_config(self.cfg)
        EXIT_FLAG.set()
        if self.tray_icon:
            self.tray_icon.stop()
        self.root.destroy()

    def render_ui(self):
        with DATA_LOCK:
            d = shared_data.copy()
        max_name_len = self.cfg["max_proc_name_len"]

        content = (
            f"系统:{self.os_info}\n"
            f"CPU:{self.cpu_full_name}\n"
            f"显卡:{d['gpu_name']}\n"
            f"物理内存:{self.mem_total_gb} GB\n"
            f"已开机时间:{d['up_time_str']}"
        )
        self.info_label.config(text=content)

        # CPU进度条
        cpu_color = self.bar_warn if d["cpu_pct"] >= self.threshold else self.bar_normal
        self.cpu_bar.coords(self.cpu_fill, 0, 0, self.bar_w * d["cpu_pct"] / 100, self.bar_h)
        self.cpu_bar.itemconfig(self.cpu_fill, fill=cpu_color)
        self.cpu_text.config(text=f"{d['cpu_pct']}%")

        # 内存进度条
        mem_color = self.bar_warn if d["mem_pct"] >= self.threshold else self.bar_normal
        self.mem_bar.coords(self.mem_fill, 0, 0, self.bar_w * d["mem_pct"] / 100, self.bar_h)
        self.mem_bar.itemconfig(self.mem_fill, fill=mem_color)
        self.mem_text.config(text=f"{d['mem_pct']}%")

        # GPU占用进度条
        gpu_color = self.bar_warn if d["gpu_load"] >= self.threshold else self.bar_normal
        self.gpu_bar.coords(self.gpu_fill,0,0, self.bar_w * d["gpu_load"] /100, self.bar_h)
        self.gpu_bar.itemconfig(self.gpu_fill, fill=gpu_color)
        self.gpu_text.config(text=f"{d['gpu_load']:.1f}%")

        # ========= 磁盘渲染:和CPU/GPU放在同一个grid,完美对齐 =========
        # 先清空磁盘旧控件(保留前3行CPU/内存/GPU)
        for w in self.bar_frame.winfo_children():
            info = w.grid_info()
            if int(info["row"]) >= self.disk_start_row:
                w.destroy()
        row_idx = self.disk_start_row
        for disk in d["disks"]:
            letter = disk["letter"]
            pct = disk["percent"]
            color = self.bar_warn if pct >= self.threshold else self.bar_normal
            tk.Label(self.bar_frame, text=letter, bg=self.bg_color, fg=self.txt_label, font=("微软雅黑", 9)).grid(row=row_idx, column=0, sticky="w", pady=3)
            bar = tk.Canvas(self.bar_frame, width=self.bar_w, height=self.bar_h, bg="#2c2c38", highlightthickness=0)
            bar.grid(row=row_idx, column=1, padx=6)
            fill = bar.create_rectangle(0,0, self.bar_w * pct / 100, self.bar_h, fill=color)
            txt = tk.Label(self.bar_frame, text=f"{pct}%", bg=self.bg_color, fg=self.txt_value, font=("微软雅黑",9))
            txt.grid(row=row_idx, column=2)
            row_idx += 1

        if row_idx == self.disk_start_row:
            tk.Label(self.bar_frame, text="无可用磁盘", bg=self.bg_color, fg="#888888", font=("微软雅黑",9)).grid(row=row_idx,column=0)

        # 网速
        self.net_label.config(text=f"网络 ↑{d['upload']:.2f}MB/s ↓{d['download']:.2f}MB/s")

        # CPU进程列表
        cpu_text_lines = []
        for idx, p in enumerate(d["top_cpu_proc"]):
            name_short = truncate_name(p['name'], max_name_len)
            cpu_text_lines.append(f"{idx+1:2d}. {name_short} {p['cpu_percent']:.1f}%")
        self.cpu_proc_label.config(text="\n".join(cpu_text_lines))

        # 内存进程列表
        mem_text_lines = []
        for idx, p in enumerate(d["top_mem_proc"]):
            name_short = truncate_name(p['name'], max_name_len)
            mem_text_lines.append(f"{idx+1:2d}. {name_short} {p['mem_mb']:.0f}MB")
        self.mem_proc_label.config(text="\n".join(mem_text_lines))

        self.root.after(self.cfg["refresh_interval"], self.render_ui)

if __name__ == "__main__":
    ctypes.windll.shcore.SetProcessDpiAwareness(2)
    if not check_single_instance():
        print("监控程序已运行,退出")
        sys.exit(0)
    root = tk.Tk()
    app = FloatSysMonitor(root)
    root.mainloop()

新建一个config.json,内容如下:

{
    "name":"今天过的怎么样? 梦想是不是更远了?",
    "panel_width": 315,
    "refresh_interval": 4000,
    "max_proc_name_len": 24,
    "bar_width": 200,
    "bar_height": 12,
    "alert_threshold": 80,
    "bg_color": "#1a1a22",
    "txt_label": "#b8c2cc",
    "txt_value": "#72e0a0",
    "bar_normal_color": "#40aa70",
    "bar_warn_color": "#dd4444",
    "net_color": "#ffdd77",
    "blacklist": ["system idle process", "svchost.exe"],
    "disk_ignore": ["Z:", "Y:"],
    "win_x": -1,
    "win_y": 0,
    "top_cpu_count": 13,
    "top_mem_count": 13
}

打包可以使用pyinstaller,命令如下:

pyinstaller -F -w --name SysMonitor --hidden-import wmi --hidden-import pystray._win32 main.py -i your_icon.ico

在文件目录会生成dist目录,里面就是生成好的exe文件。

本文为原创文章,转载请注明出处。

原文链接:http://www.quartlog.com/post/自研windows版conky

评论(0)

还没有评论,来抢沙发吧~

验证码