spinner 추가
This commit is contained in:
parent
f6af247743
commit
0a63ae00d7
|
|
@ -0,0 +1,29 @@
|
|||
# loading_overlay.py
|
||||
from PyQt6.QtWidgets import QWidget, QLabel
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QMovie
|
||||
|
||||
class LoadingOverlay(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setStyleSheet("background-color: rgba(0, 0, 0, 150);")
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
|
||||
|
||||
self.spinner = QLabel(self)
|
||||
self.spinner.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.movie = QMovie("spinner.gif")
|
||||
self.spinner.setMovie(self.movie)
|
||||
|
||||
layout = self.spinner.geometry()
|
||||
self.resize(parent.size())
|
||||
self.spinner.resize(100, 100)
|
||||
self.spinner.move((self.width() - 100) // 2, (self.height() - 100) // 2)
|
||||
self.hide()
|
||||
|
||||
def start(self):
|
||||
self.movie.start()
|
||||
self.show()
|
||||
|
||||
def stop(self):
|
||||
self.movie.stop()
|
||||
self.hide()
|
||||
|
|
@ -1,60 +1,65 @@
|
|||
from PyQt6.QtWidgets import (
|
||||
QApplication, QWidget, QVBoxLayout, QLabel, QGridLayout, QProgressBar
|
||||
)
|
||||
from PyQt6.QtCore import Qt, QTimer
|
||||
# main.py
|
||||
from PyQt6.QtWidgets import QApplication, QWidget, QGridLayout, QVBoxLayout
|
||||
from PyQt6.QtCore import QTimer
|
||||
import sys
|
||||
from loading_overlay import LoadingOverlay
|
||||
from monitor_data import get_monitor_data
|
||||
from monitor_card import MonitorCard # 카드 UI는 따로 분리해도 좋음
|
||||
|
||||
class LoadingScreen(QWidget):
|
||||
class Dashboard(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("Server Monitor Dashboard")
|
||||
self.setFixedSize(960, 640)
|
||||
self.setWindowTitle("서버 모니터링 - 로딩 중")
|
||||
layout = QVBoxLayout()
|
||||
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.label = QLabel("서버 상태를 불러오는 중...")
|
||||
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.spinner = QProgressBar()
|
||||
self.spinner.setRange(0, 0) # 무한 로딩 표시
|
||||
self.cards = {}
|
||||
self.titles = [
|
||||
"CPU", "RAM", "Disk", "Uptime",
|
||||
"CPU Temp", "GPU Temp", "GPU Usage", "Swap",
|
||||
"Download", "Upload", "Alive", "Processes"
|
||||
]
|
||||
|
||||
layout.addWidget(self.label)
|
||||
layout.addWidget(self.spinner)
|
||||
self.setLayout(layout)
|
||||
# 메인 레이아웃
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
class MonitoringGrid(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setFixedSize(960, 640)
|
||||
self.setWindowTitle("서버 모니터링")
|
||||
# 카드 그리드
|
||||
self.grid = QGridLayout()
|
||||
self.grid.setSpacing(10)
|
||||
self.layout.addLayout(self.grid)
|
||||
|
||||
grid = QGridLayout()
|
||||
grid.setSpacing(10)
|
||||
# 카드 생성
|
||||
for i, title in enumerate(self.titles):
|
||||
row = i // 4
|
||||
col = i % 4
|
||||
card = MonitorCard(title)
|
||||
self.grid.addWidget(card, row, col)
|
||||
self.cards[title] = card
|
||||
|
||||
for row in range(3):
|
||||
for col in range(4):
|
||||
label = QLabel(f"서버 {row * 3 + col + 1}")
|
||||
label.setStyleSheet("background-color: #e0e0e0; padding: 20px; border: 1px solid #aaa;")
|
||||
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
grid.addWidget(label, row, col)
|
||||
# 오버레이 생성
|
||||
self.overlay = LoadingOverlay(self)
|
||||
self.overlay.start()
|
||||
|
||||
self.setLayout(grid)
|
||||
# 데이터 수신 후
|
||||
QTimer.singleShot(2000, self.finish_loading)
|
||||
|
||||
class MainApp:
|
||||
def __init__(self):
|
||||
self.app = QApplication(sys.argv)
|
||||
self.loading = LoadingScreen()
|
||||
self.grid = MonitoringGrid()
|
||||
# 주기적 업데이트
|
||||
self.timer = QTimer()
|
||||
self.timer.timeout.connect(self.update_data)
|
||||
self.timer.start(3000)
|
||||
|
||||
def run(self):
|
||||
self.loading.show()
|
||||
def finish_loading(self):
|
||||
self.overlay.stop()
|
||||
self.update_data()
|
||||
|
||||
# 3초 후 로딩 화면 종료하고 그리드 표시
|
||||
QTimer.singleShot(3000, self.show_grid)
|
||||
sys.exit(self.app.exec())
|
||||
def update_data(self):
|
||||
data = get_monitor_data()
|
||||
for key in self.titles:
|
||||
self.cards[key].update_value(data.get(key, "--"))
|
||||
|
||||
def show_grid(self):
|
||||
self.loading.close()
|
||||
self.grid.show()
|
||||
|
||||
if __name__ == "__main__":
|
||||
MainApp().run()
|
||||
app = QApplication(sys.argv)
|
||||
dashboard = Dashboard()
|
||||
dashboard.show()
|
||||
sys.exit(app.exec())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
# monitor_card.py
|
||||
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QMovie
|
||||
|
||||
class MonitorCard(QWidget):
|
||||
def __init__(self, title, bg_color="#2e2e2e"):
|
||||
super().__init__()
|
||||
self.setStyleSheet(f"""
|
||||
background-color: {bg_color};
|
||||
border-radius: 10px;
|
||||
border: 1px solid #444;
|
||||
""")
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.title = QLabel(title)
|
||||
self.title.setStyleSheet("font-weight: bold; font-size: 16px; color: white;")
|
||||
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.value = QLabel("--")
|
||||
self.value.setStyleSheet("font-size: 24px; font-weight: bold; color: white;")
|
||||
self.value.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.spinner = QLabel()
|
||||
self.spinner.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.movie = QMovie("spinner.gif")
|
||||
self.spinner.setMovie(self.movie)
|
||||
self.spinner.hide()
|
||||
|
||||
layout.addWidget(self.title)
|
||||
layout.addWidget(self.value)
|
||||
layout.addWidget(self.spinner)
|
||||
self.setLayout(layout)
|
||||
|
||||
def start_loading(self):
|
||||
self.value.hide()
|
||||
self.spinner.show()
|
||||
self.movie.start()
|
||||
|
||||
def stop_loading(self):
|
||||
self.movie.stop()
|
||||
self.spinner.hide()
|
||||
self.value.show()
|
||||
|
||||
def update_value(self, text):
|
||||
self.stop_loading()
|
||||
self.value.setText(text)
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# monitor_data.py
|
||||
import psutil
|
||||
import subprocess
|
||||
import GPUtil
|
||||
import time
|
||||
|
||||
def format_uptime():
|
||||
uptime_seconds = time.time() - psutil.boot_time()
|
||||
days = int(uptime_seconds // 86400)
|
||||
hours = int((uptime_seconds % 86400) // 3600)
|
||||
minutes = int((uptime_seconds % 3600) // 60)
|
||||
return f"{days}d {hours:02d}h {minutes:02d}m" if days > 0 else f"{hours:02d}h {minutes:02d}m"
|
||||
|
||||
def get_cpu_temp():
|
||||
try:
|
||||
output = subprocess.check_output(['sensors'], universal_newlines=True)
|
||||
for line in output.splitlines():
|
||||
if "Package id 0:" in line or "Core 0:" in line:
|
||||
temp_str = line.split(":")[1].strip().split("°")[0]
|
||||
return f"{float(temp_str)}°C"
|
||||
except Exception:
|
||||
return "---"
|
||||
|
||||
def get_gpu_temp():
|
||||
try:
|
||||
gpus = GPUtil.getGPUs()
|
||||
return f"{gpus[0].temperature}°C" if gpus else "---"
|
||||
except Exception:
|
||||
return "---"
|
||||
|
||||
def get_gpu_usage():
|
||||
try:
|
||||
gpus = GPUtil.getGPUs()
|
||||
return f"{gpus[0].load * 100:.1f}%" if gpus else "---"
|
||||
except Exception:
|
||||
return "---"
|
||||
|
||||
def get_net_speed(interface='enp0s31f6', interval=1):
|
||||
try:
|
||||
start = psutil.net_io_counters(pernic=True)[interface]
|
||||
time.sleep(interval)
|
||||
end = psutil.net_io_counters(pernic=True)[interface]
|
||||
download = (end.bytes_recv - start.bytes_recv) / 1024 / interval
|
||||
upload = (end.bytes_sent - start.bytes_sent) / 1024 / interval
|
||||
return f"{download:.2f} KB/s", f"{upload:.2f} KB/s"
|
||||
except Exception:
|
||||
return "---", "---"
|
||||
|
||||
def check_alive(ip="192.168.0.101"):
|
||||
try:
|
||||
result = subprocess.run(["ping", "-c", "1", "-W", "1", ip],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
return "True" if result.returncode == 0 else "False"
|
||||
except Exception:
|
||||
return "---"
|
||||
|
||||
def get_monitor_data():
|
||||
download, upload = get_net_speed()
|
||||
return {
|
||||
"CPU": f"{psutil.cpu_percent()}%",
|
||||
"RAM": f"{psutil.virtual_memory().percent}%",
|
||||
"Disk": f"{psutil.disk_usage('/').percent}%",
|
||||
"Uptime": format_uptime(),
|
||||
"CPU Temp": get_cpu_temp(),
|
||||
"GPU Temp": get_gpu_temp(),
|
||||
"GPU Usage": get_gpu_usage(),
|
||||
"Swap": f"{psutil.swap_memory().percent}%",
|
||||
"Download": download,
|
||||
"Upload": upload,
|
||||
"Alive": check_alive(),
|
||||
"Processes": str(len(psutil.pids()))
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# main.py
|
||||
# main.py
|
||||
from PyQt6.QtWidgets import QApplication, QWidget, QGridLayout
|
||||
from PyQt6.QtCore import QTimer
|
||||
import sys
|
||||
from monitor_data import get_monitor_data
|
||||
from monitor_card import MonitorCard # 카드 UI는 따로 분리해도 좋음
|
||||
|
||||
from loading_overlay import LoadingOverlay
|
||||
|
||||
class Dashboard(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
# 카드들 배치
|
||||
self.layout = QVBoxLayout(self)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
# 오버레이 생성
|
||||
self.overlay = LoadingOverlay(self)
|
||||
|
||||
# 로딩 시작
|
||||
self.overlay.start()
|
||||
|
||||
# 데이터 수신 후
|
||||
QTimer.singleShot(2000, self.finish_loading)
|
||||
|
||||
def finish_loading(self):
|
||||
self.overlay.stop()
|
||||
# 카드들에 값 업데이트
|
||||
Loading…
Reference in New Issue