Styling PyQt6 Applications - Default and Custom QSS Stylesheets

Introduction

In this guide, we'll take a look at how to style a PyQt application.

If you're unfamiliar with PyQt, read our Guide to Working with Python's PyQT Framework

We'll start with PyQt's default themes and how to change these, before moving forward to using different types of custom styling.

Default PyQt Themes

PyQt works with default OS-based themes. This means that not specifying a theme will give the application a different look on different systems.

Your application will look different on a Windows 10 machine as opposed to a Linux machine.

There are many styles or themes that ship with PyQt, other than the default themes.

To keep a uniform look and feel to our application while distributing to multiple operating systems we'll want to change the default theme with either a pre-built one or build our own. Alternatively, you can keep a native look depending on the operating system.

Check All Available System-Styles

Since the default system styles differ from system to system, not every system will have the same default styles available.

Luckily, PyQt has a built-in function to retrieve all the available styles, kept in a dictionary. Let's take a look at all the available system styles:

# The QStyleFactory object holds all the default system styles.
from PyQt6.QtWidgets import QStyleFactory
print(QStyleFactory.keys())

On a Windows machine, this will return the three following styles:

['windowsvista', 'Windows', 'Fusion']

On Linux, on the other hand, it'll return:

['Breeze', 'Oxygen', 'QtCurve', 'Windows', 'Fusion']

To find out which default style is applied to an existing application, you can access the objectName() via app.style():

import sys
from PyQt6.QtWidgets import QApplication

app = QApplication(sys.argv)
print(app.style().objectName())

The result, again, depends on your operating system:

windowsvista

Applying System Styles to PyQt6 Applications

To change the default system style to another style we can use the setStyle() method on the QApplication instance,, with another style as an argument.

Let's set the default style to Fusion in a small application:

import sys
from PyQt6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
app = QApplication(sys.argv)

# Set the 'Fusion' system style
app.setStyle('Fusion')

# Create the parent Widget of the Widgets added to the layout
window = QWidget()

# Create the Vertical Box Layout Manager, setting the window as parent by passing it in the constructor.
layout = QVBoxLayout(window)

# Create the button Widgets we will add to the layout.
# Add the button Widgets to the VerticalBoxLayout
layout.addWidget(QPushButton('One'))
layout.addWidget(QPushButton('Two'))
layout.addWidget(QPushButton('Three'))
layout.addWidget(QPushButton('Four'))
layout.addWidget(QPushButton('Five'))

# Show the parent Widget
window.show()

# Launch the application
sys.exit(app.exec())

Now, this applies the Fusion stylesheet to our elements, changing their appearance:

Custom PyQt6 Styles

Although these styles are really nice - you might have a different vision for your application. What if you'd like to change the buttons to be red, but keep the rest of the Fusion stylesheet applied?

Much the same way you can stylize HTML pages - you can also stylize PyQt applications - inline and through QSS Stylesheets.

QSS Stylesheets take inspiration from CSS Stlyesheets and have a borrowed syntax with a tiny tweak.

Adding Inline Style to PyQt6 Applications

When the amount of styling code doesn't warrant a separate, standalone QSS File, it's easiest to write some styling code inline - that is, within the Python file in which your application resides.

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

Similar to styling HTML pages inline, it's not considered the best practice, but it is fine for prototyping, testing or really small tweaks.

Each QWidget accepts a setStyleSheet() function, which accepts a CSS string:

widget.setStyleSheet(
    """
    CSS SYNTAX
    """
)

For example, if we want to apply a color to a widget, set its font family and size, we can simply use the all-too-familiar CSS syntax:

...
button = QPushButton('One')
button.setStyleSheet(
    "background-color: #262626; "
    "font-family: times; "
    "font-size: 20px;"
)

layout.addWidget(button)

If we replaced the original button addition code with this, the application would look like:

Now, if we want to style another component, we apply the setStyleSheet() function to it. This quickly becomes a problem if you want to style multiple components...

Although you can apply the setStyleSheet() function to the QApplication instance and apply styling globally to the entire application. Though, if you're already there, might as well create a new custom stylesheet and use it instead of inline styling code.

Creating Custom Stylesheets

The operating system styles are just stylesheets present in different shipments of PyQt. There's nothing stopping you from defining your own QSS Stylesheet made specifically for your application.

Additionally, using stylesheets fixes a myriad of problems that can arise from styling your components inline, besides the fact that it makes sense to separate business logic from styling code.

QSS files are very similar to CSS files - the only difference is how you identify elements you'd like to style. You can't assign a unique ID to a certain widget to style it individually. You'll have to lump together apples with apples and style widget types the same.

Optionally, you can also style objects within widgets individually from the widget itself:

QPushButton {
    background-color: blue;
}

QLabel#title {
    font-size: 15px;
}

The first style will define our background-color for all the QPushButton objects in the application.

The second style will only style the title object of a QLabel.

To include a QSS file to your application, you can apply it by reading the file and using the QApplication.setStyleSheet(str) function:

# Open the qss styles file and read in the CSS-like styling code
with open('styles.qss', 'r') as f:
    style = f.read()

    # Set the stylesheet of the application
    app.setStyleSheet(style)

Really, these files are just the container for our style strings.

Styling a Demonstration Application

With all of this in mind, let's create a simple QSS stylesheet and apply it to a simple demo application:

import sys
from PyQt6.QtWidgets import (QApplication, QTableWidget, QTableWidgetItem)
from PyQt6.QtGui import QColor

# Declare our table values
nordic_countries = [('Norway', 'Oslo', 'Yes'),
          ('Iceland', 'Reykjavik', 'Yes'),
          ('Denmark', 'Copenhagen', 'Yes'),
          ('Belgium', 'Brussels','No')]
          
# Create the Qt Application
app = QApplication(sys.argv)

# Create the QTableWidget Widget
table = QTableWidget()

# Set the row count of the table to the length of the 'nordic_countries' variable
table.setRowCount(len(nordic_countries))

# Since every country in our 'nordic_countries' variable has the same amount of attributes
# we take the amount (3) of the first country and use this as the number of columns
table.setColumnCount(len(nordic_countries[0]))

# Set the Horizontal headers using setHorizontalHeaderLabels()
table.setHorizontalHeaderLabels(['Country', 'Capital', 'Scandinavian?'])

# Loop through every country in our 'nordic_countries' variable
for i, (country, capital, scandinavian_bool) in enumerate(nordic_countries):

    # Make a QTableWidgetItem --> acts as an item in a table
    item_country = QTableWidgetItem(country)
    item_capital = QTableWidgetItem(capital)
    item_scandinavian_bool = QTableWidgetItem(scandinavian_bool)

    # Set the value of the items
    table.setItem(i, 0, item_country)
    table.setItem(i, 1, item_capital)
    table.setItem(i, 2, item_scandinavian_bool)

# Finally show the table
table.show()

# Open the sqq styles file and read in the CSS-alike styling code
with open('styles.qss', 'r') as f:
    style = f.read()
    # Set the stylesheet of the application
    app.setStyleSheet(style)

# Launch the application
sys.exit(app.exec())

And within the styles.qss file:

QTableWidget {
    font-family: Titillium;
    font-size: 20px;
}

QTableWidget::item {
    background-color: #D3D3D3;

}

QTableWidget::item:hover {
    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e7effd, stop: 1 #cbdaf1);
    border: 1px solid #bfcde4;
}

Conclusion

In this guide, we've taken a look at how to style PyQt6 Applications in Python. We've explored standard operating system styles, how to style them using inline code as well as how to create custom QSS Stylesheets.

Last Updated: March 6th, 2023
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms