PYTHON GUI

[ PySide6 ] QLineEdit 완벽 가이드 (2부) - 시각적 속성과 이벤트 처리

나루하루001 2025. 5. 18. 20:01
반응형



소개


이전 글에서는 QLineEdit의

텍스트 관리와 입력 제어 메서드에 대해 알아보았습니다.

 

이번 글에서는 QLineEdit의

시각적 속성을 제어하는 메서드와 이벤트 처리 방법에 대해 자세히 알아보겠습니다.

 

사용자 인터페이스의 미적 요소와 상호작용을 개선하여 더 나은 사용자 경험을 제공하는 방법을 배워봅시다.

시각적 속성 메서드

 

모양 설정 메서드

 

QLineEdit의 기본적인 모양을 설정하는 메서드들입니다:

  • setPlaceholderText(text) - 입력 필드가 비어 있을 때 표시되는 텍스트를 설정합니다.
  • placeholderText() - 현재 설정된 자리 표시자 텍스트를 반환합니다.
  • setReadOnly(boolean) - 읽기 전용 모드를 설정합니다.
  • isReadOnly() - 읽기 전용 모드인지 확인합니다.
  • setFrame(boolean) - 프레임 표시 여부를 설정합니다.
  • hasFrame() - 프레임이 표시되는지 확인합니다.
  • setClearButtonEnabled(boolean) - 지우기 버튼 활성화 여부를 설정합니다.
  • isClearButtonEnabled() - 지우기 버튼이 활성화되어 있는지 확인합니다.
from PySide6.QtWidgets import QLineEdit

# 자리 표시자 텍스트 설정
line_edit = QLineEdit()
line_edit.setPlaceholderText("이름을 입력하세요")
print(line_edit.placeholderText())  # 출력: "이름을 입력하세요"

# 읽기 전용 모드 설정
read_only_edit = QLineEdit("이 텍스트는 수정할 수 없습니다")
read_only_edit.setReadOnly(True)
print(read_only_edit.isReadOnly())  # 출력: True

# 프레임 제거
frameless_edit = QLineEdit()
frameless_edit.setFrame(False)
print(frameless_edit.hasFrame())  # 출력: False

# 지우기 버튼 활성화
clear_button_edit = QLineEdit()
clear_button_edit.setClearButtonEnabled(True)
print(clear_button_edit.isClearButtonEnabled())  # 출력: True

 

💡 팁: setClearButtonEnabled(True)를 사용하면 입력 필드에 텍스트가 있을 때 오른쪽에 X 버튼이 나타나 사용자가 쉽게 텍스트를 지울 수 있습니다. 모바일 앱과 같은 사용자 경험을 제공하고 싶을 때 유용합니다.

 

정렬 관련 메서드

 

QLineEdit 내의 텍스트 정렬을 제어하는 메서드입니다:

  • setAlignment(alignment) - 텍스트 정렬 방식을 설정합니다.
  • alignment() - 현재 텍스트 정렬 방식을 반환합니다.

정렬 옵션:

  • Qt.AlignLeft - 왼쪽 정렬 (기본값)
  • Qt.AlignRight - 오른쪽 정렬
  • Qt.AlignCenter - 가운데 정렬
  • Qt.AlignJustify - 양쪽 정렬
from PySide6.QtWidgets import QLineEdit
from PySide6.QtCore import Qt

# 왼쪽 정렬 (기본값)
left_edit = QLineEdit("왼쪽 정렬 텍스트")
left_edit.setAlignment(Qt.AlignLeft)

# 오른쪽 정렬
right_edit = QLineEdit("오른쪽 정렬 텍스트")
right_edit.setAlignment(Qt.AlignRight)

# 가운데 정렬
center_edit = QLineEdit("가운데 정렬 텍스트")
center_edit.setAlignment(Qt.AlignCenter)

print(center_edit.alignment())  # 출력: Qt.AlignCenter

 

스타일 및 색상 메서드

 

QLineEdit의 스타일과 색상을 설정하는 방법입니다:

  • setStyleSheet(style) - CSS 스타일 시트를 적용합니다.
  • setFont(font) - 폰트를 설정합니다.
  • setTextMargins(left, top, right, bottom) - 텍스트 여백을 설정합니다.
  • textMargins() - 현재 텍스트 여백을 반환합니다.
