/
sosh6yug
/
Random
Обзор
Документация
Войти
/
sosh6yug
/
Random
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
10.py
391 строка
19 KB
sosh6yug
create: .getignore, 10.py, README.md, task_history.json
05 май 2026, 15:08
Верифицирован
05 май 2026, 15:08
1c0bb0c
Код
Авторство
О чём код?
import tkinter as tk from tkinter import ttk, messagebox import random import json import os from datetime import datetime # ------------------------------- # Предопределённые задачи # ------------------------------- DEFAULT_TASKS = [ {"name": "Прочитать статью", "type": "учёба"}, {"name": "Сделать зарядку", "type": "спорт"}, {"name": "Ответить на письма", "type": "работа"}, {"name": "Изучить Python", "type": "учёба"}, {"name": "Пробежка 5 км", "type": "спорт"}, {"name": "Составить отчёт", "type": "работа"}, {"name": "Посмотреть лекцию", "type": "учёба"}, {"name": "Йога 15 мин", "type": "спорт"}, {"name": "Провести встречу", "type": "работа"}, {"name": "Решить задачи", "type": "учёба"}, {"name": "Отжимания 30 раз", "type": "спорт"}, {"name": "Запланировать неделю", "type": "работа"} ] HISTORY_FILE = "task_history.json" class TaskGeneratorApp: def __init__(self, root): self.root = root self.root.title("Генератор случайных задач") self.root.geometry("750x600") self.root.resizable(True, True) self.root.configure(bg='#f0f7ff') # Данные self.tasks = DEFAULT_TASKS.copy() self.history = [] self.load_history() # Переменная для фильтра self.filter_type = tk.StringVar(value="Все") # Создание интерфейса self.create_widgets() # Обновление отображения self.refresh_history_display() # Обработка закрытия окна self.root.protocol("WM_DELETE_WINDOW", self.on_close) # ------------------------------- # Создание интерфейса # ------------------------------- def create_widgets(self): # Заголовок title_frame = tk.Frame(self.root, bg='#f0f7ff') title_frame.pack(fill=tk.X, pady=10) title_label = tk.Label(title_frame, text="🎲 Генератор случайных задач", font=("Arial", 18, "bold"), bg='#f0f7ff', fg='#2c3e50') title_label.pack() # Основной фрейм main_frame = tk.Frame(self.root, bg='#f0f7ff') main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10) # ---- Панель генерации ---- generate_frame = tk.LabelFrame(main_frame, text="Генерация задачи", font=("Arial", 12, "bold"), bg='#f0f7ff') generate_frame.pack(fill=tk.X, pady=10) self.current_task_label = tk.Label(generate_frame, text="Нажмите кнопку\nчтобы получить задачу", font=("Arial", 14), bg='#ffffff', fg='#2c3e50', relief=tk.RAISED, padx=20, pady=20) self.current_task_label.pack(pady=10, padx=20, fill=tk.X) self.generate_btn = tk.Button(generate_frame, text="✨ Сгенерировать задачу ✨", command=self.generate_task, font=("Arial", 12, "bold"), bg='#3498db', fg='white', padx=20, pady=5, activebackground='#2980b9', cursor='hand2') self.generate_btn.pack(pady=10) # ---- Панель фильтрации ---- filter_frame = tk.LabelFrame(main_frame, text="Фильтрация истории", font=("Arial", 12, "bold"), bg='#f0f7ff') filter_frame.pack(fill=tk.X, pady=10) filter_row = tk.Frame(filter_frame, bg='#f0f7ff') filter_row.pack(pady=10) tk.Label(filter_row, text="Тип задачи:", font=("Arial", 10), bg='#f0f7ff').pack(side=tk.LEFT, padx=5) self.filter_combo = ttk.Combobox(filter_row, textvariable=self.filter_type, values=["Все", "учёба", "спорт", "работа"], state="readonly", width=15) self.filter_combo.pack(side=tk.LEFT, padx=5) self.filter_combo.bind("<<ComboboxSelected>>", lambda e: self.refresh_history_display()) tk.Button(filter_row, text="🔄 Сбросить фильтр", command=self.reset_filter, bg='#95a5a6', fg='white', cursor='hand2').pack(side=tk.LEFT, padx=10) tk.Button(filter_row, text="➕ Добавить задачу", command=self.add_task_dialog, bg='#27ae60', fg='white', cursor='hand2').pack(side=tk.LEFT, padx=10) # ---- История задач ---- history_frame = tk.LabelFrame(main_frame, text="История сгенерированных задач", font=("Arial", 12, "bold"), bg='#f0f7ff') history_frame.pack(fill=tk.BOTH, expand=True, pady=10) # Список с прокруткой list_container = tk.Frame(history_frame, bg='#f0f7ff') list_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) scrollbar = tk.Scrollbar(list_container) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.history_listbox = tk.Listbox(list_container, yscrollcommand=scrollbar.set, font=("Consolas", 10), bg='#ffffff', selectmode=tk.SINGLE, height=12) self.history_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.config(command=self.history_listbox.yview) # Контекстное меню self.context_menu = tk.Menu(self.root, tearoff=0) self.context_menu.add_command(label="📋 Копировать задачу", command=self.copy_selected_task) self.context_menu.add_command(label="🗑️ Удалить из истории", command=self.delete_selected_task) self.history_listbox.bind("<Button-3>", self.show_context_menu) # ---- Нижняя панель ---- bottom_frame = tk.Frame(main_frame, bg='#f0f7ff') bottom_frame.pack(fill=tk.X, pady=10) self.status_label = tk.Label(bottom_frame, text="Готов к работе", font=("Arial", 9), bg='#f0f7ff', fg='#7f8c8d') self.status_label.pack(side=tk.LEFT) tk.Button(bottom_frame, text="🗑️ Очистить историю", command=self.clear_history, bg='#e74c3c', fg='white', cursor='hand2').pack(side=tk.RIGHT, padx=5) tk.Button(bottom_frame, text="📊 Статистика", command=self.show_statistics, bg='#3498db', fg='white', cursor='hand2').pack(side=tk.RIGHT, padx=5) # ------------------------------- # Логика генерации задачи # ------------------------------- def generate_task(self): """Выбирает случайную задачу и добавляет в историю""" if not self.tasks: messagebox.showwarning("Нет задач", "Сначала добавьте задачи через кнопку «Добавить задачу»") return task = random.choice(self.tasks) # Добавляем в историю с временной меткой history_entry = { "name": task["name"], "type": task["type"], "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } self.history.insert(0, history_entry) # Новые записи в начало # Сохраняем историю self.save_history() # Отображаем текущую задачу emoji = self.get_type_emoji(task["type"]) self.current_task_label.config(text=f"{emoji} {task['name']}\n(тип: {task['type']})", fg='#27ae60', font=("Arial", 14, "bold")) # Обновляем список истории self.refresh_history_display() # Обновляем статус self.status_label.config(text=f"✓ Сгенерирована задача: {task['name']}") # Визуальный эффект кнопки self.generate_btn.config(text="✅ Сгенерировано!", bg='#27ae60') self.root.after(1000, lambda: self.generate_btn.config(text="✨ Сгенерировать задачу ✨", bg='#3498db')) def get_type_emoji(self, task_type): """Возвращает эмодзи для типа задачи""" emojis = { "учёба": "📚", "спорт": "🏃", "работа": "💼" } return emojis.get(task_type, "🎯") # ------------------------------- # Работа с историей # ------------------------------- def refresh_history_display(self): """Обновляет отображение истории с учётом фильтра""" self.history_listbox.delete(0, tk.END) # Фильтрация filtered_history = self.history if self.filter_type.get() != "Все": filtered_history = [t for t in self.history if t["type"] == self.filter_type.get()] if not filtered_history: self.history_listbox.insert(tk.END, "📭 Нет задач по выбранному фильтру") return # Отображение задач for task in filtered_history: emoji = self.get_type_emoji(task["type"]) display_text = f"[{task['timestamp']}] {emoji} {task['type'].upper()} → {task['name']}" self.history_listbox.insert(tk.END, display_text) self.status_label.config(text=f"Показано: {len(filtered_history)} из {len(self.history)} записей") def reset_filter(self): """Сбрасывает фильтр""" self.filter_type.set("Все") self.refresh_history_display() self.status_label.config(text="Фильтр сброшен") def copy_selected_task(self): """Копирует выбранную задачу в буфер обмена""" selection = self.history_listbox.curselection() if selection: task_text = self.history_listbox.get(selection[0]) self.root.clipboard_clear() self.root.clipboard_append(task_text) self.status_label.config(text="✓ Задача скопирована в буфер обмена") messagebox.showinfo("Успех", "Задача скопирована в буфер обмена!") def delete_selected_task(self): """Удаляет выбранную задачу из истории""" selection = self.history_listbox.curselection() if selection: if messagebox.askyesno("Подтверждение", "Удалить эту задачу из истории?"): # Находим и удаляем задачу filtered = self.get_filtered_history() if selection[0] < len(filtered): task_to_delete = filtered[selection[0]] self.history = [t for t in self.history if t != task_to_delete] self.save_history() self.refresh_history_display() self.status_label.config(text="✓ Задача удалена из истории") def get_filtered_history(self): """Возвращает отфильтрованную историю""" if self.filter_type.get() == "Все": return self.history return [t for t in self.history if t["type"] == self.filter_type.get()] def clear_history(self): """Очищает всю историю""" if messagebox.askyesno("Подтверждение", "Вы уверены, что хотите очистить всю историю?"): self.history = [] self.save_history() self.refresh_history_display() self.status_label.config(text="История очищена") def show_context_menu(self, event): """Показывает контекстное меню""" selection = self.history_listbox.curselection() if selection: self.context_menu.post(event.x_root, event.y_root) # ------------------------------- # Добавление новых задач # ------------------------------- def add_task_dialog(self): """Диалог для добавления новой задачи""" dialog = tk.Toplevel(self.root) dialog.title("Добавить задачу") dialog.geometry("450x300") dialog.transient(self.root) dialog.grab_set() dialog.configure(bg='#f0f7ff') # Центрирование окна dialog.update_idletasks() x = self.root.winfo_x() + (self.root.winfo_width() - 450) // 2 y = self.root.winfo_y() + (self.root.winfo_height() - 300) // 2 dialog.geometry(f"+{x}+{y}") # Поля ввода tk.Label(dialog, text="Название задачи:", font=("Arial", 10, "bold"), bg='#f0f7ff').pack(pady=(15, 5)) name_entry = tk.Entry(dialog, width=50, font=("Arial", 10)) name_entry.pack(pady=5, padx=20) tk.Label(dialog, text="Тип задачи:", font=("Arial", 10, "bold"), bg='#f0f7ff').pack(pady=(10, 5)) type_var = tk.StringVar(value="учёба") type_combo = ttk.Combobox(dialog, textvariable=type_var, values=["учёба", "спорт", "работа"], state="readonly", width=20) type_combo.pack(pady=5) def save_task(): name = name_entry.get().strip() task_type = type_var.get() # Проверка на пустую строку if not name: messagebox.showerror("Ошибка", "Название задачи не может быть пустым!", parent=dialog) return # Проверка на дубликат for task in self.tasks: if task["name"].lower() == name.lower() and task["type"] == task_type: messagebox.showwarning("Предупреждение", "Такая задача уже существует!", parent=dialog) return # Добавление задачи self.tasks.append({"name": name, "type": task_type}) messagebox.showinfo("Успех", f"Задача «{name}» добавлена!", parent=dialog) self.status_label.config(text=f"Добавлена задача: {name}") dialog.destroy() btn_frame = tk.Frame(dialog, bg='#f0f7ff') btn_frame.pack(pady=20) tk.Button(btn_frame, text="Сохранить", command=save_task, bg='#27ae60', fg='white', font=("Arial", 10), width=12).pack(side=tk.LEFT, padx=5) tk.Button(btn_frame, text="Отмена", command=dialog.destroy, bg='#e74c3c', fg='white', font=("Arial", 10), width=12).pack(side=tk.LEFT, padx=5) name_entry.focus() # ------------------------------- # Статистика # ------------------------------- def show_statistics(self): """Показывает статистику по задачам""" if not self.history: messagebox.showinfo("Статистика", "Нет данных для статистики. Сначала сгенерируйте несколько задач.") return total = len(self.history) study = len([t for t in self.history if t["type"] == "учёба"]) sport = len([t for t in self.history if t["type"] == "спорт"]) work = len([t for t in self.history if t["type"] == "работа"]) stats_text = f"""📊 Статистика сгенерированных задач: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📌 Всего задач: {total} 📚 Учёба: {study} ({study/total*100:.1f}%) 🏃 Спорт: {sport} ({sport/total*100:.1f}%) 💼 Работа: {work} ({work/total*100:.1f}%) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📝 Доступно задач в списке: {len(self.tasks)} 🕐 Первая запись: {self.history[-1]['timestamp'] if self.history else 'Нет'} 🕐 Последняя запись: {self.history[0]['timestamp'] if self.history else 'Нет'} """ messagebox.showinfo("Статистика", stats_text) # ------------------------------- # Работа с JSON # ------------------------------- def load_history(self): """Загружает историю из JSON файла""" if os.path.exists(HISTORY_FILE): try: with open(HISTORY_FILE, "r", encoding="utf-8") as f: self.history = json.load(f) self.status_label.config(text=f"Загружено {len(self.history)} записей из истории") except (json.JSONDecodeError, IOError) as e: print(f"Ошибка загрузки: {e}") self.history = [] def save_history(self): """Сохраняет историю в JSON файл""" try: with open(HISTORY_FILE, "w", encoding="utf-8") as f: json.dump(self.history, f, ensure_ascii=False, indent=2) return True except Exception as e: print(f"Ошибка сохранения: {e}") return False def on_close(self): """Обработчик закрытия окна""" self.save_history() self.root.destroy() # ------------------------------- # Запуск приложения # ------------------------------- if __name__ == "__main__": root = tk.Tk() app = TaskGeneratorApp(root) root.mainloop()