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.
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.