본문 바로가기

PyQt GUI

PyQt GUI (8) : 프레임을 사용하여 UI창 구분하여 활용하기 - QFrame

728x90

윈도우 탐색기는 크게 폴더트리 부분과 폴더의 내용을 보여주는 부분으로 나눠져 있습니다. 

폴더트리와 폴더의 내용을 보여주는 부분에는 희미하게 회색으로 세로방향 선이 그어져 있는데, 그냥 보면 잘 안 보여서 검은색 굵은 라인으로 그렸습니다. 이 선을 좌우로 움직이면서 폴더트리 부분을 크게 볼 수도 있고, 반대로 폴더의 내용을 더 크게 볼 수 도 있습니다. 

위 예시는 폴더트리 부분을 크게 보고 폴더의 내용창 부분을 작게 줄인 것 입니다. 

 

이처럼 UI에서는 서로 다른 역할을 하는 두 부분을 동시에 보여줘야할 일이 있습니다. 그리고 사용자의 편의를 위해서 그 두 부분의 영역의 넓이를 위와 같이 조절할 수 있는 기능이 있어야 합니다. 

 

PyQt GUI에서는 QFrame이라는 위젯을 이용해서 위 기능을 수행합니다. Frame은 우리말로 "틀" 또는 "액자"를 뜻하는데, 하나의 UI에 여러개의 액자를 두고 각 액자의 크기를 원하는 용도에 맞게 조절하는 방법입니다. 이번 포스팅에서는 QFrame 위젯을 이용하여 위와 같이 하나의 메인 레이아웃에 여러개의 Frame을 만드는 것을 알아보겠습니다. 

 

우선 전체 코드는 아래와 같습니다. 아래 코드를 복-붙 한다음에 프로그램을 실행하면 됩니다. 

import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *


class Main(QDialog):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        main_layout = QVBoxLayout()

        frame_1 = QFrame()
        frame_1.setFrameShape(QFrame.Panel | QFrame.Sunken)
        frame_2 = QFrame()
        frame_2.setFrameShape(QFrame.Panel | QFrame.Sunken)

        layout_1 = QVBoxLayout()
        layout_2 = QVBoxLayout()

        button_1 = QPushButton("button_1")
        button_2 = QPushButton("button_2")

        layout_1.addWidget(button_1)
        layout_2.addWidget(button_2)

        frame_1.setLayout(layout_1)
        frame_2.setLayout(layout_2)

        spliter_1 = QSplitter(Qt.Horizontal)
        spliter_1.addWidget(frame_1)
        spliter_1.addWidget(frame_2)

        main_layout.addWidget(spliter_1)

        self.setLayout(main_layout)
        self.resize(500, 500)
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main = Main()
    sys.exit(app.exec_())

위 프로그램을 실행하면 아래와 같은 UI를 얻을 수 있습니다. 

좌-우 두개의 틀(Frame)이 생긴것이 보이는지요? 그리고 중간에 있는 세로 방향의 구분자를 좌우로 이동시키면 좌우 틀의 크기를 마음대로 조절할 수 있습니다. 이 코드에서는 두 개의 Frame을 생성하고, 이 두 프레임을 QSpliter를 생성하여 QSpliter에 추가한 것 입니다. 즉, 가장 작은 요소 부터 큰 요소 순서대로 정렬을 하면

 

위젯 -> 레이아웃 -> 프레임 -> 스플리터 -> 레이아웃

 

순서대로 구성 요소들을 만들어 최종 UI를 형성하는 것 입니다. 반대로 큰 요소 부터 설명하면 (항상 나오는 위젯 -> 레이아웃과 최종적으로 생성하게 되는 메인 레이아웃은 당연하니 생략하도록 하겠습니다), 

 

수평방향 스플리터를 생성하여, 이 스플리터에 frame_1과 frame_2를 추가한다.

frame_1과 frame_2에는 각각 layout_1, layout_2를 설정한다

 

