简单计算器
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import operator
from typing import Callable, Dict
class Calculator:
"""简单计算器"""
def __init__(self):
self.window = tk.Tk()
self.window.title("简单计算器")
self.window.geometry("300x400")
self.window.resizable(False, False)
# 设置样式
self.style = ttk.Style()
self.style.configure('TButton', font=('Arial', 12))
self.style.configure('TEntry', font=('Arial', 14))
# 创建显示框
self.display_var = tk.StringVar()
self.display = ttk.Entry(
self.window,
textvariable=self.display_var,
justify='right',
font=('Arial', 20)
)
self.display.grid(row=0, column=0, columnspan=4, padx=5, pady=5, sticky='nsew')
# 定义按钮布局
self.buttons = [
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+'
]
# 创建按钮
self.create_buttons()
# 配置网格权重
for i in range(5):
self.window.grid_rowconfigure(i, weight=1)
for i in range(4):
self.window.grid_columnconfigure(i, weight=1)
# 绑定键盘事件
self.bind_keys()
# 初始化计算器状态
self.reset_calculator()
def create_buttons(self):
"""创建按钮"""
row = 1
col = 0
for button in self.buttons:
cmd = lambda x=button: self.click(x)
btn = ttk.Button(
self.window,
text=button,
command=cmd,
width=5
)
btn.grid(row=row, column=col, padx=2, pady=2, sticky='nsew')
col += 1
if col > 3:
col = 0
row += 1
# 添加清除按钮
clear_btn = ttk.Button(
self.window,
text='C',
command=self.clear,
width=5
)
clear_btn.grid(row=row, column=col, padx=2, pady=2, sticky='nsew')
def bind_keys(self):
"""绑定键盘事件"""
self.window.bind('', lambda event: self.calculate())
self.window.bind('', lambda event: self.backspace())
self.window.bind('', lambda event: self.clear())
# 绑定数字键
for i in range(10):
self.window.bind(str(i), lambda event, num=i: self.click(str(num)))
# 绑定运算符
self.window.bind('+', lambda event: self.click('+'))
self.window.bind('-', lambda event: self.click('-'))
self.window.bind('*', lambda event: self.click('*'))
self.window.bind('/', lambda event: self.click('/'))
self.window.bind('.', lambda event: self.click('.'))
def reset_calculator(self):
"""重置计算器状态"""
self.current_number = ''
self.first_number = None
self.operation = None
self.start_new_number = True
self.display_var.set('0')
def click(self, value: str):
"""处理按钮点击事件"""
if value.isdigit() or value == '.':
if self.start_new_number:
self.current_number = value
self.start_new_number = False
else:
if value == '.' and '.' in self.current_number:
return
self.current_number += value
self.display_var.set(self.current_number)
elif value in ['+', '-', '*', '/']:
if self.first_number is None:
self.first_number = float(self.current_number)
else:
self.calculate()
self.operation = value
self.start_new_number = True
elif value == '=':
self.calculate()
def calculate(self):
"""执行计算"""
if self.first_number is None or self.operation is None:
return
try:
second_number = float(self.current_number)
operations = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv
}
result = operations[self.operation](self.first_number, second_number)
# 格式化结果
if result.is_integer():
self.display_var.set(int(result))
else:
self.display_var.set(f"{result:.8f}".rstrip('0').rstrip('.'))
self.first_number = result
self.start_new_number = True
self.operation = None
except ZeroDivisionError:
messagebox.showerror("错误", "除数不能为零!")
self.clear()
except Exception as e:
messagebox.showerror("错误", f"计算错误: {str(e)}")
self.clear()
def clear(self):
"""清除显示"""
self.reset_calculator()
def backspace(self):
"""退格"""
if not self.start_new_number:
self.current_number = self.current_number[:-1]
if not self.current_number:
self.current_number = '0'
self.start_new_number = True
self.display_var.set(self.current_number)
def run(self):
"""运行计算器"""
self.window.mainloop()
if __name__ == '__main__':
calculator = Calculator()
calculator.run()
文件管理器
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog, messagebox
import os
from datetime import datetime
import shutil
from typing import Optional, List
import threading
import queue
class FileManager:
"""简单文件管理器"""
def __init__(self):
self.window = tk.Tk()
self.window.title("文件管理器")
self.window.geometry("800x600")
# 设置样式
self.style = ttk.Style()
self.style.configure('Treeview', font=('Arial', 10))
self.style.configure('TButton', font=('Arial', 10))
# 创建主框架
self.main_frame = ttk.Frame(self.window)
self.main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# 创建工具栏
self.create_toolbar()
# 创建文件树
self.create_file_tree()
# 创建状态栏
self.create_statusbar()
# 初始化变量
self.current_path = os.path.expanduser("~")
self.queue = queue.Queue()
# 更新文件列表
self.update_file_list()
# 启动消息处理线程
self.process_queue()
def create_toolbar(self):
"""创建工具栏"""
toolbar = ttk.Frame(self.main_frame)
toolbar.pack(fill=tk.X, padx=5, pady=5)
# 上级目录按钮
self.up_button = ttk.Button(
toolbar,
text="上级目录",
command=self.go_up
)
self.up_button.pack(side=tk.LEFT, padx=2)
# 刷新按钮
self.refresh_button = ttk.Button(
toolbar,
text="刷新",
command=self.update_file_list
)
self.refresh_button.pack(side=tk.LEFT, padx=2)
# 新建文件夹按钮
self.new_folder_button = ttk.Button(
toolbar,
text="新建文件夹",
command=self.create_folder
)
self.new_folder_button.pack(side=tk.LEFT, padx=2)
# 删除按钮
self.delete_button = ttk.Button(
toolbar,
text="删除",
command=self.delete_selected
)
self.delete_button.pack(side=tk.LEFT, padx=2)
# 路径输入框
self.path_var = tk.StringVar()
self.path_entry = ttk.Entry(
toolbar,
textvariable=self.path_var
)
self.path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=2)
self.path_entry.bind('', lambda e: self.navigate_to_path())
def create_file_tree(self):
"""创建文件树"""
# 创建树形视图
columns = ('name', 'size', 'type', 'modified')
self.tree = ttk.Treeview(
self.main_frame,
columns=columns,
show='headings'
)
# 设置列标题
self.tree.heading('name', text='名称', command=lambda: self.sort_tree('name'))
self.tree.heading('size', text='大小', command=lambda: self.sort_tree('size'))
self.tree.heading('type', text='类型', command=lambda: self.sort_tree('type'))
self.tree.heading('modified', text='修改时间', command=lambda: self.sort_tree('modified'))
# 设置列宽
self.tree.column('name', width=300)
self.tree.column('size', width=100)
self.tree.column('type', width=100)
self.tree.column('modified', width=150)
# 添加滚动条
scrollbar = ttk.Scrollbar(self.main_frame, orient=tk.VERTICAL, command=self.tree.yview)
self.tree.configure(yscrollcommand=scrollbar.set)
# 放置组件
self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 绑定双击事件
self.tree.bind('', self.on_double_click)
# 绑定右键菜单
self.create_context_menu()
def create_statusbar(self):
"""创建状态栏"""
self.statusbar = ttk.Label(
self.window,
text="",
anchor=tk.W
)
self.statusbar.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=2)
def create_context_menu(self):
"""创建右键菜单"""
self.context_menu = tk.Menu(self.window, tearoff=0)
self.context_menu.add_command(label="打开", command=self.open_selected)
self.context_menu.add_command(label="复制", command=self.copy_selected)
self.context_menu.add_command(label="剪切", command=self.cut_selected)
self.context_menu.add_command(label="粘贴", command=self.paste_files)
self.context_menu.add_separator()
self.context_menu.add_command(label="删除", command=self.delete_selected)
self.context_menu.add_command(label="重命名", command=self.rename_selected)
self.tree.bind('', self.show_context_menu)
def show_context_menu(self, event):
"""显示右键菜单"""
try:
self.context_menu.tk_popup(event.x_root, event.y_root)
finally:
self.context_menu.grab_release()
def update_file_list(self):
"""更新文件列表"""
# 清空树形视图
for item in self.tree.get_children():
self.tree.delete(item)
try:
# 获取文件列表
items = os.listdir(self.current_path)
# 添加文件和文件夹
for item in items:
full_path = os.path.join(self.current_path, item)
try:
stats = os.stat(full_path)
# 获取文件信息
size = self.format_size(stats.st_size)
modified = datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M')
if os.path.isdir(full_path):
type = "文件夹"
size = ""
else:
type = os.path.splitext(item)[1][1:].upper() or "文件"
self.tree.insert('', 'end', values=(item, size, type, modified))
except Exception as e:
print(f"Error processing {item}: {e}")
# 更新路径显示
self.path_var.set(self.current_path)
# 更新状态栏
self.update_status()
except Exception as e:
messagebox.showerror("错误", f"无法访问目录: {str(e)}")
def format_size(self, size: int) -> str:
"""格式化文件大小"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if size < 1024:
return f"{size:.1f} {unit}"
size /= 1024
return f"{size:.1f} PB"
def update_status(self):
"""更新状态栏"""
try:
items = os.listdir(self.current_path)
files = sum(1 for item in items if os.path.isfile(os.path.join(self.current_path, item)))
folders = sum(1 for item in items if os.path.isdir(os.path.join(self.current_path, item)))
self.statusbar.config(text=f"{folders} 个文件夹,{files} 个文件")
except Exception as e:
self.statusbar.config(text="")
def go_up(self):
"""转到上级目录"""
parent = os.path.dirname(self.current_path)
if parent != self.current_path:
self.current_path = parent
self.update_file_list()
def navigate_to_path(self):
"""导航到指定路径"""
path = self.path_var.get()
if os.path.exists(path):
self.current_path = path
self.update_file_list()
else:
messagebox.showerror("错误", "路径不存在!")
def on_double_click(self, event):
"""处理双击事件"""
selection = self.tree.selection()
if selection:
item = self.tree.item(selection[0])
name = item['values'][0]
path = os.path.join(self.current_path, name)
if os.path.isdir(path):
self.current_path = path
self.update_file_list()
else:
self.open_file(path)
def open_file(self, path: str):
"""打开文件"""
try:
os.startfile(path)
except Exception as e:
messagebox.showerror("错误", f"无法打开文件: {str(e)}")
def create_folder(self):
"""创建新文件夹"""
name = filedialog.askstring("新建文件夹", "请输入文件夹名称:")
if name:
path = os.path.join(self.current_path, name)
try:
os.mkdir(path)
self.update_file_list()
except Exception as e:
messagebox.showerror("错误", f"创建文件夹失败: {str(e)}")
def delete_selected(self):
"""删除选中的文件或文件夹"""
selection = self.tree.selection()
if not selection:
return
if not messagebox.askyesno("确认", "确定要删除选中的项目吗?"):
return
for item in selection:
values = self.tree.item(item)['values']
path = os.path.join(self.current_path, values[0])
try:
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)
except Exception as e:
messagebox.showerror("错误", f"删除失败: {str(e)}")
self.update_file_list()
def rename_selected(self):
"""重命名选中的文件或文件夹"""
selection = self.tree.selection()
if not selection:
return
old_name = self.tree.item(selection[0])['values'][0]
new_name = filedialog.askstring("重命名", "请输入新名称:", initialvalue=old_name)
if new_name and new_name != old_name:
old_path = os.path.join(self.current_path, old_name)
new_path = os.path.join(self.current_path, new_name)
try:
os.rename(old_path, new_path)
self.update_file_list()
except Exception as e:
messagebox.showerror("错误", f"重命名失败: {str(e)}")
def copy_selected(self):
"""复制选中的文件或文件夹"""
selection = self.tree.selection()
if selection:
self.clipboard = []
self.clipboard_op = 'copy'
for item in selection:
name = self.tree.item(item)['values'][0]
self.clipboard.append(os.path.join(self.current_path, name))
def cut_selected(self):
"""剪切选中的文件或文件夹"""
selection = self.tree.selection()
if selection:
self.clipboard = []
self.clipboard_op = 'cut'
for item in selection:
name = self.tree.item(item)['values'][0]
self.clipboard.append(os.path.join(self.current_path, name))
def paste_files(self):
"""粘贴文件或文件夹"""
if not hasattr(self, 'clipboard') or not self.clipboard:
return
for src in self.clipboard:
if not os.path.exists(src):
continue
dst = os.path.join(self.current_path, os.path.basename(src))
try:
if self.clipboard_op == 'copy':
if os.path.isdir(src):
shutil.copytree(src, dst)
else:
shutil.copy2(src, dst)
elif self.clipboard_op == 'cut':
shutil.move(src, dst)
except Exception as e:
messagebox.showerror("错误", f"粘贴失败: {str(e)}")
if self.clipboard_op == 'cut':
self.clipboard = []
self.update_file_list()
def sort_tree(self, col):
"""排序树形视图"""
# 获取所有项目
items = [(self.tree.set(item, col), item) for item in self.tree.get_children('')]
# 排序
items.sort()
# 重新插入项目
for index, (val, item) in enumerate(items):
self.tree.move(item, '', index)
def process_queue(self):
"""处理消息队列"""
try:
while True:
func, args = self.queue.get_nowait()
func(*args)
self.queue.task_done()
except queue.Empty:
self.window.after(100, self.process_queue)
def run(self):
"""运行文件管理器"""
self.window.mainloop()
if __name__ == '__main__':
file_manager = FileManager()
file_manager.run()