如何编写带界面的实用脚本

wen 实用脚本 1

本文目录导读:

如何编写带界面的实用脚本

  1. 使用 Python + Tkinter(最简单)
  2. 使用 Python + PyQt5(功能强大)
  3. 使用 HTML + JavaScript + Python后端(Web界面)
  4. 使用 Electron(桌面应用,跨平台)
  5. 最佳实践建议:

我来介绍几种编写带界面脚本的方法,从简单到复杂:

使用 Python + Tkinter(最简单)

文件管理工具示例:

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import os
import shutil
class FileManager:
    def __init__(self, root):
        self.root = root
        self.root.title("文件管理工具")
        self.root.geometry("500x400")
        # 创建界面组件
        self.create_widgets()
    def create_widgets(self):
        # 文件选择区域
        frame = ttk.Frame(self.root, padding="10")
        frame.grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(frame, text="选择文件", 
                  command=self.select_file).grid(row=0, column=0, padx=5)
        self.file_label = ttk.Label(frame, text="未选择文件")
        self.file_label.grid(row=0, column=1, padx=5)
        # 操作按钮区域
        frame2 = ttk.Frame(self.root, padding="10")
        frame2.grid(row=1, column=0, sticky=(tk.W, tk.E))
        ttk.Button(frame2, text="重命名", 
                  command=self.rename_file).grid(row=0, column=0, padx=5)
        ttk.Button(frame2, text="复制", 
                  command=self.copy_file).grid(row=0, column=1, padx=5)
        ttk.Button(frame2, text="移动", 
                  command=self.move_file).grid(row=0, column=2, padx=5)
        ttk.Button(frame2, text="删除", 
                  command=self.delete_file).grid(row=0, column=3, padx=5)
    def select_file(self):
        filename = filedialog.askopenfilename()
        if filename:
            self.file_label.config(text=filename)
    def rename_file(self):
        # 实现重命名功能
        pass
    def copy_file(self):
        # 实现复制功能
        pass
    def move_file(self):
        # 实现移动功能
        pass
    def delete_file(self):
        # 实现删除功能
        pass
# 运行应用
if __name__ == "__main__":
    root = tk.Tk()
    app = FileManager(root)
    root.mainloop()

使用 Python + PyQt5(功能强大)

