21. Properties
Qt provides a property system that allows classes derived from QObject to declare properties using the QtCore.Property class. It enables dynamic access, introspection, and binding through the Qt’s meta-object system. Qt’s properties are similar to Python’s native properties, making them less important in Python than in C++, but there are still situations where using Qt properties in PySide6 is necessary or recommended:
- When exposing PySide6 objects to QML, only Qt properties are visible.
- To animate custom widget attributes using
QpropertyAnimation, the target must be defined as a Qt property. - They are useful for conditional styling with Qt style sheets.
Properties can include read/write methods, notifications via signals and other options1:
1 Property(self, type: type,
2 fget: Optional[Callable] = None,
3 fset: Optional[Callable] = None,
4 freset: Optional[Callable] = None,
5 fdel: Optional[Callable] = None,
6 doc: str = '',
7 notify: Optional[PySide6.QtCore.Signal] = None,
8 designable: bool = True,
9 scriptable: bool = True,
10 stored: bool = True, user: bool = False,
11 constant: bool = False,
12 final: bool = False) -> PySide6.QtCore.Property
Although only the type parameter is not marked as optional, you should at minimum set type and fget to create a functional read-only property.
21.1 Declaring Basic Properties
PySide6 provides two ways of declaring properties:
- Passing all the arguments to
Property. - Using the
@Propertydecorator, which lets you split the property declaration into multiple parts.
![]() |
You are building a custom dashboard widget for a fitness tracking app that displays current user name, steps taken and a configurable daily steps goal. To provide clean access to this data, you create a subclass of QLabel with properties: user name as read-only (get value from the OS), steps taken from sensor data and daily goal as read-write (user-configurable). |
To create Qt properties in PySide6:
Create a
QObjectsubclass. SubclassQLabel, letting the caller optionally initialize it with thedaily_goalparameter.-
Declare the backing attributes. We need three fields:
self._user_name. Simulate getting the currently logged-in user name and assign it to this field.self._steps. This field is initialized with zero.self._daily_goal, initialized with thedaily_goalparameter.
-
Declare the properties. Declare a Qt property for each of the backing attributes:
- Use the
@Propertydecorator to declareuserNameas a read-only string property, returningself._user_name. Client code will not be able to modify it. - Declare a getter (
steps()) and setter (getSteps()) for the second property and usePropertyto create it. The property has the same name as the getter, i.e.steps. Note thatstepsis declared as a class-level attribute. - Use the
@Propertydecorator to declare thedailyGoalgetter anddailyGoalsetter separately.
Now, in the main window code, you can access all three properties using the familiar Python syntax.
1 def set_daily_goal(self, goal):
2 self.steps_label.dailyGoal = goal

21.2 Properties Notification and Reset
Beyond basic getters and setters, the Qt property system has built-in support for resetting properties - this lets you declare a method that restores a property to its default value with a QMetaProperty.reset() call. It also supports automatic property change notifications via signals, allowing client code to receive signals whenever the value of a property changes.
![]() |
You are creating a theme selector widget for an application. The widget stores the current theme as a property (“Light”, “Dark”, or “System”). Other UI components should be notified of theme changes, and user should be able to restore the default theme. |
To create a resettable property that supports change notifications:
Create a
QObjectsubclass and add a custom signal to it. We create a class for selecting the application theme - it contains a single combobox where each item represents an available theme. The property backing attribute is_theme, initially set toNone. The signal,themeChanged, is emitted whenever the property value changes.Declare the property getter and setter. The property is named
themeand we declare its getter and setter the same way as in the previous section.Declare the property reset method.
resetTheme()setsthemeto its default value, contained in_default_theme.Declare the property itself, providing the getter, setter and reset methods, and the notify signal. The
themeproperty is a string and its setter emits the notify signal only when the new value is different from the property current value. The reset method simply calls the setter with the default theme name as the argument.
In the main window code, add the theme selector widget the layout, providing it the available themes (‘Light’, ‘Dark’ and ‘System’), We also add a push button to reset the theme, and five push buttons to demonstrate the theme change effects. When the user selects a theme, themeChanged is emitted and the theme colors are applied using a stylesheet.
When the user presses the Reset theme button, the theme property is set to its default value (‘System’). Instead of calling the reset method directly, this is done by calling QMetaProperty.reset().

