ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [PyQt5] 5. layout
    Python/PyQt5 2021. 5. 19. 14:18
    반응형

    레이아웃은 위젯들을 담아두는 틀입니다. 

    레이아웃을 잘 이용하면 
    자동으로 줄 맞춤이 되고, 
    좌표를 하드 코딩할 필요가 없어 
    유연한 GUI를 만들 수 있기 때문에, 
    무척 편합니다. 

    하드 코딩은 데이터를 직접 코드 내에 넣어두는 것을 말합니다. 
    레이아웃을 사용하면 (좌표에 관련된) 숫자는 거의 사용하지 않습니다. 

    최상위 위젯을 QMainWindow에서 QWidget으로 바꿨습니다.
    이유는 마지막에... 

    QVBoxLayout 

    QVBoxLayout이라는 클래스가 보입니다.
    V는 Vertical(세로)에서 나왔다는 걸 알 수 있죠. 

    QVBoxLayout 클래스로 layout 인스턴스를 만들어서
    layout 인스턴스에 위젯들을 하나씩 addWidget 해 주었습니다. 

    addWidget으로 상위 위젯에 add해주기 때문에
    하위 위젯의 두 번째 인수로 상위 위젯(self 등)을
    일일이 작성하지 않아도 됩니다.  

    마무리로 self.setLayout(layout) 해 주었고요. 

     

    from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget
    
    
    class MyWidget(QWidget):  # QMainWindow 에서 QWidget 으로 바꿨습니다.
        def __init__(self):
            super().__init__()
    
            self.label = QLabel('label')
            self.button1 = QPushButton('button1')
            self.button1.clicked.connect(self.button1_clicked)
            self.button2 = QPushButton('button2')
            self.button2.clicked.connect(self.button2_clicked)
    
            layout = QVBoxLayout()
            layout.addWidget(self.label)
            layout.addWidget(self.button1)
            layout.addWidget(self.button2)
            self.setLayout(layout)
    
        def button1_clicked(self):
            self.label.setText('Clicked')
    
        def button2_clicked(self):
            self.label.setText('')
    
    
    app = QApplication([])
    my_window = MyWidget()
    my_window.show()
    app.exec_()
    

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-1.py

    결과는 다음과 같습니다.  

    줄이 잘 맞습니다. 

     

    이런 레이아웃들이 준비되어 있습니다.  

    • QVBoxLayout: 위젯들을 세로(위 -> 아래) 순서대로 배열합니다.
    • QHBoxLayout: 위젯들을 가로(좌 -> 우) 순서대로 배열합니다.
    • QGridLayout: 위젯들을 Grid의 지정된 Row, Column에 배열합니다.
    • QFormLayout: 두 개의 위젯을 하나의 Row에 넣어줍니다. 폼 만들 때 편하겠죠?

     

    QHBoxLayout

    from PyQt5.QtWidgets import *
    
    
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
    
            layout = QHBoxLayout()
            layout.addWidget(QPushButton('AAA'))
            layout.addWidget(QPushButton('BBB'))
            layout.addWidget(QPushButton('CCC'))
            self.setLayout(layout)
    
    
    app = QApplication([])
    my_window = MyWindow()
    my_window.show()
    app.exec_()

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-2.py

     

    QGridLayout

    from PyQt5.QtWidgets import *
    
    
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
    
            layout = QGridLayout()
            layout.addWidget(QPushButton('AAA'), 0, 0)
            layout.addWidget(QPushButton('BBB'), 0, 1)
            layout.addWidget(QPushButton('CCC'), 1, 1)
            self.setLayout(layout)
    
    
    app = QApplication([])
    my_window = MyWindow()
    my_window.show()
    app.exec_()

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-3.py

     

    QFormLayout

    from PyQt5.QtWidgets import *
    
    
    class MyWindow(QWidget):
        def __init__(self):
            super().__init__()
    
            layout = QFormLayout()
            layout.addRow(QPushButton('AAA'), QPushButton('BBB'))
            layout.addRow(QPushButton('CCC'), QPushButton('DDD'))
            self.setLayout(layout)
    
    
    app = QApplication([])
    my_window = MyWindow()
    my_window.show()
    app.exec_()

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-4.py

     

    레이아웃(Layout)의 중첩

    계산기를 만들어 보겠습니다.

    layout을 위아래로 나눠서,
    layout_upper에는 숫자 창(LineEdit)과 C 버튼을 
    layout_lower에는 나머지 버튼들을 넣었습니다. 

    layout_upper는 위젯을 가로로 배열하는 QHBoxLayout을 사용했고,
    layout_lower에는 위젯을 Grid로 배열을 해주는 QGridLayout을 사용했고, 
    전체적인 레이아웃(layout)에는 위젯을 세로로 배열하는 QVBoxLayout을 사용했습니다.

    layout을 상위 layout에 합칠 때는 addLayout을 씁니다.

    from PyQt5.QtWidgets import *
    
    
    class MyWidget(QWidget):
        def __init__(self):
            super().__init__()
    
            self.line_edit = QLineEdit('0')
            self.button0 = QPushButton('0')
            self.button1 = QPushButton('1')
            self.button2 = QPushButton('2')
            self.button3 = QPushButton('3')
            self.button4 = QPushButton('4')
            self.button5 = QPushButton('5')
            self.button6 = QPushButton('6')
            self.button7 = QPushButton('7')
            self.button8 = QPushButton('8')
            self.button9 = QPushButton('9')
            self.button_add = QPushButton('+')
            self.button_sub = QPushButton('-')
            self.button_mul = QPushButton('*')
            self.button_div = QPushButton('/')
            self.button_clear = QPushButton('C')
            self.button_dot = QPushButton('.')
            self.button_equal = QPushButton('=')
    
            layout_upper = QHBoxLayout()
            layout_upper.addWidget(self.line_edit)
            layout_upper.addWidget(self.button_clear)
    
            layout_lower = QGridLayout()
            layout_lower.addWidget(self.button7, 0, 0)
            layout_lower.addWidget(self.button8, 0, 1)
            layout_lower.addWidget(self.button9, 0, 2)
            layout_lower.addWidget(self.button4, 1, 0)
            layout_lower.addWidget(self.button5, 1, 1)
            layout_lower.addWidget(self.button6, 1, 2)
            layout_lower.addWidget(self.button1, 2, 0)
            layout_lower.addWidget(self.button2, 2, 1)
            layout_lower.addWidget(self.button3, 2, 2)
            layout_lower.addWidget(self.button0, 3, 0)
            layout_lower.addWidget(self.button_dot, 3, 1)
            layout_lower.addWidget(self.button_equal, 3, 2)
            layout_lower.addWidget(self.button_sub, 0, 3)
            layout_lower.addWidget(self.button_div, 1, 3)
            layout_lower.addWidget(self.button_mul, 2, 3)
            layout_lower.addWidget(self.button_add, 3, 3)
        
            layout = QVBoxLayout()
            layout.addLayout(layout_upper)
            layout.addLayout(layout_lower)
            self.setLayout(layout)
    
    
    app = QApplication([])
    my_window = MyWidget()
    my_window.show()
    app.exec_()
    

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-5.py

     

    QMainWindow

    QMainWindow를 Designer에서 보면
    다른 최상위 위젯과 달리
    지울 수 없는 QWidget 클래스의 centralwidget 객체(이름은 변경 가능)가 있습니다. 

    그래서 코드를 직접 작성할 때는 다음과 같이 해주셔야 합니다. 

    QWidget의 객체를 만들고,
    central_widget = QWidget()

    레이아웃을 작성하고

    이 객체에 레이아웃을 등록하고
    central_widget.setLayout(layout)

    마지막에는 setCentralWidget으로 그 위젯을 등록합니다. 
    self.setCentralWidget(central_widget)

    from PyQt5.QtWidgets import (QApplication, QLabel, QMainWindow,
                                 QPushButton, QVBoxLayout, QWidget)
    
    
    class MyWidget(QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.label = QLabel('label')
            self.button1 = QPushButton('button1')
            self.button1.clicked.connect(self.button1_clicked)
            self.button2 = QPushButton('button2')
            self.button2.clicked.connect(self.button2_clicked)
    
            central_widget = QWidget()
            layout = QVBoxLayout()
            layout.addWidget(self.label)
            layout.addWidget(self.button1)
            layout.addWidget(self.button2)
            central_widget.setLayout(layout)
            self.setCentralWidget(central_widget)
    
        def button1_clicked(self):
            self.label.setText('Clicked')
    
        def button2_clicked(self):
            self.label.setText('')
    
    
    app = QApplication([])
    my_window = MyWidget()
    my_window.show()
    app.exec_()
    

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-6-1.py

    아래 방식으로 작성해도 됩니다만...
    전 위 방식이 더 편합니다. 

            central_widget = QWidget()
            layout = QVBoxLayout(central_widget)  # 이렇게 작성해도 됩니다만
            layout.addWidget(self.label)
            layout.addWidget(self.button1)
            layout.addWidget(self.button2)
            self.setCentralWidget(central_widget)

    https://github.com/pycrawling/pyqt5_study/blob/main/pyqt5_study_05-6.py

     

    대규모의 GUI를 작성하거나 
    상태바와 메뉴가 필요할 때는 
    이런 구조가 편리하겠으나..

    간단한 구조의 GUI를 만들 때는 
    굳이 필요한 것 같지 않습니다. 

    반응형
Designed by Tistory.