from PySide6.QtWidgets import QLineEdit
from PySide6.QtGui import QFont

# 스타일시트를 사용한 스타일링
styled_edit = QLineEdit("스타일이 적용된 텍스트")
styled_edit.setStyleSheet("""
    QLineEdit {
        background-color: #f0f8ff;
        border: 2px solid #6495ed;
        border-radius: 5px;
        padding: 5px;
        color: #4169e1;
    }
    QLineEdit:focus {
        border: 2px solid #1e90ff;
        background-color: #e6f2ff;
    }
""")

# 폰트 설정
font_edit = QLineEdit("커스텀 폰트가 적용된 텍스트")
font = QFont("Arial", 12, QFont.Bold)
font_edit.setFont(font)

# 텍스트 여백 설정
margin_edit = QLineEdit("여백이 적용된 텍스트")
margin_edit.setTextMargins(10, 5, 10, 5)
left, top, right, bottom = margin_edit.textMargins()
print(f"여백: 왼쪽 {left}, 위 {top}, 오른쪽 {right}, 아래 {bottom}")

 

💡 스타일시트 팁: QLineEdit의 다양한 상태(일반, 포커스, 비활성화 등)에 따라 다른 스타일을 적용할 수 있습니다. 예를 들어 QLineEdit:hover, QLineEdit:disabled 등의 선택자를 사용하여 다양한 상태에 맞는 스타일을 지정할 수 있습니다.



이벤트 및 시그널

 

기본 시그널

 

QLineEdit은 사용자 상호작용에 반응하기 위한 다양한 시그널을 제공합니다:

  • textChanged(text) - 텍스트가 변경될 때마다 발생합니다.
  • textEdited(text) - 사용자가 직접 텍스트를 편집할 때만 발생합니다(프로그램적으로 변경된 경우에는 발생하지 않음).
  • returnPressed() - 사용자가 Enter/Return 키를 누를 때 발생합니다.
  • editingFinished() - 사용자가 편집을 완료하고 포커스를 잃을 때 발생합니다.
  • selectionChanged() - 텍스트 선택이 변경될 때 발생합니다.
  • cursorPositionChanged(old, new) - 커서 위치가 변경될 때 발생합니다.
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel

class SignalDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QLineEdit 시그널 데모")
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout(self)
        
        # 텍스트 입력 필드
        self.line_edit = QLineEdit()
        layout.addWidget(self.line_edit)
        
        # 상태 표시 라벨
        self.status_label = QLabel("상태: 대기 중")
        layout.addWidget(self.status_label)
        
        # 현재 텍스트 표시 라벨
        self.text_label = QLabel("텍스트: ")
        layout.addWidget(self.text_label)
        
        # 커서 위치 표시 라벨
        self.cursor_label = QLabel("커서 위치: 0")
        layout.addWidget(self.cursor_label)
        
        # 시그널 연결
        self.line_edit.textChanged.connect(self.on_text_changed)
        self.line_edit.textEdited.connect(self.on_text_edited)
        self.line_edit.returnPressed.connect(self.on_return_pressed)
        self.line_edit.editingFinished.connect(self.on_editing_finished)
        self.line_edit.cursorPositionChanged.connect(self.on_cursor_position_changed)
        
        self.resize(300, 150)
        
    def on_text_changed(self, text):
        self.text_label.setText(f"텍스트: {text}")
        
    def on_text_edited(self, text):
        self.status_label.setText("상태: 편집 중")
        
    def on_return_pressed(self):
        self.status_label.setText("상태: Enter 키 입력됨")
        
    def on_editing_finished(self):
        self.status_label.setText("상태: 편집 완료")
        
    def on_cursor_position_changed(self, old, new):
        self.cursor_label.setText(f"커서 위치: {new} (이전: {old})")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    demo = SignalDemo()
    demo.show()
    sys.exit(app.exec())

 

고급 시그널 활용

 

시그널을 활용한 고급 기능 구현 방법입니다:

  • 실시간 입력 검증
  • 자동 대소문자 변환
  • 입력 지연 처리 (타이핑 완료 후 처리)
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel
from PySide6.QtCore import QTimer

class AdvancedSignalDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("고급 시그널 활용 데모")
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout(self)
        
        # 실시간 검증 필드 (이메일 형식)
        layout.addWidget(QLabel("이메일 입력 (실시간 검증):"))
        self.email_edit = QLineEdit()
        self.email_edit.setPlaceholderText("example@email.com")
        self.email_edit.textChanged.connect(self.validate_email)
        layout.addWidget(self.email_edit)
        self.email_status = QLabel("상태: 대기 중")
        layout.addWidget(self.email_status)
        
        # 자동 대문자 변환 필드
        layout.addWidget(QLabel("자동 대문자 변환:"))
        self.uppercase_edit = QLineEdit()
        self.uppercase_edit.setPlaceholderText("소문자 입력 시 자동으로 대문자로 변환됩니다")
        self.uppercase_edit.textEdited.connect(self.convert_to_uppercase)
        layout.addWidget(self.uppercase_edit)
        
        # 입력 지연 처리 필드 (검색어 입력 등에 유용)
        layout.addWidget(QLabel("입력 지연 처리 (타이핑 완료 후 0.5초 후 처리):"))
        self.delayed_edit = QLineEdit()
        self.delayed_edit.setPlaceholderText("타이핑을 멈추면 0.5초 후 처리됩니다")
        self.delayed_edit.textChanged.connect(self.setup_delay)
        layout.addWidget(self.delayed_edit)
        self.delay_status = QLabel("상태: 대기 중")
        layout.addWidget(self.delay_status)
        
        # 타이머 초기화
        self.delay_timer = QTimer()
        self.delay_timer.setSingleShot(True)
        self.delay_timer.timeout.connect(self.process_delayed_input)
        
        self.resize(400, 250)
        
    def validate_email(self, text):
        import re
        email_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
        if not text:
            self.email_status.setText("상태: 대기 중")
            self.email_edit.setStyleSheet("")
        elif email_pattern.match(text):
            self.email_status.setText("상태: 유효한 이메일 형식")
            self.email_edit.setStyleSheet("border: 1px solid green;")
        else:
            self.email_status.setText("상태: 유효하지 않은 이메일 형식")
            self.email_edit.setStyleSheet("border: 1px solid red;")
    
    def convert_to_uppercase(self, text):
        cursor_pos = self.uppercase_edit.cursorPosition()
        self.uppercase_edit.setText(text.upper())
        self.uppercase_edit.setCursorPosition(cursor_pos)
    
    def setup_delay(self, text):
        self.delay_status.setText("상태: 입력 중...")
        # 이전 타이머 취소하고 새 타이머 시작
        self.delay_timer.stop()
        self.delay_timer.start(500)  # 0.5초 후 실행
    
    def process_delayed_input(self):
        text = self.delayed_edit.text()
        self.delay_status.setText(f"상태: 처리 완료! 입력된 텍스트: {text}")
        # 실제 애플리케이션에서는 여기서 검색 등의 작업 수행

if __name__ == "__main__":
    app = QApplication(sys.argv)
    demo = AdvancedSignalDemo()
    demo.show()
    sys.exit(app.exec())



고급 기능과 활용법

 

자동완성 기능

 

QLineEdit에 자동완성 기능을 추가하는 방법입니다:

  • setCompleter(completer) - 자동완성 객체를 설정합니다.
  • completer() - 현재 설정된 자동완성 객체를 반환합니다.
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel, QCompleter

class CompleterDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("자동완성 데모")
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout(self)
        
        layout.addWidget(QLabel("국가 이름을 입력하세요 (자동완성):"))
        
        # 자동완성 기능이 있는 입력 필드
        self.country_edit = QLineEdit()
        
        # 자동완성 데이터
        countries = ["대한민국", "미국", "일본", "중국", "영국", "프랑스", "독일", "캐나다", 
                    "호주", "뉴질랜드", "러시아", "이탈리아", "스페인", "브라질", "멕시코"]
        
        # 자동완성 객체 생성 및 설정
        completer = QCompleter(countries)
        completer.setCaseSensitivity(False)  # 대소문자 구분 안 함
        self.country_edit.setCompleter(completer)
        
        layout.addWidget(self.country_edit)
        layout.addWidget(QLabel("입력 시 자동완성 목록이 표시됩니다."))
        
        self.resize(300, 150)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    demo = CompleterDemo()
    demo.show()
    sys.exit(app.exec())

 

