reworked with tkinter, UI improements needed
This commit is contained in:
parent
d3878857af
commit
3ae07ca289
26 changed files with 1488 additions and 1751 deletions
|
|
@ -1,160 +1,153 @@
|
|||
"""
|
||||
CelestialDialog - диалог управления небесными телами
|
||||
Аналог CelestialBodiesDialogController из JavaFX версии
|
||||
CelestialDialog - диалог управления небесными телами (tkinter)
|
||||
"""
|
||||
from PySide6.QtWidgets import (
|
||||
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QListWidget,
|
||||
QPushButton, QLineEdit, QInputDialog, QMessageBox
|
||||
)
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
|
||||
from services.config_service import ConfigService
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
|
||||
|
||||
class CelestialDialog(QDialog):
|
||||
class CelestialDialog(tk.Toplevel):
|
||||
"""Диалог для управления списком небесных тел"""
|
||||
|
||||
def __init__(self, parent, config_service: ConfigService):
|
||||
def __init__(self, parent, config_service):
|
||||
super().__init__(parent)
|
||||
|
||||
self.parent = parent
|
||||
self.config_service = config_service
|
||||
self.setWindowTitle("Небесные тела")
|
||||
self.setMinimumSize(400, 500)
|
||||
self.resize(450, 550)
|
||||
|
||||
# Загружаем текущий список
|
||||
self.celestial_bodies = self.config_service.get_celestial_bodies()
|
||||
self.selected_body = None
|
||||
|
||||
self.title("Celestial Bodies")
|
||||
self.geometry("500x550")
|
||||
self.minsize(450, 500)
|
||||
self.transient(parent)
|
||||
self.grab_set()
|
||||
|
||||
self._create_ui()
|
||||
self._update_list()
|
||||
self._center_window()
|
||||
|
||||
def _create_ui(self):
|
||||
"""Создаёт интерфейс диалога"""
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setSpacing(15)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
# Main frame
|
||||
main_frame = ttk.Frame(self, padding="20")
|
||||
main_frame.pack(fill='both', expand=True)
|
||||
|
||||
# Заголовок
|
||||
title_label = QLabel("Управление небесными телами")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(16)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(title_label)
|
||||
# Title
|
||||
ttk.Label(main_frame, text="Celestial Bodies", font=('Segoe UI', 14, 'bold')).pack(pady=(0, 10))
|
||||
ttk.Label(main_frame, text="List of observation targets", font=('Segoe UI', 10)).pack(pady=(0, 15))
|
||||
|
||||
# Подпись
|
||||
subtitle_label = QLabel("Список объектов для наблюдения")
|
||||
subtitle_font = QFont()
|
||||
subtitle_font.setPointSize(11)
|
||||
subtitle_font.setBold(True)
|
||||
subtitle_label.setFont(subtitle_font)
|
||||
layout.addWidget(subtitle_label)
|
||||
# Listbox with scrollbar
|
||||
list_frame = ttk.Frame(main_frame)
|
||||
list_frame.pack(fill='both', expand=True, pady=(0, 10))
|
||||
|
||||
# Список небесных тел
|
||||
self.bodies_list = QListWidget()
|
||||
self.bodies_list.itemClicked.connect(lambda item: self._select_body(item.text()))
|
||||
layout.addWidget(self.bodies_list)
|
||||
scrollbar = ttk.Scrollbar(list_frame)
|
||||
scrollbar.pack(side='right', fill='y')
|
||||
|
||||
# Поле для добавления нового
|
||||
add_layout = QHBoxLayout()
|
||||
self.bodies_listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set, height=15,
|
||||
bg='#2d2d2d', fg='#e0e0e0',
|
||||
selectbackground='#4CAF50', selectforeground='white',
|
||||
font=('Segoe UI', 10))
|
||||
self.bodies_listbox.pack(fill='both', expand=True)
|
||||
scrollbar.config(command=self.bodies_listbox.yview)
|
||||
|
||||
self.new_body_entry = QLineEdit()
|
||||
self.new_body_entry.setPlaceholderText("Название объекта (например: M31, NGC 224)")
|
||||
self.new_body_entry.returnPressed.connect(self._add_celestial_body)
|
||||
add_layout.addWidget(self.new_body_entry)
|
||||
|
||||
add_btn = QPushButton("➕ Добавить")
|
||||
add_btn.clicked.connect(self._add_celestial_body)
|
||||
add_layout.addWidget(add_btn)
|
||||
|
||||
layout.addLayout(add_layout)
|
||||
|
||||
# Кнопки удаления и редактирования
|
||||
buttons_layout = QHBoxLayout()
|
||||
|
||||
self.remove_btn = QPushButton("❌ Удалить выбранный")
|
||||
self.remove_btn.setEnabled(False)
|
||||
self.remove_btn.clicked.connect(self._remove_celestial_body)
|
||||
buttons_layout.addWidget(self.remove_btn)
|
||||
|
||||
self.edit_btn = QPushButton("✏ Редактировать")
|
||||
self.edit_btn.setEnabled(False)
|
||||
self.edit_btn.clicked.connect(self._edit_celestial_body)
|
||||
buttons_layout.addWidget(self.edit_btn)
|
||||
|
||||
layout.addLayout(buttons_layout)
|
||||
|
||||
# Кнопка закрытия
|
||||
close_btn = QPushButton("Закрыть")
|
||||
close_btn.clicked.connect(self.accept)
|
||||
close_layout = QHBoxLayout()
|
||||
close_layout.addStretch()
|
||||
close_layout.addWidget(close_btn)
|
||||
layout.addLayout(close_layout)
|
||||
|
||||
def _update_list(self):
|
||||
"""Обновляет отображение списка небесных тел"""
|
||||
self.bodies_list.clear()
|
||||
for body in self.celestial_bodies:
|
||||
self.bodies_list.addItem(body)
|
||||
self._selected_body = None
|
||||
self.remove_btn.setEnabled(False)
|
||||
self.edit_btn.setEnabled(False)
|
||||
self.bodies_listbox.insert('end', body)
|
||||
|
||||
def _select_body(self, body: str):
|
||||
"""Выделяет объект в списке"""
|
||||
self._selected_body = body
|
||||
self.remove_btn.setEnabled(True)
|
||||
self.edit_btn.setEnabled(True)
|
||||
self.bodies_listbox.bind('<<ListboxSelect>>', self._on_body_select)
|
||||
|
||||
# Add new body
|
||||
add_frame = ttk.Frame(main_frame)
|
||||
add_frame.pack(fill='x', pady=(0, 10))
|
||||
|
||||
self.new_body_entry = ttk.Entry(add_frame)
|
||||
self.new_body_entry.pack(side='left', fill='x', expand=True, padx=(0, 10))
|
||||
ttk.Button(add_frame, text="Add", command=self._add_celestial_body).pack(side='right')
|
||||
|
||||
# Buttons
|
||||
btn_frame = ttk.Frame(main_frame)
|
||||
btn_frame.pack(pady=(0, 10))
|
||||
|
||||
self.remove_btn = ttk.Button(btn_frame, text="Remove Selected", command=self._remove_celestial_body, state='disabled')
|
||||
self.remove_btn.pack(side='left', padx=5)
|
||||
|
||||
self.edit_btn = ttk.Button(btn_frame, text="Edit Selected", command=self._edit_celestial_body, state='disabled')
|
||||
self.edit_btn.pack(side='left', padx=5)
|
||||
|
||||
# Close button
|
||||
ttk.Button(main_frame, text="Close", command=self.destroy).pack(pady=10)
|
||||
|
||||
def _center_window(self):
|
||||
self.update_idletasks()
|
||||
x = self.parent.winfo_x() + (self.parent.winfo_width() // 2) - (self.winfo_width() // 2)
|
||||
y = self.parent.winfo_y() + (self.parent.winfo_height() // 2) - (self.winfo_height() // 2)
|
||||
self.geometry(f'+{x}+{y}')
|
||||
|
||||
def _on_body_select(self, event):
|
||||
selection = self.bodies_listbox.curselection()
|
||||
if selection:
|
||||
self.selected_body = self.bodies_listbox.get(selection[0])
|
||||
self.remove_btn.config(state='normal')
|
||||
self.edit_btn.config(state='normal')
|
||||
|
||||
def _add_celestial_body(self):
|
||||
"""Добавляет новое небесное тело"""
|
||||
new_body = self.new_body_entry.text()
|
||||
if not new_body or not new_body.strip():
|
||||
QMessageBox.warning(self, "Ошибка", "Введите название объекта")
|
||||
new_body = self.new_body_entry.get().strip()
|
||||
if not new_body:
|
||||
messagebox.showwarning("Warning", "Please enter object name!", parent=self)
|
||||
return
|
||||
|
||||
new_name = new_body.strip()
|
||||
if new_name in self.celestial_bodies:
|
||||
QMessageBox.warning(self, "Ошибка", f"Объект '{new_name}' уже существует!")
|
||||
if new_body in self.celestial_bodies:
|
||||
messagebox.showwarning("Warning", f"Object '{new_body}' already exists!", parent=self)
|
||||
return
|
||||
|
||||
self.celestial_bodies.append(new_name)
|
||||
self.config_service.add_celestial_body(new_name)
|
||||
self._update_list()
|
||||
self.new_body_entry.clear()
|
||||
QMessageBox.information(self, "Успех", f"Объект '{new_name}' добавлен")
|
||||
self.celestial_bodies.append(new_body)
|
||||
self.config_service.add_celestial_body(new_body)
|
||||
self.bodies_listbox.insert('end', new_body)
|
||||
self.new_body_entry.delete(0, 'end')
|
||||
messagebox.showinfo("Success", f"Object '{new_body}' added", parent=self)
|
||||
|
||||
def _remove_celestial_body(self):
|
||||
"""Удаляет выбранное небесное тело"""
|
||||
if hasattr(self, '_selected_body') and self._selected_body:
|
||||
reply = QMessageBox.question(self, "Подтверждение",
|
||||
f"Удалить объект '{self._selected_body}'?",
|
||||
QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
self.celestial_bodies.remove(self._selected_body)
|
||||
self.config_service.remove_celestial_body(self._selected_body)
|
||||
self._update_list()
|
||||
QMessageBox.information(self, "Успех", f"Объект '{self._selected_body}' удалён")
|
||||
if self.selected_body:
|
||||
reply = messagebox.askyesno("Remove Object", f"Remove '{self.selected_body}'?", parent=self)
|
||||
if reply:
|
||||
self.celestial_bodies.remove(self.selected_body)
|
||||
self.config_service.remove_celestial_body(self.selected_body)
|
||||
self.bodies_listbox.delete(0, 'end')
|
||||
for body in self.celestial_bodies:
|
||||
self.bodies_listbox.insert('end', body)
|
||||
self.selected_body = None
|
||||
self.remove_btn.config(state='disabled')
|
||||
self.edit_btn.config(state='disabled')
|
||||
|
||||
def _edit_celestial_body(self):
|
||||
"""Редактирует выбранное небесное тело"""
|
||||
if hasattr(self, '_selected_body') and self._selected_body:
|
||||
new_name, ok = QInputDialog.getText(self, "Редактировать",
|
||||
f"Изменить '{self._selected_body}' на:",
|
||||
text=self._selected_body)
|
||||
if ok and new_name and new_name.strip():
|
||||
new_name = new_name.strip()
|
||||
if new_name != self._selected_body:
|
||||
if self.selected_body:
|
||||
dialog = tk.Toplevel(self)
|
||||
dialog.title("Edit Celestial Body")
|
||||
dialog.geometry("350x120")
|
||||
dialog.transient(self)
|
||||
dialog.grab_set()
|
||||
|
||||
ttk.Label(dialog, text="New name:", font=('Segoe UI', 10)).pack(pady=15)
|
||||
entry = ttk.Entry(dialog, width=40)
|
||||
entry.insert(0, self.selected_body)
|
||||
entry.pack(pady=5)
|
||||
entry.focus()
|
||||
|
||||
def save():
|
||||
new_name = entry.get().strip()
|
||||
if new_name and new_name != self.selected_body:
|
||||
if new_name in self.celestial_bodies:
|
||||
QMessageBox.warning(self, "Ошибка", f"Объект '{new_name}' уже существует!")
|
||||
messagebox.showerror("Error", f"Object '{new_name}' already exists!", parent=dialog)
|
||||
return
|
||||
|
||||
idx = self.celestial_bodies.index(self._selected_body)
|
||||
old_name = self.celestial_bodies[idx]
|
||||
idx = self.celestial_bodies.index(self.selected_body)
|
||||
self.celestial_bodies[idx] = new_name
|
||||
self.config_service.update_celestial_body(old_name, new_name)
|
||||
self._update_list()
|
||||
QMessageBox.information(self, "Успех", f"Объект переименован в '{new_name}'")
|
||||
self.config_service.update_celestial_body(self.selected_body, new_name)
|
||||
self.bodies_listbox.delete(0, 'end')
|
||||
for body in self.celestial_bodies:
|
||||
self.bodies_listbox.insert('end', body)
|
||||
dialog.destroy()
|
||||
elif new_name == self.selected_body:
|
||||
dialog.destroy()
|
||||
else:
|
||||
messagebox.showwarning("Warning", "Please enter a name!", parent=dialog)
|
||||
|
||||
ttk.Button(dialog, text="Save", command=save).pack(pady=10)
|
||||
dialog.bind('<Return>', lambda e: save())
|
||||
Loading…
Add table
Add a link
Reference in a new issue