본문 바로가기

PyQt GUI

PyQt GUI (18) 괜찮은 테마 소개 : qt_material

728x90

PyQt에서는 별다른 스타일 설정을 하지 않으면, GUI는 회색 혹은 흰색의 색 조합으로 구성 됩니다. 

위 이미지는 예전에 만들었던 계산기의 기본 UI 입니다. 흰색, 회색, 조금 더 진한 회색 등으로만 구성 돼 있습니다. 

GUI와 관련된 10번째 포스팅에서는 회색 UI를 위와 같이 유채색의 UI로 변경하였습니다. 이 포스팅에서는 직접 각 위젯마다 스타일을 정의하고, 각 위젯에다 setStyleSheet 메서드를 통해서 스타일을 설정하였습니다. 

 

이전 포스팅에서 했던것과 같이 모든 GUI의 구성 요소들에다 원하는 스타일을 설정할 수 있지만, 그렇게 하면 (1) 너무 귀찮고, (2) 미적 감각이 없는 경우에는 꾸민 스타일이 이쁘지 않을 수 있다는 문제가 있습니다. 

 

(1)의 문제를 해결하기 위해서는 모든 위젯이나 아이얼로그에다가 하나하나 스타일을 설정해 주면 되는데, 처음에는 문제가 없지만, 프로그램이 점점 커진다면 중간 중간 빼먹은 위젯이 하나 둘 나오기 때문에 귀찮아 집니다. 

 

(2)의 문제를 해결하는 것은 무척이나 어려운데, 타고난 미적 감각이 없다면, 아무리 노력을 하더라도 이쁜 UI를 만드는 것이 불가능할 수 있습니다. 그냥 아무것도 사용하지 않은 기본 회색의 UI가 더 이쁠 수 있습니다. 

 

위 문제를 극복하는 좋은 방법은 이미 나와 있는 괜찮은 테마를 다운 받아 사용하는 것 입니다. 그 중에서 최근에 qt_material 이라는 테마를 알게 됐는데, 괜찮은 테마인 것 같아서 이를 소개하려고 합니다. 

 

https://pypi.org/project/qt-material/

 

qt-material

Material inspired stylesheet for PySide2, PySide6, PyQt5 and PyQt6.

pypi.org

위 홈페이지에서 소스나 whl을 다운 받아서 설치하면 되고, 아니면 그냥 pip 명령어를 입력하여 간단하게 설치할 수 도 있습니다. 설치 방법에 대해서는 위 페이지에 설명이 돼 있으니 그냥 따라하면 됩니다. 

 

설치를 하고 나면, 사용법은 무척 간단한데, qt_material를 import하고 원하는 테마를 정한 뒤 적용만 시켜 주면 됩니다. 

from qt_material import apply_stylesheet, QtStyleTools

지난 포스팅에서 만든 계산이 어플에다가 테마를 적용해 보겠습니다. 

    def set_style(self):
        with open("update_style", 'r') as f:
            self.setStyleSheet(f.read())
QDialog{
background:white;
}

QPushButtonOperation{
background-color:rgba(80, 188, 223, 0.5);
color:black;
border-radius:5px;
}

QPushButtonNumber{
background-color:rgba(247, 230, 0, 0.5);
color:black;
border-radius:5px;
}

예전 코드에서는 아래와 같이 스타일을 위젯 마다 설정하고, setStyleSheet 메서드를 활용하여, 적용했습니다. 이 부분을 대신하여 qt_material 을 이용하면 됩니다. 

class Main(QDialog, QtStyleTools):

    def set_style(self):
        #with open("update_style", 'r') as f:
        #    self.setStyleSheet(f.read())

        extra = {}
        extra['font_family'] = 'Roboto'
        extra['density_scale'] = str(0)
        theme = 'light_pink.xml'
        invert = True
        self.apply_stylesheet(self, theme=theme, extra=extra, invert_secondary=invert)

코드에서 두 부분이 바뀌었는데, 첫 번째로 Main 클래스를 정의할 때, QtStyleTools를 함께 상속 받았습니다. qt_material에서 제공하는 클래스로 테마와 관련된 클랫 입니다. 두 번째는 extra = {} 아래 부분인데, 이 부분은 qt_material를 이용하여 스타일을 적용하는 부분입니다. apply_stylesheet 메서드를 이용하여 스타일을 적용할 수 있는데, theme, extra, invert_secondary 의 추가 옵션이 있습니다. 이에 대해서는 위 qt_material 의 홈페이지에 설명이 돼 있습니다. 

 

