first commit
This commit is contained in:
653
multi_file_main.py
Normal file
653
multi_file_main.py
Normal file
@@ -0,0 +1,653 @@
|
||||
"""
|
||||
다중 파일 처리 애플리케이션 클래스
|
||||
여러 PDF/DXF 파일을 배치로 처리하고 결과를 CSV로 저장하는 기능을 제공합니다.
|
||||
|
||||
Author: Claude Assistant
|
||||
Created: 2025-07-14
|
||||
Version: 1.0.0
|
||||
"""
|
||||
|
||||
import flet as ft
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
import time
|
||||
|
||||
# 프로젝트 모듈 임포트
|
||||
from config import Config
|
||||
from multi_file_processor import MultiFileProcessor, BatchProcessingConfig, generate_default_csv_filename
|
||||
from ui_components import MultiFileUIComponents
|
||||
from utils import DateTimeUtils
|
||||
|
||||
# 로깅 설정
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MultiFileApp:
|
||||
"""다중 파일 처리 애플리케이션 클래스"""
|
||||
|
||||
def __init__(self, page: ft.Page):
|
||||
self.page = page
|
||||
self.selected_files = []
|
||||
self.processing_results = []
|
||||
self.is_processing = False
|
||||
self.is_cancelled = False
|
||||
self.is_paused = False
|
||||
self.processor = None
|
||||
|
||||
# UI 컴포넌트 참조
|
||||
self.file_picker = None
|
||||
self.files_container = None
|
||||
self.clear_files_button = None
|
||||
self.batch_analysis_button = None
|
||||
|
||||
# 배치 설정 컴포넌트
|
||||
self.organization_selector = None
|
||||
self.concurrent_files_slider = None
|
||||
self.enable_batch_mode = None
|
||||
self.save_intermediate_results = None
|
||||
self.include_error_files = None
|
||||
self.csv_output_path = None
|
||||
self.browse_button = None
|
||||
|
||||
# 진행률 컴포넌트
|
||||
self.overall_progress_bar = None
|
||||
self.progress_text = None
|
||||
self.current_status_text = None
|
||||
self.timing_info = None
|
||||
self.log_container = None
|
||||
self.cancel_button = None
|
||||
self.pause_resume_button = None
|
||||
|
||||
# 결과 컴포넌트
|
||||
self.summary_stats = None
|
||||
self.results_table = None
|
||||
self.save_csv_button = None
|
||||
self.save_cross_csv_button = None # 새로 추가
|
||||
self.save_excel_button = None
|
||||
self.clear_results_button = None
|
||||
|
||||
# 시간 추적
|
||||
self.start_time = None
|
||||
|
||||
# Gemini API 키 확인
|
||||
self.init_processor()
|
||||
|
||||
def init_processor(self):
|
||||
"""다중 파일 처리기 초기화"""
|
||||
try:
|
||||
config_errors = Config.validate_config()
|
||||
if config_errors:
|
||||
logger.error(f"설정 오류: {config_errors}")
|
||||
return
|
||||
|
||||
# Gemini API 키가 있는지 확인
|
||||
gemini_api_key = Config.get_gemini_api_key()
|
||||
if not gemini_api_key:
|
||||
logger.error("Gemini API 키가 설정되지 않았습니다")
|
||||
return
|
||||
|
||||
self.processor = MultiFileProcessor(gemini_api_key)
|
||||
logger.info("다중 파일 처리기 초기화 완료")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"다중 파일 처리기 초기화 실패: {e}")
|
||||
|
||||
def build_ui(self) -> ft.Column:
|
||||
"""다중 파일 처리 UI 구성"""
|
||||
|
||||
# 파일 업로드 섹션
|
||||
upload_section = self.create_file_upload_section()
|
||||
|
||||
# 배치 설정 섹션
|
||||
settings_section = self.create_batch_settings_section()
|
||||
|
||||
# 진행률 섹션
|
||||
progress_section = self.create_progress_section()
|
||||
|
||||
# 결과 섹션
|
||||
results_section = self.create_results_section()
|
||||
|
||||
# 좌측 컨트롤 패널
|
||||
left_panel = ft.Container(
|
||||
content=ft.Column([
|
||||
upload_section,
|
||||
ft.Divider(height=10),
|
||||
settings_section,
|
||||
ft.Divider(height=10),
|
||||
progress_section,
|
||||
], scroll=ft.ScrollMode.AUTO),
|
||||
col={"sm": 12, "md": 5, "lg": 4},
|
||||
padding=10,
|
||||
)
|
||||
|
||||
# 우측 결과 패널
|
||||
right_panel = ft.Container(
|
||||
content=results_section,
|
||||
col={"sm": 12, "md": 7, "lg": 8},
|
||||
padding=10,
|
||||
)
|
||||
|
||||
# ResponsiveRow를 사용한 좌우 분할 레이아웃
|
||||
main_layout = ft.ResponsiveRow([left_panel, right_panel])
|
||||
|
||||
return ft.Column([
|
||||
main_layout
|
||||
], expand=True, scroll=ft.ScrollMode.AUTO)
|
||||
|
||||
def create_file_upload_section(self) -> ft.Container:
|
||||
"""파일 업로드 섹션 생성"""
|
||||
upload_container = MultiFileUIComponents.create_multi_file_upload_section(
|
||||
on_files_selected=self.on_files_selected,
|
||||
on_batch_analysis_click=self.on_batch_analysis_click,
|
||||
on_clear_files_click=self.on_clear_files_click
|
||||
)
|
||||
|
||||
# 참조 저장
|
||||
self.file_picker = upload_container.content.controls[-1] # 마지막 요소가 file_picker
|
||||
self.files_container = upload_container.content.controls[4] # files_container
|
||||
self.clear_files_button = upload_container.content.controls[2].controls[1]
|
||||
self.batch_analysis_button = upload_container.content.controls[2].controls[2]
|
||||
|
||||
# overlay에 추가
|
||||
self.page.overlay.append(self.file_picker)
|
||||
|
||||
return upload_container
|
||||
|
||||
def create_batch_settings_section(self) -> ft.Container:
|
||||
"""배치 설정 섹션 생성"""
|
||||
(
|
||||
container,
|
||||
self.organization_selector,
|
||||
self.concurrent_files_slider,
|
||||
self.enable_batch_mode,
|
||||
self.save_intermediate_results,
|
||||
self.include_error_files,
|
||||
self.csv_output_path,
|
||||
self.browse_button
|
||||
) = MultiFileUIComponents.create_batch_settings_section()
|
||||
|
||||
# 슬라이더 변경 이벤트 처리
|
||||
self.concurrent_files_slider.on_change = self.on_concurrent_files_change
|
||||
|
||||
# 경로 선택 버튼 이벤트 처리
|
||||
self.browse_button.on_click = self.on_browse_csv_path_click
|
||||
|
||||
return container
|
||||
|
||||
def create_progress_section(self) -> ft.Container:
|
||||
"""진행률 섹션 생성"""
|
||||
(
|
||||
container,
|
||||
self.overall_progress_bar,
|
||||
self.progress_text,
|
||||
self.current_status_text,
|
||||
self.timing_info,
|
||||
self.log_container,
|
||||
self.cancel_button,
|
||||
self.pause_resume_button
|
||||
) = MultiFileUIComponents.create_batch_progress_section()
|
||||
|
||||
# 버튼 이벤트 처리
|
||||
self.cancel_button.on_click = self.on_cancel_click
|
||||
self.pause_resume_button.on_click = self.on_pause_resume_click
|
||||
|
||||
return container
|
||||
|
||||
def create_results_section(self) -> ft.Container:
|
||||
"""결과 섹션 생성"""
|
||||
(
|
||||
container,
|
||||
self.summary_stats,
|
||||
self.results_table,
|
||||
self.save_csv_button,
|
||||
self.save_cross_csv_button, # 새로 추가
|
||||
self.save_excel_button,
|
||||
self.clear_results_button
|
||||
) = MultiFileUIComponents.create_batch_results_section()
|
||||
|
||||
# 버튼 이벤트 처리
|
||||
self.save_csv_button.on_click = self.on_save_csv_click
|
||||
self.save_cross_csv_button.on_click = self.on_save_cross_csv_click # 새로 추가
|
||||
self.save_excel_button.on_click = self.on_save_excel_click
|
||||
self.clear_results_button.on_click = self.on_clear_results_click
|
||||
|
||||
return container
|
||||
|
||||
# 이벤트 핸들러들
|
||||
|
||||
def on_files_selected(self, e: ft.FilePickerResultEvent):
|
||||
"""파일 선택 이벤트 핸들러"""
|
||||
if e.files:
|
||||
# 선택된 파일들을 기존 목록에 추가 (중복 제거)
|
||||
existing_paths = {f.path for f in self.selected_files}
|
||||
new_files = [f for f in e.files if f.path not in existing_paths]
|
||||
|
||||
if new_files:
|
||||
self.selected_files.extend(new_files)
|
||||
MultiFileUIComponents.update_selected_files_list(
|
||||
self.files_container,
|
||||
self.selected_files,
|
||||
self.clear_files_button,
|
||||
self.batch_analysis_button
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"{len(new_files)}개 파일 추가됨 (총 {len(self.selected_files)}개)",
|
||||
"info"
|
||||
)
|
||||
else:
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"선택된 파일들이 이미 목록에 있습니다",
|
||||
"warning"
|
||||
)
|
||||
else:
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"파일 선택이 취소되었습니다",
|
||||
"info"
|
||||
)
|
||||
|
||||
self.page.update()
|
||||
|
||||
def on_clear_files_click(self, e):
|
||||
"""파일 목록 지우기 이벤트 핸들러"""
|
||||
file_count = len(self.selected_files)
|
||||
self.selected_files.clear()
|
||||
|
||||
MultiFileUIComponents.update_selected_files_list(
|
||||
self.files_container,
|
||||
self.selected_files,
|
||||
self.clear_files_button,
|
||||
self.batch_analysis_button
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"{file_count}개 파일 목록 초기화",
|
||||
"info"
|
||||
)
|
||||
|
||||
self.page.update()
|
||||
|
||||
def on_batch_analysis_click(self, e):
|
||||
"""배치 분석 시작 이벤트 핸들러"""
|
||||
if not self.selected_files:
|
||||
return
|
||||
|
||||
if self.is_processing:
|
||||
return
|
||||
|
||||
if not self.processor:
|
||||
self.show_error_dialog("처리기 오류", "다중 파일 처리기가 초기화되지 않았습니다.")
|
||||
return
|
||||
|
||||
# 비동기 처리 시작
|
||||
self.page.run_task(self.start_batch_processing)
|
||||
|
||||
def on_concurrent_files_change(self, e):
|
||||
"""동시 처리 수 변경 이벤트 핸들러"""
|
||||
value = int(e.control.value)
|
||||
# 슬라이더 레이블 업데이트
|
||||
# 상위 Container에서 텍스트 찾아서 업데이트
|
||||
try:
|
||||
settings_container = e.control.parent.parent # Column -> Container
|
||||
text_control = settings_container.content.controls[2].controls[1].controls[0] # 해당 텍스트
|
||||
text_control.value = f"동시 처리 수: {value}개"
|
||||
self.page.update()
|
||||
except:
|
||||
logger.warning("슬라이더 레이블 업데이트 실패")
|
||||
|
||||
def on_browse_csv_path_click(self, e):
|
||||
"""CSV 저장 경로 선택 이벤트 핸들러"""
|
||||
# 간단한 구현 - 현재 디렉토리 + 자동 생성 파일명 설정
|
||||
default_filename = generate_default_csv_filename()
|
||||
default_path = os.path.join(os.getcwd(), "results", default_filename)
|
||||
|
||||
self.csv_output_path.value = default_path
|
||||
self.page.update()
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"CSV 저장 경로 설정: {default_filename}",
|
||||
"info"
|
||||
)
|
||||
|
||||
def on_cancel_click(self, e):
|
||||
"""처리 취소 이벤트 핸들러"""
|
||||
if self.is_processing:
|
||||
self.is_cancelled = True
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"사용자가 처리를 취소했습니다",
|
||||
"warning"
|
||||
)
|
||||
self.page.update()
|
||||
|
||||
def on_pause_resume_click(self, e):
|
||||
"""일시정지/재개 이벤트 핸들러"""
|
||||
# 현재 구현에서는 단순한 토글 기능만 제공
|
||||
if self.is_processing:
|
||||
self.is_paused = not self.is_paused
|
||||
if self.is_paused:
|
||||
self.pause_resume_button.text = "재개"
|
||||
self.pause_resume_button.icon = ft.Icons.PLAY_ARROW
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"처리가 일시정지되었습니다",
|
||||
"warning"
|
||||
)
|
||||
else:
|
||||
self.pause_resume_button.text = "일시정지"
|
||||
self.pause_resume_button.icon = ft.Icons.PAUSE
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"처리가 재개되었습니다",
|
||||
"success"
|
||||
)
|
||||
self.page.update()
|
||||
|
||||
def on_save_csv_click(self, e):
|
||||
"""CSV 저장 이벤트 핸들러"""
|
||||
if not self.processing_results:
|
||||
self.show_error_dialog("저장 오류", "저장할 결과가 없습니다.")
|
||||
return
|
||||
|
||||
self.page.run_task(self.save_results_to_csv)
|
||||
|
||||
def on_save_cross_csv_click(self, e):
|
||||
"""Cross-Tabulated CSV 저장 이벤트 핸들러 (새로 추가)"""
|
||||
if not self.processing_results:
|
||||
self.show_error_dialog("저장 오류", "저장할 결과가 없습니다.")
|
||||
return
|
||||
|
||||
self.page.run_task(self.save_cross_tabulated_csv)
|
||||
|
||||
def on_save_excel_click(self, e):
|
||||
"""Excel 저장 이벤트 핸들러"""
|
||||
if not self.processing_results:
|
||||
self.show_error_dialog("저장 오류", "저장할 결과가 없습니다.")
|
||||
return
|
||||
|
||||
# Excel 저장 기능 (향후 구현)
|
||||
self.show_info_dialog("개발 중", "Excel 저장 기능은 곧 추가될 예정입니다.")
|
||||
|
||||
def on_clear_results_click(self, e):
|
||||
"""결과 초기화 이벤트 핸들러"""
|
||||
self.processing_results.clear()
|
||||
|
||||
MultiFileUIComponents.update_batch_results(
|
||||
self.summary_stats,
|
||||
self.results_table,
|
||||
self.processing_results,
|
||||
self.save_csv_button,
|
||||
self.save_cross_csv_button, # 새로 추가
|
||||
self.save_excel_button,
|
||||
self.clear_results_button
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"결과가 초기화되었습니다",
|
||||
"info"
|
||||
)
|
||||
|
||||
self.page.update()
|
||||
|
||||
# 비동기 처리 함수들
|
||||
|
||||
async def start_batch_processing(self):
|
||||
"""배치 처리 시작"""
|
||||
try:
|
||||
self.is_processing = True
|
||||
self.is_cancelled = False
|
||||
self.is_paused = False
|
||||
self.start_time = time.time()
|
||||
|
||||
# UI 상태 업데이트
|
||||
self.batch_analysis_button.disabled = True
|
||||
self.cancel_button.disabled = False
|
||||
self.pause_resume_button.disabled = False
|
||||
|
||||
# 처리 설정 구성
|
||||
config = BatchProcessingConfig(
|
||||
organization_type=self.organization_selector.value,
|
||||
enable_gemini_batch_mode=self.enable_batch_mode.value,
|
||||
max_concurrent_files=int(self.concurrent_files_slider.value),
|
||||
save_intermediate_results=self.save_intermediate_results.value,
|
||||
output_csv_path=self.csv_output_path.value or None,
|
||||
include_error_files=self.include_error_files.value
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"배치 처리 시작: {len(self.selected_files)}개 파일",
|
||||
"info"
|
||||
)
|
||||
|
||||
# 파일 경로 추출
|
||||
file_paths = [f.path for f in self.selected_files]
|
||||
|
||||
# 진행률 콜백 함수
|
||||
def progress_callback(current: int, total: int, status: str):
|
||||
elapsed_time = time.time() - self.start_time if self.start_time else 0
|
||||
estimated_remaining = (elapsed_time / current * (total - current)) if current > 0 else 0
|
||||
|
||||
MultiFileUIComponents.update_batch_progress(
|
||||
self.overall_progress_bar,
|
||||
self.progress_text,
|
||||
self.current_status_text,
|
||||
self.timing_info,
|
||||
current,
|
||||
total,
|
||||
status,
|
||||
elapsed_time,
|
||||
estimated_remaining
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
status,
|
||||
"success" if "완료" in status else "info"
|
||||
)
|
||||
|
||||
self.page.update()
|
||||
|
||||
# 처리 실행
|
||||
self.processing_results = await self.processor.process_multiple_files(
|
||||
file_paths, config, progress_callback
|
||||
)
|
||||
|
||||
# 결과 표시
|
||||
MultiFileUIComponents.update_batch_results(
|
||||
self.summary_stats,
|
||||
self.results_table,
|
||||
self.processing_results,
|
||||
self.save_csv_button,
|
||||
self.save_cross_csv_button, # 새로 추가
|
||||
self.save_excel_button,
|
||||
self.clear_results_button
|
||||
)
|
||||
|
||||
# 요약 정보
|
||||
summary = self.processor.get_processing_summary()
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"처리 완료! 성공: {summary['success_files']}, 실패: {summary['failed_files']}, 성공률: {summary['success_rate']}%",
|
||||
"success"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"배치 처리 오류: {e}")
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"처리 오류: {str(e)}",
|
||||
"error"
|
||||
)
|
||||
self.show_error_dialog("처리 오류", f"배치 처리 중 오류가 발생했습니다:\n{str(e)}")
|
||||
|
||||
finally:
|
||||
# UI 상태 복원
|
||||
self.is_processing = False
|
||||
self.batch_analysis_button.disabled = False
|
||||
self.cancel_button.disabled = True
|
||||
self.pause_resume_button.disabled = True
|
||||
self.pause_resume_button.text = "일시정지"
|
||||
self.pause_resume_button.icon = ft.Icons.PAUSE
|
||||
self.page.update()
|
||||
|
||||
async def save_results_to_csv(self):
|
||||
"""결과를 CSV로 저장"""
|
||||
try:
|
||||
if not self.processor:
|
||||
self.show_error_dialog("오류", "처리기가 초기화되지 않았습니다.")
|
||||
return
|
||||
|
||||
# CSV 경로 설정
|
||||
output_path = self.csv_output_path.value
|
||||
if not output_path:
|
||||
# 자동 생성
|
||||
results_dir = os.path.join(os.getcwd(), "results")
|
||||
os.makedirs(results_dir, exist_ok=True)
|
||||
output_path = os.path.join(results_dir, generate_default_csv_filename())
|
||||
|
||||
# CSV 저장
|
||||
await self.processor.save_results_to_csv(output_path)
|
||||
|
||||
self.show_info_dialog(
|
||||
"저장 완료",
|
||||
f"배치 처리 결과가 CSV 파일로 저장되었습니다:\n\n{output_path}"
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"CSV 저장 완료: {os.path.basename(output_path)}",
|
||||
"success"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"CSV 저장 오류: {e}")
|
||||
self.show_error_dialog("저장 오류", f"CSV 저장 중 오류가 발생했습니다:\n{str(e)}")
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"CSV 저장 실패: {str(e)}",
|
||||
"error"
|
||||
)
|
||||
|
||||
async def save_cross_tabulated_csv(self):
|
||||
"""Cross-tabulated CSV로 저장 (새로 추가)"""
|
||||
try:
|
||||
# Cross-tabulated CSV 내보내기 모듈 임포트
|
||||
from cross_tabulated_csv_exporter import CrossTabulatedCSVExporter, generate_cross_tabulated_csv_filename
|
||||
|
||||
exporter = CrossTabulatedCSVExporter()
|
||||
|
||||
# CSV 경로 설정
|
||||
results_dir = os.path.join(os.getcwd(), "results")
|
||||
os.makedirs(results_dir, exist_ok=True)
|
||||
|
||||
# Cross-tabulated CSV 파일명 생성
|
||||
cross_csv_filename = generate_cross_tabulated_csv_filename("batch_key_value_analysis")
|
||||
output_path = os.path.join(results_dir, cross_csv_filename)
|
||||
|
||||
# Cross-tabulated CSV 저장
|
||||
success = exporter.export_cross_tabulated_csv(
|
||||
self.processing_results,
|
||||
output_path,
|
||||
include_coordinates=True,
|
||||
coordinate_source="auto"
|
||||
)
|
||||
|
||||
if success:
|
||||
self.show_info_dialog(
|
||||
"Key-Value CSV 저장 완료",
|
||||
f"분석 결과가 Key-Value 형태의 CSV 파일로 저장되었습니다:\n\n{output_path}\n\n" +
|
||||
"이 CSV는 다음과 같은 형태로 구성됩니다:\n" +
|
||||
"- file_name: 파일명\n" +
|
||||
"- file_type: 파일 형식\n" +
|
||||
"- key: 속성 키\n" +
|
||||
"- value: 속성 값\n" +
|
||||
"- x, y: 좌표 정보 (가능한 경우)"
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"Key-Value CSV 저장 완료: {os.path.basename(output_path)}",
|
||||
"success"
|
||||
)
|
||||
else:
|
||||
self.show_error_dialog(
|
||||
"저장 실패",
|
||||
"Key-Value CSV 저장에 실패했습니다. 로그를 확인해주세요."
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
"Key-Value CSV 저장 실패",
|
||||
"error"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Cross-tabulated CSV 저장 오류: {e}")
|
||||
self.show_error_dialog(
|
||||
"저장 오류",
|
||||
f"Key-Value CSV 저장 중 오류가 발생했습니다:\n{str(e)}"
|
||||
)
|
||||
|
||||
MultiFileUIComponents.add_log_message(
|
||||
self.log_container,
|
||||
f"Key-Value CSV 저장 실패: {str(e)}",
|
||||
"error"
|
||||
)
|
||||
|
||||
# 유틸리티 함수들
|
||||
|
||||
def show_error_dialog(self, title: str, message: str):
|
||||
"""오류 다이얼로그 표시"""
|
||||
from ui_components import UIComponents
|
||||
|
||||
dialog = UIComponents.create_error_dialog(title, message)
|
||||
|
||||
def close_dialog(e):
|
||||
dialog.open = False
|
||||
self.page.update()
|
||||
|
||||
dialog.actions[0].on_click = close_dialog
|
||||
self.page.dialog = dialog
|
||||
dialog.open = True
|
||||
self.page.update()
|
||||
|
||||
def show_info_dialog(self, title: str, message: str):
|
||||
"""정보 다이얼로그 표시"""
|
||||
from ui_components import UIComponents
|
||||
|
||||
dialog = UIComponents.create_info_dialog(title, message)
|
||||
|
||||
def close_dialog(e):
|
||||
dialog.open = False
|
||||
self.page.update()
|
||||
|
||||
dialog.actions[0].on_click = close_dialog
|
||||
self.page.dialog = dialog
|
||||
dialog.open = True
|
||||
self.page.update()
|
||||
|
||||
|
||||
# 사용 예시
|
||||
if __name__ == "__main__":
|
||||
def main_multi_file(page: ft.Page):
|
||||
"""다중 파일 처리 앱 테스트 실행"""
|
||||
page.title = "다중 파일 처리 테스트"
|
||||
page.theme_mode = ft.ThemeMode.LIGHT
|
||||
|
||||
app = MultiFileApp(page)
|
||||
ui = app.build_ui()
|
||||
page.add(ui)
|
||||
|
||||
ft.app(target=main_multi_file)
|
||||
Reference in New Issue
Block a user