728x90

 

1. Signal, Slot, Connect 라이브러리

더보기
from PySide6.QtCore import Signal, Slot, QObject, QUrl
  • Signal은 PySide6.QtCore 에서 가져옵니다.
  • PySide6는 Signal, Slot (PyQt6는 pyqtSignal, pyqtSlot)

 

2. Signal 선언 문법

더보기

A. Signal 선언 문법

mysignal = Signal(자료형...)

Signal은 클래스 변수(class attribute) 로 선언해야 합니다.

(※ 인스턴스 변수로 선언하면 동작하지 않습니다.)

 

 

 

 

B. Signal 선언 문법 예시

 

B.1 정수 하나 전달
mysignal = Signal(int)

 

 

B.2 문자열 하나 전달

mysignal = Signal(str)

 

 

B.3 QUrl 전달

mysignal = Signal(QUrl)
 
 

B.3 여러 인자 전달 (int, str, int)

mysignal = Signal(int, str, int)

 

 

B.4 인자 없는 Signal

 

mysignal = Signal()

 

 

 

 

C. Signal 사용 예시

 

C.1 Signal (클래스 변수) 생성

class MyObjectA(QObject):
    sig = Signal(int)

 

 

C.2 Signal 사용 방법

a = MyObjectA()
a.sig.connect(...)
a.sig.emit(10)      # 정상 작동

 


- 시그널 살펴보기

더보기

A잘못된 Signal 사용 예시

 

A.1 Signal (클래스 변수) 생성

class MyObjectB(QObject):
    def __init__(self):
        self.sig = Signal(int)

 

 

A.2 Signal 사용 방법

a = MyObjectB()
a.sig.connect(...)   # 에러 또는 동작 안함
a.sig.emit(10)       # Qt 메타시스템에서 인식되지 않음

 

 

 

 

B. 잘못된 Signal 살펴보기

 

B.1 정상

class MyObjectA(QObject):
    mysignal = Signal(int)

이 코드가 실행되면:

  1. Python이 MyObjectA 클래스를 정의하고
  2. PySide6가 클래스 내부의 Signal들을 스캔하여
  3. Qt 메타오브젝트 시스템에
    → “이 클래스는 mysignal(int) 시그널을 가진다” 라고 등록한다.
  4. 이 등록 과정이 끝나야 emit()  connect() 가 정상적으로 동작함
    → 즉, Signal은 클래스 정의 시점(class body) 에 반드시 존재해야 한다.

 

 

B.2 비정상

class MyObjectB(QObject):
    def __init__(self):
        super().__init__()
        self.mysignal = Signal(int)   # Qt가 인식하지 못함

이렇게 하면:

  1. 클래스 정의 시점에는 Signal이 없음
  2. Signal(int) 는 Qt 에 등록되지 않은 일반 파이썬 변수일 뿐
  3. Qt 이벤트 시스템이 이 신호를 모름
    • .connect() 에러 발생 가능
    • .emit() 해도 Qt가 받지 못함
    • 진짜 Signal로 동작하지 않음
    • 이유: Qt는 클래스 단계에서만 Signal을 스캔하고 등록하기 때문.

 

 

B.3 상세

  • 파이썬 OOP 관점에서, Signal은 “클래스 기능”이다. Signal은 객체마다 다른 데이터가 아니라
    • 클래스 자체가 가진 기능(Functionality)
    • 인스턴스마다 동일한 Signal 구조
  • 예시
    • 사람(Person)의 나이(age)는 객체마다 다르므로 >> 인스턴스 변수를 만들어 처리합니다.
    • 하지만 “버튼이 클릭되면 신호를 발생시킨다” 같은 기능은
      모든 버튼(Button) 객체가 공통으로 가지는 기능 >>  클래스 레벨에서 처리합니다.
  • 따라서 Signal은 타입(type) 정보에 속하며 >> 인스턴스 변수로 만들 이유가 없다. 

 

3. Slot 선언 문법

더보기

A. Slot은 일반 함수도 Slot이 될 수 있습니다.

def slot_function(self, value):
    print(value)

 

 

 

 

B. @Slot() 데코레이터

: 슬롯을 더 명확하게 하려면 @Slot() 데코레이터를 사용합니다.

 

B.1 Slot 선언 기본

@Slot(int)
def slot_function(self, value):
    print("받은 값:", value)
 
 
 

