KeiStory

PySide6 를 이용해 100만건 데이터 바인딩 및 가상화

 

pyside6 설치

pip install pySide6

 

코드

import sys
import random
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                               QHBoxLayout, QPushButton, QLabel, QLineEdit, 
                               QStatusBar, QStackedWidget, QTableWidget, QTableWidgetItem, QAbstractScrollArea)
from PySide6.QtGui import QIcon
from PySide6.QtCore import Qt, QSize, QTimer

# 메인 윈도우 클래스 정의
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("회원가입 애플리케이션")  # 윈도우 제목 설정
        self.setGeometry(100, 100, 800, 600)  # 윈도우 크기 및 위치 설정

        # 메인 위젯 설정
        main_widget = QWidget()  # 중앙 위젯 생성
        self.setCentralWidget(main_widget)  # 메인 윈도우에 중앙 위젯 설정
        main_layout = QHBoxLayout(main_widget)  # 메인 레이아웃 설정 (수평 레이아웃)

        # 왼쪽 메뉴 생성
        self.left_menu = LeftMenu(self)  # 왼쪽 메뉴 위젯 생성
        main_layout.addWidget(self.left_menu)  # 메인 레이아웃에 왼쪽 메뉴 추가

        # 메인 콘텐츠 영역 생성
        self.content_stack = QStackedWidget()  # 스택 위젯 생성 (여러 위젯 중 하나를 표시)
        main_layout.addWidget(self.content_stack)  # 메인 레이아웃에 콘텐츠 스택 추가

        # 회원가입 폼 추가
        self.signup_form = SignupForm()  # 회원가입 폼 생성
        self.content_stack.addWidget(self.signup_form)  # 콘텐츠 스택에 회원가입 폼 추가

        # 상태바 추가
        self.statusBar = QStatusBar()  # 상태바 생성
        self.setStatusBar(self.statusBar)  # 메인 윈도우에 상태바 설정
        self.statusBar.showMessage("준비")  # 상태바에 기본 메시지 표시

        # 왼쪽 메뉴 토글 버튼 연결
        self.left_menu.toggle_button.clicked.connect(self.toggle_menu)  # 토글 버튼 클릭 시 메뉴 토글 함수 호출

    # 왼쪽 메뉴를 토글하는 함수
    def toggle_menu(self):
        if self.left_menu.width() == 200:  # 현재 메뉴 너비가 200일 경우
            self.left_menu.setFixedWidth(50)  # 메뉴 너비를 50으로 줄임
        else:
            self.left_menu.setFixedWidth(200)  # 그렇지 않으면 메뉴 너비를 200으로 늘림

