157 lines
3.9 KiB
Python
157 lines
3.9 KiB
Python
# 엔트리포인트 — 스플래시 화면 표시 후 백그라운드 초기화, GUI 실행
|
|
import multiprocessing
|
|
import sys
|
|
|
|
from logger import setup_logging, teardown_logging
|
|
|
|
from PyQt5.QtWidgets import QApplication
|
|
from PyQt5.QtGui import QIcon
|
|
|
|
from utils.path_helper import get_path
|
|
from gui.main_window import MainWindow
|
|
from gui.splash_screen import SplashScreen, InitWorker
|
|
|
|
ICON_PATH = get_path("assets", "images", "ant_logo.png")
|
|
|
|
|
|
def _apply_windows_taskbar_icon(app_id: str = "ant.vision.inspection.1.0"):
|
|
if sys.platform != "win32":
|
|
return
|
|
try:
|
|
import ctypes
|
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
|
|
except Exception as e:
|
|
print(f"[main] AppUserModelID 설정 실패: {e}")
|
|
|
|
|
|
def main():
|
|
# setup_logging() must be called inside main(), not at module level.
|
|
# On Windows, multiprocessing spawns subprocesses that re-import __main__,
|
|
# and module-level setup_logging() would corrupt the log file and replace
|
|
# builtins.print in every worker process.
|
|
setup_logging()
|
|
|
|
_apply_windows_taskbar_icon()
|
|
|
|
app = QApplication(sys.argv)
|
|
icon = QIcon(ICON_PATH)
|
|
app.setWindowIcon(icon)
|
|
app.setStyleSheet(_DARK_STYLE)
|
|
|
|
splash = SplashScreen()
|
|
splash.show()
|
|
QApplication.processEvents()
|
|
|
|
worker = InitWorker()
|
|
worker.progress.connect(splash.update_progress)
|
|
|
|
def on_finished(results):
|
|
window = MainWindow(
|
|
results["insight"],
|
|
results["basler"],
|
|
results["config"],
|
|
plc_client=results.get("plc"),
|
|
)
|
|
window.setWindowIcon(icon)
|
|
window.show()
|
|
splash.close()
|
|
|
|
def cleanup():
|
|
results["insight"].disconnect()
|
|
results["basler"].disconnect()
|
|
if results["db"].is_connected():
|
|
results["db"].disconnect()
|
|
plc = results.get("plc")
|
|
if plc and plc.is_connected():
|
|
plc.disconnect()
|
|
|
|
app.aboutToQuit.connect(cleanup)
|
|
|
|
worker.finished.connect(on_finished)
|
|
worker.start()
|
|
|
|
try:
|
|
ret = app.exec_()
|
|
finally:
|
|
|
|
teardown_logging()
|
|
|
|
sys.exit(ret)
|
|
|
|
|
|
_DARK_STYLE = """
|
|
QWidget {
|
|
background-color: #1a1a1a;
|
|
color: #ffffff;
|
|
font-size: 14px;
|
|
}
|
|
QGroupBox {
|
|
background-color: #222222;
|
|
border: 1px solid #444444;
|
|
border-radius: 6px;
|
|
margin-top: 14px;
|
|
padding: 10px 8px 8px 8px;
|
|
}
|
|
QGroupBox::title {
|
|
subcontrol-origin: margin;
|
|
left: 10px;
|
|
padding: 0 4px;
|
|
color: #aaaaaa;
|
|
}
|
|
QPushButton {
|
|
background-color: #2e2e2e;
|
|
color: #ffffff;
|
|
border: 1px solid #555555;
|
|
border-radius: 4px;
|
|
min-height: 56px;
|
|
padding: 0 20px;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover { background-color: #3a3a3a; }
|
|
QPushButton:pressed { background-color: #1e1e1e; }
|
|
QPushButton:checked { background-color: #0055cc; border-color: #0077ff; }
|
|
QPushButton:disabled { color: #666666; }
|
|
QLineEdit, QSpinBox, QDoubleSpinBox {
|
|
background-color: #2a2a2a;
|
|
color: #ffffff;
|
|
border: 1px solid #555555;
|
|
border-radius: 4px;
|
|
padding: 6px 8px;
|
|
min-height: 38px;
|
|
}
|
|
QLabel { color: #ffffff; }
|
|
QListWidget {
|
|
background-color: #222222;
|
|
color: #ffffff;
|
|
border: 1px solid #444444;
|
|
outline: none;
|
|
}
|
|
QListWidget::item:selected { background-color: #0055cc; }
|
|
QProgressBar {
|
|
background-color: #2a2a2a;
|
|
border: 1px solid #555555;
|
|
border-radius: 4px;
|
|
text-align: center;
|
|
min-height: 22px;
|
|
}
|
|
QProgressBar::chunk { background-color: #0055cc; border-radius: 4px; }
|
|
QCheckBox { min-height: 38px; }
|
|
QCheckBox::indicator { width: 22px; height: 22px; }
|
|
QScrollBar:vertical {
|
|
background: #2a2a2a;
|
|
width: 10px;
|
|
border-radius: 5px;
|
|
}
|
|
QScrollBar::handle:vertical {
|
|
background: #555555;
|
|
border-radius: 5px;
|
|
min-height: 30px;
|
|
}
|
|
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; }
|
|
"""
|
|
|
|
|
|
if __name__ == "__main__":
|
|
multiprocessing.freeze_support()
|
|
main()
|