B.2 여러 인자를 사용하는 Slot 선언

@Slot(int, str, int)
def other_slot(self, a, b, c):
    print(a, b, c)
 
 
 

B.3 반환 타입 명시도 가능

 
@Slot(int, result=str)
def convert_to_str(self, value):
    return str(value)

- slot @데코레이터 살펴보기

더보기

A. @Slot 데코레이터는 필수가 아닙니다.

: 선택사항(Optional)으로, 아래 두 코드는 완전히 동일하게 동작합니다:

 

데코레이터 사용:

@Slot(int)
def on_slider_changed(self, value):
    ...

 

데코레이터 없음:

 
def on_slider_changed(self, value):
    ...
  

 

 

 

B. @Slot 을 사용하는 이유

  1. 성능 최적화 (미세하지만 존재)
    Slot이 C++ Qt 구조에 더 효율적으로 연결됩니다.
  2. 자료형 명시로 인자 오류 방지
    Signal이 int를 보내는데 Slot이 str 받으면 오류 가능→ @Slot(int) 로 명확하게 문서화 및 검증
  3. 대규모 프로젝트에서 유지보수 용이
    IDE 자동완성 도움실수 감소코드 명확성 증가
  4. Qt C++ 시그널/슬롯 구조와 더 동일한 형태

 

 

 

 

C. @Slot을 사용하지 않아도 되는 경우

  • 작은 프로젝트
  • 복잡한 시그널/파라미터 구조 없음
  • 단순 버튼/슬라이더 이벤트 처리

 

 

 

 

D. 실전에서 가장 효과적으로 사용하는 방식

  • 중소규모 프로젝트
    @Slot 생략하고, 필요 시 @Slot 사용(자유롭고 유지보수 쉬움)
  • 대규모 구조화된 프로젝트 / 팀 개발 / Qt Designer 연동 프로젝트
    → Signal/Slot 타입 명시하는 것이 안정성↑
    → @Slot(int) 적극 활용
  • 사용자 정의 Signal이 많을 경우→ Signal(int, str ...) → @Slot(int, str) 맞춰 쓰기(버그 예방)

 

5. Connect 선언 문법

: Signal → Slot 연결

더보기
A. 선언
 
A.1 Signal 선언 기본 - 정수 하나 전달
mysignal = Signal(int)

 

 

A.2 Slot 선언 기본

@Slot(int)
def slot_function(self, value):
    print("받은 값:", value)
 
 
A.3 Connect 선언 기본
self.mysignal.connect(self.slot_function)

 

 


 

 

B. 실행
 
B.1 Signal 의 emit 하면:
self.mysignal.emit(123)
 

 

B.2 Slot 실행됨:

 
받은 값: 123

 

6. Signal / Slot 활용 예제

: QSlider 예제 확장 (1)

더보기

목표

 

 

 

 

A. 파이참에서 프로젝트 생성하기

 

파이참에서 프로젝트 생성하기

1. 일반 프로젝트 생성하기더보기 2. 새 프로젝트 시작하기더보기Case A. 새 프로젝트 생성 Case B. 새 프로젝트 생성 Case C. 새 프로젝트 생성 3. 커스텀 가상환경으로 프로젝트 시작하기 더보기

basiclike.tistory.com

 

 

B. Signal & Slot 구조 이해하기 (3)

 

Signal & Slot 구조 이해하기 (3)

1. 학습 목표 (Learning Objectives):슬라이더(QSlider) 위젯을 사용해 Signal/Slot 구조를 이해더보기슬라이더(QSlider)의 valueChanged(int) Signal 구조 이해Slider가 Signal을 발생시키며 “값(data)”을 Slot 함수에 자

basiclike.tistory.com

 

 

C. 

 

 

 

 

import sys
from PySide6.QtCore import Qt, Signal, Slot
from PySide6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout

 

 

 

 

# [1] 예제 위젯 생성
class SliderExample(QWidget):

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Signal & Slot 확장 예제")
        self.resize(300, 150)

        # [2] 슬라이더 생성
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(1)
        self.slider.setMaximum(100)
        self.slider.setValue(25)

 

 

 

 

    # [3] 슬롯 함수 생성
    @Slot(int)
    def respond_to_slider(self, value):
        print("slider moved to:", value)

 

 

 

 

        # [4] Signal → Slot 연결
        self.slider.valueChanged.connect(self.respond_to_slider)

 

 

 

 

        # [5] 레이아웃 추가 (이 부분이 없으면 화면에 안 보임)
        layout = QVBoxLayout(self)
        layout.addWidget(self.slider)

 

 

 

 

