自学内容网 自学内容网

Python-基于PyQt5,subprocess,sys的命令行工具(最终版)

 前言:在程序员的日常工作中,常常会接触到计算机中的两个常见的命令行工具:CMD(命令提示符)和PowerShell。我们经常会使用它们来执行系统命令和自动化任务。其中CMDWindows NT系列操作系统中的命令行解释器,源自早期的MS-DOS。基于DOS命令(没错,就是我们常说的DDOS攻击中的DOS),语法相对简单,适合执行基础任务,主要用于执行批处理文件(.bat.cmd格式的文件)和基本的系统命令,并不支持对脚本文件等的操作(比如我们在CMD中输入运行Python脚本文件的命令时,CMD会显示没有权限)。相比之下,PowerShell则显得更现代化一些。PowerShell由微软开发,首次发布于2006年,旨在提供更强大的命令行环境和脚本语言。它支持复杂的脚本和自动化任务,能够管理本地和远程系统,处理对象而非纯文本(这和CMD的区别就比较大)。Powershell基于.NET框架,支持面向对象的脚本编写,语法更现代,功能更强大。可以这么说,Powershell是在CMD的基础上演变而来的更强大的命令行工具。话不多说,今天我们就一起来学习如何利用Python来编写一个类似CMD的命令行工具。

编程思路:本次编程中,我们将会调用到诸如PyQt5,subprocess,sys等库。其中,PyQt5为第三方库,sys,subprocess为标准库。我们将会利用PyQt5被用于创建一个简单的命令行工具的图形用户界面。通过使用PyQt5的QWidget,QVBoxLayout,QTextEdit,QLineEdit,QLabel和QPushButton等组件,构建出一个具有输入框、输出区域和按钮的命令行工具界面。同时,PyQt5中的信号与槽机制被用于将用户的输入和按钮点击事件等与程序反馈联系起来,使得应用程序具有人机交互特性。sys是一个Python的一个标准库,它将提供了对PyCharm相关的变量和函数的访问。我们将使用它来与PyCharm进行交互,例如获取系统的命令行参数、控制Python的运行时环境、访问系统中特定的参数和函数等。subprocess库比较简单,它同样是Python标准库中的一个模块,用于创建新的进程,连接到管道,并获取管道返回的状态码。 本次我们还会额外导入oslogging库。其中,logging用于创建和管理日志,os则用来获取计算机的相关信息。

第一步:导入库

标准库:sys,subprocess,os,logging。

第三方库:PyQt5。

#导入库
import sys
import subprocess
import os
import logging
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QTextEdit, QLineEdit,
    QLabel, QPushButton, QTabWidget, QCompleter, QToolButton,
    QHBoxLayout, QMessageBox, QMenuBar, QMenu, QAction)
from PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtGui import (
    QTextCursor, QSyntaxHighlighter, QTextCharFormat,
    QColor)

第二步:数据预处理

这里主要是对日志数据和主题参数等进行初始化处理。

