本文目录导读:

- 使用 Python + Tkinter(最简单)
- 使用 Python + PyQt5(功能强大)
- 使用 HTML + JavaScript + Python后端(Web界面)
- 使用 Electron(桌面应用,跨平台)
- 最佳实践建议:
我来介绍几种编写带界面脚本的方法,从简单到复杂:
使用 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);
最佳实践建议:
-
选择框架建议
- 简单工具:Python Tkinter
- 专业桌面应用:PyQt5 / Electron
- Web界面:Flask + HTML/JS
- 系统集成:结合实际需求选择
-
界面设计原则
- 保持简洁直观
- 提供清晰的反馈
- 错误处理友好
- 支持撤销/恢复
-
功能实现技巧
- 异步处理耗时操作
- 使用线程池
- 完善日志记录
- 支持配置保存
-
部署分发
- PyInstaller(Python)
- Electron Builder
- Docker(Web版)
选择合适的技术栈,根据用户需求逐步完善功能,学会使用现成的UI库和组件能大大提升开发效率。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播