ubuntu环境下 基于Python 打包的 批量命令行可视化操作工具 GUI
文章目录
- 一.需求:
- 二.原理支撑:
- 三.简单Demo
- 四.封装成GUI
- 1.依赖库
- 2.代码
- 五.打包成可执行文件
- 六.命令行的配置
- 七.运行效果
一.需求:
作为测试工程师,为了到现场高效的调试,部署工作,需要一个可视化的工具,避免繁琐的记命令行和敲命令行,直接把命令行集成到可视化工具,运行某些命令时,点击按钮即可实现。
- 命令行配置简单,可动态添加命令行
- 支持多窗口运行
- 支持多命令行运行
- 支持命令行的顺序运行
二.原理支撑:
python os库下的system()函数
system("gnome-terminal --window -e 'bash -c \"pwd;ls;exec bash\"' --tab -e 'bash -c \"pwd; exec bash\"'");
其中:
gnome-terminal --window -e 'bash -c "pwd;ls; — 开启一个终端窗口 并运行 pwd和 ls
【先运行pwd后,再运行ls,同一个窗口不同命令用“;”间隔】
–tab -e ‘bash -c “pwd; exec bash”’" ---- 同一个窗口下开启另外一个tab 并运行指令 pwd
三.简单Demo
import os# 启动ROS2必须操作的前置条件, 运行ros2指令前需要添加的。
ros_path = "source /opt/ros/humble/setup.bash "# 这些是一些语法格式的需要 不需要修改
win_cmd = "gnome-terminal --window -e 'bash -c \"" + ros_path
tab_cmd = " --tab -e 'bash -c \"" + ros_path
end_cmd = ";exec bash\"'"def run_win(cmd):# 运行的第一个窗口终端cmd = win_cmd+cmd+end_cmdreturn cmddef run_tab(cmd, t):# 运行的标签终端delay_t = "sleep {};".format(str(t))cmd = tab_cmd+delay_t+cmd+end_cmdreturn cmd# t 指令运行之间的时间间隔
def run_cmd(cmds, t = 2):# 合成命令cmd = run_win(cmds[0])for i in range(1, len(cmds)):cmd = cmd + run_tab(cmds[i], t*i)#print(cmd)# 运行指令os.system(cmd)# 单窗口多指令 “;” 间隔
cmds = ["export TURTLEBOT3_MODEL=waffle;export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models;ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False"]# 多窗口多指令 列表 , 间隔
# cmds = ["export TURTLEBOT3_MODEL=waffle","export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models","ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False"]run_cmd(cmds)
四.封装成GUI
1.依赖库
PyQt5 5.15.6
PyYAML 5.4.1
pyinstaller 6.13.0
2.代码
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication,QVBoxLayout
from PyQt5.QtWidgets import QSystemTrayIcon, QPushButton,QMenu,QAction,QGridLayout
from PyQt5.QtGui import QIcon
# from system_hotkey import SystemHotkey # 热键#
from Ui_tools import Ui_MainWindow
from PyQt5.QtCore import Qt
import os
import yaml# 启动ROS2必须操作的前置条件, 运行ros2指令前需要添加的。
ros_path = "source /opt/ros/humble/setup.bash;"# 这些是一些语法格式的需要 不需要修改
win_cmd = "gnome-terminal --window -e 'bash -c \"" + ros_path
tab_cmd = " --tab -e 'bash -c \"" + ros_path
end_cmd = ";exec bash\"'"def run_win(cmd):# 运行的第一个窗口终端cmd = win_cmd+cmd+end_cmdreturn cmddef run_tab(cmd, t):# 运行的标签终端delay_t = "sleep {};".format(str(t))cmd = tab_cmd+delay_t+cmd+end_cmdreturn cmd# t 指令运行之间的时间间隔
def run_cmd(cmds, t = 2):# 合成命令cmd = run_win(cmds[0])for i in range(1, len(cmds)):cmd = cmd + run_tab(cmds[i], t*i)print("命令合成",cmd)# 运行指令os.system(cmd)# # 单窗口多指令 “;” 间隔
# cmds = ["export TURTLEBOT3_MODEL=waffle;export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models;ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False"]
# # 多窗口多指令 列表 , 间隔
# # cmds = ["export TURTLEBOT3_MODEL=waffle","export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models","ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False"]
# run_cmd(cmds)# 按钮样式设置
btn_style = """QPushButton {background-color: #87CEEB; /* 背景颜色 */border-radius: 10px; /* 圆角 */color: #000000; /* 文字颜色 */font-size: 25px; /* 字体大小 */font-family: "Microsoft YaHei"; /* 字体类型 */padding: 10px 10px; /* 内边距 */}QPushButton:hover {background-color: #00FFFF; /* 鼠标悬停时的背景颜色 */}QPushButton:pressed {background-color: #00BFFF; /* 按下时的背景颜色 */}"""
show_style ="""QPushButton {background-color: #B0C4DE; /* 背景颜色 */border-radius: 10px; /* 圆角 */color: #000000; /* 文字颜色 */font-size: 1px; /* 字体大小 */font-family: "Microsoft YaHei"; /* 字体类型 */padding: 10px 10px; /* 内边距 */background-image: url({0});background-position: center center;}QPushButton:hover {background-color: #808080; /* 鼠标悬停时的背景颜色 */}QPushButton:pressed {background-color: #696969; /* 按下时的背景颜色 */} """current_style = """QPushButton {background-color: #00BFFF; /* 背景颜色 */border-radius: 10px; /* 圆角 */color: #000000; /* 文字颜色 */font-size: 25px; /* 字体大小 */font-family: "Microsoft YaHei"; /* 字体类型 */padding: 10px 10px; /* 内边距 */}"""# 获取当前目录
current_dir = os.getcwd()# 获取data文件夹的路径
data_dir = os.path.join(current_dir, 'data')def get_dirs():'''获取当前目录下的data文件夹下的所有分区,及分区下的所有文件夹返回类型:列表下的字典[{'专业区': []}, {'办公区': ['a2345', 'WPS']}, {'工具区': []}, {'检测区': ['DiskGenius']}]'''result_list = []# 获取data文件夹中所有文件夹的名称result_list = [name for name in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, name))]return result_listclass MyMainWindow(QMainWindow,Ui_MainWindow): def __init__(self,parent =None):super(MyMainWindow,self).__init__(parent)# 读取命令行配置文件self.yaml_dict = Noneself.yaml_table = []self.yaml_table_current = None # 当前选中的组项self.read_yaml()# 初始化界面self.createTrayIcon()# 热键# self.hk_switch = SystemHotkey()# 绑定快捷键# self.hk_switch.register(('control','alt',"z"),callback=lambda x:self.hotkey_callback())# 创建按钮self.create_menu_button()# 第一次加载触发self.first_load()# 读取当前cmd_conf.yaml文件def read_yaml(self):with open('cmd_conf.yaml', 'r', encoding='utf-8') as f:result = yaml.load(f.read(), Loader=yaml.FullLoader)table_list = list(result.keys()) # 获取字典的键self.yaml_dict = resultself.yaml_table = table_list# 托盘设置def createTrayIcon(self):# 创建窗口self.setupUi(self)self.setWindowIcon(QIcon("tray.png"))self.setWindowTitle("Cmd Visual V1.0")# 创建系统托盘图标self.tray_icon = QSystemTrayIcon(self)self.tray_icon.setIcon(QIcon("tray.png"))self.tray_icon.setVisible(True)# 设置托盘图标的菜单menu = QMenu()show_action = QAction("显示窗口", menu)quit_action = QAction("退出", menu)menu.addAction(show_action)menu.addAction(quit_action)self.tray_icon.setContextMenu(menu)# 绑定菜单事件show_action.triggered.connect(self.show)quit_action.triggered.connect(self.close)# 创建一个表格布局self.grid_layout = QGridLayout()# 事件绑定def hotkey_callback(self):#判断当前窗口状态if self.isHidden():self.show()self.activateWindow()else:self.hide()# 列表创建菜单按钮def create_menu_button(self):layout_menu = QVBoxLayout()for i,menu_i in enumerate(self.yaml_table):menu_i = QPushButton(menu_i)# 设置手形menu_i.setCursor(Qt.PointingHandCursor)# 设置背景色为浅蓝色,圆角,选中时为深蓝色menu_i.setStyleSheet(btn_style)# 设置最小高度menu_i.setMinimumHeight(40)# 绑定事件menu_i.clicked.connect(self.button_clicked)# 添加到布局里layout_menu.addWidget(menu_i)if(i==0):menu_i.setStyleSheet(current_style)self.frame.setLayout(layout_menu)# 创建展示区按钮def create_show_button(self, subName):temp_list = []# self.temp_dir = os.path.join(data_dir, subName)# 获取data文件夹中所有文件夹的名称temp_list = self.yaml_dict.get(subName).keys()temp_list = list(temp_list)# print(temp_list)# # 根据列表创建按钮self.buttons = [QPushButton(f"{i}") for i in temp_list]# 在表格布局中添加按钮exe_icon = QIcon()for i, button in enumerate(self.buttons):button.setCursor(Qt.PointingHandCursor)# button.setStyleSheet(show_style)button.setMinimumSize(128, 50)button.setMaximumSize(128, 50)self.grid_layout.addWidget(button, i // 6, i % 6)# 绑定事件button.clicked.connect(self.start_exe)# # 添加到主窗口self.frame_2.setLayout(self.grid_layout)# 第一次加载时触发def first_load(self):self.create_show_button(self.yaml_table[0])self.yaml_table_current = self.yaml_table[0]# 按钮点击事件def button_clicked(self):#判断是哪个按钮的事件sender = self.sender()self.yaml_table_current = sender.text()# 获取self.frame中QVBoxLayout里的所有按钮for button in self.frame.findChildren(QPushButton):# 判断当前按钮是否为点击按钮if button == sender:# 设计当前按钮的背景色为深蓝色sender.setStyleSheet(current_style)# 清除frame2上的控件for i in reversed(range(self.grid_layout.count())): self.grid_layout.itemAt(i).widget().setParent(None)# 这里触发切换展示区的功能按钮self.create_show_button(sender.text())else:# 设置其他按钮保存原样button.setStyleSheet(btn_style)# 点击启动事件def start_exe(self):cmd_list = []# 获取当前按钮的文本current_test = self.sender().text()# 获取当前触发的指令current_cmd = self.yaml_dict.get(self.yaml_table_current).get(current_test)# 判断是多窗口指令【列表类型】,还是单窗口指令【字符串】if isinstance(current_cmd, list):cmd_list = current_cmdelse:cmd_list.append(current_cmd)print(cmd_list)# 运行当前指令run_cmd(cmd_list)if __name__ == "__main__":app = QApplication(sys.argv)myWin = MyMainWindow()myWin.show()sys.exit(app.exec_())
五.打包成可执行文件
这里的代码 xxx.py 改成 上面代码的文件名称
pyinstaller -F -w xxx.py
六.命令行的配置
一级:主题
子任务: shell指令
其中:
主题 -左侧标题栏的名称
子任务-按钮名称
shell指令-一个或在一组的指令,根据需求来
注意:
(1)指令之间有前后关系的,可以在同一窗口运行多指令;
(2)无则可配置成多窗口,独立运行;
(3)指令内部有空格,需要用双引号括起,避免与yaml语法冲突。
# 第一个工具栏
建图:# 多窗口指令 用 "-" 间隔多窗口指令录制包:- "ls"- "pwd"- "ls -l"- "ros2"- "cd ~"# 单窗口多指令 用 ";" 间隔多条指令创建地图: "ls;pwd;ros2"核对地图: "ros2"# 第二个工具栏
自驾:打开可视化: "ls"# 第三个工具栏
边界:打开配置文件: "ls"运行脚本: "pwd"拷贝到车端: "ros2"打开车端配置文件: "ls"超声波:打开配置文件: "cd ~/legion_framework/modules/perception/uss/uss_detection/bin/conf/perception/uss/uss_detection"数据可视化:ros_bag:
七.运行效果
相关文章:

