임베디드/Qt for python

[Qt] GUI with Qt : QMainWindow

KimuGamJa 2024. 5. 13. 00:42

 

QMainWindow

 

QMainWindow
  • QWidget 을 상속받은 하나의 클래스
  • QWidget 을 기반으로 메뉴/상태표시줄/툴바 등 자주 쓰는 Window 형태를 미리 구현해 둔 클래스
  • 라즈베리파이에서 QWidget 을 썼을 때 QtDesigner와 Python 코드가 호환 문제 (버그)가 존재하지만, QMainWindow에서는 호환이 잘 된다!!
  • https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QMainWindow.html#qmainwindow

 

 

QWidget VS QMainWindow 비교

 

[QWidget 클래스 이용]

class MyApp(QWidget):
    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)
        self.btn1 = QPushButton("Top")
        self.btn2 = QPushButton("Bottom")
        self.vlay.addWidget(self.btn1)
        self.vlay.addWidget(self.btn2)

 

self.vlay = QVBoxLayout(self)

해당 객체는 self = win을 상위 객체로 두기 때문에,

해당 객체를 생성하면 win창에 바로 나타나게 된다.

 

class MyApp(QWidget):  → class MyApp(QMainWindow):  

하지만, 다음과 같이 QMainWindow를 상속받도록 하면 win창에 아무것도 나타나지 않는다.

 

그 이유는 QMainWindow가 다음과 같은 구조로 이루어져 있기 때문이다.

 

따라서, QMainWindow를 사용할 때는 setCentralWidget() 메서드를 사용하여 각각에 대한 위젯을 설정해주어야 한다.

 

 

[QMainWindow 이용]

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)

 

위와 같이, QMainWindow의 CentralWidget 으로 mainWidget을 등록해줌으로써

버튼이 win창에 뜨도록 하였다.

(setCentralWidget()으로는 layout등록이 불가하기 때문에 별도로 mainWidget()을 만들어 등록한 것을 알 수 있다.)

 

 

 

 

QMainWindow - Central Widget 설정

#QMainWindow 사용하기
#QMainWidnow 는 CentralWidget 영역에 Widget을 배치해야 한다.
#여러 개의 Widget을 배치하기 위해 레이아웃을 이용해 Design 후, CentralWidget 에 레이아웃을 등록한다.
from PySide6.QtWidgets import *

#QMainWindow class 를 상속받은 MyApp Class
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)
        
        #QWidget() 객체 생성
        mainWidget = QWidget()
        #Qwidget 객체에 수평배치 레이아웃을 등록한다.
        mainWidget.setLayout(self.vlay)
        
        #QMainWindow의 CentralWidget 으로 mainWidget을 등록한다.
        #CentralWidget은 1개의 Widget만 등록이 가능하다.
        self.setCentralWidget(mainWidget)

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

 

▶ App에 위젯 등록하기

setCentralWidget(QWidget 객체)

  • QMainWindow의 CentralWidget 으로 mainWidget을 등록한다.
  • CentralWidget은 1개의 Widget만 등록이 가능하다.
  • QWidget() 인스턴스만 등록 가능하다.

 


 

 

QMainWindow - Status Bar 설정

#QMainWindow 의 StatusBar 사용하기
#QMainWindow 에는 StatusBar 를 다루기 위한 메서드들이 정의되어 있다.
#StatusBar() : statusBar 객체 생성
#.showMessage() : statusBar에 메시지를 출력한다.

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)

        #statusBar() 객체 생성
        self.bar = self.statusBar()
        #statusBar에 메시지 출력
        self.bar.showMessage("BBQ")
        
if __name__ == '__main__':
    app = QApplication()
    win = MyApp()
    win.show()
    app.exec()

 

 

▶ statusBar 객체 생성

statusBar()

 

 

▶ statusBar에 메시지 출력

Bar객체.showMessage("text")

 

 


 

Menu Bar & QAction