#日志配置管理
logging.basicConfig(
    filename='cli_tool.log',
    level=logging.ERROR,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

#主题颜色配置
THEMES =\
    {
    "dark": {
        "bg": "#2D2D2D",
        "fg": "#CCCCCC",
        "input_bg": "#404040",
        "output_bg": "#1E1E1E",
        "button_bg": "#3C3C3C",
        "highlight_command": "#4EC9B0",
        "highlight_path": "#569CD6"
    },
    "light": {
        "bg": "#FFFFFF",
        "fg": "#000000",
        "input_bg": "#F0F0F0",
        "output_bg": "#FFFFFF",
        "button_bg": "#E0E0E0",
        "highlight_command": "#008000",
        "highlight_path": "#0000FF"
    },
    "blue": {
        "bg": "#1E3A5F",
        "fg": "#FFFFFF",
        "input_bg": "#2A4A7F",
        "output_bg": "#1E3A5F",
        "button_bg": "#3C5F9F",
        "highlight_command": "#00FF00",
        "highlight_path": "#00FFFF"
    },
    "green": {
        "bg": "#1E5F3A",
        "fg": "#FFFFFF",
        "input_bg": "#2A7F4A",
        "output_bg": "#1E5F3A",
        "button_bg": "#3C9F5F",
        "highlight_command": "#00FF00",
        "highlight_path": "#00FFFF"
    },
    "purple": {
        "bg": "#3A1E5F",
        "fg": "#FFFFFF",
        "input_bg": "#4A2A7F",
        "output_bg": "#3A1E5F",
        "button_bg": "#5F3C9F",
        "highlight_command": "#FF00FF",
        "highlight_path": "#FF00FF"
    },
    "orange": {
        "bg": "#5F3A1E",
        "fg": "#FFFFFF",
        "input_bg": "#7F4A2A",
        "output_bg": "#5F3A1E",
        "button_bg": "#9F5F3C",
        "highlight_command": "#FFA500",
        "highlight_path": "#FFA500"
    }}

第三步:创建功能类

接下来我们会创建两个功能类:命令行工具生成类和语法高亮类。

其中语法高亮类用于对提取的文本(文本框中)内容中的关键字进行高亮处理(包括命令和路径)。

命令行工具生成类则将GUI中各控件的布局与信号,槽之间的联系。

相比于上次,本次两个功能类又新增了几大个性化功能:

1,扩展主题切换功能(可以通过主题菜单在六种颜色主题中选择)。

2,新增文本内容搜索功能(可在输出的文本内容中搜索指定内容(存在则用黄色高亮显示))。

3,新增输入行高亮显示(提示用户命令执行起始位置)。

4,新增color命令自定义输出内容的颜色。

#命令行高亮类
class CommandHighlighter(QSyntaxHighlighter):
    def __init__(self, document, theme):
        super().__init__(document)
        self.theme = theme
        self.update_rules()

    def update_rules(self):
        self.highlight_rules = []
        # 命令高亮
        command_format = QTextCharFormat()
        command_format.setForeground(QColor(self.theme["highlight_command"]))
        self.highlight_rules.append((r'\b(ls|cd|mkdir|rmdir|cp|mv|rm|cat|echo|python|pip)\b', command_format))

        # 路径高亮
        path_format = QTextCharFormat()
        path_format.setForeground(QColor(self.theme["highlight_path"]))
        self.highlight_rules.append((r'\/[\w\/\.\-]+', path_format))

    def highlightBlock(self, text):
        for pattern, format in self.highlight_rules:
            expression = QRegExp(pattern)
            index = expression.indexIn(text)
            while index >= 0:
                length = expression.matchedLength()
                self.setFormat(index, length, format)
                index = expression.indexIn(text, index + length)


#命令行工具主类
class CommandLineTool(QWidget):
    #初始化函数
    def __init__(self):
        super().__init__()
        self.current_theme = "light"
        self.command_history = []
        self.history_index = -1
        self.highlighters = []  # 保存所有高亮器实例
        self.text_color = QColor("#000000")  # 默认文本颜色
        self.initUI()

    #用户界面初始化函数
    def initUI(self):
        # 窗口设置
        self.setWindowTitle('高级终端工具')
        self.setGeometry(100, 100, 1000, 800)

        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(0, 0, 0, 0)

        # 菜单栏
        menubar = QMenuBar()
        theme_menu = menubar.addMenu("主题")
        for theme_name in THEMES.keys():
            action = QAction(theme_name, self)
            action.triggered.connect(lambda _, name=theme_name: self.change_theme(name))
            theme_menu.addAction(action)
        main_layout.setMenuBar(menubar)

        # 工具栏
        toolbar = QHBoxLayout()

        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("搜索...")
        self.search_input.returnPressed.connect(self.search_text)
        toolbar.addWidget(self.search_input)

        # 搜索按钮
        search_button = QPushButton("搜索")
        search_button.clicked.connect(self.search_text)
        toolbar.addWidget(search_button)
        main_layout.addLayout(toolbar)

        # 标签页系统
        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)

        # 添加标签页按钮
        self.new_tab_btn = QToolButton()
        self.new_tab_btn.setText("添加标签页")
        self.new_tab_btn.clicked.connect(self.add_tab)
        self.tabs.setCornerWidget(self.new_tab_btn, Qt.TopRightCorner)
        main_layout.addWidget(self.tabs)
        self.setLayout(main_layout)

        # 初始化第一个标签页
        self.add_tab()
        self.apply_theme(THEMES[self.current_theme])


    def add_tab(self):#标签页添加函数
        tab = QWidget()
        layout = QVBoxLayout()

        self.command_input = QLineEdit()
        self.command_input.returnPressed.connect(lambda: self.execute_command(self.command_input))

        #XXX
        completer = QCompleter(self.get_common_commands())
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.command_input.setCompleter(completer)

        #SSS
        self.output_area = QTextEdit()
        self.output_area.setReadOnly(True)

        # 语法高亮实现
        highlighter = CommandHighlighter(self.output_area.document(), THEMES[self.current_theme])
        self.highlighters.append(highlighter)

        # 清除按钮
        clear_btn = QPushButton("清空输出")
        clear_btn.clicked.connect(self.output_area.clear)

        layout.addWidget(QLabel("Microsoft Windows [版本 10.0.22631.4751](c) Microsoft Corporation。保留所有权利。\n请输入命令:"))
        layout.addWidget(self.command_input)
        layout.addWidget(self.output_area)
        layout.addWidget(clear_btn)

        tab.setLayout(layout)
        self.tabs.addTab(tab, f"终端 {self.tabs.count() + 1}")
        self.apply_theme(THEMES[self.current_theme], tab)

    def close_tab(self, index):
        if self.tabs.count() > 1:
            widget = self.tabs.widget(index)
            widget.deleteLater()
            self.tabs.removeTab(index)

    def execute_command(self, input_widget):
        command = input_widget.text()
        if not command.strip():
            return

        self.command_history.append(command)
        self.history_index = len(self.command_history)

        #color命令实现
        if command.startswith("color"):
            self.change_text_color(command)
            input_widget.clear()
            return

        #try-except实现运行命令
        try:
            result = subprocess.check_output(
                command, shell=True,
                stderr=subprocess.STDOUT,
                text=True
            )
        except subprocess.CalledProcessError as e:
            result = f"命令执行失败: {e.output}"
            logging.error(f"命令执行失败: {command}\n{e.output}")
        except Exception as e:
            result = f"错误: {str(e)}"
            logging.error(f"命令执行失败: {command}\n{str(e)}")

        #显示结果
        current_tab = self.tabs.currentWidget()
        output_area = current_tab.findChild(QTextEdit)

        #模仿color命令
        cursor = output_area.textCursor()
        cursor.movePosition(QTextCursor.End)
        os_info = os.environ['USERNAME']
        cursor.insertText(f"PS C:\\Users\\{os_info}  ", self.get_text_format(QColor("gold")))  # 金色
        cursor.insertText(f"{command}\n", QTextCharFormat())  # 默认格式
        cursor.insertText(result, self.get_text_format(self.text_color))  # 自定义颜色格式

        #文本移到底部
        cursor.movePosition(QTextCursor.End)
        output_area.setTextCursor(cursor)
        input_widget.clear()

    def get_text_format(self, color):
        #获取文本格式
        format = QTextCharFormat()
        format.setForeground(color)
        return format

    def change_text_color(self, command):
        #color命令函数
        try:
            color = command.split()[1]
            self.text_color = QColor(color)
        except IndexError:
            current_tab = self.tabs.currentWidget()
            output_area = current_tab.findChild(QTextEdit)
            output_area.append("用法: color <颜色名称或十六进制值>")
        except Exception as e:
            current_tab = self.tabs.currentWidget()
            output_area = current_tab.findChild(QTextEdit)
            output_area.append(f"颜色设置失败: {str(e)}")


    def search_text(self):
        #文本搜索
        search_term = self.search_input.text()
        if not search_term:
            return

        current_tab = self.tabs.currentWidget()
        output_area = current_tab.findChild(QTextEdit)
        document = output_area.document()
        cursor = output_area.textCursor()

        #清除之前的高亮效果,容易找
        cursor.setPosition(0)
        cursor.movePosition(QTextCursor.End, QTextCursor.KeepAnchor)
        cursor.setCharFormat(QTextCharFormat())

        #标注
        format = QTextCharFormat()
        format.setBackground(QColor("yellow"))
        cursor = document.find(search_term)
        while not cursor.isNull():
            cursor.mergeCharFormat(format)
            cursor = document.find(search_term, cursor)


    def change_theme(self, theme_name):
        #主题切换
        self.current_theme = theme_name
        self.apply_theme(THEMES[theme_name])

    def apply_theme(self, theme, widget=None):
        target = widget if widget else self
        #主题循环
        for highlighter in self.highlighters:
            highlighter.theme = theme
            highlighter.update_rules()
            highlighter.rehighlight()
        def set_style(w):
            if isinstance(w, QTextEdit):
                w.setStyleSheet(f"""
                    background-color: {theme['output_bg']};
                    color: {theme['fg']};
                    border: none;
                    padding: 10px;
                """)
            elif isinstance(w, QLineEdit):
                w.setStyleSheet(f"""
                    background-color: {theme['input_bg']};
                    color: {theme['fg']};
                    border: 1px solid {theme['fg']};
                    padding: 5px;
                """)
            elif isinstance(w, QPushButton):
                w.setStyleSheet(f"""
                    background-color: {theme['button_bg']};
                    color: {theme['fg']};
                    border: none;
                    padding: 5px 10px;
                """)
            elif isinstance(w, QWidget):
                w.setStyleSheet(f"background-color: {theme['bg']}; color: {theme['fg']};")

            for child in w.children():
                set_style(child)

        set_style(target)


    def get_common_commands(self):
        #关键字补全
        return [
            'ls', 'cd', 'mkdir', 'rmdir', 'cp', 'mv', 'rm',
            'cat', 'echo', 'python', 'pip', 'git', 'ssh',
            'scp', 'grep', 'find', 'chmod', 'color'
        ]

    def keyPressEvent(self, event):
        current_tab = self.tabs.currentWidget()
        input_widget = current_tab.findChild(QLineEdit)

        if event.key() == Qt.Key_Up:
            if self.history_index > 0:
                self.history_index -= 1
                input_widget.setText(self.command_history[self.history_index])
        elif event.key() == Qt.Key_Down:
            if self.history_index < len(self.command_history) - 1:
                self.history_index += 1
                input_widget.setText(self.command_history[self.history_index])
        else:
            super().keyPressEvent(event)

    def closeEvent(self, event):
        #退出窗口
        reply = QMessageBox.question(
            self, '确认退出',
            "你确定要退出吗?",
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

第四步:还是和上次一样,这里我们也需要创建一个单独的片段来驱动命令行生成类中各函数的运行。

#驱动程序单元
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CommandLineTool()
    window.show()
    sys.exit(app.exec_())

第五步:完整代码展示

#导入库
import sys
import subprocess
import os
import logging
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QTextEdit, QLineEdit,
    QLabel, QPushButton, QTabWidget, QCompleter, QToolButton,
    QHBoxLayout, QMessageBox, QMenuBar, QMenu, QAction)