💡 자동완성 팁: QCompleter는 정적 목록뿐만 아니라 QAbstractItemModel을 사용하여 동적 데이터 소스에서도 자동완성을 지원합니다. 이를 활용하면 데이터베이스나 네트워크 요청을 통해 자동완성 항목을 동적으로 가져올 수 있습니다.

 

액션 추가

 

QLineEdit에 아이콘 버튼을 추가하는 방법입니다:

  • addAction(action, position) - 지정된 위치에 액션(아이콘 버튼)을 추가합니다.
  • removeAction(action) - 액션을 제거합니다.

 

액션 위치 옵션:

  • QLineEdit.LeadingPosition - 입력 필드 왼쪽
  • QLineEdit.TrailingPosition - 입력 필드 오른쪽
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QLabel
from PySide6.QtGui import QAction, QIcon

class ActionDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QLineEdit 액션 데모")
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout(self)
        
        layout.addWidget(QLabel("검색 입력 필드:"))
        
        # 검색 입력 필드
        self.search_edit = QLineEdit()
        self.search_edit.setPlaceholderText("검색어를 입력하세요")
        
        # 검색 아이콘 액션 추가 (오른쪽)
        search_action = QAction(self)
        search_action.setIcon(QIcon.fromTheme("search"))  # 시스템 아이콘 사용
        search_action.triggered.connect(self.perform_search)
        self.search_edit.addAction(search_action, QLineEdit.TrailingPosition)
        
        # 설정 아이콘 액션 추가 (왼쪽)
        settings_action = QAction(self)
        settings_action.setIcon(QIcon.fromTheme("preferences-system"))  # 시스템 아이콘 사용
        settings_action.triggered.connect(self.show_settings)
        self.search_edit.addAction(settings_action, QLineEdit.LeadingPosition)
        
        layout.addWidget(self.search_edit)
        
        # 상태 표시 라벨
        self.status_label = QLabel("상태: 대기 중")
        layout.addWidget(self.status_label)
        
        # 지우기 버튼 활성화
        self.search_edit.setClearButtonEnabled(True)
        
        self.resize(350, 150)
        
    def perform_search(self):
        search_text = self.search_edit.text()
        if search_text:
            self.status_label.setText(f"상태: '{search_text}' 검색 중...")
        else:
            self.status_label.setText("상태: 검색어를 입력하세요")
        
    def show_settings(self):
        self.status_label.setText("상태: 검색 설정 메뉴 열기")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    demo = ActionDemo()
    demo.show()
    sys.exit(app.exec())

 

💡 액션 팁: 아이콘이 없는 시스템에서는 QIcon.fromTheme()이 작동하지 않을 수 있습니다. 이 경우 직접 이미지 파일을 지정하여 아이콘을 생성할 수 있습니다: QIcon("path/to/icon.png")



실전 예제


이제 지금까지 배운 메서드들을 활용한 실용적인 예제를 살펴보겠습니다.

 

예제 1: 고급 검색 입력 필드

 

검색 기능을 가진 고급 입력 필드를 구현한 예제입니다.

자동완성, 검색 기록, 실시간 검색 제안 기능을 포함합니다.

import sys
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLineEdit, 
                              QLabel, QCompleter, QListWidget)
from PySide6.QtCore import Qt, QStringListModel, QTimer
from PySide6.QtGui import QAction, QIcon