ubuntu环境下 基于Python 打包的 批量命令行可视化操作工具 GUI
文章目录 一.需求:二.原理支撑:三.简单Demo四.封装成GUI1.依赖库2.代码 五.打包成可执行文件六.命令行的配置七.运行效果 一.需求: 作为测试工程师,为了到现场高效的调试,部署工作,需要一个可视化的工具&a…...
docker介绍与常用命令汇总
docker简介 docker是什么? Docker 是一个开源的应用容器引擎,它可以让开发者将应用与运行环境打包成一个标准的、可移植的容器(Container),在任何地方都可以快速部署和运行,无需关心底层环境是否一致。 …...
[创业之路-369]:企业战略管理案例分析-9-战略制定-差距分析的案例之华为
一、综合案例 在战略制定中,华为通过差距分析明确战略方向,以应对市场挑战和实现长期发展目标。 以下为具体案例与分析: 1、案例背景 华为在通信设备领域崛起过程中,始终将差距分析作为战略制定的核心环节。面对国际竞争对手&…...

谷歌宣布推出 Android 的新安全功能,以防止诈骗和盗窃
在上周二的 Android Show 上,也就是Google I/O 开发者大会之前,谷歌宣布了 Android 的全新安全和隐私功能。这些新功能包括对通话、屏幕共享、消息、设备访问和系统级权限的全新保护。谷歌希望通过这些功能保护用户免遭诈骗,在设备被盗或被攻…...

