-
[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 화면의 배치 순서로 결정된다.
'임베디드 > Qt for python' 카테고리의 다른 글
[Qt] GUI with Qt : Visualization (0) 2024.05.13 [Qt] GUI with Qt : QWidget (0) 2024.05.13 [Qt] GUI with Qt : QTimer, QThread (0) 2024.05.13 [Qt] GUI with Qt : Text Editor, Qt Designer, Qt API (0) 2024.05.13 [Qt] GUI with Qt : QMainWindow (0) 2024.05.13