import tkinter as tk from tkinter import ttk, messagebox import json import os # ファイル名 DATA_FILE = "sample.cvd" # デフォルトのフィールド定義 (main.pyと合わせる) FIELDS = [ 'Name', 'Type', 'Score_Math_Logic', 'Score_English', 'Score_Science', 'Score_Humanities', 'Extraversion', 'Sensitivity', 'Independence', 'Gender_Code' ] # 表示用ラベル (日本語) FIELD_LABELS = { 'Name': '名前', 'Type': 'Student/Teacher', 'Score_Math_Logic': '数理・論理 (数学全般) (0.0: 不可/苦手 ~ 1.0: 指導可能/得意) ', 'Score_English': '英語・語学 (英語全般) (0.0: 不可/苦手 ~ 1.0: 指導可能/得意) ', 'Score_Science': '自然科学 (物理・化学・生物) (0.0: 不可/苦手 ~ 1.0: 指導可能/得意) ', 'Score_Humanities': '文脈・教養 (国語・社会) (0.0: 不可/苦手 ~ 1.0: 指導可能/得意) ', 'Extraversion': '外向性 0.0(無口・内向) ~ 1.0(おしゃべり・外向) ', 'Sensitivity': '傷つきやすさ/受容力 0.0(ドライ・論理的) ~ 1.0(共感的・繊細) ', 'Independence': '独立性 0.0(依存的・手がかかる) ~ 1.0(自律的・放置OK) ', 'Gender_Code': '性別 (0:女性, 1:男性)' } # デフォルトデータ (main.pyと同じものを初期値として持つ) DEFAULT_DATA = { 'Name': [ '講師A (理系エース)', '講師B (英語特化)', '講師C (文系オール)', '講師D (数学・物理)', '講師E (心理・生物)', '生徒1 (理系志望)', '生徒2 (英語苦手)', '生徒3 (国語のみ得意)', '生徒4 (全教科平均)', '生徒5 (難関国立)', '生徒6 (勉強嫌い)' ], 'Type': ['Teacher', 'Teacher', 'Teacher', 'Teacher', 'Teacher', 'Student', 'Student', 'Student', 'Student', 'Student', 'Student'], 'Score_Math_Logic': [0.9, 0.1, 0.2, 0.9, 0.4, 0.8, 0.4, 0.1, 0.5, 0.9, 0.1], 'Score_English': [0.6, 0.9, 0.8, 0.3, 0.5, 0.6, 0.2, 0.3, 0.5, 0.9, 0.2], 'Score_Science': [0.9, 0.1, 0.1, 0.9, 0.8, 0.7, 0.2, 0.1, 0.4, 0.8, 0.1], 'Score_Humanities': [0.2, 0.5, 0.9, 0.1, 0.6, 0.3, 0.5, 0.9, 0.5, 0.8, 0.2], 'Extraversion': [0.5, 0.8, 0.9, 0.2, 0.7, 0.2, 0.8, 0.4, 0.6, 0.5, 0.6], 'Sensitivity': [0.3, 0.6, 0.8, 0.1, 0.9, 0.7, 0.4, 0.9, 0.5, 0.3, 0.5], 'Independence': [0.8, 0.5, 0.7, 0.9, 0.6, 0.5, 0.3, 0.4, 0.7, 0.9, 0.1], 'Gender_Code': [1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0] } class DataEditorApp: def __init__(self, root): self.root = root self.root.title("Compatibility Vector Data Editor") self.root.geometry("800x600") self.data_rows = [] self.create_widgets() self.load_data() def create_widgets(self): # 左側: リストボックス left_frame = tk.Frame(self.root, width=250) left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10) tk.Label(left_frame, text="登録").pack() self.listbox = tk.Listbox(left_frame) self.listbox.pack(fill=tk.BOTH, expand=True) self.listbox.bind('<>', self.on_select) # ボタン類 btn_frame = tk.Frame(left_frame) btn_frame.pack(fill=tk.X, pady=5) tk.Button(btn_frame, text="追加", command=self.add_entry).pack(side=tk.LEFT, fill=tk.X, expand=True) tk.Button(btn_frame, text="削除", command=self.delete_entry).pack(side=tk.LEFT, fill=tk.X, expand=True) tk.Button(left_frame, text="保存", command=self.save_data, bg="lightblue").pack(fill=tk.X, pady=5) # 右側: 編集フォーム right_frame = tk.Frame(self.root) right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10) self.entries = {} row_idx = 0 for field in FIELDS: label_text = FIELD_LABELS.get(field, field) lbl = tk.Label(right_frame, text=label_text + ":", anchor="e") lbl.grid(row=row_idx, column=0, sticky="ew", padx=5, pady=2) entry = tk.Entry(right_frame) entry.grid(row=row_idx, column=1, sticky="ew", padx=5, pady=2) self.entries[field] = entry row_idx += 1 right_frame.columnconfigure(1, weight=1) # 更新ボタン tk.Button(right_frame, text="更新", command=self.update_entry, bg="lightgreen").grid(row=row_idx, column=0, columnspan=2, pady=10, sticky="ew") def load_data(self): if os.path.exists(DATA_FILE): try: with open(DATA_FILE, 'r', encoding='utf-8') as f: raw_data = json.load(f) except Exception as e: messagebox.showerror("Error", f"Failed to load file: {e}") raw_data = DEFAULT_DATA else: raw_data = DEFAULT_DATA self.data_rows = [] count = len(raw_data['Name']) for i in range(count): row = {} for field in FIELDS: if field in raw_data and i < len(raw_data[field]): row[field] = raw_data[field][i] else: row[field] = "" self.data_rows.append(row) self.refresh_list() def refresh_list(self): self.listbox.delete(0, tk.END) for row in self.data_rows: self.listbox.insert(tk.END, row['Name']) def on_select(self, event): idx = self.listbox.curselection() if not idx: return index = idx[0] data = self.data_rows[index] for field in FIELDS: self.entries[field].delete(0, tk.END) self.entries[field].insert(0, str(data.get(field, ""))) def add_entry(self): new_row = {field: "" for field in FIELDS} new_row['Name'] = "New Entry" self.data_rows.append(new_row) self.refresh_list() self.listbox.selection_clear(0, tk.END) self.listbox.selection_set(tk.END) self.on_select(None) def update_entry(self): idx = self.listbox.curselection() if not idx: self.show_selection_popup_for_update() return index = idx[0] new_data = {} for field in FIELDS: val = self.entries[field].get() if field in ['Name', 'Type']: new_data[field] = val else: try: new_data[field] = float(val) except ValueError: new_data[field] = 0.0 self.data_rows[index] = new_data self.refresh_list() self.listbox.selection_set(index) messagebox.showinfo("Info", "更新しました") def show_selection_popup_for_update(self): # ポップアップウィンドウ作成 top = tk.Toplevel(self.root) top.title("更新対象を選択") top.geometry("300x400") tk.Label(top, text="更新するデータを選択してください:").pack(pady=5) lb = tk.Listbox(top) lb.pack(fill=tk.BOTH, expand=True, padx=10, pady=5) for row in self.data_rows: lb.insert(tk.END, row['Name']) def on_ok(): selection = lb.curselection() if not selection: messagebox.showwarning("Warning", "選択されていません") return index = selection[0] self.listbox.selection_clear(0, tk.END) self.listbox.selection_set(index) self.listbox.see(index) top.destroy() self.update_entry() tk.Button(top, text="決定", command=on_ok, bg="lightgreen").pack(pady=10) def delete_entry(self): idx = self.listbox.curselection() if not idx: return index = idx[0] del self.data_rows[index] self.refresh_list() for field in FIELDS: self.entries[field].delete(0, tk.END) def save_data(self): output_data = {field: [] for field in FIELDS} for row in self.data_rows: for field in FIELDS: output_data[field].append(row.get(field)) try: with open(DATA_FILE, 'w', encoding='utf-8') as f: json.dump(output_data, f, indent=4, ensure_ascii=False) messagebox.showinfo("Success", f"Saved to {DATA_FILE}") except Exception as e: messagebox.showerror("Error", f"Failed to save: {e}") if __name__ == "__main__": root = tk.Tk() app = DataEditorApp(root) root.mainloop()