"""Folder-only default interface.""" import os from pathlib import Path import queue import threading import tkinter as tk from tkinter import ttk,filedialog,messagebox import sys PACKAGE = Path(__file__).resolve().parents[1] WORKSPACE = PACKAGE.parents[1] sys.path.insert(0, str(PACKAGE / 'src')) from bridge_drawing_extractor import extract_folder def run_folder(folder, log): result = extract_folder(folder, converter_path=WORKSPACE / 'Code/giyang_extract/libredwg/dwgread.exe', on_progress=log) return result.output_dir, [(b.xlsx_path, b.data) for b in result.workbooks], result.files class AutoApp: def __init__(self,root): self.root=root;self.busy=False;self.events=queue.Queue();self.last_output=None root.title('도면 폴더 → 교각 입력 엑셀');root.geometry('960x640');root.minsize(760,520) self.folder=tk.StringVar();self.status=tk.StringVar(value='도면이 들어 있는 폴더를 선택하세요.') frame=ttk.Frame(root,padding=16);frame.pack(fill='both',expand=True);frame.columnconfigure(0,weight=1);frame.rowconfigure(5,weight=1) ttk.Label(frame,text='도면 폴더에서 자동 추출',font=('맑은 고딕',16,'bold')).grid(row=0,column=0,columnspan=2,sticky='w',pady=(0,12)) ttk.Label(frame,text='종평면·받침배치·ELEVATION에서 추출합니다. 기존 엑셀 없이 IP 연결·500mm 단위 치수 산정.').grid(row=1,column=0,columnspan=2,sticky='w',pady=(0,12)) ttk.Entry(frame,textvariable=self.folder).grid(row=2,column=0,sticky='ew',padx=(0,8)) ttk.Button(frame,text='도면 폴더 선택',command=self.choose).grid(row=2,column=1) buttons=ttk.Frame(frame);buttons.grid(row=3,column=0,columnspan=2,sticky='w',pady=12) self.start_button=ttk.Button(buttons,text='자동 추출 시작',command=self.start);self.start_button.pack(side='left',padx=(0,8)) ttk.Button(buttons,text='결과 폴더 열기',command=self.open_output).pack(side='left') self.progress=ttk.Progressbar(frame,mode='indeterminate');self.progress.grid(row=4,column=0,columnspan=2,sticky='ew',pady=(0,8)) self.text=tk.Text(frame,state='disabled',wrap='word',font=('맑은 고딕',10));self.text.grid(row=5,column=0,columnspan=2,sticky='nsew') scroll=ttk.Scrollbar(frame,command=self.text.yview);scroll.grid(row=5,column=2,sticky='ns');self.text.configure(yscrollcommand=scroll.set) ttk.Label(frame,textvariable=self.status,wraplength=870).grid(row=6,column=0,columnspan=2,sticky='w',pady=10) ttk.Label(frame,text='결과: 선택 폴더의 _도면추출결과. 판독이 모호한 값은 공란·검토 사유로 표시합니다.',wraplength=870).grid(row=7,column=0,columnspan=2,sticky='w') root.after(100,self.poll) def choose(self): folder=filedialog.askdirectory() if folder:self.folder.set(folder) def append(self,text): self.text.configure(state='normal');self.text.insert('end',text+'\n');self.text.see('end');self.text.configure(state='disabled') def start(self): if self.busy:return folder=self.folder.get() if not folder or not Path(folder).is_dir():messagebox.showerror('폴더 선택','유효한 도면 폴더를 선택하세요.');return self.busy=True;self.start_button.state(['disabled']);self.progress.start();self.status.set('도면을 읽고 있습니다…') def worker(): try:self.events.put(('done',run_folder(folder,log=lambda s:self.events.put(('log',s))))) except Exception as e:self.events.put(('error',str(e))) threading.Thread(target=worker,daemon=True).start() def poll(self): try: while True: kind,value=self.events.get_nowait() if kind=='log':self.append(value);continue self.busy=False;self.start_button.state(['!disabled']);self.progress.stop() if kind=='error':self.status.set('처리 실패 — 판독 메시지를 확인하세요.');self.append(value) else: folder,outputs,inventory=value;self.last_output=folder issues=sum(r['value'] is None and r['status']!='대상외' for _,result in outputs for r in result['records']) failed=sum(x['status']=='읽기 실패' for x in inventory) self.status.set(f'엑셀 {len(outputs)}개 저장 · 검토 {issues}셀 · 파일 읽기 실패 {failed}개') self.append('저장 위치: '+str(folder));self.append('CSV의 검토 사유와 파일판독내역.json을 확인하세요.') except queue.Empty:pass self.root.after(100,self.poll) def open_output(self): if self.last_output and self.last_output.exists():os.startfile(str(self.last_output)) if __name__ == '__main__': root = tk.Tk() app = AutoApp(root) root.mainloop()