21.3 Constant and Non-Stored Properties
The Qt property system supports both constant and non-stored properties. A constant property cannot have a getter method or a change notify signal. Marking a property as stored indicates that it doesn’t exist on its own but depends on other values and also indicates that it needs to be saved when storing the object’s state.
![]() |
You are building a user signup widget for a company portal. The widget uses a fixed email domain (@company.com) that applies to all users and never changes. Based on the user’s input, the widget automatically generates a username from the first and last name, and then forms the email address by combining that username with the company domain. |
To create constant and non-stored properties:
Subclass
QWidgetto create a custom widget. The company domain (‘company.com’) is constant so we just assign the string literal to a field. First and last name need to be provided by the user so we provide two line edits for their entry. Declare two properties,firstnameandlastnamewith getters and setters.Declare a constant property. The
domainproperty is declared as constant by setting the@Propertydecoratorconstantargument to false (the default is true).Declare non-stored properties. The
usernameandemailproperties are declared as non-stored by setting thestoredaragument to false and their value is provided based onfirstname,lastnameanddomainvalues. Note that neitherusernamenoremailhave setters declared.
Now, when you enter the user first and last name, the email field is updated automatically:

21.4 Dynamic Properties for Validation-Based Styling
Qt allows you to attach dynamic properties to any object using QObject.setProperty() by specifying a property name and value. Python natively supports dynamic properties too, which might make this Qt feature seem redundant in PySide6 applications. However, Qt style sheets support conditional widget styling based on Qt property values2 and this is where dynamic properties become useful, allowing you to flexibly (re)style widgets by setting or updating their custom properties.
![]() |
You are designing a user registration form featuring a QLineEdit field for email. To provide instant visual feedback, you set a dynamic property based on input validation (i.e., checking for valid email formats), and use Qt Style Sheets to apply the field borders, highlighting invalid entries in real-time. |
To use dynamic properties for conditional widget styling:
Add the widget that will be styled dynamically. Here, we need to style a line edit based on its text whenever it changes. The style changes are applied based on a simple regular expressions pattern that checks if a string is a valid email address. Validation is performed when the text changes so we connect
textChanged()to a slot.-
Set the style sheet for it. This is where the conditional styling happens based on a custom property named
isValid:- If the line edit does not have a dynamic property with that name (
QLineEdit) no custom styling is applied and it is styled using the application style sheet. - If
isValidexists and is set totrue(QLineEdit[isValid='true']) its border is set to color green. - If
isValidexists and its value isfalse(QLineEdit[isValid='false']) its border is set to red.
Set a dynamic property value to trigger conditional widget styling. In the
validate_email()slot check if the line edit contains empty text and if it is, remove theisValidproperty from the line edit object by setting it toNone. If the line edit contains text, validate it using Python’s regular expressions, and setisValidaccordingly. Finally, re-apply the style sheet by updating the line edit:
1 self.email_edit.style().unpolish(self.email_edit)
2 self.email_edit.style().polish(self.email_edit)
3 self.email_edit.update()
While the entered email address is invalid, the line edit has a red border:

21.5 Animating Custom Properties
The QPropertyAnimation class interpolates over Qt properties3, making it possible to animate Qt widgets.
![]() |
You are building an animated system monitor widget for a desktop app. The widget needs to be updated periodically and reusable across several indicators (CPU, RAM). |
To animate a custom Qt property:
Create a custom Qt widget and add a property to it. Here, the custom
AnimatedBarwidget is capable of displaying any indicator in the range from 0 to 100 percents using a progress bar. It also contains a label to display the current indicator value in percents. Add a custom property namedvalueto the widget and in its setter method update the inner progress bar value and the label text.AnimatedBarneeds to be reusable so external code passes a function that provides indicator values to it (data_function).Add a
QPropertyAnimationobject to the widget.QProperyAnimation.__init__()accepts the target object and the target property’s name as parameters. Set the animation’s duration and easing curve type as well.Animate the property. The property is animated periodically so we use a
QTimerto call therefresh()slot, in which we set the animation start and end values and start it.
Now, when you start the application, it shows two bars that animate the machine CPU and memory values and are updated each second. Note that you don’t set the property value explicitly but with calling QPropertyAnimation.setEndValue().

21.6 Inspecting Properties with QMetaObject
Qt’s meta-object system lets you inspect both static and dynamic properties of any QObject at runtime.
![]() |
You are building a property inspector widget for a desktop app. Given a target widget, the inspector lists all its static properties via QMetaObject followed by any dynamic properties. |
To inspect properties with QMetaObject:
Create a widget that inspects and displays an object’s properties. The widget name is
PropertyInspectorand its__init__()accepts the target widget as a parameter. It has a button to inspect the target object properties and a read-only text edit to display the results.Implement a method to inspect the target object’s properties. The
inspect()slot retrieves the targetsmetaObject(), loops frompropertyOffset()topropertyCount()toread static properties, then loops overdynamicProeprtyNames()to read dynamic properties. Use a try/except block when reading values as some of them may not be readable from Python.Create a property inspector object and add it to the main window. The example uses a
QlineEditas the target widget, setting its object name and adding one dynamic property withsetProperty()so both static and dynamic properties are shown.
Now, when you start the application and click the Inspect Properties button, the text edit shows every static proeprty of the QlineEdit (objectName, text, placeholderText, etc.) followed by the dynamic property extraData that you added at runtime.

