soma0sd

코딩 & 과학 & 교육

PyQt5: 제목표시줄 스타일 바꾸기 2. 제목표시줄 기능

반응형

제목표시줄의 기능

윈도우 등 GUI를 지원하는 운영체제(OS)의 제목 표시줄은 응용프로그램의 이름을 표시하는 것 뿐만 아니라 몇 가지 기능을 담고있기도 합니다. 이름 부분을 더블클릭하면 응용프로그램 창을 최대화하거나 기본 크기로 바꿀 수 있으며, 클릭 후 이동하면 창의 위치를 바꿀 수 있습니다.

또한 닫기와 최소화 버튼 등 기능버튼 또한 제목표시줄에 있기 때문에, 특별한 이유가 없다면 사용자의 편의를 위해 새로 만든 제목표시줄에도 같은 기능을 구현하는 것이 좋습니다.

스크립트

"""윈도우 타이틀 꾸미기
https://soma0sd.tistory.com/
"""
import os
import sys
from PyQt5 import QtWidgets, QtGui, QtCore

ROOT_PATH = os.path.dirname(os.path.abspath(__file__))


class MainWindow(QtWidgets.QWidget):
    """메인 윈도우"""
    qss = """
        QWidget {
            color: #000000;
            background: #888;
        }
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.setStyleSheet(self.qss)

        # 레이아웃과 타이틀바 위젯 생성
        window_vbox = QtWidgets.QVBoxLayout(self)
        window_vbox.setContentsMargins(0, 0, 0, 0)
        titlebar_widget = MainTitleBar(self)
        titlebar_widget.setObjectName("windowTitle")
        content_vbox = QtWidgets.QVBoxLayout()
        content_vbox.setContentsMargins(3, 3, 3, 3)

        # 타이틀바와 컨텐츠 박스 안의 내용물을 생성
        content_textedit = QtWidgets.QTextEdit()

        # 각 항목을 레이아웃에 배치
        content_vbox.addWidget(content_textedit)
        window_vbox.addWidget(titlebar_widget)
        window_vbox.addLayout(content_vbox)


class MainTitleBar(QtWidgets.QWidget):
    """제목 표시줄 위젯"""
    qss = """
        QWidget {
            color: #FFFFFF;
            background: #333333;
            height: 32px;
        }
        QLabel {
            color: #FFFFFF;
            background: #333333;
            font-size: 16px;
            padding: 5px 5px;
        }
        QToolButton {
            background: #333333;
            border: none;
        }
        QToolButton:hover{
            background: #444444;
        }
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        self.bar_height = 36
        self.parent = parent
        self.has_clicked = False
        self.is_maximized = False
        self.setStyleSheet(self.qss)
        layout = QtWidgets.QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        label = QtWidgets.QLabel("윈도우 이름")
        label.setFixedHeight(self.bar_height)
        btn_minimize = self.create_tool_btn('minimize.png')
        btn_minimize.clicked.connect(self.show_minimized)
        btn_close = self.create_tool_btn('close.png')
        btn_close.clicked.connect(self.close)

        layout.addWidget(label)
        layout.addWidget(btn_minimize)
        layout.addWidget(btn_close)

    def create_tool_btn(self, icon_path):
        """제목표시줄 아이콘 생성"""
        icon = os.path.join(ROOT_PATH, 'img', icon_path)
        btn = QtWidgets.QToolButton(self)
        btn.setIcon(QtGui.QIcon(icon))
        btn.setIconSize(QtCore.QSize(self.bar_height, self.bar_height))
        btn.setFixedSize(self.bar_height, self.bar_height)
        return btn

    def show_minimized(self):
        """버튼 명령: 최소화"""
        self.parent.showMinimized()

    def close(self):
        """버튼 명령: 닫기"""
        self.parent.close()

    def mousePressEvent(self, event):
        """오버로딩: 마우스 클릭 이벤트
        - 제목 표시줄 클릭시 이동 가능 플래그
        """
        if event.button() == QtCore.Qt.LeftButton:
            self.parent.is_moving = True
            self.parent.offset = event.pos()

    def mouseMoveEvent(self, event):
        """오버로딩: 마우스 이동 이벤트
        - 제목 표시줄 드래그시 창 이동
        """
        if self.parent.is_moving:
            self.parent.move(event.globalPos() - self.parent.offset)

    def mouseDoubleClickEvent(self, event):
        """오버로딩: 더블클릭 이벤트
        - 제목 표시줄 더블클릭시 최대화
        """
        if self.is_maximized:
            self.parent.showNormal()
            self.is_maximized = False
        else:
            self.parent.showMaximized()
            self.is_maximized = True

if __name__ == "__main__":
    APP = QtWidgets.QApplication(sys.argv)
    WINDOW = MainWindow()
    WINDOW.show()
    APP.exec()

설명

전체 구조를 담당하는 CLASS::MainWindow에서 제목표시줄 부분을 따로 떼어 CLASS::MainTitleBar로 만들었습니다.

이 스크립트는 제목표시줄 버튼에 이미지를 사용합니다. 결과 예시에서는 Material Icons에서 이미지를 구했습니다. {스크립트 경로}/img/디렉토리 안에 닫기 버튼 아이콘 이미지인 close.png와 최소화 버튼 아이콘 이미지인 minimize.png를 사용합니다. 이미지가 없는 경우에 스크립트를 실행하면 오류를 출력하지 않고 빈 버튼으로 보이게 됩니다.

반응형
태그:

댓글

End of content

No more pages to load