# QMainWindow 의 Menu Bar 사용하기
# Menu Bar를 생성하고, QAction을 등록한다.
# QAction은 slot 함수를 등록해, User가 원하는 동작을 수행할 수 있다.
# QAciont은 단축키를 등록해 쉽게 조작이 가능하다.

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)

        # menuBar객체 menu 생성, menuBar() 는 QMainWindow 에 멤버함수
        self.menu = self.menuBar()
        # menuBar 에 File 메뉴 추가, &를 붙이면 단축키 사용이 가능하다. Alt+F
        self.menuFile = self.menu.addMenu("&File")
        # menuBar 에 Edit 메뉴 추가, &를 붙이면 단축키 사용이 가능하다. Alt+E
        self.menuEdit = self.menu.addMenu("&Edit")

        # QAction() 객체 생성, 단축키 사용
        self.openAction = QAction("&Open", self)
        # openAction 과 open() 를 연결, Open 메뉴 클릭 시, open() 호출
        self.openAction.triggered.connect(self.open)
        # 키보드 단축키 추가, Ctrl+O 누르면 Open 메뉴 선택
        self.openAction.setShortcut(QKeySequence("Ctrl+O"))

        # menuFile 에 openAction 객체 등록, File 메뉴 클릭 시, Open 메뉴 창이 나타난다.
        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()

 

⭐&뒤에는 상태바, 메뉴의 이름이 들어간다!

이때, 단순히 이름만 작성하지 않고 &을 붙이면 단축키가 설정된다.

 

따라서 위와 같이 코드를 작성한 뒤,alt + F 를 누르면 "File" 상태바가 트리거 되고,alt + E 를 누르면 "Edit" 상태바가 트리거 된다.

 

■ menuBar 생성

        # menuBar객체 menu 생성, menuBar() 는 QMainWindow 에 멤버함수
        self.menu = self.menuBar()
        # menuBar 에 File 메뉴 추가, &를 붙이면 단축키 사용이 가능하다. Alt+F
        self.menuFile = self.menu.addMenu("&File")
        # menuBar 에 Edit 메뉴 추가, &를 붙이면 단축키 사용이 가능하다. Alt+E
        self.menuEdit = self.menu.addMenu("&Edit")
        
        ```
        QAction 객체 생성
        ```
        
        # menuFile 에 openAction 객체 등록, File 메뉴 클릭 시, Open 메뉴 창이 나타난다.
        self.menuFile.addAction(self.openAction)copy

 

 메뉴바 객체 생성

menuBar()

 

 메뉴바 객체에 메뉴 등록

Bar객체.addMenu("메뉴이름")

 

 메뉴에 Action 등록

Bar객체.addAction()(QAction객체)

 

 

 

■ QAction 생성

 

        # QAction() 객체 생성, 단축키 사용
        self.openAction = QAction("&Open", self)
        # openAction 과 open() 를 연결, Open 메뉴 클릭 시, open() 호출
        self.openAction.triggered.connect(self.open)
        # 키보드 단축키 추가, Ctrl+O 누르면 Open 메뉴 선택
        self.openAction.setShortcut(QKeySequence("Ctrl+O"))

        # menuFile 에 openAction 객체 등록, File 메뉴 클릭 시, Open 메뉴 창이 나타난다.
        self.menuFile.addAction(self.openAction)

    def open(self):
        self.lbl.setText("Open 선택")
        
    def click(self):
        self.lbl.setText("클릭")copy

 

 

▶  🚨QtGui 패키지 import 해야 한다.

from PySide6.QtGui import *

 

 

 QAction 객체 생성

QAction()

 

 동작 함수 등록

QAction객체.triggered.connect(연결함수)

 

 단축키 등록

QAction객체.setShortcut(QkeySequence("단축키"))

 

 

 

 

💡 [참고] Modal vs Modaless

  • Modal 창
    • 최상위 창만 사용 가능 ( 하위 창 제어 불가 )
    • exec() 사용
    • ex) 메모장의 저장 창을 띄우면, 메모창 글씨를 수정 불가
  • Modaless 창
    • 모든 창 사용 가능
    • show() 사용
    • ex) 메모장의 바꾸기 창은 하위 창 글씨를 수정할 수 있다