from PyQt5.QtCore import Qt, QRegExp
from PyQt5.QtGui import (
    QTextCursor, QSyntaxHighlighter, QTextCharFormat,
    QColor)

#日志配置管理
logging.basicConfig(
    filename='cli_tool.log',
    level=logging.ERROR,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

#主题颜色配置
THEMES =\
    {
    "dark": {
        "bg": "#2D2D2D",
        "fg": "#CCCCCC",
        "input_bg": "#404040",
        "output_bg": "#1E1E1E",
        "button_bg": "#3C3C3C",
        "highlight_command": "#4EC9B0",
        "highlight_path": "#569CD6"
    },
    "light": {
        "bg": "#FFFFFF",
        "fg": "#000000",
        "input_bg": "#F0F0F0",
        "output_bg": "#FFFFFF",
        "button_bg": "#E0E0E0",
        "highlight_command": "#008000",
        "highlight_path": "#0000FF"
    },
    "blue": {
        "bg": "#1E3A5F",
        "fg": "#FFFFFF",
        "input_bg": "#2A4A7F",
        "output_bg": "#1E3A5F",
        "button_bg": "#3C5F9F",
        "highlight_command": "#00FF00",
        "highlight_path": "#00FFFF"
    },
    "green": {
        "bg": "#1E5F3A",
        "fg": "#FFFFFF",
        "input_bg": "#2A7F4A",
        "output_bg": "#1E5F3A",
        "button_bg": "#3C9F5F",
        "highlight_command": "#00FF00",
        "highlight_path": "#00FFFF"
    },
    "purple": {
        "bg": "#3A1E5F",
        "fg": "#FFFFFF",
        "input_bg": "#4A2A7F",
        "output_bg": "#3A1E5F",
        "button_bg": "#5F3C9F",
        "highlight_command": "#FF00FF",
        "highlight_path": "#FF00FF"
    },
    "orange": {
        "bg": "#5F3A1E",
        "fg": "#FFFFFF",
        "input_bg": "#7F4A2A",
        "output_bg": "#5F3A1E",
        "button_bg": "#9F5F3C",
        "highlight_command": "#FFA500",
        "highlight_path": "#FFA500"
    }}


#命令行高亮类
class CommandHighlighter(QSyntaxHighlighter):
    def __init__(self, document, theme):
        super().__init__(document)
        self.theme = theme
        self.update_rules()

    def update_rules(self):
        self.highlight_rules = []
        # 命令高亮
        command_format = QTextCharFormat()
        command_format.setForeground(QColor(self.theme["highlight_command"]))
        self.highlight_rules.append((r'\b(ls|cd|mkdir|rmdir|cp|mv|rm|cat|echo|python|pip)\b', command_format))

        # 路径高亮
        path_format = QTextCharFormat()
        path_format.setForeground(QColor(self.theme["highlight_path"]))
        self.highlight_rules.append((r'\/[\w\/\.\-]+', path_format))

    def highlightBlock(self, text):
        for pattern, format in self.highlight_rules:
            expression = QRegExp(pattern)
            index = expression.indexIn(text)
            while index >= 0:
                length = expression.matchedLength()
                self.setFormat(index, length, format)
                index = expression.indexIn(text, index + length)


#命令行工具主类
class CommandLineTool(QWidget):
    #初始化函数
    def __init__(self):
        super().__init__()
        self.current_theme = "light"
        self.command_history = []
        self.history_index = -1
        self.highlighters = []  # 保存所有高亮器实例
        self.text_color = QColor("#000000")  # 默认文本颜色
        self.initUI()

    #用户界面初始化函数
    def initUI(self):
        # 窗口设置
        self.setWindowTitle('高级终端工具')
        self.setGeometry(100, 100, 1000, 800)

        # 主布局
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(0, 0, 0, 0)

        # 菜单栏
        menubar = QMenuBar()
        theme_menu = menubar.addMenu("主题")
        for theme_name in THEMES.keys():
            action = QAction(theme_name, self)
            action.triggered.connect(lambda _, name=theme_name: self.change_theme(name))
            theme_menu.addAction(action)
        main_layout.setMenuBar(menubar)

        # 工具栏
        toolbar = QHBoxLayout()

        # 搜索框
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("搜索...")
        self.search_input.returnPressed.connect(self.search_text)
        toolbar.addWidget(self.search_input)

        # 搜索按钮
        search_button = QPushButton("搜索")
        search_button.clicked.connect(self.search_text)
        toolbar.addWidget(search_button)
        main_layout.addLayout(toolbar)

        # 标签页系统
        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)

        # 添加标签页按钮
        self.new_tab_btn = QToolButton()
        self.new_tab_btn.setText("添加标签页")
        self.new_tab_btn.clicked.connect(self.add_tab)
        self.tabs.setCornerWidget(self.new_tab_btn, Qt.TopRightCorner)
        main_layout.addWidget(self.tabs)
        self.setLayout(main_layout)

        # 初始化第一个标签页
        self.add_tab()
        self.apply_theme(THEMES[self.current_theme])


    def add_tab(self):#标签页添加函数
        tab = QWidget()
        layout = QVBoxLayout()

        self.command_input = QLineEdit()
        self.command_input.returnPressed.connect(lambda: self.execute_command(self.command_input))

        #XXX
        completer = QCompleter(self.get_common_commands())
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.command_input.setCompleter(completer)

        #SSS
        self.output_area = QTextEdit()
        self.output_area.setReadOnly(True)

        # 语法高亮实现
        highlighter = CommandHighlighter(self.output_area.document(), THEMES[self.current_theme])
        self.highlighters.append(highlighter)

        # 清除按钮
        clear_btn = QPushButton("清空输出")
        clear_btn.clicked.connect(self.output_area.clear)

        layout.addWidget(QLabel("Microsoft Windows [版本 10.0.22631.4751](c) Microsoft Corporation。保留所有权利。\n请输入命令:"))
        layout.addWidget(self.command_input)
        layout.addWidget(self.output_area)
        layout.addWidget(clear_btn)

        tab.setLayout(layout)
        self.tabs.addTab(tab, f"终端 {self.tabs.count() + 1}")
        self.apply_theme(THEMES[self.current_theme], tab)

    def close_tab(self, index):
        if self.tabs.count() > 1:
            widget = self.tabs.widget(index)
            widget.deleteLater()
            self.tabs.removeTab(index)

    def execute_command(self, input_widget):
        command = input_widget.text()
        if not command.strip():
            return

        self.command_history.append(command)
        self.history_index = len(self.command_history)

        #color命令实现
        if command.startswith("color"):
            self.change_text_color(command)
            input_widget.clear()
            return

        #try-except实现运行命令
        try:
            result = subprocess.check_output(
                command, shell=True,
                stderr=subprocess.STDOUT,
                text=True
            )
        except subprocess.CalledProcessError as e:
            result = f"命令执行失败: {e.output}"
            logging.error(f"命令执行失败: {command}\n{e.output}")
        except Exception as e:
            result = f"错误: {str(e)}"
            logging.error(f"命令执行失败: {command}\n{str(e)}")

        #显示结果
        current_tab = self.tabs.currentWidget()
        output_area = current_tab.findChild(QTextEdit)

        #模仿color命令
        cursor = output_area.textCursor()
        cursor.movePosition(QTextCursor.End)
        os_info = os.environ['USERNAME']
        cursor.insertText(f"PS C:\\Users\\{os_info}  ", self.get_text_format(QColor("gold")))  # 金色
        cursor.insertText(f"{command}\n", QTextCharFormat())  # 默认格式
        cursor.insertText(result, self.get_text_format(self.text_color))  # 自定义颜色格式

        #文本移到底部
        cursor.movePosition(QTextCursor.End)
        output_area.setTextCursor(cursor)
        input_widget.clear()

    def get_text_format(self, color):
        #获取文本格式
        format = QTextCharFormat()
        format.setForeground(color)
        return format

    def change_text_color(self, command):
        #color命令函数
        try:
            color = command.split()[1]
            self.text_color = QColor(color)
        except IndexError:
            current_tab = self.tabs.currentWidget()
            output_area = current_tab.findChild(QTextEdit)
            output_area.append("用法: color <颜色名称或十六进制值>")
        except Exception as e:
            current_tab = self.tabs.currentWidget()
            output_area = current_tab.findChild(QTextEdit)
            output_area.append(f"颜色设置失败: {str(e)}")


    def search_text(self):
        #文本搜索
        search_term = self.search_input.text()
        if not search_term:
            return

        current_tab = self.tabs.currentWidget()
        output_area = current_tab.findChild(QTextEdit)
        document = output_area.document()
        cursor = output_area.textCursor()

        #清除之前的高亮效果,容易找
        cursor.setPosition(0)
        cursor.movePosition(QTextCursor.End, QTextCursor.KeepAnchor)
        cursor.setCharFormat(QTextCharFormat())

        #标注
        format = QTextCharFormat()
        format.setBackground(QColor("yellow"))
        cursor = document.find(search_term)
        while not cursor.isNull():
            cursor.mergeCharFormat(format)
            cursor = document.find(search_term, cursor)


    def change_theme(self, theme_name):
        #主题切换
        self.current_theme = theme_name
        self.apply_theme(THEMES[theme_name])

    def apply_theme(self, theme, widget=None):
        target = widget if widget else self
        #主题循环
        for highlighter in self.highlighters:
            highlighter.theme = theme
            highlighter.update_rules()
            highlighter.rehighlight()
        def set_style(w):
            if isinstance(w, QTextEdit):
                w.setStyleSheet(f"""
                    background-color: {theme['output_bg']};
                    color: {theme['fg']};
                    border: none;
                    padding: 10px;
                """)
            elif isinstance(w, QLineEdit):
                w.setStyleSheet(f"""
                    background-color: {theme['input_bg']};
                    color: {theme['fg']};
                    border: 1px solid {theme['fg']};
                    padding: 5px;
                """)
            elif isinstance(w, QPushButton):
                w.setStyleSheet(f"""
                    background-color: {theme['button_bg']};
                    color: {theme['fg']};
                    border: none;
                    padding: 5px 10px;
                """)
            elif isinstance(w, QWidget):
                w.setStyleSheet(f"background-color: {theme['bg']}; color: {theme['fg']};")

            for child in w.children():
                set_style(child)

        set_style(target)


    def get_common_commands(self):
        #关键字补全
        return [
            'ls', 'cd', 'mkdir', 'rmdir', 'cp', 'mv', 'rm',
            'cat', 'echo', 'python', 'pip', 'git', 'ssh',
            'scp', 'grep', 'find', 'chmod', 'color'
        ]

    def keyPressEvent(self, event):
        current_tab = self.tabs.currentWidget()
        input_widget = current_tab.findChild(QLineEdit)

        if event.key() == Qt.Key_Up:
            if self.history_index > 0:
                self.history_index -= 1
                input_widget.setText(self.command_history[self.history_index])
        elif event.key() == Qt.Key_Down:
            if self.history_index < len(self.command_history) - 1:
                self.history_index += 1
                input_widget.setText(self.command_history[self.history_index])
        else:
            super().keyPressEvent(event)

    def closeEvent(self, event):
        #退出窗口
        reply = QMessageBox.question(
            self, '确认退出',
            "你确定要退出吗?",
            QMessageBox.Yes | QMessageBox.No,
            QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

#驱动程序单元
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = CommandLineTool()
    window.show()
    sys.exit(app.exec_())

第六步:运行效果展示

由于图片过多,放在我的下一篇文章中了

 第七步:操作指南

运行程序:

1. 错误处理:
   - 如果命令执行失败,错误信息会显示在输出区域,并记录到日志文件中。

2. 添加标签:

  - 点击窗口左上角的"主题"菜单,在菜单中点击选择即可。

3. 删除当前所有内容:

  - 点击窗口下方的"清空输出"按钮。

4. 输入并执行命令:

  - 在输入框中输入命令并回车(按下Enter键)。

5. 关闭窗口:
  - 点击窗口关闭按钮时,会弹出确认对话框。
  - 只有用户明确选择“是”时,窗口才会关闭。

6. 文本颜色切换:

  - 在输入框中输入color <颜色> 命令并回车。例如:color red 或 color #00FF00,下一个命令输出的文本内容就会呈现为输入红色。 

7. 搜索文本:
  - 在工具栏的搜索框中输入文本,按下回车或点击“搜索”按钮。
  - 搜索到的文本会用黄色来高亮显示。

第八步:注意事项

- 该工具仅支持文本操作,无法对脚本进行直接操作。

- 存在退出机制错误问题。


原文地址:https://blog.csdn.net/2401_83954530/article/details/145500933

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!