Qt/C++编写音视频实时通话程序/画中画/设备热插拔/支持本地摄像头和桌面
一、前言 近期有客户提需求,需要在嵌入式板子上和电脑之间音视频通话,要求用Qt开发,可以用第三方的编解码组件,能少用就尽量少用,以便后期移植起来方便。如果换成5年前的知识储备,估计会采用纯网络通信收发…...
Android trace presentFence屏幕显示的帧
Android trace presentFence屏幕显示的帧 presentFence :当帧成功显示到屏幕时,present fence就会signal。 FrameMissed/GpuFrameMissed/HwcFrameMissed表示上一次合成的结果,当SurfaceFlinger合成后显示到屏幕上,present fence就…...
Spring是如何实现scope作用域支持
众所周知在Spring的Bean当中是存在两种作用域的,即单例模式与多例模式,可通过scope来指定 下面就是注册一个多例Bean <bean id"people" class"org.qlspringframework.beans.ioc.bean.People" scope"prototype"> …...
Helm Chart 中配置多个 Docker Registry 地址以实现备用访问
在 Helm Chart 中配置多个 Docker Registry 地址以实现备用访问,可以通过以下几种方式实现: 1. 在 values.yaml 中定义多个 Registry 在 values.yaml 中定义主 Registry 和备用 Registry,以便在部署时灵活切换: # values.yaml …...
FreeSWITCH rtcp-mux 测试
rtcp 跟 rtp 占用同一个端口,这就是 rtcp 复用 Fs 呼出是这样的: originate [rtcp_muxtrue][rtcp_audio_interval_msec5000]user/1001 &echo 需要同时指定 rtcp_audio_interval_msec,否则 rtcp_mux 不能生效 Fs 呼入不需要配置…...

