/qt-material

Material inspired stylesheet for PySide2, PySide6, PyQt5 and PyQt6

Primary LanguagePythonBSD 2-Clause "Simplified" LicenseBSD-2-Clause

Qt-Material

This is another stylesheet for PySide6, PySide2, PyQt5 and PyQt6, which looks like Material Design (close enough).

GitHub top language PyPI - License PyPI PyPI - Status PyPI - Python Version GitHub last commit CodeFactor Grade Documentation Status

There is some custom dark themes: dark And light: light

Navigation

Install

pip install qt-material

Usage

import sys
from PySide6 import QtWidgets
# from PySide2 import QtWidgets
# from PyQt5 import QtWidgets
from qt_material import apply_stylesheet

# create the application and the main window
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()

# setup stylesheet
apply_stylesheet(app, theme='dark_teal.xml')

# run
window.show()
app.exec_()

Themes

from qt_material import list_themes

list_themes()
WARNING:root:qt_material must be imported after PySide or PyQt!





['dark_amber.xml',
 'dark_blue.xml',
 'dark_cyan.xml',
 'dark_lightgreen.xml',
 'dark_pink.xml',
 'dark_purple.xml',
 'dark_red.xml',
 'dark_teal.xml',
 'dark_yellow.xml',
 'light_amber.xml',
 'light_blue.xml',
 'light_cyan.xml',
 'light_cyan_500.xml',
 'light_lightgreen.xml',
 'light_pink.xml',
 'light_purple.xml',
 'light_red.xml',
 'light_teal.xml',
 'light_yellow.xml']

Custom colors

Color Tool is the best way to generate new themes, just choose colors and export as Android XML, the theme file must look like:

<!--?xml version="1.0" encoding="UTF-8"?-->
<resources>
<color name="primaryColor">#00e5ff</color>
<color name="primaryLightColor">#6effff</color>
<color name="secondaryColor">#f5f5f5</color>
<color name="secondaryLightColor">#ffffff</color>
<color name="secondaryDarkColor">#e6e6e6</color>
<color name="primaryTextColor">#000000</color>
<color name="secondaryTextColor">#000000</color>
</resources>

Save it as my_theme.xml or similar and apply the style sheet from Python.

apply_stylesheet(app, theme='dark_teal.xml')

Light themes

Light themes will need to add invert_secondary argument as True.

apply_stylesheet(app, theme='light_red.xml', invert_secondary=True)

Environ variables

There is a environ variables related to the current theme used, these variables are for consult purpose only.

Environ variable Description Example
QTMATERIAL_PRIMARYCOLOR Primary color #2979ff
QTMATERIAL_PRIMARYLIGHTCOLOR A bright version of the primary color #75a7ff
QTMATERIAL_SECONDARYCOLOR Secondary color #f5f5f5
QTMATERIAL_SECONDARYLIGHTCOLOR A bright version of the secondary color #ffffff
QTMATERIAL_SECONDARYDARKCOLOR A dark version of the primary color #e6e6e6
QTMATERIAL_PRIMARYTEXTCOLOR Color for text over primary background #000000
QTMATERIAL_SECONDARYTEXTCOLOR Color for text over secondary background #000000
QTMATERIAL_THEME Name of theme used light_blue.xml

Alternative QPushButtons and custom fonts

There is an extra argument for accent colors and custom fonts.

extra = {

    # Button colors
    'danger': '#dc3545',
    'warning': '#ffc107',
    'success': '#17a2b8',

    # Font
    'font_family': 'Roboto',
}

apply_stylesheet(app, 'light_cyan.xml', invert_secondary=True, extra=extra)

The accent colors are applied to QPushButton with the corresponding class property:

pushButton_danger.setProperty('class', 'danger')
pushButton_warning.setProperty('class', 'warning')
pushButton_success.setProperty('class', 'success')

extra

Custom stylesheets

Custom changes can be performed by overwriting the stylesheets, for example:

QPushButton {{
  color: {QTMATERIAL_SECONDARYCOLOR};
  text-transform: none;
  background-color: {QTMATERIAL_PRIMARYCOLOR};
}}

