ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Qt] GUI with Qt : Qwidget
    임베디드/Qt for python 2024. 5. 12. 23:02

     

    Qt란? : GUI 프로그램 개발용 Cross Flatform Framework
    • Qt의 모토 : One framework, One Codebase, Any Platform

     

    ⭐Qt for Python
    • Qt는 C++기반 Framework이다.
      => 하지만, 다른 언어로 제작된 Library 를 Python 으로 호출할 수 있는 연결 모듈인 python Binding 모듈을 이용하면 Qt for Python을 다룰 수 있다!
    • ✅ 사용할 Qt Python Binding Set : PySide (Qt 공식 Framework) 
    • ✅ 사용할 Qt IDE : Qt Designer (LGPL)
      => Qt Designer는 Editor가 포함되어 있지 않기 때문에 PyCharm과 함께 사용한다.
    • [참고] Qt for Python document : https://doc.qt.io/qtforpython-6/index.html

     

     

    🩵Widget ( 위젯)
    class MyApp(QWidget):
        def __init__(self):
            super().__init__()
            self.main()
    
                ```
                생략
                ```

     

     

    💚Qt 기본 실습코드 - 창 2개 띄우기
    from PySide6.QtWidgets import *
    
    
    class MyApp(QWidget):
        def __init__(self, name):
            super().__init__()
            self.appName = name  # 생성자에서 appName 설정
            self.main()
    
        def main(self):
            # App Title
            self.setWindowTitle(self.appName)
            # 윈도우 x좌표, y좌표, 가로크기, 세로크기
            self.setGeometry(0, 0, 400, 300)
    
    
    if __name__ == '__main__':
        app = QApplication()
        win1 = MyApp("win1")
        win1.show()
        win2 = MyApp("win2")
        win2.show()
        app.exec()

     


     

    Qt 사용하기 - 기본 구성

     

    App + widget

    if __name__ == '__main__':
        app = QApplication()
        win = MyApp()
        win.show()
        app.exec()

     

     

    ■ QApplication 인스턴스 생성

    QApplication()

    • QApplication에 대한 인스턴스 생성
    • 이벤트를 받는다.
    • App 전체에 대한 정보가 담겨 있다.
    • App 프로그램에는 1개의 QApplication 인스턴스가 존재한다.
    • .exec( ) 함수를 통해 프로그램을 직접 끄기 전까지 무한 루프를 돌며, 이벤트(클릭이벤트, 종료이벤트 등 사용자 행동)를 기다리게 한다.

     

     

    ■ Qwidget 객체 생성

     win = MyApp()

    • 여기서 MyApp()은 QWidget을 상속받은 GUI Widget 클래스이다.
    • wind 객체는 눈에 보일 수 있는 기본 위젯 (window) 이다.
    • show() 메서드를 호출해야 눈에 보여진다.
    • 화면을 구성하고, Widget 내부에 다른 Widget 추가가 가능하다.

     


     

    QWidget을 상속받은 GUI Widget 클래스 정의

     

    💡 클래스에서 사용되는 self는 해당 클래스로 생성한객체를 나타낸다.
    => 즉, win = MyApp() 객체 생성시, class에서 self는 win을 의미한다.

    class MyApp(QWidget):
        def __init__(self):
            super().__init__()
            self.main()
    
        def main(self):
            # App Title
            self.setWindowTitle("Qt GUI App")
            # 윈도우 x좌표, y좌표, 가로크기, 세로크기
            self.setGeometry(0, 0, 400, 300)

    QWidget 클래스로부터 상속받는다!

     

     

     

    ■ 생성자 함수

        def __init__(self):
            super().__init__()
            #부모 클래스의 생성자를 호출
            # 이 경우, QWidget 클래스의 생성자를 호출하여 MyApp 클래스의 인스턴스를 초기화
            self.main()
            #클래스 내부의 다른 메서드인 main()을 호출

     

     

    ■ App Widget 꾸미기

        def main(self):
            # App Title
            self.setWindowTitle("Qt GUI App")
            # 윈도우 x좌표, y좌표, 가로크기, 세로크기
            self.setGeometry(0, 0, 400, 300)

     

    .setWindowTitle(text) : widget 창 제목 변경

     

    .setGeometry(위치x, 위치y, 가로, 세로) : 상위 객체를 기준으로 widget의 위치와 가로 세로 크기 정하고 띄운다.

    • 여기서 self(=win)의 상위객체는 app창(=윈도우창)이므로, 윈도우 창을 기준으로 0, 0 위치에 win 창을 생성한다.

     


     

     

    Qt 사용 예제

     

     

    🖤공통 메서드

     

     .setGeometry(위치x, 위치y, 가로, 세로) :상위 객체를 기준으로 widget의 위치와 가로 세로 크기 정하고 띄운다.

     

    .setText(텍스트) : text를 지정한다.

     

     

     

    ❤️QLabel
            #"Hello!" 문구와 함께 레이블을 win에 생성
            self.lbl = QLabel("Hello!", self)
            #레이블의 위치를 win 기준으로 100,100 위치에 가로 50, 세로 50의 크기로 생성
            self.lbl.setGeometry(100, 100, 50, 50)

     

    QLabel("label text", 부모위젯) : label 생성 및 text 지정

    • 부모 위젯을 지정하면 QLabel은 그 위젯의 자식으로 추가되며, 부모 위젯이 삭제되면 QLabel도 삭제된다.
    • 만약 None이나 다른 부모를 지정하지 않으면, QLabel은 최상위 윈도우에 배치된

     


     

    🩷QPushButton
            self.btn = QPushButton("버튼 클릭", self)
            self.btn.setGeometry(100, 0, 100, 100)

     

     QPushButton("button text", 부모위젯) : botton 생성 및 text 지정

     

     


     

    🧡QLineEdit

            self.lineEdit = QLineEdit(self)
    	inputText = self.lineEdit.text()

     

    QLineEdit(부모위젯) : 한 줄 입력받는 텍스트에디터 생성

     

    QLineEdit객체.text() : QLineEdit에 입력된 값을 반환해준다.

     


     

    💛QMessageBox

            self.msg = QMessageBox()
            
            self.msg.setText( self.lineEdit.text() ) #QMessageBox의 text를 텍스트에디터에 적힌 text로 정한다.
            
            self.msg.exec()
            #QMessageBox는 독립적인 창이므로, User가 닫기 버튼을 누를 때까지 실행될 수 있게 .exec() 사용한다.

     

    QMessageBox() : QMessageBox 객체를 생성한다.

     

    Box객체.exec(): QMessageBox는 독립적인 창이므로, User가 닫기 버튼을 누를 때까지 실행될 수 있게 .exec() 해주어야 한다.

     

    🚨여기서, exec()를 사용하는 경우, 해당 창을 Modal 창이 되기 때문에

    닫기 전까진 다른 창을 제어하지 못한다.

     


     

    Signal & Slot
    • Signal : 위젯을 통해 감지되는 신호
    • Slot : Signal을 감지, Signal에 대응하는 함수 호출
      (하나의 Widget/Signal에는 여러 Slot 이 존재 할 수 있다.)

     

    from PySide6.QtWidgets import *
    
    class MyApp(QWidget):
        def __init__(self):
            super().__init__()
            self.main()
    
        def main(self):
            self.setWindowTitle("Qt GUI App")
            self.setGeometry(0, 0, 400, 300)
            
            self.btn = QPushButton("버튼 클릭", self)
            self.btn.setGeometry(100, 0, 100, 100)
            
            #버튼의 clicked 시그널이 발생 시, KFC() 호출하도록 연결
            self.btn.clicked.connect(self.KFC)
        
        #버튼이 clicked 시그널 발생 시 호출되는 KFC() 
        def KFC(self):
            print("click")
    
    if __name__ == '__main__':
        app = QApplication()
        win = MyApp()
        win.show()
        app.exec()

     

     

     

    ■ 시그널(signal)과 슬롯(slot)을 연결하기

    객체.이벤트.connect(함수)

            self.btn.clicked.connect(self.KFC)
    • self.btn객체를 clicked 할 때, self.KFC() 함수를 호출하도록 시그널과 슬롯을 연결한다.
    • 즉, User가 버튼을 누르는 순간, 버튼이 눌리는 signal 인 clicked 가 발생한다.
    • slot은 버튼의 clicked 시그널이 발생하면, KFC() 호출해준다.

     

    💡[참고] 몇몇 widget의 Event

    더보기

    ▶ QPushButton 이벤트

    • pressed(): 버튼을 누를 때마다 발생
    • released(): 버튼에서 손을 뗄 때마다 발생
    • toggled(bool): 버튼의 상태가 변경될 때마다 발생

     

    ▶ QLabel 이벤트

    • mousePressEvent(event): 마우스 버튼을 누르면 발생
    • mouseReleaseEvent(event): 마우스 버튼을 뗄 때 발생
    • mouseMoveEvent(event): 마우스를 움직일 때 발생
    • enterEvent(event): 위젯에 마우스 커서가 들어갈 때 발생
    • leaveEvent(event): 위젯에서 마우스 커서가 나갈 때 발생
    • keyPressEvent(event): 키를 누르면 발생
    • keyReleaseEvent(event): 키를 뗄 때 발생
    • focusInEvent(event): 위젯이 포커스를 받을 때 발생
    • focusOutEvent(event): 위젯이 포커스를 잃을 때 발생

     

    ▶ QLineEdit 이벤트

    • editingFinished(): 편집이 완료되었을 때 발생
    • returnPressed(): 엔터 키를 눌렀을 때 발생
    • textChanged(const QString &text): 텍스트가 변경될 때 발생
    • cursorPositionChanged(int old, int new): 커서 위치가 변경될 때 발생

     

    ▶ QCheckBox 이벤트

    • stateChanged(int state): 체크박스의 상태가 변경될 때 발생하는 시그널. 상태는 Qt.CheckState로 나타남.

     

    QRadioButton 이벤트

    • toggled(bool checked): 라디오 버튼이 토글될 때 발생

     

    QListWidget 이벤트

    • currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous): 현재 선택된 항목이 변경될 때 발생
    • itemClicked(QListWidgetItem *item): 항목을 클릭할 때 발생
    • itemDoubleClicked(QListWidgetItem *item): 항목을 더블 클릭할 때 발생

     


     

    Qt Desiner & Layout

     

    Qt Designer란?
    • 위젯을 코드로 생성하고 배치하는 것이 아닌, 마우스를 이용하여 편리하게 배치하는 프로그램 (즉, GUI 프로그램)

     

     

    Layout을 써야하는 이유
    • 현대 장치들은 Display 사이즈가 모두 다르기 때문에 절대좌표/크기로 위젯을 배치하면 제대로 보이지 않는다.
    • => 따라서 Layout 기반 배치를 통해 다양한 크기의 Display에서도 모두 동작할 수 있도록 해주어야 한다.

     

     

    💚Layout 

    ⭐각각의 widget을 독립적으로 먼저 만든 후, 

    상위객체.addWidget(하위객체) 함수를 이용해 widget을 넣고

    상위객체.addLayout( 하위객체 ) 함수를 이용해 layout을 넣는

    방식으로 개발한다! 

    #수직 배치, 수평 배치 레이아웃을 같이 사용한 샘플코드
    #디자인을 보고, 어떤 레이아웃을 사용할 지 결정하고 사용해야 한다.
    #QHBoxLayout : 수평배치 레이아웃 생성
    #.addLayout() : 레이아웃을 추가하는 API
    
    from PySide6.QtWidgets import *
    class MyApp(QWidget):
        def __init__(self):
            super().__init__()
            self.main()
    
        def main(self):
            self.setWindowTitle("Qt GUI App")
            self.setGeometry(0, 0, 300, 300)
            
            #버튼 3개 생성
            self.btn1 = QPushButton("Top")
            self.btn2 = QPushButton("LEFT")
            self.btn3 = QPushButton("RIGHT")
            
            #수직배치, 수평배치 레이아웃 생성
            self.vlay = QVBoxLayout(self)
            self.hlay = QHBoxLayout(self)
            
            #수직배치 레이아웃에 btn1 추가
            self.vlay.addWidget(self.btn1)
            
            #수평배치 레이아웃에 btn2, btn3 추가
            self.hlay.addWidget(self.btn2)
            self.hlay.addWidget(self.btn3)
            
            #수직배치 레이아웃에 수평배치 레이아웃 
            self.vlay.addLayout(self.hlay)
    
    if __name__ == '__main__':
        app = QApplication()
        win = MyApp()
        win.show()
        app.exec()

     

     

     수직 레이아웃 객체 생성

    QVBoxLayout(부모객체)

     

     수평 레이아웃 객체 생성

    QHBoxLayout(부모객체)

     

    ▶ 레이아웃에 객체 추가

    레이아웃객체.addWidget(추가할객체)

     

    ▶ 레이아웃에 레이아 추가

    레이아웃객체.addLayout(추가할객체)

     

    수직배치애 객체를 add하면 수직으로 들어가고,

    수평배치에 객체를 add하면 수평으로 들어간다!

     

     

    💡 [참고] 코드순서 == 배치순서이다.

    • addWidget() , addLayout() 등 코드 작성 순서가 GUI 화면의 배치 순서로 결정된다.

     

Designed by Tistory.
-->