c++ 类的语法4
测试析构函数、虚函数、纯虚函数: void testClass5() {class Parent {public:Parent(int x) { cout << "Parent构造: " << x << endl; }~Parent() {cout << "调用Parent析构函数" << endl;}virtual string toSt…...

NMOS和PMOS的区别
1 区分NMOS和PMOS:衬底箭头指向G级的是NMOS,衬底箭头背向G级的是PMOS 2 区分D和S级:针对NMOS,体二极管的正方向为S级;针对PMOS,体二极管正的方向为D级 3 区分电流方向:针对NMOS,电…...

java云原生实战之graalvm 环境安装
windows环境安装 在Windows环境下安装GraalVM并启用原生镜像功能时,需要Visual Studio的组件支持。具体要点如下: 核心依赖: 需要安装Visual Studio 2022或更新版本,并确保勾选以下组件: "使用C的桌面开发"…...

2025年电工杯新规发布-近三年题目以及命题趋势
电工杯将于2025.5.23 周五早八正式开赛,该竞赛作为上半年度竞赛规模最大的竞赛,因免报名费、一级学会承办等因素,被众多高校认可。本文将在从2025年竞赛新规、历史赛题选题分析、近年优秀论文分享、竞赛模板分析等进行电工杯备赛,…...
python打卡day30@浙大疏锦行
知识点回顾: 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何导入 具体操作步骤: 在桌面…...

替换word中的excel
PostMapping("/make/report/target/performance/first") public AjaxResult makeTargetReportFirst(RequestBody MakeReportDTO makeReportDTO) {Map<String, String> textReplaceMap new HashMap<>();// 替换日期LocalDateTime nowData LocalDateTime…...

大模型服务如何实现高并发与低延迟
写在前面 大型语言模型(LLM)正以前所未有的速度渗透到各行各业,从智能客服、内容创作到代码生成、企业知识库,其应用场景日益丰富。然而,将这些强大的 AI 能力转化为稳定、高效、可大规模应用的服务,却面临着巨大的挑战,其中高并发处理能力和低响应延迟是衡量服务质量的…...
异丙肌苷市场:现状、挑战与未来展望
摘要 本文聚焦异丙肌苷市场,深入分析了其市场规模与增长趋势、应用价值与市场驱动因素、面临的挑战以及竞争格局。异丙肌苷作为一种具有重要应用价值的改性核苷衍生物,在药物研发和治疗领域展现出潜力,但市场发展也面临诸多挑战。文章最后为…...

OBS Studio:windows免费开源的直播与录屏软件
OBS Studio是一款免费、开源且跨平台的直播与录屏软件。其支持 Windows、macOS 和 Linux。OBS适用于,有直播需求的人群或录屏需求的人群。 Stars 数64,323Forks 数8413 主要特点 推流:OBS Studio 支持将视频实时推流至多个平台,如 YouTube、…...
[ 计算机网络 ] | 宏观谈谈计算机网络
(目录占位) 网络间通信,本质是不同的两个用户通信;本质是两个不同主机上的两个进程间通信。 因为物理距离的提升,就衍生出了很多问题。TCP/IP协议栈 / OSI七层模型,将协议分层,每一层都是为了…...

经典面试题:TCP 三次握手、四次挥手详解
在网络通信的复杂架构里,“三次握手”与“四次挥手”仿若一座无形的桥梁,它们是连接客户端与服务器的关键纽带。这座“桥梁”不仅确保了连接的稳固建立,还保障了连接的有序结束,使得网络世界中的信息能够顺畅、准确地流动。 在面…...

高光谱数据处理技术相关
一、Savitzky-Golay(SG)平滑 1. 基本概念 Savitzky-Golay(SG)平滑是一种基于局部多项式拟合的卷积算法,主要用于信号处理(如光谱、色谱数据)的去噪和平滑。其核心思想是通过滑动窗口内的多项式拟合来保留信号的原始特征(如峰形、宽度),同时抑制高频噪声。 2. 技术原…...
【动态规划】P10988 [蓝桥杯 2023 国 Python A] 走方格|普及+
本文涉及知识点 C动态规划 P10988 [蓝桥杯 2023 国 Python A] 走方格 题目描述 给定一个 N N N 行 N N N 列的方格,第 i i i 行第 j j j 列的方格坐标为 ( i , j ) (i, j) (i,j),高度为 H i , j H_{i,j} Hi,j。小蓝从左上角坐标 ( 0 , 0 ) …...
Rocketmq leader选举机制,通过美国大选解释
通过2020年美国大选的比喻,可以形象地解释RocketMQ的Leader选举机制(以DLedger模式为例)。我们将美国大选中的关键角色和流程映射到RocketMQ的集群中,帮助理解其工作原理。 1. 角色类比 美国大选RocketMQ DLedger集群说明选民&am…...

机器视觉的PVC卷对卷丝印应用
在现代工业制造领域,PVC卷对卷丝印工艺凭借其高效、灵活的特点,广泛应用于广告制作、包装印刷、电子产品装饰等多个行业。然而,在高速连续的丝印过程中,如何确保印刷图案的精准定位、色彩一致性以及质量稳定性,一直是困…...
利用 SQL Server 作业实现异步任务处理,简化系统架构
在现代企业系统中,异步任务是不可或缺的组成部分,例如: 电商系统中的订单超时取消; 报表系统中的异步数据导出; CRM 系统中的客户积分计算。 传统的实现方式通常涉及引入消息队列(如 RabbitMQ、Kafka&a…...

LabVIEW数据库使用说明
介绍LabVIEW如何在数据库中插入记录以及执行 SQL 查询,适用于对数据库进行数据管理和操作的场景。借助 Database Connectivity Toolkit,可便捷地与指定数据库交互。 各 VI 功能详述 左侧 VI 功能概述:实现向数据库表中插入数据的操作。当输入…...
MATLAB实现GAN用于图像分类
生成对抗网络(GAN)是一种强大的生成模型,由生成器(Generator)和判别器(Discriminator)组成。生成器用于生成图像,判别器用于判断图像是真实的还是生成的。在MATLAB中实现GAN用于图像…...

25考研经验贴(11408)
声明:以下内容都仅代表个人观点 数学一(130) 25考研数学一难度介绍:今年数学一整体不难,尤其是选填部分,大题的二型线面和概率论大题个人感觉比较奇怪,其他大题还是比较容易的。.26如何准备&a…...

java中的Filter使用详解
Filter(过滤器)是 Java Web 开发的核心组件之一,用于在请求到达 Servlet 或响应返回客户端之前进行拦截和处理。以下是其核心功能、使用方法和实际场景的详细解析: 一、Filter 的作用与原理 核心作用 Filter 充当请求与响应之间的…...
PostgreSQL初体验
目录 一、PostgreSQL 核心概述 (一)定义与定位 (二)核心特性与优势 (三)应用场景 二、PostgreSQL 安装实战(基于 OpenEuler 24) (一)编译安装ÿ…...