class AdvancedSearchField(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("고급 검색 입력 필드")
        self.search_history = []
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout(self)
        
        # 검색 필드 생성
        self.search_edit = QLineEdit()
        self.search_edit.setPlaceholderText("검색어를 입력하세요")
        self.search_edit.setClearButtonEnabled(True)
        self.search_edit.setMinimumWidth(300)
        
        # 스타일 적용
        self.search_edit.setStyleSheet("""
            QLineEdit {
                border: 2px solid #c0c0c0;
                border-radius: 15px;
                padding: 8px 15px;
                background-color: #f5f5f5;
                font-size: 14px;
            }
            QLineEdit:focus {
                border-color: #3a7bd5;
                background-color: white;
            }
        """)
        
        # 검색 아이콘 추가
        search_action = QAction(self)
        search_action.setIcon(QIcon.fromTheme("search", QIcon("search.png")))
        search_action.triggered.connect(self.perform_search)
        self.search_edit.addAction(search_action, QLineEdit.TrailingPosition)
        
        # 자동완성 설정
        self.search_terms = ["Python", "PySide6", "Qt", "QLineEdit", "PyQt", 
                            "GUI 개발", "위젯", "이벤트 처리", "시그널", "슬롯"]
        self.completer = QCompleter()
        self.completer_model = QStringListModel()
        self.update_completer()
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setFilterMode(Qt.MatchContains)
        self.search_edit.setCompleter(self.completer)
        
        # 시그널 연결
        self.search_edit.returnPressed.connect(self.perform_search)
        self.search_edit.textChanged.connect(self.on_text_changed)
        
        layout.addWidget(self.search_edit)
        
        # 검색 결과 및 제안 목록
        self.results_label = QLabel("검색 결과가 여기에 표시됩니다")
        layout.addWidget(self.results_label)
        
        self.suggestion_list = QListWidget()
        self.suggestion_list.setVisible(False)
        self.suggestion_list.itemClicked.connect(self.use_suggestion)
        layout.addWidget(self.suggestion_list)
        
        # 검색 기록 표시
        self.history_label = QLabel("최근 검색 기록:")
        layout.addWidget(self.history_label)
        
        self.history_list = QListWidget()
        self.history_list.itemClicked.connect(self.use_history_item)
        layout.addWidget(self.history_list)
        
        # 지연 검색을 위한 타이머
        self.search_timer = QTimer()
        self.search_timer.setSingleShot(True)
        self.search_timer.timeout.connect(self.show_suggestions)
        
        self.resize(400, 400)
    
    def update_completer(self):
        """자동완성 데이터 업데이트"""
        all_terms = list(set(self.search_terms + self.search_history))
        self.completer_model.setStringList(all_terms)
        self.completer.setModel(self.completer_model)
    
    def on_text_changed(self, text):
        """텍스트 변경 시 호출"""
        if text:
            # 0.3초 후에 제안 표시
            self.search_timer.start(300)
        else:
            self.suggestion_list.clear()
            self.suggestion_list.setVisible(False)
    
    def show_suggestions(self):
        """검색어 제안 표시"""
        text = self.search_edit.text()
        if not text:
            return
            
        self.suggestion_list.clear()
        
        # 검색어와 일치하는 제안 찾기
        suggestions = [term for term in self.search_terms + self.search_history 
                      if text.lower() in term.lower()]
        
        if suggestions:
            for suggestion in suggestions[:5]:  # 최대 5개 제안만 표시
                self.suggestion_list.addItem(suggestion)
            self.suggestion_list.setVisible(True)
        else:
            self.suggestion_list.setVisible(False)
    
    def use_suggestion(self, item):
        """제안 항목 선택 시 호출"""
        self.search_edit.setText(item.text())
        self.suggestion_list.setVisible(False)
        self.perform_search()
    
    def use_history_item(self, item):
        """검색 기록 항목 선택 시 호출"""
        self.search_edit.setText(item.text())
        self.perform_search()
    
    def perform_search(self):
        """검색 실행"""
        search_text = self.search_edit.text()
        if not search_text:
            return
            
        self.results_label.setText(f"'{search_text}' 검색 결과 표시 중...")
        
        # 검색 기록에 추가
        if search_text not in self.search_history:
            self.search_history.insert(0, search_text)
            self.search_history = self.search_history[:10]  # 최대 10개 기록 유지
            
            # 검색 기록 목록 업데이트
            self.history_list.clear()
            for item in self.search_history:
                self.history_list.addItem(item)
            
            # 자동완성 업데이트
            self.update_completer()
        
        self.suggestion_list.setVisible(False)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    search_field = AdvancedSearchField()
    search_field.show()
    sys.exit(app.exec())

 

예제 2: 다중 필드 폼 검증

 

여러 입력 필드를 포함하는 폼에서 실시간 유효성 검사를 구현한 예제입니다.

import sys
import re
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLineEdit, 
                              QLabel, QPushButton, QFormLayout, QHBoxLayout)