입니다. 이 부분에 해당하는 코딩은 (즉, 이번 포스팅의 핵심적인 코딩은) 아래와 같습니다. 

        frame_1 = QFrame()  # 프레임 생성
        frame_1.setFrameShape(QFrame.Panel | QFrame.Sunken) # 프레임 스타일 설정
        
        layout_1 = QVBoxLayout()
        button_1 = QPushButton("button_1")
        layout_1.addWidget(button_1) # 프레임에 넣을 레이아웃 생성
        
        frame_1.setLayout(layout_1) # 생성한 레이아웃을 프레임에 적용
        
        spliter_1 = QSplitter(Qt.Horizontal) #스플리터 생성
        spliter_1.addWidget(frame_1) #스플리터에 frame_1 추가
        spliter_1.addWidget(frame_2) #스플리터에 frame_2 추가
        
        main_layout.addWidget(spliter_1) #스플리터 위젯을 메인 레이아웃에 추가

당연히 layout_1에는 원하는 레이아웃을 생성해 주면 됩니다. 최종적으로 main_layout에 적용이 되는 위젯은 스플리터 위젯으로 이 예시에서는 Horizontal 방향의 스플릿을 설정하였습니다. 스플리터는 Qt.Horizontal을 통해서 좌우 방향의 스플리터를 만들 수 있고, Qt.Vertical를 통해서 위아래 방향의 스플리터를 만들 수 있습니다. 

 

코드의 윗 부분에

        frame_1.setFrameShape(QFrame.Panel | QFrame.Sunken)

는 프레임의 스타일을 정해주는 것인데, 

와 같은 옵션으로 스타일을 설정할 수 있습니다. 

 

스플리터와 프레임을 활용하여 전체 UI를 만드는 것은 마치 QVBoxLayout, QHBoxLayout을 이용하여 위젯을 배치하는 것과 방법적으로 보면 별반 차이가 없습니다. 즉 스플리터가 레이아웃에 대응되고, 프레임이 위젯이 대응된다고 할 수 있습니다. 

 

QVBoxLayout, QHBoxLayout를 소개하는 포스팅에서 두 레이아웃을 함께 사용하여 다양한 형태로 위젯을 배치하였던 것 처럼, 여러개의 Horizontal, Vertical 스플리터를 이용하여 원하는 형태의 다양한 프레임 배치를 할 수 있습니다. 

위 UI는 Vertical 스플리터와 Horizontal 스플리터를 활용하여 전체창을 3분할 한 UI입니다. 핵심적인 코딩은

        spliter_1 = QSplitter(Qt.Horizontal)
        spliter_1.addWidget(frame_1)
        spliter_1.addWidget(frame_2)

        spliter_2 = QSplitter(Qt.Vertical)
        spliter_2.addWidget(spliter_1)
        spliter_2.addWidget(frame_3)

        main_layout.addWidget(spliter_2)

와 같습니다. 우선 위 두 프레임을 spliter_1를 통해서 구성하고, spliter_2에서는 앞서 만든 spliter_1과 아래 부분의 frame_3을 추가하였습니다. 앞서 언급한대로 QHBoxLayout과 QVBoxLayout을 이용하여 위젯을 배치한것과 크게 다르지 않습니다. 

화면 중간에 있는 가로, 세로 스플리터바를 통해서 프레임의 크기를 원하는대로 조절할 수 있습니다. 물론 각 프레임에 설정 돼 있는 레이아웃이나 위젯의 크기 정책에 따라서 프레임의 크기 변경에 제한이 있을 수 도 있습니다. 

 

프레임의 사이즈(비율)이 초기값은 아래와 같은 문법으로 지정할 수 있습니다. 

        spliter_1.setSizes([100, 200])
        spliter_2.setSizes([100, 200])

이렇게 하면, spliter_1은 기본적으로 100:200 의 비율로 프레임의 크기가 정해지고, spliter_2 역시 기본적으로 100:200 의 비율로 프레임의 크기가 정해집니다. 위 설정을 추가하고 프로그램을 실행하면, 

와 같이 프레임의 크기가 적용 되었음을 확인할 수 있습니다. 

728x90