-
工具开发缘由:
由于在工作中经常会遇到需要给设备下发指令来进行操作,并且大部门指令都是固定的,并且有些还特别长,不易记住,经常通过复制&粘贴去下发效率不高,很繁琐,因此想做一个简单的小工具,可以直接通过点击按键的方式下发指令。当然有的人可能觉得用bat脚本不也可以嘛,当然也是可以的,但是如果命令行多了,每次执行的命令行顺序不固定,那是不是需要写很多个.bat脚本呢?当然这个就各求所需了哈。 -
下面介绍一下工具实现的界面是怎样的。
a.一个简单的输出框,用于输出命令行执行的回显
b.所有命令行都通过点击按钮下发
c.界面大致如下(很简洁)
-
UI需求:
a.每个按钮都可以自定义名称和指令
b.按键数量可以根据指令数量自动生成(例:我只有3个指令则只生成3个按钮)
c.回显内容的字体用颜色区分,便于快速识别。(下发的指令回显用黑色字体,执行返回结果用蓝色字体,报错的结果用红色字体)
d.按键为每行显示2个(如果命令行比较多的话也可以显示多个,可自行修改代码) -
实现思路
a.UI界面可以通过wxpython来做
b.命令行指令的下发可以通过subprocess来实现
c.按键名称和指令可以通过json文档来获取,key为按键名,value为指令,注:JSON文件名为command.json
d.按键数量通过循环自动生成,json中有多少key则生成多少按键。
e.json文件应与执行代码放在同一文件夹下,若没有json文档,首先会提示报错,然后会自动生成一份初始化json文件。
json文件样式:
5.代码:
# -- encoding:utf-8 --
import sys
import subprocess
import wx
import json
import os
class MyFrame(wx.Frame):
def __init__(self, parent, id, title, pos, size):
self.keys = [] # 用于存储json文件中的key的值,即命令行名称
self.names = [] # 用于存储json文件中的key的值,即命令行名称(因为后面会使用keys,但是keys的结果被改变,因此再另创建一个列表保持命令行名称)
wx.Frame.__init__(self, parent, id, title, pos, size)
# 获取json文本中的信息,并转换为JSON格式
self.panel = wx.Panel(self) # 创建一个panel
self.setting_panel()
# 初始化的数据,如果没有json文件,则会重新创建一个。
def creat_init(self):
data = {
'name1': 'command1',
'name2': 'command2',
'name3': 'command3',
'name4': 'command4'
}
read_me = '''
1.将command_tool.exe工具与command.json放在同一文件夹中(同一路径下)
2.command.json文件里面的数据必须以{“key”:"value"}的形式存储,其中必须为英文大括号,英文双引号以及英文冒号。
3.key的值可自定义,为按键名称,value的值为命令行
4.该工具建议最多设置18个命令行(左侧显示的Button数量),如果设置多了,可能无法完整显示后面的button,如果显示屏够大,可以尝试拉大工具窗口试试。
5.Button名字建议别太长,否则界面会不美观
'''
with open('command.json', 'a') as file:
file.write(json.dumps(data, indent=2))
# 如果没有readme.txt指导文件,也新创建一个指导文件
if not os.path.exists('ReadMe.text'):
with open('ReadMe.txt', 'a', encoding='utf-8') as file:
file.write(read_me)
# 创建UI并实现相关功能
def setting_panel(self):
border_h = 10 # 横向间隔
border_v = 15 # 纵向间隔
h_all = [] # 存储按键行数的列表,例如第一行的变量为h_all_0,第二行为h_all_1.注:每行两个button
self.variable = self.keys # 将button的变量名variable设置为keys的值(此变量名的值可以随便取,但是在for循环中要不断变化)
title = self.keys
# 标题
self.title = wx.StaticText(self.panel, id=-1, label="命令行调试工具", pos=(140, 50))
# 文本输出框 (pos是输出框位置,size是大小,可自行修改)
self.output_box = wx.TextCtrl(self.panel, pos=(330, 55), size=(720, 510), style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH|wx.EXPAND)
# 从command.json文件中读取命令行信息
try:
with open('command.json', 'r') as file:
file_data = file.read()
self.json_data = json.loads(file_data)
for json_key in self.json_data:
self.keys.append(json_key) # 将key值放入self.keys列表中以备后用
self.names.append(json_key) # 将key值放入self.names列表中以备后用
except:
self.output_box.SetDefaultStyle(wx.TextAttr(wx.RED)) # 将输出文字颜色变红
if not os.path.exists('command.json'):
self.output_box.AppendText('ERROR!!没有找到command.json文件!!\n已为您重新创建command.json文件,请阅读ReadMe指南进行操作!\n或将command.json文件与工具放在同一文件夹目录下!')
self.creat_init()
else:
self.output_box.AppendText("ERROR!未知错误!\n请检查command.json文件格式是否正确!")
self.output_box.SetDefaultStyle(wx.TextAttr(wx.NullColour)) # 将输出文字颜色变为默认黑色
# 创建Button,有多少条命令行则创建多少个Button,将Button名设置为json数据的key值(即命令行名称)
for i in range(len(self.keys)):
self.variable[i] = wx.Button(self.panel, label=title[i]) # 创建一个button
self.variable[i].Bind(wx.EVT_BUTTON, lambda evt, type=self.names[i]: self.command_exe(type)) # 按键事件,调用command_exe方法实现
# 获取一共有多少行按钮(每行两个按钮),如果按钮个数是偶数,则为按钮数除以2的商,如果按钮数为奇数,则行数为按钮数除以2加1
for i in range(len(self.keys) // 2):
h_all.append("h_all_" + str(i))
if len(self.keys) % 2 !=0:
h_all.append("h_all_" + str(len(self.keys)//2+1))
# 界面排版,每两个按钮一行
# 标题(横向位置显示)
h_title = wx.BoxSizer(wx.HORIZONTAL)
h_title.Add(self.title, proportion=0, flag=wx.MINIMIZE, border=20)
# Button(横向位置显示)
for i in range(len(h_all)):
h_all[i] = wx.BoxSizer(wx.HORIZONTAL)
h_all[i].Add(self.variable[i*2], proportion=0, flag=wx.LEFT | wx.RIGHT, border=border_h)
try:
h_all[i].Add(self.variable[i*2+1], proportion=0, flag=wx.LEFT | wx.RIGHT, border=border_h)
except:
pass
# 标题的纵向显示
v_all = wx.BoxSizer(wx.VERTICAL)
v_all.Add(h_title, proportion = 0, flag=wx.BOTTOM|wx.LEFT|wx.ALIGN_CENTER|wx.RIGHT|wx.TOP, border=15)
# 所有按键的纵向显示
for i in range(len(h_all)):
v_all.Add(h_all[i], proportion=0, flag=wx.BOTTOM | wx.LEFT | wx.TOP, border=border_v)
self.panel.SetSizer(v_all)
# 命令执行方法
def command_exe(self, type):
if type in self.names:
self.output_box.AppendText('--' * 20 + ' ' + type + ' ' + '--' * 20 + '\n')
try:
result = subprocess.Popen(self.json_data[type], stdout=subprocess.PIPE, shell=True)
self.output_box.AppendText(self.json_data[type] + '\n')
self.output_box.SetDefaultStyle(wx.TextAttr(wx.BLUE)) # 将后面输出字段设置为蓝色
self.output_box.AppendText(result.stdout.read().decode('gbk', "ignore"))
self.output_box.SetDefaultStyle(wx.TextAttr(wx.NullColour)) # 将后面输出字段设置为默认颜色(黑色)
except:
self.output_box.SetDefaultStyle(wx.TextAttr(wx.RED)) # 将后面输出字段设置为红色
self.output_box.AppendText('ERROR! ' + type + ' failed!' + '\n')
self.output_box.SetDefaultStyle(wx.TextAttr(wx.NullColour)) # 将后面输出字段设置为默认颜色(黑色)
else:
print('ERROR!!')
if __name__ == "__main__":
app = wx.App()
frame = MyFrame(parent=None, id=-1, title="命令行调试工具_v0.1", pos=(50, 30), size=(1100, 650)) # 可通过修改size值来自行修改窗口大小
frame.Show()
app.MainLoop()
6.总结:
工具实现不难,算上注释和空行才100多行代码,为了便于他人读懂特地加了很多注释。
功能的核心就是subprocess模块的运用,wxpython只是创建一个UI界面,然后便于灵活显示和执行,我们用json文件存储命令行,然后通过读取json存储的数据,来获取按键名和命令行。灵活显示则通过一个简单的for循环来实现。是不是so easy?
这样我们就可以把常用的命令行写入command.json文件中,然后想执行那个直接点击就可以了。后面如果有其他需求也可以自行完善。