# [6] 실행 영역
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SliderExample()
    window.show()
    sys.exit(app.exec())

 

 

 

 

import sys
from PySide6.QtCore import Qt, Signal, Slot
from PySide6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout

# [1] 예제 위젯 생성
class SliderExample(QWidget):

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Signal & Slot 확장 예제")
        self.resize(300, 150)

        # [2] 슬라이더 생성
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(1)
        self.slider.setMaximum(100)
        self.slider.setValue(25)

        # [4] Signal → Slot 연결
        self.slider.valueChanged.connect(self.respond_to_slider)

        # [5] 레이아웃 추가 (이 부분이 없으면 화면에 안 보임)
        layout = QVBoxLayout(self)
        layout.addWidget(self.slider)

    # [3] 슬롯 함수 생성
    @Slot(int)
    def respond_to_slider(self, value):
        print("slider moved to:", value)

# [6] 실행 영역
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = SliderExample()
    window.show()
    sys.exit(app.exec())​

- Qt 에서 구현 과제입니다.

 

7. Signal / Slot 활용 예제

: QSlider 예제 확장 (2)

더보기

목표

 

 

 

  

    # [1] 사용자 정의 Signal: 처리된 값을 전달하고 싶을 때 사용
    processedValueSignal = Signal(int)

 

 

 

 

from PySide6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout, QLabel

        # [2] UI 구성
        self.label_original = QLabel("원본 값: -")
        self.label_processed = QLabel("처리된 값(×2): -")

 

 

 

 

        # [3] 레이아웃 추가
        layout.addWidget(self.label_original)
        layout.addWidget(self.label_processed)

 

 

 

 

        # [4] 레이블에 출력 슬롯 로직
        self.label_original.setText(f"원본 값: {value}")

        # [5] 사용자 정의 *Signal - 슬롯 내부에 시그널 역할 추가
        # value × 2 를 Custom Signal 로 emit
        processed_value = value * 2
        self.processedValueSignal.emit(processed_value)

 

 

 

 

    # [6] 사용자 정의 *Signal을 받는 Slot 구현
    @Slot(int)
    def on_processed_value(self, value):
        print("커스텀 시그널:", value)
        self.label_processed.setText(f"처리된 값(×2): {value}")

 

 

 

 

        # [7] 사용자 정의 Signal → 사용자 정의 Slot 연결
        self.processedValueSignal.connect(self.on_processed_value)

 

 

 

 

import sys
from PySide6.QtCore import Qt, Signal, Slot
from PySide6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout, QLabel

class SliderExample(QWidget):

    # [1] 사용자 정의 Signal: 처리된 값을 전달하고 싶을 때 사용
    processedValueSignal = Signal(int)

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Signal & Slot 확장 예제")
        self.resize(300, 150)

        # [2] UI 구성
        self.label_original = QLabel("원본 값: -")
        self.label_processed = QLabel("처리된 값(×2): -")

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(1)
        self.slider.setMaximum(100)
        self.slider.setValue(25)

        self.slider.valueChanged.connect(self.respond_to_slider)
        # [7] 사용자 정의 Signal → 사용자 정의 Slot 연결
        self.processedValueSignal.connect(self.on_processed_value)

        layout = QVBoxLayout(self)
        layout.addWidget(self.slider)
        # [3] 레이아웃 추가
        layout.addWidget(self.label_original)
        layout.addWidget(self.label_processed)

    @Slot(int)
    def respond_to_slider(self, value):
        print("slider moved to:", value)
        # [4] 레이블에 출력 슬롯 로직
        self.label_original.setText(f"원본 값: {value}")

        # [5] 사용자 정의 *Signal - 슬롯 내부에 시그널 역할 추가
        # value × 2 를 Custom Signal 로 emit
        processed_value = value * 2
        self.processedValueSignal.emit(processed_value)

    # [6] 사용자 정의 *Signal을 받는 Slot 구현
    @Slot(int)
    def on_processed_value(self, value):
        print("커스텀 시그널:", value)
        self.label_processed.setText(f"처리된 값(×2): {value}")

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

- Qt 에서 구현 과제입니다.