가장 간단한 옵션을 위와 같이 설정하였습니다. 이 경우에는 light_pink 밝은 핑크색 계열의 테마가 적용 됩니다. 

결과는 위와 같습니다. 단순하게 색만 변하는 것이 아니라, 글꼴, 사이즈 등 모든 구성 요소의 스타일이 변하게 됩니다. 위 버튼을 클릭하게 되면 흰색이었던 버튼이 핑크색으로 변하게 됩니다. 다양한 테마가 있으니, 하나 하나 적용을 해 보고 원하는 테마를 선택하면 됩니다. 

 

테마를 만든 개발자가 신경을 많이 써서 정한 스타일이기 때문에, 그대로 사용해도 문제가 없습니다. 그러나 간혹 특정한 위젯에 대한 스타일을 변경하고 싶을 수가 있는데, 이때는 원하는 부분만 추가하여 다시 스타일을 적용하면 됩니다. 

        extra = {}
        extra['font_family'] = 'Roboto'
        extra['density_scale'] = str(0)
        theme = 'light_pink.xml'
        invert = True
        self.apply_stylesheet(self, theme=theme, extra=extra, invert_secondary=invert)

        custom1 = "\nQPushButton:hover {{\n background-color: {QTMATERIAL_SECONDARYLIGHTCOLOR};\n}}".format(**os.environ)
        custom2 = "\nQPushButton:pressed {{\n background-color: {QTMATERIAL_PRIMARYCOLOR};\n}}".format(**os.environ)

        stylesheet = self.styleSheet()
        stylesheet = stylesheet + custom1 + custom2
        print(stylesheet)
        self.setStyleSheet(stylesheet)

위 코드 중간 쯤에 있는 self.apply_stylesheet(~~~) 이후에 여러 줄이 추가 되었습니다. 

custom1, custom2는 PushButton의 hover, pressed에 대한 스타일 입니다. 이를 우리가 원하는 대로 수정하려고 합니다. qt_material의 기본 테마에서는 PushButton의 hover에 대한 설정이 따로 없습니다. 그래서 마우스 커서가 버튼 위에 있다고 하더라도 버튼의 스타일에는 아무런 변화가 없습니다. 이런 경우에는 해당 버튼이 클릭을 할 수 있는 버튼인지에 대한 인식이 어렵기 때문에, 버튼에는 항상 hover 스타일의 설정을 해 주는게 좋습니다.

 

위의 custom1과 같이 hover 설정을 해 줄 수 있습니다. background-color : "원하는 색" 과 같이 원하는 색을 써 주면 되는데, 아무 색이나 해도 되지만, 되도록이면 다른 테마들과 룩앤필이 맞는 색을 선태하면 좋기 때문에, 해당 테마의 기본색을 써 주는 것이 좋습니다. 이 경우에는 위와 같이 하면 됩니다. 이에 대해서는 qt_material 홈페이지에 설명이 잘 돼 있습니다. 

 

다음에는 custom1, custom2 스타일을 추가해 주어야 하는데요, 이는 기존에 설정 돼 있는 스타일일을 모두 갖고 온 다음에, 거기에다가 custom1, custom2를 추가하고, 추가된 스타일을 다시 설정하는 방법으로 적용할 수 있습니다. 그 부분이 이 코드의 아래 5줄 입니다. 

 

위 프로그램은 PushButton, LineEdit 정도만 사용하기 때문에, 별다른 변화가 없는 것 처럼 보입니다. 하지만, qt_material에서는 다양한 위젯에 대해서 스타일을 미리 정의해 두었으니, 다양한 위젯에 대해서 테스트를 해 보면 좋을 것 같습니다.

 

한 가지 주의해야할 것은, qt_material의 기본 스타일과 pyqt의 기본 스타일이 서로 충돌을 일으킬 수 있다는 것 입니다. 예를 들면, qt_material 에서는 QPushButton이나 QTableView 등의 위젯의 text를 대문자로 표시하는 스타일이 기본으로 설정 돼 있습니다. 따라서 이 스타일을 원치 않을 경우에는 위와 같이 스타일을 직접 변경 시켜주어야 합니다. 

728x90