123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
import tkinter as tk
|
|
from tkinter import filedialog, messagebox
|
|
from typing import Optional, Dict, Any
|
|
|
|
class DataFileSelectorDialog(tk.Toplevel):
|
|
"""
|
|
A modal dialog window for selecting a data file and its type.
|
|
|
|
This dialog prompts the user to browse for a file and specify whether
|
|
it contains a "Vector" or a "Matrix".
|
|
"""
|
|
|
|
def __init__(self, master: tk.Tk, initial_dir: str):
|
|
"""
|
|
Initializes the dialog.
|
|
|
|
Args:
|
|
master: The parent tk.Tk window.
|
|
initial_dir: The initial directory for the file browser.
|
|
"""
|
|
super().__init__(master)
|
|
self.title("Select Data File")
|
|
self.transient(master) # Keep dialog on top of the main window
|
|
self.grab_set() # Make the dialog modal
|
|
|
|
# --- Internal state ---
|
|
self._file_path = tk.StringVar()
|
|
self._data_type = tk.StringVar(value="Vector") # Default selection
|
|
self._initial_dir = initial_dir
|
|
self.result: Optional[Dict[str, Any]] = None
|
|
|
|
self._create_widgets()
|
|
self._center_window()
|
|
|
|
# This call blocks until the window is destroyed
|
|
self.wait_window(self)
|
|
|
|
def _create_widgets(self) -> None:
|
|
"""Creates and arranges the widgets in the dialog."""
|
|
main_frame = tk.Frame(self, padx=15, pady=15)
|
|
main_frame.pack(expand=True, fill=tk.BOTH)
|
|
|
|
# --- File Path Selection ---
|
|
file_frame = tk.Frame(main_frame)
|
|
file_frame.pack(fill=tk.X, pady=(0, 10))
|
|
|
|
lbl_file = tk.Label(file_frame, text="File Path:")
|
|
lbl_file.pack(side=tk.LEFT, padx=(0, 5))
|
|
|
|
entry_file = tk.Entry(file_frame, textvariable=self._file_path, width=40)
|
|
entry_file.pack(side=tk.LEFT, fill=tk.X, expand=True)
|
|
|
|
btn_browse = tk.Button(file_frame, text="Browse...", command=self._browse_file)
|
|
btn_browse.pack(side=tk.LEFT, padx=(5, 0))
|
|
|
|
# --- Data Type Selection ---
|
|
type_frame = tk.LabelFrame(main_frame, text="Data Type", padx=10, pady=10)
|
|
type_frame.pack(fill=tk.X, pady=5)
|
|
|
|
rb_vector = tk.Radiobutton(
|
|
type_frame, text="Vector (Single Column)", variable=self._data_type, value="Vector"
|
|
)
|
|
rb_vector.pack(anchor=tk.W)
|
|
|
|
rb_matrix = tk.Radiobutton(
|
|
type_frame, text="Matrix (Header + Data)", variable=self._data_type, value="Matrix"
|
|
)
|
|
rb_matrix.pack(anchor=tk.W)
|
|
|
|
# --- Action Buttons ---
|
|
button_frame = tk.Frame(main_frame)
|
|
button_frame.pack(fill=tk.X, pady=(15, 0))
|
|
|
|
btn_load = tk.Button(button_frame, text="Load", command=self._load_data)
|
|
btn_load.pack(side=tk.RIGHT)
|
|
|
|
btn_cancel = tk.Button(button_frame, text="Cancel", command=self._cancel)
|
|
btn_cancel.pack(side=tk.RIGHT, padx=(0, 10))
|
|
|
|
def _center_window(self) -> None:
|
|
"""Centers the dialog on the screen."""
|
|
self.update_idletasks() # Ensure window size is calculated
|
|
|
|
# Get screen and window dimensions
|
|
screen_width = self.winfo_screenwidth()
|
|
screen_height = self.winfo_screenheight()
|
|
window_width = self.winfo_width()
|
|
window_height = self.winfo_height()
|
|
|
|
# Calculate position
|
|
pos_x = (screen_width // 2) - (window_width // 2)
|
|
pos_y = (screen_height // 2) - (window_height // 2)
|
|
|
|
self.geometry(f"{window_width}x{window_height}+{pos_x}+{pos_y}")
|
|
self.resizable(False, False)
|
|
|
|
def _browse_file(self) -> None:
|
|
"""Opens the system's file browser dialog."""
|
|
filename = filedialog.askopenfilename(
|
|
initialdir=self._initial_dir,
|
|
title="Select a CSV data file",
|
|
filetypes=(("CSV files", "*.csv"), ("All files", "*.*"))
|
|
)
|
|
if filename:
|
|
self._file_path.set(filename)
|
|
|
|
def _load_data(self) -> None:
|
|
"""Validates the inputs and sets the result."""
|
|
file_path = self._file_path.get()
|
|
if not file_path:
|
|
messagebox.showwarning("Input Missing", "Please select a file path.", parent=self)
|
|
return
|
|
|
|
self.result = {
|
|
"file_path": file_path,
|
|
"data_type": self._data_type.get()
|
|
}
|
|
self.destroy()
|
|
|
|
def _cancel(self) -> None:
|
|
"""Closes the dialog without setting a result."""
|
|
self.result = None
|
|
self.destroy() |