批量重命名工具:

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
import os
class BatchRename(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        self.setWindowTitle('批量重命名工具')
        self.setGeometry(300, 300, 600, 400)
        # 主布局
        layout = QVBoxLayout()
        # 文件夹选择
        folder_layout = QHBoxLayout()
        self.folder_input = QLineEdit()
        self.folder_input.setPlaceholderText('选择文件夹...')
        self.browse_button = QPushButton('浏览')
        self.browse_button.clicked.connect(self.browse_folder)
        folder_layout.addWidget(self.folder_input)
        folder_layout.addWidget(self.browse_button)
        # 重命名规则
        rule_group = QGroupBox('重命名规则')
        rule_layout = QVBoxLayout()
        # 前缀
        prefix_layout = QHBoxLayout()
        prefix_layout.addWidget(QLabel('前缀:'))
        self.prefix_input = QLineEdit()
        prefix_layout.addWidget(self.prefix_input)
        rule_layout.addLayout(prefix_layout)
        # 后缀
        suffix_layout = QHBoxLayout()
        suffix_layout.addWidget(QLabel('后缀:'))
        self.suffix_input = QLineEdit()
        suffix_layout.addWidget(self.suffix_input)
        rule_layout.addLayout(suffix_layout)
        # 起始编号
        number_layout = QHBoxLayout()
        number_layout.addWidget(QLabel('起始编号:'))
        self.number_input = QSpinBox()
        self.number_input.setRange(1, 9999)
        number_layout.addWidget(self.number_input)
        rule_layout.addLayout(number_layout)
        rule_group.setLayout(rule_layout)
        # 预览列表
        self.file_list = QListWidget()
        # 执行按钮
        self.execute_button = QPushButton('执行重命名')
        self.execute_button.clicked.connect(self.rename_files)
        # 添加到主布局
        layout.addLayout(folder_layout)
        layout.addWidget(rule_group)
        layout.addWidget(QLabel('文件预览:'))
        layout.addWidget(self.file_list)
        layout.addWidget(self.execute_button)
        self.setLayout(layout)
    def browse_folder(self):
        folder = QFileDialog.getExistingDirectory(self, '选择文件夹')
        if folder:
            self.folder_input.setText(folder)
            self.load_files(folder)
    def load_files(self, folder):
        self.file_list.clear()
        for file in os.listdir(folder):
            if os.path.isfile(os.path.join(folder, file)):
                self.file_list.addItem(file)
    def rename_files(self):
        folder = self.folder_input.text()
        prefix = self.prefix_input.text()
        suffix = self.suffix_input.text()
        start_num = self.number_input.value()
        if not folder or not os.path.exists(folder):
            QMessageBox.warning(self, '错误', '请选择有效的文件夹')
            return
        count = 0
        for i in range(self.file_list.count()):
            old_name = self.file_list.item(i).text()
            old_path = os.path.join(folder, old_name)
            # 构建新文件名
            ext = os.path.splitext(old_name)[1]
            new_name = f"{prefix}{start_num + i}{suffix}{ext}"
            new_path = os.path.join(folder, new_name)
            try:
                os.rename(old_path, new_path)
                count += 1
            except Exception as e:
                QMessageBox.warning(self, '错误', f'重命名失败: {old_name}')
        QMessageBox.information(self, '成功', f'成功重命名 {count} 个文件')
        self.load_files(folder)
# 运行应用
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = BatchRename()
    window.show()
    sys.exit(app.exec_())

使用 HTML + JavaScript + Python后端(Web界面)

系统监控工具网页版:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">系统监控工具</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            background: #f0f2f5;
            margin: 0;
            padding: 20px;
        }
        .container {
            max-width: 1000px;
            margin: 0 auto;
        }
        .stats-grid {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
            margin-bottom: 20px;
        }
        .stat-card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .stat-value {
            font-size: 32px;
            font-weight: bold;
            color: #1890ff;
        }
        .stat-label {
            color: #666;
            margin-bottom: 10px;
        }
        button {
            background: #1890ff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }
        button:hover {
            background: #40a9ff;
        }
        #log-output {
            background: #000;
            color: #0f0;
            padding: 15px;
            border-radius: 4px;
            height: 200px;
            overflow-y: auto;
            font-family: monospace;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>系统监控工具</h1>
        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-label">CPU使用率</div>
                <div class="stat-value" id="cpu">0%</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">内存使用</div>
                <div class="stat-value" id="memory">0%</div>
            </div>
            <div class="stat-card">
                <div class="stat-label">磁盘使用</div>
                <div class="stat-value" id="disk">0%</div>
            </div>
        </div>
        <div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
            <h2>性能趋势</h2>
            <canvas id="trendChart"></canvas>
        </div>
        <div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
            <h2>操作面板</h2>
            <button onclick="runCommand('start_service')">启动服务</button>
            <button onclick="runCommand('stop_service')">停止服务</button>
            <button onclick="runCommand('reboot')">重启系统</button>
            <button onclick="runCommand('update_all')">更新所有包</button>
        </div>
        <div style="background: white; padding: 20px; border-radius: 8px;">
            <h2>系统日志</h2>
            <div id="log-output"></div>
        </div>
    </div>
    <script>
        // 更新统计信息
        function updateStats() {
            fetch('/api/stats')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('cpu').textContent = data.cpu + '%';
                    document.getElementById('memory').textContent = data.memory + '%';
                    document.getElementById('disk').textContent = data.disk + '%';
                    // 更新图表
                    updateChart(data);
                });
        }
        // 图表更新
        let chart;
        function updateChart(data) {
            const ctx = document.getElementById('trendChart').getContext('2d');
            if (!chart) {
                chart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: [],
                        datasets: [{
                            label: 'CPU',
                            data: [],
                            borderColor: 'rgb(255, 99, 132)',
                            backgroundColor: 'rgba(255, 99, 132, 0.2)'
                        }, {
                            label: 'Memory',
                            data: [],
                            borderColor: 'rgb(54, 162, 235)',
                            backgroundColor: 'rgba(54, 162, 235, 0.2)'
                        }]
                    },
                    options: { responsive: true }
                });
            }
            // 更新数据
            chart.data.labels.push(new Date().toLocaleTimeString());
            chart.data.datasets[0].data.push(data.cpu);
            chart.data.datasets[1].data.push(data.memory);
            chart.update();
        }
        // 执行命令
        function runCommand(command) {
            fetch('/api/command', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ command: command })
            })
            .then(response => response.json())
            .then(data => {
                logOutput(data.message);
            });
        }
        // 日志输出
        function logOutput(message) {
            const log = document.getElementById('log-output');
            const entry = document.createElement('div');
            entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
            log.appendChild(entry);
            log.scrollTop = log.scrollHeight;
        }
        // 定时更新
        setInterval(updateStats, 5000);
        updateStats();
    </script>
</body>
</html>

Python后端:

from flask import Flask, jsonify, request, render_template
import psutil
import subprocess
import json
app = Flask(__name__)
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/api/stats')
def get_stats():
    cpu_percent = psutil.cpu_percent(interval=1)
    memory_percent = psutil.virtual_memory().percent
    disk_percent = psutil.disk_usage('/').percent
    return jsonify({
        'cpu': cpu_percent,
        'memory': memory_percent,
        'disk': disk_percent
    })
@app.route('/api/command', methods=['POST'])
def execute_command():
    data = request.json
    command = data.get('command')
    commands = {
        'start_service': 'sudo systemctl start myservice',
        'stop_service': 'sudo systemctl stop myservice',
        'reboot': 'sudo reboot',
        'update_all': 'sudo apt-get update && sudo apt-get upgrade -y'
    }
    cmd = commands.get(command, 'echo "Unknown command"')
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
        return jsonify({'message': f'命令执行完成: {result.stdout}'})
    except Exception as e:
        return jsonify({'message': f'命令执行失败: {str(e)}'})
if __name__ == '__main__':
    app.run(debug=True)

使用 Electron(桌面应用,跨平台)

package.json:

{
  "name": "system-monitor",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^21.0.0"
  }
}

main.js:

const { app, BrowserWindow } = require('electron');
function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    });
    win.loadFile('index.html');
}
app.whenReady().then(createWindow);

最佳实践建议:

  1. 选择框架建议

    • 简单工具:Python Tkinter
    • 专业桌面应用:PyQt5 / Electron
    • Web界面:Flask + HTML/JS
    • 系统集成:结合实际需求选择
  2. 界面设计原则

    • 保持简洁直观
    • 提供清晰的反馈
    • 错误处理友好
    • 支持撤销/恢复
  3. 功能实现技巧

    • 异步处理耗时操作
    • 使用线程池
    • 完善日志记录
    • 支持配置保存
  4. 部署分发

    • PyInstaller(Python)
    • Electron Builder
    • Docker(Web版)

选择合适的技术栈,根据用户需求逐步完善功能,学会使用现成的UI库和组件能大大提升开发效率。

抱歉,评论功能暂时关闭!