# 왼쪽 메뉴 클래스 정의
class LeftMenu(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedWidth(200)  # 메뉴의 기본 너비 설정
        self.setStyleSheet("background-color: #2E3440; color: #D8DEE9;")  # 배경 및 텍스트 색상 설정
        layout = QVBoxLayout(self)  # 수직 레이아웃 설정

        # 메뉴 토글 버튼 생성
        self.toggle_button = QPushButton("≡")  # 토글 버튼 (≡) 생성
        self.toggle_button.setStyleSheet("background-color: #4C566A; color: #D8DEE9; border: none;")  # 버튼 스타일 설정
        layout.addWidget(self.toggle_button)  # 레이아웃에 토글 버튼 추가

        # 메뉴 항목 생성
        menu_items = ["홈", "프로필", "설정"]  # 메뉴 항목 리스트
        for item in menu_items:
            button = QPushButton(item)  # 각 항목에 대한 버튼 생성
            button.setStyleSheet("background-color: #4C566A; color: #D8DEE9; border: none; padding: 10px;")  # 버튼 스타일 설정
            layout.addWidget(button)  # 레이아웃에 버튼 추가

        layout.addStretch()  # 빈 공간을 추가하여 메뉴가 위쪽에 고정되도록 함

# 회원가입 폼 클래스 정의
class SignupForm(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout(self)  # 수직 레이아웃 설정

        layout.addWidget(QLabel("회원가입"))  # 회원가입 제목 라벨 추가

        # 회원가입 입력 폼 레이아웃 생성
        form_layout = QVBoxLayout()
        fields = ["이름", "이메일", "비밀번호", "비밀번호 확인"]  # 입력 필드 리스트
        self.inputs = {}  # 입력 필드를 저장할 딕셔너리

        for field in fields:
            field_layout = QHBoxLayout()  # 각 필드를 위한 수평 레이아웃 생성
            label = QLabel(field)  # 필드 라벨 생성
            label.setFixedWidth(80)  # 라벨의 고정 너비 설정
            input_field = QLineEdit()  # 입력 필드 생성
            input_field.setFixedWidth(300)  # 입력 필드의 고정 너비 설정
            if "비밀번호" in field:
                input_field.setEchoMode(QLineEdit.Password)  # 비밀번호 필드는 비밀번호 모드로 설정
            field_layout.addWidget(label)  # 라벨을 레이아웃에 추가
            field_layout.addWidget(input_field)  # 입력 필드를 레이아웃에 추가
            form_layout.addLayout(field_layout)  # 폼 레이아웃에 필드 레이아웃 추가
            self.inputs[field] = input_field  # 딕셔너리에 입력 필드 저장

        layout.addLayout(form_layout)  # 메인 레이아웃에 폼 레이아웃 추가

        signup_button = QPushButton("가입하기")  # 가입하기 버튼 생성
        signup_button.setStyleSheet("background-color: #5E81AC; color: #ECEFF4; padding: 10px; border-radius: 5px;")  # 버튼 스타일 설정
        signup_button.clicked.connect(self.signup)  # 버튼 클릭 시 회원가입 함수 호출
        layout.addWidget(signup_button)  # 메인 레이아웃에 버튼 추가

        # 데이터 그리드 추가
        self.data_grid = QTableWidget()  # 테이블 위젯 생성
        self.data_grid.setColumnCount(10)  # 컬럼 수 설정
        self.data_grid.setHorizontalHeaderLabels(["이름", "이메일", "비밀번호", "주소", "전화번호", "생년월일", "성별", "회원번호", "가입일", "상태"])
        self.data_grid.setRowCount(0)  # 초기에는 행을 설정하지 않음
        self.data_grid.setVerticalScrollMode(QTableWidget.ScrollPerPixel)  # 스크롤 가상화 처리
        self.data_grid.verticalScrollBar().valueChanged.connect(self.on_scroll)  # 스크롤 시 데이터 로드 함수 호출
        layout.addWidget(self.data_grid)  # 메인 레이아웃에 그리드 추가

        # 조회 버튼 추가
        load_data_button = QPushButton("데이터 조회")  # 데이터 조회 버튼 생성
        load_data_button.setStyleSheet("background-color: #5E81AC; color: #ECEFF4; padding: 10px; border-radius: 5px;")  # 버튼 스타일 설정
        load_data_button.clicked.connect(self.load_data)  # 버튼 클릭 시 데이터 로드 함수 호출
        layout.addWidget(load_data_button)  # 메인 레이아웃에 버튼 추가

        self.loaded_rows = 0  # 로드된 행 수를 추적
        self.total_rows = 1000000  # 총 행 수

    # 회원가입 함수
    def signup(self):
        # 여기에 회원가입 로직을 구현합니다.
        print("회원가입 시도:")  # 콘솔에 회원가입 시도 메시지 출력
        for field, input_field in self.inputs.items():
            print(f"{field}: {input_field.text()}")  # 각 입력 필드의 값을 출력

    # 초기 데이터 로드 함수
    def load_data(self):
        self.add_rows(1000)  # 처음에는 1000개의 행을 로드

    # 스크롤 시 추가 데이터 로드 함수
    def on_scroll(self, value):
        if value == self.data_grid.verticalScrollBar().maximum():
            self.add_rows(1000)  # 스크롤이 끝에 도달하면 1000개의 행 추가 로드

    # 데이터 그리드에 행을 추가하는 함수
    def add_rows(self, count):
        if self.loaded_rows >= self.total_rows:
            return  # 모든 데이터를 이미 로드한 경우 반환

        new_row_count = min(self.loaded_rows + count, self.total_rows)
        self.data_grid.setRowCount(new_row_count)

        for row in range(self.loaded_rows, new_row_count):
            name = f"사용자{row}"
            email = f"user{row}@example.com"
            password = "******"
            address = f"주소 {row}번지"
            phone = f"010-{random.randint(1000, 9999)}-{random.randint(1000, 9999)}"
            birthdate = f"19{random.randint(50, 99)}-{random.randint(1, 12):02d}-{random.randint(1, 28):02d}"
            gender = random.choice(["남", "여"])
            member_id = f"M{row:06d}"
            signup_date = f"2024-{random.randint(1, 12):02d}-{random.randint(1, 28):02d}"
            status = random.choice(["활성", "비활성"])

            data = [name, email, password, address, phone, birthdate, gender, member_id, signup_date, status]
            for col, value in enumerate(data):
                self.data_grid.setItem(row, col, QTableWidgetItem(value))

        self.loaded_rows = new_row_count

# 애플리케이션 실행 코드ㅏ사
if __name__ == "__main__":
    app = QApplication(sys.argv)  # 애플리케이션 객체 생성
    window = MainWindow()  # 메인 윈도우 객체 생성
    window.show()  # 메인 윈도우 표시
    sys.exit(app.exec())  # 애플리케이션 실행 및 종료 코드

 

윈도우 응용 프로그램 개발에 사용을 해도 문제가 없어보입니다.

 

반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band