세상이 변했다. 낮은 화소의 디스플레이와 적은 수의 버튼으로 Cost를 낮추는게 당연했던 임베디드의 세계가 변하기 시작했다.
즉, 사용자의 GUI사용과 같은 편의성 보다는 단가, 성능, 정확성, 신뢰성이 가장 중요했다.
하지만 최근 차량의 인포테인먼트, 가전제품(냉장고 디스플레이),스마트 홈의 월패드 등등 다양한 GUI가 등장했다. 또한 스마트폰의 보편화로 사람들이 터치가 익숙해지기도 했다.
보편화된 GUI Solution은 없다.
그럴만 하다. 임베디드 제품은 보드/칩셋이 다 다르니 힘들거다.
그나마
LGVL : 오픈소스 - 무료
TouchGFX : ST칩셋이면 무료
Embedded Wizard : 개인은 무료
Qt가 가장 많이 쓰이는 임베디드 GUI Solution이다.
(LG에서도 쓴다. webOS 검색해보자)
Qt는 linux뿐만 아니라 Windows, MacOS, Android, VxWorks등등 대부분 플랫폼을 지원한다.
네트워크, 그래픽, DB사용등을 위한 쉬운 API를 제공하고, 언어는 C++기반에 python도 지원한다.
즉, 모니터를 제외하고 OS랑 API는 책임지겠다
왼쪽에 라이센스 선택이 있으며, 선택에 따라 오른쪽 Tools들이 비활성화(회색, 사용불가) 된다.
GPL : 모든 소스코드 공개(비상업용, 교육용) <- 공짜
LGPL : 특정 모듈만 사용치 않으면 소스코드 비공개 가능(상업용)
https://www.qt.io/product/features
있다. MFC라는 윈도우 전용이 있다.
그런데 Qt는 윈도우, 리눅스, 모바일 앱 모두 제작 가능하고,
무엇보다 C++를 주력언어로 한다.(물론 파이썬도 가능하며, 여기선 파이썬으로 진행한다. 나중에 C++로도 공부해야겠다)
C++ Document https://doc.qt.io/qt-5.15/reference-overview.html
Python Document https://doc.qt.io/qtforpython-6/index.html
Qt Creator(QC)
Qt의 대표 IDE 다만, GPL이다.
Editor + Qt Quick Designer + Qt Designer를 포함하고, 디버깅 SVC 크로스컴파일 가상에뮬 추가함
Qt Quick Designer
포토샵과 통합이 가능하다.
Qt Designer <- Day2에서 다룸
일반적인 UI Desinger다. 또한 LGPL이다.
Editor가 없다는 단점이 있다.
Pycharm Community Edition을 설치한다. (현재 23.11.07에 설치하면 3.12가 자동적으로 같이 설치된다)
사진과 같이 진행한다. (가상환경 확인)
테스트 (main.py)
from PySide6.QtWidgets import *
class ClassName(QWidget):
def __init__(self):
super().__init__()
self.main()
def main(self):
pass
if __name__ == '__main__':
#app 은 QApplication에 대한 인스턴스; 이벤트를 받는다.
app = QApplication()
#win은 화면을 구성하고, Widget내부에 다른 Widget추가 가능하다.
win = ClassName()
win.show()
#이벤트 기다리며 무한 대기
app.exec()
아래처럼 나오면 성공
def main(self):
self.setWindowTitle("창 제목")
self.setGeometry(500, 500, 400, 300) # 시작위치x, 시작위치y, width, height
signal은 인터럽트라고 생각하면 편하다. 각 Widget마다 여러 signal이 존재한다. 사용자의 작업이 signal이 된다.
Slot은 javascript의 이벤트 리스너라고 생각하면 편하다. Signal을 감지하고, 대응되는 함수를 호출한다. 이때 함수를 slot함수라고 한다. callback함수라고 생각하면 편하다.
하나의 widget엔 여러 slot이 존재
버튼과 라벨을 만들고 버튼을 클릭하면 라벨의 텍스트가 바뀐다.
from PySide6.QtWidgets import *
class ClassName(QWidget):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("이름 뭐하지?")
self.setGeometry(0, 0, 400, 300)
self.LabelName = QLabel("라벨에 뭐 쓰지?", self)
self.LabelName.setGeometry(100, 100, 50, 50)
self.ButtonName = QPushButton("클릭 버튼 텍스트", self)
self.ButtonName.setGeometry(100, 0, 100, 100)
self.ButtonName.clicked.connect(self.KFC)
def KFC(self):
self.LabelName.setText('클릭했당')
if __name__ == '__main__':
app = QApplication()
win = ClassName()
win.show()
app.exec()
QlineEdit은 사용자가 작성이 가능한 텍스트 박스이다.
QMessageBox는 알림창 용도로 쓰인다.
버튼을 누르면 라인에딧의 글이 라벨로 간다.
.text()는 text를 가져오고, .setText("문자열")는 문자열로 바꾼다.
from PySide6.QtWidgets import *
class ClassName(QWidget):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("뭐로하지")
self.setGeometry(800, 500, 400, 300)
self.lineEdit = QLineEdit(self)
self.btn = QPushButton("라인에딧 -> 라벨", self)
self.btn.setGeometry(0, 50, 100, 50)
self.btn.clicked.connect(self.KFC)
self.lbl = QLabel("HOHO", self)
self.lbl.setGeometry(0, 100, 100, 50)
def KFC(self):
self.lbl.setText(self.lineEdit.text())
if __name__ == '__main__':
app = QApplication()
win = ClassName()
win.show()
app.exec()
문자열을 입력하고 클릭을 누르면 메세지 박스가 나타난다.
메세지 박스가 나온 상태에서 하위 창은 선택이 불가능하다.
(만약, 선택을 하고 싶다면 self.msg.exec()을 self.msg.show()로 바꿔주자. Modal에서 자세히)
from PySide6.QtWidgets import *
class ClassName(QWidget):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("Qt GUI App")
self.setGeometry(0, 0, 300, 150)
self.lineEdit = QLineEdit(self)
self.btn = QPushButton("클릭", self)
self.btn.setGeometry(150, 0, 50, 50)
self.btn.clicked.connect(self.KFC)
# 버튼이 눌리면,
def KFC(self):
self.msg = QMessageBox()
self.msg.setText(self.lineEdit.text())
self.msg.exec()
if __name__ == '__main__':
app = QApplication()
win = ClassName()
win.show()
app.exec()
절대좌표만으로 widgewt을 배치하면 크기가 다른 display마다 문제가 생긴다.
200,200을 시작 좌표로 잡았는데 display가 그보다 작으면 안 보인다.
따라서 Layout을 잡는다.
QVBoxLayout() 수직배치
QHBoxLayout() 수평배치
.addWidget() 위젯 추가
.addLayout() 레이아웃 추가 hlay, vlay
레이아웃을 해보자
1
221
21 222 23
3
41 42
from PySide6.QtWidgets import *
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("Box Layout")
self.setGeometry(800, 800, 300, 300)
self.btn1 = QPushButton("1")
self.btn21 = QPushButton("21")
self.btn221 = QPushButton("221")
self.btn222 = QPushButton("222")
self.btn23 = QPushButton("23")
self.btn3 = QPushButton("3")
self.btn41 = QPushButton("41")
self.btn42 = QPushButton("42")
self.vlay = QVBoxLayout(self)
self.vlay.addWidget(self.btn1)
self.vlay22 = QVBoxLayout(self)
self.hlay2 = QHBoxLayout(self)
self.vlay22.addWidget(self.btn221)
self.vlay22.addWidget(self.btn222)
self.hlay2.addWidget(self.btn21)
self.hlay2.addLayout(self.vlay22)
self.hlay2.addWidget(self.btn23)
self.vlay.addLayout(self.hlay2)
self.vlay.addWidget(self.btn3)
self.hlay4 = QHBoxLayout(self)
self.hlay4.addWidget(self.btn41)
self.hlay4.addWidget(self.btn42)
self.vlay.addLayout(self.hlay4)
if __name__ == '__main__':
app = QApplication()
win = MyApp()
win.show()
app.exec()
layout은 창의 크기와 상관없이 항상 같은 위치를 준수한다.
창을 늘리거나 줄여보자
반복작업을 줄이기 위해 자주 만드는 Form형태의 Layout을 쉽게 만드는 Layout이다.
self.form = QFormLayout(self)
self.form.addRow("name", layout)
or
self.form.addWidget(layout)
Qt GUI Window Class 대표적 3개
QWidget : 기본 객체, 화면에 출력되는 컨트롤을 나타냄
QMainWindow : Qwidget을 상속받고 추가 구현(업그레이드판), 메뉴,툴바,상태표시줄,전용 레이아웃 가짐
QDialog : 단순 정보 알림/입력 창 용도, 확인/취소 버튼처럼 다양한 버튼이 존재한다.
우리는 여기서 QMainWindow를 씀.
변경사항
class MyApp(QMainWindow):
추가사항
mainWidget = QWidget()
mainWidget.setLayout(self.vlay)
self.setCentralWidget(mainWidget)
from PySide6.QtWidgets import *
class MyApp(QMainWindow):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("Qt GUI App")
self.setGeometry(0, 0, 300, 300)
self.vlay = QVBoxLayout()
self.btn1 = QPushButton("Top")
self.btn2 = QPushButton("Bottom")
self.vlay.addWidget(self.btn1)
self.vlay.addWidget(self.btn2)
mainWidget = QWidget()
mainWidget.setLayout(self.vlay)
self.setCentralWidget(mainWidget)
if __name__ == '__main__':
app = QApplication()
win = MyApp()
win.show()
app.exec()
self.bar = self.statusBar() 상태표시줄 객체 생성
self.bar.showMessage("어쩌구저쩌구") 문자열을 메세지로 출력
생략
mainWidget = QWidget()
mainWidget.setLayout(self.vlay)
self.setCentralWidget(mainWidget)
self.bar = self.statusBar()
self.bar.showMessage("어쩌구저쩌구")
if __name__ == '__main__':
생략
단축키는 ALT키와 그 외의 키를 누른다.
from PySide6.QtWidgets import *
from PySide6.QtGui import *
class MyApp(QMainWindow):
def __init__(self):
super().__init__()
self.main()
def main(self):
self.setWindowTitle("Qt GUI App")
self.setGeometry(0, 0, 300, 300)
self.vlay = QVBoxLayout()
self.lbl = QLabel("KFC")
self.btn = QPushButton("클릭")
self.btn.clicked.connect(self.click)
self.vlay.addWidget(self.lbl)
self.vlay.addWidget(self.btn)
mainWidget = QWidget()
mainWidget.setLayout(self.vlay)
self.setCentralWidget(mainWidget)
#-------------------------------------------------------
self.menu = self.menuBar()
self.menuFile = self.menu.addMenu("&File")
self.menuEdit = self.menu.addMenu("&Edit")
self.openAction = QAction("&Open", self)
self.openAction.triggered.connect(self.open)
self.openAction.setShortcut(QKeySequence("Ctrl+O"))
self.menuFile.addAction(self.openAction)
#--------------------------------------------------------
def open(self):
self.lbl.setText("Open 선택")
def click(self):
self.lbl.setText("클릭")
if __name__ == '__main__':
app = QApplication()
win = MyApp()
win.show()
app.exec()
Modal은 가장 자식의 창만 사용이 가능케 만든다. 예를들어 메모장을 Save As하면 메모장을 못 건들인다. exec()
Modaless는 모든 창 사용이 가능하다. 예를들어 메모장의 도움말 보기와 같다. show()