给cmd控制台程序 套壳 美化

news2024/11/16 9:19:16

给cmd控制台程序套壳美化,可以获取程序的标准输出和报错信息。

# _*_ coding: utf-8 _*_
""" 控制台程序启动器,杜绝黑窗口。
Time:     2023/10/18 15:28
Author:   Jyun
Version:  V 0.1
File:     main.py
Blog:     https://ctrlcv.blog.csdn.net
"""
import os
import subprocess
import threading
import time
import tkinter as tk

# 设置 Python 的标准输出编码[配置项]
os.environ['PYTHONIOENCODING'] = 'gbk'

# 窗口标题[配置项]
TITLE_BAR_TEXT = "Demo v1.0"

# 程序名称[配置项]
MAIN_TITLE = "Program Name"

# 程序停止时的状态提示[配置项]
STOPPED_STATE_TEXT = "Program stopped."

# 程序运行时的状态提示[配置项]
RUNNING_STATE_TEXT = "Program running."

# 程序启动脚本(可以是打包后的exe程序)[配置项]
COMMAND = ['python', 'test_program.py']

THREADS_LIST = []


def async_way(func):
    def wrapper(*args, **kwargs):
        t = threading.Thread(target=func, args=args, kwargs=kwargs)
        t.setDaemon(True)
        t.start()
        THREADS_LIST.append(t)
        return t  # 返回线程对象用于后续操作

    return wrapper


class GUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.process = None

        self.title(TITLE_BAR_TEXT)
        self.configure(bg="white")
        self.resizable(False, False)
        self.protocol("WM_DELETE_WINDOW", self.destroy)

        # 主标题
        self.label = tk.Label(self, text=MAIN_TITLE, font=("微软雅黑", 16), anchor="w", justify="left", bg="white")
        self.label.pack(fill="x", padx=25, pady=5)

        # 状态、操作栏块
        self.div = tk.Frame(self, bg="white")
        self.div.pack(fill="x", padx=25, pady=5)

        # 当前状态显示TXT
        self.state = tk.Label(self.div, text="Status Action Bar", font=("微软雅黑", 12), anchor="w", justify="left",
                              bg="white")
        self.state.pack(side="left")

        # 日志显示区
        self.log_text = tk.Text(self, wrap=tk.WORD, width=60, height=20, bg="#f6f6f6", borderwidth=0, padx=10, pady=10)
        self.log_text.pack(padx=25, pady=(5, 25))

        # 停止按钮(如不需要 注释即可)
        self.stop_button = tk.Button(self.div, text="停止", width=10, command=self.stop, bd=0, bg="#ff8787")
        self.stop_button.pack(side="right")

        # 启动按钮(如不需要 注释即可)
        self.start_button = tk.Button(self.div, text="启动", width=10, command=self.start, bd=0, bg="#69db7c")
        self.start_button.pack(side="right")

    def log(self, message, color="black", autowrap=True):
        """ 输出日志
        :param message: 内容(行)
        :param color: 文本颜色
        :param autowrap: 是否自动换行
        :return:
        """
        message = str(message)
        if autowrap:
            message = message + "\n"

        self.log_text.tag_configure("custom_color", foreground=color)
        self.log_text.insert(tk.END, message, "custom_color")
        self.log_text.see(tk.END)

    # @async_way
    def start(self):
        """ 启动子程序
        :return:
        """
        self.state["text"] = RUNNING_STATE_TEXT
        if self.process is not None:
            self.log("程序正在运行,若要重新启动,请先停止", "red")
            return

        self.process = subprocess.Popen(COMMAND, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        self.read_child_output()
        self.read_child_error()

    def stop(self):
        """ 停止子程序
        :return:
        """
        # 程序正常运行时`self.process.poll()`为None
        if self.process is not None and self.process.poll() is None:
            self.process.terminate()
            self.log(f"等待进程结束:{self.process.pid}")
            self.wait_process_exit()
        else:
            self.process = None  # !
            self.state["text"] = STOPPED_STATE_TEXT
            self.log("程序已经停止")
            self.log(f'辅助线程: {len(THREADS_LIST)}')
            self.release_thread()

    @async_way
    def read_child_output(self):
        """ 获取子进程的标准输出
        :return:
        """
        while True:
            try:
                output = self.process.stdout.readline()
            except UnicodeDecodeError as e:
                self.log(f'主线程输出解码错误 UnicodeDecodeError: {e}', color="red")
                continue
            if not output:
                break
            self.log(output, autowrap=False)

    @async_way
    def read_child_error(self):
        """ 获取子进程的错误信息
        :return:
        """
        while True:
            output = self.process.stderr.readline()
            if not output:
                break
            self.log(output, color="red", autowrap=False)

    @async_way
    def wait_process_exit(self):
        """ 等待进程结束
        :return:
        """
        while self.process.poll() is None:
            time.sleep(1)
        self.log(f"进程已结束,退出代码为 {self.process.poll()}")
        self.process = None
        self.state["text"] = STOPPED_STATE_TEXT

    def release_thread(self):
        """ 释放已结束的线程
        :return:
        """
        for thread in THREADS_LIST:
            if not thread.is_alive():
                thread.join()
                THREADS_LIST.remove(thread)
                self.log(f"释放线程:{thread}")

    def run(self):
        self.mainloop()


if __name__ == '__main__':
    gui = GUI()
    gui.run()

# TODO: 待实现
#  启动后自动运行子程序
#  添加日志长度限制
#  添加标题栏图标
#  添加程序图标

GUI示例:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1106774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机缺失pasmutility.dll怎么办,三步解决pasmutility.dll缺失

pasmutility.dll文件是windows系统中重要的dll文件,电脑一旦缺失dll文件就会导致电脑无法正常运行,同时还会唐初电脑缺失pasmutility.dll文件的提示窗口,非常影响电脑运行,那么出现计算机缺失pasmutility.dll该怎么办呢&#xff1…

为什么引入SVG文件,给它定义属性不生效原理分析

背景&#xff1a; 我使用antd 的Icon组件引入SVG图片&#xff0c;但给svg图片定义styles样式时&#xff0c;不生效&#xff0c;为什么呢&#xff1f; 我们平时用antd组件库的 < ArrowRightOutlined style{{color: red }}>时为什么会生效呢&#xff0c;但我图一这样定义就…

保护隐私就是在保护自己!如何在Android上更改应用程序权限

如果你关心隐私&#xff0c;知道如何在Android上更改应用程序权限将成为一项非常重要的技能。即使是最好的安卓应用程序也可以对手机的功能和数据进行广泛的访问&#xff0c;因此准确控制它们的使用范围会有所帮助。 一旦你在手机上加载了应用程序&#xff0c;你可能会注意到它…

Unity中Shader的Pass的复用

文章目录 前言一、怎么实现Pass的复用1、给需要引用的Pass给定特定的名字2、在需要引用 Pass 的Shader中&#xff0c;在Pass的平行位置使用 UsePass "ShaderPath PassName" 二、实现一个没被遮挡的部分显示模型原本的样子&#xff0c;遮挡部分显示模型的XRay效果1、…

一篇文章带你搞懂 单调栈 是怎么回事

首先我们要搞懂什么时候使用单调栈&#xff1f; 当我们需要找到 左边或右边 第一个 比自己大的数 或者 比自己小的数 时就要使用单调栈 单调栈实际上就是一个栈&#xff0c;他的作用就是存储我们遍历过的数字。当我们遍历数组的时候&#xff0c;遍历到后面的数组后并不知道前…

ARM 堆栈寻址类型区分

文章目录 堆栈指向分类堆栈指向数据分类满递增与满递减空递增与空递减 堆栈指向分类 根据堆栈指针的指向的方向不同&#xff0c;可以划分为向上生成型和向下生成型。 向上生成型&#xff1a; 随着数据的入栈&#xff0c;堆栈的指针逐渐增大&#xff0c;称为&#xff1a;递增…

数据结构中的七大排序(Java实现)

目录 一、直接插入排序 二、希尔排序 三、直接选择排序 四、堆排序 五、冒泡排序 六、快速排序 七、归并排序 一、直接插入排序 思想&#xff1a; 定义i下标之前的元素全部已经有序&#xff0c;遍历一遍要排序的数组&#xff0c;把i下标前的元素全部进行排序&#xff0…

Python 爬虫入门:常见工具介绍

接着我的上一篇文章《网页爬虫完全指南》&#xff0c;这篇文章将涵盖几乎所有的 Python 网页爬取工具。我们从最基本的开始讲起&#xff0c;逐步涉及到当前最前沿的技术&#xff0c;并且对它们的利弊进行分析。 当然&#xff0c;我们不能全面地介绍每个工具&#xff0c;但这篇…

C++string类重要函数模拟实现

为了和C标准库区分&#xff0c;以下代码除主函数外均在namespace空间 目录 一.成员 二、带参构造函数 三、拷贝构造函数和赋值运算符重载 四、析构函数 五、重要成员函数实现 1. c_str函数 2. operator[]重载 3. size函数和capacity函数 4.reverse函数 5. push_back和…

plink分析100个性状的批量gwas分析

大家好&#xff0c;我是邓飞。 GWAS分析时&#xff0c;3~5个性状是正常操作&#xff0c;要分析100个性状呢&#xff0c;手动修改参数&#xff0c;工作量是够了&#xff0c;但是程序员的修养体现在哪里了&#xff1f;&#xff1f;&#xff1f; 如果还是按照每个性状一个文件夹…

Jetpack:012-Jetpack中的弹出菜单

文章目录 1. 概念介绍2. 使用方法2.1 DropdownMenu2.2 DropdownMenuItem 3. 示例代码3.1 代码和注释3.2 代码难点3.3 运行效果 4. 内容总结 我们在上一章回中介绍了Jetpack中标题栏相关的内容&#xff0c;本章回中主要 弹出菜单。闲话休提&#xff0c;让我们一起Talk Android …

Appium+python+unittest搭建UI自动化框架!

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 1. 掌握一种编程语言基础&#xff0c;如java、python等。 2. 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架Appiu…

智能化巡检系统哪家好?巡检系统可以为企业单位带来什么便利?

设备点检是设备维修策略中预防维修的一个重要手段。在很多单位内也得到了广泛的应用&#xff0c;但是实施效果均不太理想&#xff0c;弄虚作假的情况时常存在。尽管现在是人手一机的时代&#xff0c;但仍然有不少企业以纸笔抄录作为点检模式&#xff0c;这样就容易存在一系列的…

HarmonyOS/OpenHarmony原生应用-ArkTS万能卡片组件Slider

滑动条组件&#xff0c;通常用于快速调节设置值&#xff0c;如音量调节、亮度调节等应用场景。该组件从API Version 7开始支持。无子组件 一、接口 Slider(options?: {value?: number, min?: number, max?: number, step?: number, style?: SliderStyle, direction?: Ax…

如何确定IP地址的具体位置?

IP地址通过几种方法帮助确定具体位置&#xff0c;尽管它们的准确性和精度因不同的情况而异。以下是几种确定具体位置的主要方法&#xff1a; 地理IP数据库&#xff1a;这是最常用的方法之一&#xff0c;它使用IP地址和地理位置数据的映射来确定用户的位置。这些数据库存储了大量…

节省工时超 1500人/天,国泰基金探索金融业人机协同新业态

“十四五”时期是我国经济实现从高速增长转变为高质量发展的关键历史时期&#xff0c;“十四五”规划向金融行业提出了数字化转型与科技监管的新要求。在新一轮科技革命和产业变革趋势下&#xff0c;新一代信息技术与金融行业融合加速&#xff0c;金融行业面临着监管要求与自身…

coreldraw2018零售版最新下载步骤

安装前一定要先退出杀毒软件&#xff1a;360杀毒、360安全卫士、腾讯管家等。 第一步&#xff1a;打开安装包 CorelDRAW2018版win下载如下:https://wm.makeding.com/iclk/?zoneid55678 CorelDRAW2018版mac下载如下:https://wm.makeding.com/iclk/?zoneid55679 第二步&…

AutoSAR入门:开发工具链介绍

1、AutoSAR愿景/目标 AutoSAR的目标&#xff0c;旨在进行嵌入式软件的标准化。 2、AutoSAR在BMS中的应用 国外公司BMS 做的比较好的有联电、大陆、德尔福、AVL 和FEV 等等&#xff0c; 现在基本上都是按照AUTOSAR架构以及ISO26262功能安全的要求来做&#xff0c;软件功能更多&…

Flutter笔记:发布一个Flutter头像模块 easy_avatar

Flutter笔记 发布一个头像Flutter模块 easy_avatar 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1339…

Stable Diffusion WebUI几种解决手崩溃的方法

1. 添加与手相关负面提示词 如何提价提示词呢? 首先有一个embeddings模型文件bad-hands-5,我们可以去各个大模型网站去搜,我是在C站上面下载的。 附上C站地址:https://civitai.com/ 下载好之后,你需要将文件放入stable-diffusion-webui\embeddings目录中。位置如下所示…