from PySide6.QtCore import Qt, Signal, QObject

class FormValidator(QObject):
    """폼 유효성 검사 클래스"""
    validation_complete = Signal(bool)  # 모든 필드 검증 완료 시그널
    
    def __init__(self):
        super().__init__()
        self.validators = {}  # 필드별 검증 함수
        self.validation_states = {}  # 필드별 검증 상태
    
    def add_validator(self, field_name, validator_func):
        """필드에 검증 함수 추가"""
        self.validators[field_name] = validator_func
        self.validation_states[field_name] = False
    
    def validate_field(self, field_name, value):
        """특정 필드 검증"""
        if field_name in self.validators:
            is_valid = self.validators[field_name](value)
            self.validation_states[field_name] = is_valid
            self.check_all_valid()
            return is_valid
        return True
    
    def check_all_valid(self):
        """모든 필드 검증 상태 확인"""
        all_valid = all(self.validation_states.values())
        self.validation_complete.emit(all_valid)
        return all_valid

class RegistrationForm(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("회원가입 폼 (실시간 검증)")
        self.validator = FormValidator()
        self.setup_ui()
        self.setup_validators()
        
    def setup_ui(self):
        main_layout = QVBoxLayout(self)
        form_layout = QFormLayout()
        
        # 사용자명 필드
        self.username_edit = QLineEdit()
        self.username_edit.setPlaceholderText("4-20자 영문, 숫자 조합")
        self.username_status = QLabel()
        username_layout = QHBoxLayout()
        username_layout.addWidget(self.username_edit)
        username_layout.addWidget(self.username_status)
        form_layout.addRow("사용자명:", username_layout)
        
        # 이메일 필드
        self.email_edit = QLineEdit()
        self.email_edit.setPlaceholderText("example@email.com")
        self.email_status = QLabel()
        email_layout = QHBoxLayout()
        email_layout.addWidget(self.email_edit)
        email_layout.addWidget(self.email_status)
        form_layout.addRow("이메일:", email_layout)
        
        # 비밀번호 필드
        self.password_edit = QLineEdit()
        self.password_edit.setEchoMode(QLineEdit.Password)
        self.password_edit.setPlaceholderText("8자 이상, 특수문자 포함")
        self.password_status = QLabel()
        password_layout = QHBoxLayout()
        password_layout.addWidget(self.password_edit)
        password_layout.addWidget(self.password_status)
        form_layout.addRow("비밀번호:", password_layout)
        
        # 비밀번호 확인 필드
        self.confirm_edit = QLineEdit()
        self.confirm_edit.setEchoMode(QLineEdit.Password)
        self.confirm_edit.setPlaceholderText("비밀번호 재입력")
        self.confirm_status = QLabel()
        confirm_layout = QHBoxLayout()
        confirm_layout.addWidget(self.confirm_edit)
        confirm_layout.addWidget(self.confirm_status)
        form_layout.addRow("비밀번호 확인:", confirm_layout)
        
        main_layout.addLayout(form_layout)
        
        # 제출 버튼
        self.submit_button = QPushButton("가입하기")
        self.submit_button.setEnabled(False)  # 초기에는 비활성화
        main_layout.addWidget(self.submit_button)
        
        # 시그널 연결
        self.username_edit.textChanged.connect(
            lambda text: self.validate_field("username", text))
        self.email_edit.textChanged.connect(
            lambda text: self.validate_field("email", text))
        self.password_edit.textChanged.connect(
            lambda text: self.validate_field("password", text))
        self.confirm_edit.textChanged.connect(
            lambda text: self.validate_field("confirm", text))
        
        self.validator.validation_complete.connect(self.update_submit_button)
        self.submit_button.clicked.connect(self.submit_form)
        
        self.resize(450, 250)
    
    def setup_validators(self):
        # 사용자명 검증: 4-20자 영문, 숫자 조합
        def validate_username(text):
            pattern = re.compile(r'^[a-zA-Z0-9]{4,20}$')
            return bool(pattern.match(text))
        
        # 이메일 검증
        def validate_email(text):
            pattern = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
            return bool(pattern.match(text))
        
        # 비밀번호 검증: 8자 이상, 특수문자 포함
        def validate_password(text):
            return len(text) >= 8 and re.search(r'[!@#$%^&*(),.?":{}|<>]', text)
        
        # 비밀번호 확인 검증
        def validate_confirm(text):
            return text == self.password_edit.text() and text != ""
        
        self.validator.add_validator("username", validate_username)
        self.validator.add_validator("email", validate_email)
        self.validator.add_validator("password", validate_password)
        self.validator.add_validator("confirm", validate_confirm)
    
    def validate_field(self, field_name, text):
        """필드 검증 및 UI 업데이트"""
        is_valid = self.validator.validate_field(field_name, text)
        
        # 상태 레이블 및 스타일 업데이트
        status_label = getattr(self, f"{field_name}_status")
        field_edit = getattr(self, f"{field_name}_edit")
        
        if not text:
            status_label.setText("")
            field_edit.setStyleSheet("")
        elif is_valid:
            status_label.setText("✓")
            status_label.setStyleSheet("color: green;")
            field_edit.setStyleSheet("border: 1px solid green;")
        else:
            if field_name == "username":
                status_label.setText("4-20자 영문, 숫자만 가능")
            elif field_name == "email":
                status_label.setText("유효한 이메일 형식이 아님")
            elif field_name == "password":
                status_label.setText("8자 이상, 특수문자 필요")
            elif field_name == "confirm":
                status_label.setText("비밀번호가 일치하지 않음")
            
            status_label.setStyleSheet("color: red;")
            field_edit.setStyleSheet("border: 1px solid red;")
    
    def update_submit_button(self, all_valid):
        """제출 버튼 활성화 상태 업데이트"""
        self.submit_button.setEnabled(all_valid)
        if all_valid:
            self.submit_button.setStyleSheet("""
                QPushButton {
                    background-color: #3a7bd5;
                    color: white;
                    padding: 8px;
                    border-radius: 4px;
                    font-weight: bold;
                }
                QPushButton:hover {
                    background-color: #2a5db0;
                }
            """)
        else:
            self.submit_button.setStyleSheet("")
    
    def submit_form(self):
        """폼 제출 처리"""
        print("폼 제출 성공!")
        print(f"사용자명: {self.username_edit.text()}")
        print(f"이메일: {self.email_edit.text()}")
        print(f"비밀번호: {'*' * len(self.password_edit.text())}")
        
        # 실제 애플리케이션에서는 여기서 서버로 데이터 전송 등의 작업 수행

if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = RegistrationForm()
    form.show()
    sys.exit(app.exec())



결론


이번 글에서는 PySide6의 QLineEdit 위젯의

시각적 속성과 이벤트 처리 메서드에 대해 알아보았습니다.

 

QLineEdit은 단순한 텍스트 입력 필드처럼 보이지만,

다양한 메서드와 기능을 활용하면 사용자 경험을 크게 향상시킬 수 있는 강력한 위젯입니다.

 

시각적 속성 메서드를 통해 입력 필드의 모양과 스타일을 사용자 정의할 수 있으며,

다양한 시그널을 활용하여 사용자 상호작용에 반응할 수 있습니다.

 

또한 자동완성, 액션 버튼 등의 고급 기능을 추가하여

더 풍부한 사용자 인터페이스를 구현할 수 있습니다.

 

실전 예제를 통해 이러한 기능들을 조합하여

고급 검색 필드와 실시간 폼 검증과 같은 복잡한 기능을 구현하는 방법도 살펴보았습니다.

 

이러한 기법들을 활용하면 사용자 친화적이고 전문적인 GUI 애플리케이션을 개발할 수 있습니다.

💡 마지막 팁: QLineEdit은 단독으로 사용할 수도 있지만, 다른 위젯들과 조합하여 사용할 때 더 큰 잠재력을 발휘합니다. QCompleter, QValidator 등의 클래스와 함께 사용하면 더욱 강력한 입력 필드를 구현할 수 있습니다. 또한 스타일시트를 활용하여 애플리케이션의 전체적인 디자인 언어와 일관성을 유지하는 것이 중요합니다.
[ 파이썬 관련 블로그 글 목록 ] 

파이썬(Python) 블로그 목록
반응형