.big_button {{
  height: 64px;
}}

Then, the current stylesheet can be extended just with:

apply_stylesheet(app, theme='light_blue.xml', css_file='custom.css')

The stylesheet can also be changed on runtime by:

stylesheet = app.styleSheet()
with open('custom.css') as file:
    app.setStyleSheet(stylesheet + file.read().format(**os.environ))

And the class style can be applied with the setProperty method:

self.main.pushButton.setProperty('class', 'big_button')

extra

Run examples

A window with almost all widgets (see the previous screenshots) are available to test all themes and create new ones.

git clone https://github.com/UN-GCPDS/qt-material.git
cd qt-material
python setup.py install
cd examples/full_features
python main.py --pyside6

theme

New themes

Do you have a custom theme? it looks good? create a pull request in themes folder and share it with all users.

Change theme in runtime

There is a qt_material.QtStyleTools class that must be inherited along to QMainWindow for change themes in runtime using the apply_stylesheet() method.

class RuntimeStylesheets(QMainWindow, QtStyleTools):
    
    def __init__(self):
        super().__init__()
        self.main = QUiLoader().load('main_window.ui', self)
        
        self.apply_stylesheet(self.main, 'dark_teal.xml')
        # self.apply_stylesheet(self.main, 'light_red.xml')
        # self.apply_stylesheet(self.main, 'light_blue.xml')

run

Integrate stylesheets in a menu

A custom stylesheets menu can be added to a project for switching across all default available themes.

class RuntimeStylesheets(QMainWindow, QtStyleTools):
    
    def __init__(self):
        super().__init__()
        self.main = QUiLoader().load('main_window.ui', self)
        
        self.add_menu_theme(self.main, self.main.menuStyles)

menu

Create new themes

A simple interface is available to modify a theme in runtime, this feature can be used to create a new theme, the theme file is created in the main directory as my_theme.xml

class RuntimeStylesheets(QMainWindow, QtStyleTools):
    
    def __init__(self):
        super().__init__()
        self.main = QUiLoader().load('main_window.ui', self)
        
        self.show_dock_theme(self.main)

dock

A full set of examples are available in the exmaples directory

Export theme

This feature able to use qt-material themes into Qt implementations using only local files.

from qt_material import export_theme

extra = {

    # Button colors
    'danger': '#dc3545',
    'warning': '#ffc107',
    'success': '#17a2b8',

    # Font
    'font_family': 'monoespace',
    'font_size': '13px',
    'line_height': '13px',

    # Density Scale
    'density_scale': '0',

    # environ
    'pyside6': True,
    'linux': True,

}

export_theme(theme='dark_teal.xml', 
             qss='dark_teal.qss', 
             rcc='resources.rcc',
             output='theme', 
             prefix='icon:/', 
             invert_secondary=False, 
             extra=extra,
            )

This script will generate both dark_teal.qss and resources.rcc and a folder with all theme icons called theme.

The files generated can be integrated into a PySide6 application just with:

import sys

from PySide6 import QtWidgets
from PySide6.QtCore import QDir
from __feature__ import snake_case, true_property

# Create application
app = QtWidgets.QApplication(sys.argv)

# Load styles
with open('dark_teal.qss', 'r') as file:
    app.style_sheet = file.read()

# Load icons
QDir.add_search_path('icon', 'theme')

# App
window = QtWidgets.QMainWindow()
checkbox = QtWidgets.QCheckBox(window)
checkbox.text = 'CheckBox'
window.show()
app.exec()

This files can also be used into non Python environs like C++.

Density scale

The extra arguments also include an option to set the density scale, by default is 0.

extra = {
    
    # Density Scale
    'density_scale': '-2',
}

apply_stylesheet(app, 'default', invert_secondary=False, extra=extra)

dock

Troubleshoots

QMenu

QMenu has multiple rendering for each Qt backend, and for each operating system. Even can be related with the style, like fusion. Then, the extra argument also supportsQMenu parameters to configure this widgest for specific combinations. This options are not affected by density scale.

extra['QMenu'] = {
    'height': 50,
    'padding': '50px 50px 50px 50px',  # top, right, bottom, left
}