aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/doc/tutorials/basictutorial
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/doc/tutorials/basictutorial')
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/clickablebutton.pngbin0 -> 7059 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst95
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/dialog.pngbin0 -> 21263 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/dialog.rst149
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/greenapplication.pngbin0 -> 2089 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons.pngbin0 -> 1599 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons.zipbin0 -> 6156 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons/forward.pngbin0 -> 1113 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons/pause.pngbin0 -> 1001 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons/play.pngbin0 -> 970 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons/previous.pngbin0 -> 1050 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/icons/stop.pngbin0 -> 1064 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/player-new.pngbin0 -> 3369 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/player.pngbin0 -> 2631 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/qml.rst79
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst173
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst263
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/signals_slots.pngbin0 -> 14787 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/style.qss23
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/tablewidget.pngbin0 -> 14509 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/tablewidget.rst97
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/translations.pngbin0 -> 25318 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/translations.rst232
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/treewidget.pngbin0 -> 3709 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/treewidget.rst79
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/uifiles.pngbin0 -> 86503 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/uifiles.rst304
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgets.pngbin0 -> 23233 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgets.rst52
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling-no.pngbin0 -> 11004 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-no.pngbin0 -> 1206 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-yes.pngbin0 -> 1596 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling-yes.pngbin0 -> 24791 bytes
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling.py58
-rw-r--r--sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst171
35 files changed, 1775 insertions, 0 deletions
diff --git a/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.png b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.png
new file mode 100644
index 000000000..bfdc23fe0
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst
new file mode 100644
index 000000000..c5464640b
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst
@@ -0,0 +1,95 @@
+Using a Simple Button
+=====================
+
+In this tutorial, we'll show you how to handle **signals and slots**
+using Qt for Python. **Signals and slots** is a Qt feature that lets
+your graphical widgets communicate with other graphical widgets or
+your python code. Our application creates a button that logs the
+`Button clicked, Hello!` message to the python console each time you
+click it.
+
+Let's start by importing the necessary PySide6 classes and python
+`sys` module:
+::
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
+ from PySide6.QtCore import Slot
+
+Let's also create a python function that logs the message to the
+console:
+::
+
+ # Greetings
+ @Slot()
+ def say_hello():
+ print("Button clicked, Hello!")
+
+.. note:: The `@Slot()` is a decorator that identifies a function as
+ a slot. It is not important to understand why for now,
+ but use it always to avoid unexpected behavior.
+
+Now, as mentioned in previous examples you must create the
+`QApplication` to run your PySide6 code:
+::
+
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+
+Let's create the clickable button, which is a `QPushButton` instance.
+To label the button, we pass a python string to the constructor:
+::
+
+ # Create a button
+ button = QPushButton("Click me")
+
+Before we show the button, we must connect it to the `say_hello()`
+function that we defined earlier. There are two ways of doing this;
+using the old style or the new style, which is more pythonic. Let's
+use the new style in this case. You can find more information about
+both these styles in the
+`Signals and Slots in PySide6 <https://wiki.qt.io/Qt_for_Python_Signals_and_Slots>`_
+wiki page.
+
+The `QPushButton` has a predefined signal called **clicked**, which
+is triggered every time the button is clicked. We'll connect this
+signal to the `say_hello()` function:
+::
+
+ # Connect the button to the function
+ button.clicked.connect(say_hello)
+
+Finally, we show the button and start the Qt main loop:
+
+.. code-block:: python
+
+ # Show the button
+ button.show()
+ # Run the main Qt loop
+ app.exec()
+
+Here is the complete code for this example:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
+ from PySide6.QtCore import Slot
+
+ @Slot()
+ def say_hello():
+ print("Button clicked, Hello!")
+
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create a button, connect it and show it
+ button = QPushButton("Click me")
+ button.clicked.connect(say_hello)
+ button.show()
+ # Run the main Qt loop
+ app.exec()
+
+After a few clicks, you will get something like this on your terminal:
+
+.. image:: clickablebutton.png
+ :alt: Clickable Button Example
diff --git a/sources/pyside6/doc/tutorials/basictutorial/dialog.png b/sources/pyside6/doc/tutorials/basictutorial/dialog.png
new file mode 100644
index 000000000..ad5690927
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/dialog.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/dialog.rst b/sources/pyside6/doc/tutorials/basictutorial/dialog.rst
new file mode 100644
index 000000000..b7712672b
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/dialog.rst
@@ -0,0 +1,149 @@
+Creating a Dialog Application
+=============================
+
+This tutorial shows how to build a simple dialog with some
+basic widgets. The idea is to let users provide their name
+in a ``QLineEdit``, and the dialog greets them on click of a
+``QPushButton``.
+
+Let us just start with a simple stub that creates and shows
+a dialog. This stub is updated during the course of this
+tutorial, but you can use this stub as is if you need to:
+::
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QDialog, QLineEdit, QPushButton
+
+ class Form(QDialog):
+
+ def __init__(self, parent=None):
+ super(Form, self).__init__(parent)
+ self.setWindowTitle("My Form")
+
+
+ if __name__ == '__main__':
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create and show the form
+ form = Form()
+ form.show()
+ # Run the main Qt loop
+ sys.exit(app.exec())
+
+The imports aren't new to you, the same for the creation of the
+``QApplication`` and the execution of the Qt main loop.
+The only novelty here is the **class definition**.
+
+You can create any class that subclasses PySide6 widgets.
+In this case, we are subclassing ``QDialog`` to define a custom
+dialog, which we name as **Form**. We have also implemented the
+``init()`` method that calls the ``QDialog``'s init method with the
+parent widget, if any. Also, the new ``setWindowTitle()`` method
+just sets the title of the dialog window. In ``main()``, you can see
+that we are creating a *Form object* and showing it to the world.
+
+Create the Widgets
+------------------
+
+We are going to create two widgets: a ``QLineEdit`` where users can
+enter their name, and a ``QPushButton`` that prints the contents of
+the ``QLineEdit``.
+So, let's add the following code to the ``init()`` method of our Form:
+::
+
+ # Create widgets
+ self.edit = QLineEdit("Write my name here..")
+ self.button = QPushButton("Show Greetings")
+
+It's obvious from the code that both widgets will show the corresponding
+texts.
+
+Create a layout to organize the Widgets
+---------------------------------------
+
+Qt comes with layout-support that helps you organize the widgets
+in your application. In this case, let's use ``QVBoxLayout`` to lay out
+the widgets vertically. Add the following code to the ``init()`` method,
+after creating the widgets:
+::
+
+ # Create layout and add widgets
+ layout = QVBoxLayout(self)
+ layout.addWidget(self.edit)
+ layout.addWidget(self.button)
+
+So, we create the layout, add the widgets with ``addWidget()``.
+
+Create the function to greet and connect the Button
+---------------------------------------------------
+
+Finally, we just have to add a function to our custom **Form**
+and *connect* our button to it. Our function will be a part of
+the Form, so you have to add it after the ``init()`` function:
+::
+
+ # Greets the user
+ def greetings(self):
+ print(f"Hello {self.edit.text()}")
+
+Our function just prints the contents of the ``QLineEdit`` to the
+python console. We have access to the text by means of the
+``QLineEdit.text()`` method.
+
+Now that we have everything, we just need to *connect* the
+``QPushButton`` to the ``Form.greetings()`` method. To do so, add the
+following line to the ``init()`` method:
+::
+
+ # Add button signal to greetings slot
+ self.button.clicked.connect(self.greetings)
+
+Once executed, you can enter your name in the ``QLineEdit`` and watch
+the console for greetings.
+
+Complete code
+-------------
+
+Here is the complete code for this tutorial:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import (QLineEdit, QPushButton, QApplication,
+ QVBoxLayout, QDialog)
+
+ class Form(QDialog):
+
+ def __init__(self, parent=None):
+ super(Form, self).__init__(parent)
+ # Create widgets
+ self.edit = QLineEdit("Write my name here")
+ self.button = QPushButton("Show Greetings")
+ # Create layout and add widgets
+ layout = QVBoxLayout()
+ layout.addWidget(self.edit)
+ layout.addWidget(self.button)
+ # Set dialog layout
+ self.setLayout(layout)
+ # Add button signal to greetings slot
+ self.button.clicked.connect(self.greetings)
+
+ # Greets the user
+ def greetings(self):
+ print(f"Hello {self.edit.text()}")
+
+ if __name__ == '__main__':
+ # Create the Qt Application
+ app = QApplication(sys.argv)
+ # Create and show the form
+ form = Form()
+ form.show()
+ # Run the main Qt loop
+ sys.exit(app.exec())
+
+
+When you execute the code, and write down your name,
+the button will display messages on the terminal:
+
+.. image:: dialog.png
+ :alt: Simple Dialog Example
diff --git a/sources/pyside6/doc/tutorials/basictutorial/greenapplication.png b/sources/pyside6/doc/tutorials/basictutorial/greenapplication.png
new file mode 100644
index 000000000..29ea0a701
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/greenapplication.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons.png b/sources/pyside6/doc/tutorials/basictutorial/icons.png
new file mode 100644
index 000000000..a5a554eba
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons.zip b/sources/pyside6/doc/tutorials/basictutorial/icons.zip
new file mode 100644
index 000000000..e279e37b8
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons.zip
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons/forward.png b/sources/pyside6/doc/tutorials/basictutorial/icons/forward.png
new file mode 100644
index 000000000..c7a532dfe
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons/forward.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons/pause.png b/sources/pyside6/doc/tutorials/basictutorial/icons/pause.png
new file mode 100644
index 000000000..d0beadb43
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons/pause.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons/play.png b/sources/pyside6/doc/tutorials/basictutorial/icons/play.png
new file mode 100644
index 000000000..345685337
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons/play.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons/previous.png b/sources/pyside6/doc/tutorials/basictutorial/icons/previous.png
new file mode 100644
index 000000000..979f18565
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons/previous.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons/stop.png b/sources/pyside6/doc/tutorials/basictutorial/icons/stop.png
new file mode 100644
index 000000000..1e88ded3a
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/icons/stop.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/player-new.png b/sources/pyside6/doc/tutorials/basictutorial/player-new.png
new file mode 100644
index 000000000..8e45c757d
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/player-new.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/player.png b/sources/pyside6/doc/tutorials/basictutorial/player.png
new file mode 100644
index 000000000..0563d3223
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/player.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/qml.rst b/sources/pyside6/doc/tutorials/basictutorial/qml.rst
new file mode 100644
index 000000000..49cd3d94a
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/qml.rst
@@ -0,0 +1,79 @@
+Your First QtQuick/QML Application
+**********************************
+
+QML_ is a declarative language that lets you develop applications
+faster than with traditional languages. It is ideal for designing the
+UI of your application because of its declarative nature. In QML, a
+user interface is specified as a tree of objects with properties. In
+this tutorial, we will show how to make a simple "Hello World"
+application with PySide6 and QML.
+
+A PySide6/QML application consists, at least, of two different files -
+a file with the QML description of the user interface, and a python file
+that loads the QML file. To make things easier, let's save both files in
+the same directory.
+
+Here is a simple QML file called :code:`view.qml`:
+
+.. code-block:: javascript
+
+ import QtQuick
+
+ Rectangle {
+ id: main
+ width: 200
+ height: 200
+ color: "green"
+
+ Text {
+ text: "Hello World"
+ anchors.centerIn: main
+ }
+ }
+
+We start by importing :code:`QtQuick`, which is a QML module.
+
+The rest of the QML code is pretty straightforward for those who
+have previously used HTML or XML files. Basically, we are creating
+a green rectangle with the size `200*200`, and adding a Text element
+that reads "Hello World". The code :code:`anchors.centerIn: main` makes
+the text appear centered within the object with :code:`id: main`,
+which is the Rectangle in this case.
+
+Now, let's see how the code looks on the PySide6.
+Let's call it :code:`main.py`:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication
+ from PySide6.QtQuick import QQuickView
+
+ if __name__ == "__main__":
+ app = QApplication()
+ view = QQuickView()
+
+ view.setSource("view.qml")
+ view.show()
+ sys.exit(app.exec())
+
+If you are already familiar with PySide6 and have followed our
+tutorials, you have already seen much of this code.
+The only novelties are that you must :code:`import QtQuick` and set the
+source of the :code:`QQuickView` object to the URL of your QML file.
+Then, similar to what you do with any Qt widget, you call
+:code:`QQuickView.show()`.
+
+.. note:: If you are programming for desktop, you should consider
+ adding `view.setResizeMode(QQuickView.SizeRootObjectToView)`
+ before showing the view.
+
+When you execute the :code:`main.py` script, you will see the following
+application:
+
+
+.. image:: greenapplication.png
+ :alt: Simple QML and Python example
+ :align: center
+
+.. _QML: https://doc.qt.io/qt-6/qmlapplications.html
diff --git a/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst b/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst
new file mode 100644
index 000000000..858293beb
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst
@@ -0,0 +1,173 @@
+.. _using_qrc_files:
+
+Using ``.qrc`` Files (``pyside6-rcc``)
+**************************************
+
+The `Qt Resource System`_ is a mechanism for storing binary files
+in an application.
+
+The files will be embedded into the application and be acessible for the
+``QFile`` class and the constructors of the ``QIcon`` and ``QPixmap``
+classes taking a file name by using a special file name starting with ``:/``.
+
+The most common uses are for custom images, icons, fonts, among others.
+
+In this tutorial you will learn how to load custom images as button icons.
+
+For inspiration, we will try to adapt the multimedia player example
+from Qt.
+
+As you can see on the following image, the ``QPushButton`` that are used
+for the media actions (play, pause, stop, and so on) are using the
+default icons meant for such actions.
+
+.. image:: player.png
+ :alt: Multimedia Player Qt Example
+
+You could make the application more attractive by designing the icons,
+but in case you don't want to design them, you can download and use them.
+
+:download:`Download icons <icons.zip>`
+
+.. image:: icons.png
+ :alt: New Multimedia icons
+
+You can find more information about the ``rcc`` command, and ``.qrc`` file
+format, and the resource system in general in the `Qt Resource System`_
+site.
+
+
+The ``.qrc`` file
+=================
+
+Before running any command, add information about the resources to a ``.qrc``
+file.
+In the following example, notice how the resources are listed in ``icons.qrc``
+
+::
+
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+ <file>icons/play.png</file>
+ <file>icons/pause.png</file>
+ <file>icons/stop.png</file>
+ <file>icons/previous.png</file>
+ <file>icons/forward.png</file>
+ </qresource>
+ </RCC>
+
+
+Generating a Python file
+=========================
+
+Now that the ``icons.qrc`` file is ready, use the ``pyside6-rcc`` tool to generate
+a Python class containing the binary information about the resources
+
+To do this, we need to run::
+
+ pyside6-rcc icons.qrc -o rc_icons.py
+
+The ``-o`` option lets you specify the output filename,
+which is ``rc_icons.py`` in this case.
+
+To use the generated file, add the following import at the top of your main Python file::
+
+ import rc_icons
+
+
+Changes in the code
+===================
+
+As you are modifying an existing example, you need to modify the following
+lines:
+
+.. code-block:: python
+
+ from PySide6.QtGui import QIcon, QKeySequence
+ playIcon = self.style().standardIcon(QStyle.SP_MediaPlay)
+ previousIcon = self.style().standardIcon(QStyle.SP_MediaSkipBackward)
+ pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause)
+ nextIcon = self.style().standardIcon(QStyle.SP_MediaSkipForward)
+ stopIcon = self.style().standardIcon(QStyle.SP_MediaStop)
+
+and replace them with the following:
+
+.. code-block:: python
+
+ from PySide6.QtGui import QIcon, QKeySequence, QPixmap
+ playIcon = QIcon(QPixmap(":/icons/play.png"))
+ previousIcon = QIcon(QPixmap(":/icons/previous.png"))
+ pauseIcon = QIcon(QPixmap(":/icons/pause.png"))
+ nextIcon = QIcon(QPixmap(":/icons/forward.png"))
+ stopIcon = QIcon(QPixmap(":/icons/stop.png"))
+
+This ensures that the new icons are used instead of the default ones provided
+by the application theme.
+Notice that the lines are not consecutive, but are in different parts
+of the file.
+
+After all your imports, add the following
+
+.. code-block:: python
+
+ import rc_icons
+
+Now, the constructor of your class should look like this:
+
+.. code-block:: python
+
+ def __init__(self):
+ super(MainWindow, self).__init__()
+
+ self.playlist = QMediaPlaylist()
+ self.player = QMediaPlayer()
+
+ toolBar = QToolBar()
+ self.addToolBar(toolBar)
+
+ fileMenu = self.menuBar().addMenu("&File")
+ openAction = QAction(QIcon.fromTheme("document-open"),
+ "&Open...", self, shortcut=QKeySequence.Open,
+ triggered=self.open)
+ fileMenu.addAction(openAction)
+ exitAction = QAction(QIcon.fromTheme("application-exit"), "E&xit",
+ self, shortcut="Ctrl+Q", triggered=self.close)
+ fileMenu.addAction(exitAction)
+
+ playMenu = self.menuBar().addMenu("&Play")
+ playIcon = QIcon(QPixmap(":/icons/play.png"))
+ self.playAction = toolBar.addAction(playIcon, "Play")
+ self.playAction.triggered.connect(self.player.play)
+ playMenu.addAction(self.playAction)
+
+ previousIcon = QIcon(QPixmap(":/icons/previous.png"))
+ self.previousAction = toolBar.addAction(previousIcon, "Previous")
+ self.previousAction.triggered.connect(self.previousClicked)
+ playMenu.addAction(self.previousAction)
+
+ pauseIcon = QIcon(QPixmap(":/icons/pause.png"))
+ self.pauseAction = toolBar.addAction(pauseIcon, "Pause")
+ self.pauseAction.triggered.connect(self.player.pause)
+ playMenu.addAction(self.pauseAction)
+
+ nextIcon = QIcon(QPixmap(":/icons/forward.png"))
+ self.nextAction = toolBar.addAction(nextIcon, "Next")
+ self.nextAction.triggered.connect(self.playlist.next)
+ playMenu.addAction(self.nextAction)
+
+ stopIcon = QIcon(QPixmap(":/icons/stop.png"))
+ self.stopAction = toolBar.addAction(stopIcon, "Stop")
+ self.stopAction.triggered.connect(self.player.stop)
+ playMenu.addAction(self.stopAction)
+
+ # many lines were omitted
+
+Executing the example
+=====================
+
+Run the application by calling ``python main.py`` to checkout the new icon-set:
+
+.. image:: player-new.png
+ :alt: New Multimedia Player Qt Example
+
+.. _`Qt Resource System`: https://doc.qt.io/qt-5/resources.html
diff --git a/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
new file mode 100644
index 000000000..0bfd9e276
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst
@@ -0,0 +1,263 @@
+.. _signals-and-slots:
+
+Signals and Slots
+=================
+
+Due to the nature of Qt, ``QObject``\s require a way to communicate, and that's
+the reason for this mechanism to be a **central feature of Qt**.
+
+In simple terms, you can understand **Signal and Slots** in the same way you
+interact with the lights in your house. When you move the light switch
+(signal) you get a result which may be that your light bulbs are switched
+on/off (slot).
+
+While developing interfaces, you can get a real example by the effect of
+clicking a button: the 'click' will be the signal, and the slot will be what
+happens when that button is clicked, like closing a window, saving a document,
+etc.
+
+.. note::
+ If you have experience with other frameworks or toolkits, it's likely
+ that you read a concept called 'callback'. Leaving the implementation
+ details aside, a callback will be related to a notification function,
+ passing a pointer to a function in case it's required due to the events
+ that happen in your program. This approach might sound similar, but
+ there are essential differences that make it an unintuitive approach,
+ like ensuring the type correctness of callback arguments, and some others.
+
+All classes that inherit from ``QObject`` or one of its subclasses, like
+``QWidget`` can contain signals and slots. **Signals are emitted by objects**
+when they change their state in a way that may be interesting to other objects.
+This is all the object does to communicate. It does not know or care whether
+anything is receiving the signals it emits. This is true information
+encapsulation, and ensures that the object can be used as a software component.
+
+**Slots can be used for receiving signals**, but they are also normal member
+functions. Just as an object does not know if anything receives its signals,
+a slot does not know if it has any signals connected to it. This ensures that
+truly independent components can be created with Qt.
+
+You can connect as many signals as you want to a single slot, and a signal can
+be connected to as many slots as you need. It is even possible to connect
+a signal directly to another signal. (This will emit the second signal
+immediately whenever the first is emitted.)
+
+Qt's widgets have many predefined signals and slots. For example,
+``QAbstractButton`` (base class of buttons in Qt) has a ``clicked()``
+signal and ``QLineEdit`` (single line input field) has a slot named
+``clear()``. So, a text input field with a button to clear the text
+could be implemented by placing a ``QToolButton`` to the right of the
+``QLineEdit`` and connecting its ``clicked()`` signal to the slot
+``clear()``. This is done using the ``connect()`` method of the signal:
+
+.. code-block:: python
+
+ button = QToolButton()
+ line_edit = QLineEdit()
+ button.clicked.connect(line_edit.clear)
+
+``connect()`` returns a ``QMetaObject.Connection`` object, which can be
+used with the ``disconnect()`` method to sever the connection.
+
+Signals can also be connected to free functions:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
+
+
+ def function():
+ print("The 'function' has been called!")
+
+ app = QApplication()
+ button = QPushButton("Call function")
+ button.clicked.connect(function)
+ button.show()
+ sys.exit(app.exec())
+
+Connections can be spelled out in code or, for widget forms,
+designed in the
+`Signal-Slot Editor <https://doc.qt.io/qt-6/designer-connection-mode.html>`_
+of *Qt Widgets Designer*.
+
+The Signal Class
+----------------
+
+When writing classes in Python, signals are declared as class level
+variables of the class ``QtCore.Signal()``. A QWidget-based button
+that emits a ``clicked()`` signal could look as
+follows:
+
+.. code-block:: python
+
+ from PySide6.QtCore import Qt, Signal
+ from PySide6.QtWidgets import QWidget
+
+ class Button(QWidget):
+
+ clicked = Signal(Qt.MouseButton)
+
+ ...
+
+ def mousePressEvent(self, event):
+ self.clicked.emit(event.button())
+
+The constructor of ``Signal`` takes a tuple or a list of Python types
+and C types:
+
+.. code-block:: python
+
+ signal1 = Signal(int) # Python types
+ signal2 = Signal(QUrl) # Qt Types
+ signal3 = Signal(int, str, int) # more than one type
+ signal4 = Signal((float,), (QDate,)) # optional types
+
+In addition to that, it can receive also a named argument ``name`` that defines
+the signal name. If nothing is passed, the new signal will have the same name
+as the variable that it is being assigned to.
+
+.. code-block:: python
+
+ # TODO
+ signal5 = Signal(int, name='rangeChanged')
+ # ...
+ rangeChanged.emit(...)
+
+Another useful option of ``Signal`` is the arguments name,
+useful for QML applications to refer to the emitted values by name:
+
+.. code-block:: python
+
+ sumResult = Signal(int, arguments=['sum'])
+
+.. code-block:: javascript
+
+ Connections {
+ target: ...
+ function onSumResult(sum) {
+ // do something with 'sum'
+ }
+
+
+.. _slot-decorator:
+
+The Slot Class
+--------------
+
+Slots in QObject-derived classes should be indicated by the decorator
+``@QtCore.Slot()``. Again, to define a signature just pass the types
+similar to the ``QtCore.Signal()`` class.
+
+.. code-block:: python
+
+ @Slot(str)
+ def slot_function(self, s):
+ ...
+
+
+``Slot()`` also accepts a ``name`` and a ``result`` keyword.
+The ``result`` keyword defines the type that will be returned and can be a C or
+Python type. The ``name`` keyword behaves the same way as in ``Signal()``. If
+nothing is passed as name then the new slot will have the same name as the
+function that is being decorated.
+
+We recommend marking all methods used by signal connections with a
+``@QtCore.Slot()`` decorator. Not doing causes run-time overhead due to the
+method being added to the ``QMetaObject`` when creating the connection. This is
+particularly important for ``QObject`` classes registered with QML, where
+missing decorators can introduce bugs.
+
+Missing decorators can be diagnosed by setting activating warnings of the
+logging category ``qt.pyside.libpyside``; for example by setting the
+environment variable:
+
+.. code-block:: bash
+
+ export QT_LOGGING_RULES="qt.pyside.libpyside.warning=true"
+
+.. _overloading-signals-and-slots:
+
+Overloading Signals and Slots with Different Types
+--------------------------------------------------
+
+It is actually possible to use signals and slots of the same name with different
+parameter type lists. This is legacy from Qt 5 and not recommended for new code.
+In Qt 6, signals have distinct names for different types.
+
+The following example uses two handlers for a Signal and a Slot to showcase
+the different functionality.
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QPushButton
+ from PySide6.QtCore import QObject, Signal, Slot
+
+
+ class Communicate(QObject):
+ # create two new signals on the fly: one will handle
+ # int type, the other will handle strings
+ speak = Signal((int,), (str,))
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+
+ self.speak[int].connect(self.say_something)
+ self.speak[str].connect(self.say_something)
+
+ # define a new slot that receives a C 'int' or a 'str'
+ # and has 'say_something' as its name
+ @Slot(int)
+ @Slot(str)
+ def say_something(self, arg):
+ if isinstance(arg, int):
+ print("This is a number:", arg)
+ elif isinstance(arg, str):
+ print("This is a string:", arg)
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+ someone = Communicate()
+
+ # emit 'speak' signal with different arguments.
+ # we have to specify the str as int is the default
+ someone.speak.emit(10)
+ someone.speak[str].emit("Hello everybody!")
+
+
+.. _signals-and-slots-strings:
+
+Specifying Signals and Slots by Method Signature Strings
+--------------------------------------------------------
+
+
+Signals and slots can also be specified as C++ method signature
+strings passed through the ``SIGNAL()`` and/or ``SLOT()`` functions:
+
+.. code-block:: python
+
+ from PySide6.QtCore import SIGNAL, SLOT
+
+ button.connect(SIGNAL("clicked(Qt::MouseButton)"),
+ action_handler, SLOT("action1(Qt::MouseButton)"))
+
+This is not normally recommended; it is only needed
+for a few cases where signals are only accessible via ``QMetaObject``
+(``QAxObject``, ``QAxWidget``, ``QDBusInterface`` or ``QWizardPage::registerField()``):
+
+.. code-block:: python
+
+ wizard.registerField("text", line_edit, "text",
+ SIGNAL("textChanged(QString)"))
+
+The signature strings can be found by querying ``QMetaMethod.methodSignature()``
+when introspecting ``QMetaObject``:
+
+.. code-block:: python
+
+ mo = widget.metaObject()
+ for m in range(mo.methodOffset(), mo.methodCount()):
+ print(mo.method(m).methodSignature())
+
+Slots should be decorated using :ref:`@Slot <slot-decorator>`.
diff --git a/sources/pyside6/doc/tutorials/basictutorial/signals_slots.png b/sources/pyside6/doc/tutorials/basictutorial/signals_slots.png
new file mode 100644
index 000000000..0801cf16e
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/signals_slots.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/style.qss b/sources/pyside6/doc/tutorials/basictutorial/style.qss
new file mode 100644
index 000000000..b84b98f05
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/style.qss
@@ -0,0 +1,23 @@
+QListWidget {
+ color: #FFFFFF;
+ background-color: #33373B;
+}
+
+QListWidget::item {
+ height: 50px;
+}
+
+QListWidget::item:selected {
+ background-color: #2ABf9E;
+}
+
+QLabel {
+ background-color: #FFFFFF;
+ qproperty-alignment: AlignCenter;
+}
+
+QPushButton {
+ background-color: #2ABf9E;
+ padding: 20px;
+ font-size: 18px;
+}
diff --git a/sources/pyside6/doc/tutorials/basictutorial/tablewidget.png b/sources/pyside6/doc/tutorials/basictutorial/tablewidget.png
new file mode 100644
index 000000000..e2549f7d0
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/tablewidget.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/tablewidget.rst b/sources/pyside6/doc/tutorials/basictutorial/tablewidget.rst
new file mode 100644
index 000000000..5c04529fd
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/tablewidget.rst
@@ -0,0 +1,97 @@
+Displaying Data Using a Table Widget
+====================================
+
+If you want to display data arranged in a table, use a ``QTableWidget`` to do
+so, without dealing with much configuration.
+
+Notice that using a ``QTableWidget`` is not the only path to display
+information in tables. You can also create a data model and display it using
+a ``QTableView``, but that is not in the scope of this tutorial.
+
+.. note:: This Widget is a ready-to-use version of something you can customize
+ further on. To know more about the Model/View architecture in Qt, refer to
+ its `official documentation <https://doc.qt.io/qt-6/model-view-programming.html>`_.
+
+1. Import ``QTableWidget``, ``QTableWidgetItem``, and ``QColor`` to display
+ background colors:
+
+ .. code-block:: python
+
+ import sys
+ from PySide6.QtGui import QColor
+ from PySide6.QtWidgets import (QApplication, QTableWidget,
+ QTableWidgetItem)
+
+2. Create a simple data model containing the list of names and hex codes for
+ different colors:
+
+ .. code-block:: python
+
+ colors = [("Red", "#FF0000"),
+ ("Green", "#00FF00"),
+ ("Blue", "#0000FF"),
+ ("Black", "#000000"),
+ ("White", "#FFFFFF"),
+ ("Electric Green", "#41CD52"),
+ ("Dark Blue", "#222840"),
+ ("Yellow", "#F9E56d")]
+
+3. Define a function to translate the hex code into an RGB equivalent:
+
+ .. code-block:: python
+
+ def get_rgb_from_hex(code):
+ code_hex = code.replace("#", "")
+ rgb = tuple(int(code_hex[i:i+2], 16) for i in (0, 2, 4))
+ return QColor.fromRgb(rgb[0], rgb[1], rgb[2])
+
+4. Initialize the ``QApplication`` singleton:
+
+ .. code-block:: python
+
+ app = QApplication()
+
+5. Configure the ``QTableWidget`` to have a number of rows equivalent
+ to the amount of items from the ``colors`` structure, and a number of
+ columns with the members of one color entry, plus one.
+ You can set the column name using the ``setHorizontalHeaderLabels`` as
+ described below:
+
+ .. code-block:: python
+
+ table = QTableWidget()
+ table.setRowCount(len(colors))
+ table.setColumnCount(len(colors[0]) + 1)
+ table.setHorizontalHeaderLabels(["Name", "Hex Code", "Color"])
+
+ .. note:: the reason of using ``+ 1`` is to include a new column where
+ we can display the color.
+
+6. Iterate the data structure, create the ``QTableWidgetItems`` instances, and
+ add them into the table using a ``x, y`` coordinate. Here the data is being
+ assigned row-per-row:
+
+ .. code-block:: python
+
+ for i, (name, code) in enumerate(colors):
+ item_name = QTableWidgetItem(name)
+ item_code = QTableWidgetItem(code)
+ item_color = QTableWidgetItem()
+ item_color.setBackground(get_rgb_from_hex(code))
+ table.setItem(i, 0, item_name)
+ table.setItem(i, 1, item_code)
+ table.setItem(i, 2, item_color)
+
+7. Show the table and execute the ``QApplication``.
+
+ .. code-block:: python
+
+ table.show()
+ sys.exit(app.exec())
+
+
+The final application will look like this:
+
+.. image:: tablewidget.png
+ :alt: QTableWidget example
+ :align: center
diff --git a/sources/pyside6/doc/tutorials/basictutorial/translations.png b/sources/pyside6/doc/tutorials/basictutorial/translations.png
new file mode 100644
index 000000000..b9fc1ba17
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/translations.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/translations.rst b/sources/pyside6/doc/tutorials/basictutorial/translations.rst
new file mode 100644
index 000000000..21c16cdcd
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/translations.rst
@@ -0,0 +1,232 @@
+.. _translations:
+
+Translating Applications
+========================
+
+.. image:: translations.png
+ :alt: Translation Image
+
+Qt Linguist
+-----------
+
+`Qt Linguist`_ and
+its related tools can be used to provide translations for applications.
+
+The :ref:`qt-linguist-example` example illustrates this. The example is
+very simple, it has a menu and shows a list of programming languages with
+multiselection.
+
+Translation works by passing the message strings through function calls that
+look up the translation. Each ``QObject`` instance provides a ``tr()``
+function for that purpose. There is also ``QCoreApplication.translate()``
+for adding translated texts to non-QObject classes.
+
+Qt ships its own translations containing the error messages and standard
+dialog captions.
+
+The linguist example has a number of messages enclosed in ``self.tr()``.
+The status bar message shown in response to a selection change uses
+a plural form depending on a count:
+
+.. code-block:: python
+
+ count = len(self._list_widget.selectionModel().selectedRows())
+ message = self.tr("%n language(s) selected", "", count)
+
+The translation workflow for the example is as follows:
+The translated messages are extracted using the ``lupdate`` tool,
+producing XML-based ``.ts`` files:
+
+.. code-block:: bash
+
+ pyside6-lupdate main.py -ts example_de.ts
+
+If ``example_de.ts`` already exists, it will be updated with the new
+messages added to the code in-between.
+
+If there are form files (``.ui``) and/or QML files (``.qml``) in the project,
+they should be passed to the ``pyside6-lupdate`` tool as well:
+
+.. code-block:: bash
+
+ pyside6-lupdate main.py main.qml form.ui -ts example_de.ts
+
+The source files generated by ``pyside6-uic`` from the form files
+should **not** be passed.
+
+The ``lupdate`` mode of ``pyside6-project`` can also be used for this. It
+collects all source files and runs ``pyside6-lupdate`` when ``.ts`` file(s)
+are given in the ``.pyproject`` file:
+
+.. code-block:: bash
+
+ pyside6-project lupdate .
+
+``.ts`` files are translated using *Qt Linguist*. Once this is complete,
+the files are converted to a binary form (``.qm`` files):
+
+.. code-block:: bash
+
+ pyside6-lrelease example_de.ts -qm example_de.qm
+
+``pyside6-project`` will build the ``.qm`` file automatically when
+``.ts`` file(s) are given in the ``.pyproject`` file:
+
+.. code-block:: bash
+
+ pyside6-project build .
+
+To avoid having to ship the ``.qm`` files, it is recommend
+to put them into a Qt resource file along with icons and other
+applications resources (see :ref:`using_qrc_files`).
+The resource file ``linguist.qrc`` provides the ``example_de.qm``
+under ``:/translations``:
+
+.. code-block:: xml
+
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource prefix="translations">
+ <file>example_de.qm</file>
+ </qresource>
+ </RCC>
+
+At runtime, the translations need to be loaded using the ``QTranslator`` class:
+
+.. code-block:: python
+
+ path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
+ translator = QTranslator(app)
+ if translator.load(QLocale.system(), 'qtbase', '_', path):
+ app.installTranslator(translator)
+ translator = QTranslator(app)
+ path = ':/translations'
+ if translator.load(QLocale.system(), 'example', '_', path):
+ app.installTranslator(translator)
+
+The code first loads the translations shipped for Qt and then
+the translations of the applications loaded from resources.
+
+The example can then be run in German:
+
+.. code-block:: bash
+
+ LANG=de python main.py
+
+.. _Qt Linguist: https://doc.qt.io/qt-6/qtlinguist-index.html
+
+GNU gettext
+-----------
+
+The `GNU gettext`_ module
+can be used to provide translations for applications.
+
+The :ref:`gettext-example` example illustrates this. The example is
+very simple, it has a menu and shows a list of programming languages with
+multiselection.
+
+Translation works by passing the message strings through function calls that
+look up the translation. It is common to alias the main translation function
+to ``_``. There is a special translation function for sentences that contain
+a plural form depending on a count ("{0} items(s) selected"). It is commonly
+aliased to ``ngettext``.
+
+Those functions are defined at the top:
+
+.. code-block:: python
+
+ import gettext
+ # ...
+ _ = None
+ ngettext = None
+
+and later assigned as follows:
+
+.. code-block:: python
+
+ src_dir = Path(__file__).resolve().parent
+ try:
+ translation = gettext.translation('example', localedir=src_dir / 'locales')
+ if translation:
+ translation.install()
+ _ = translation.gettext
+ ngettext = translation.ngettext
+ except FileNotFoundError:
+ pass
+ if not _:
+ _ = gettext.gettext
+ ngettext = gettext.ngettext
+
+This specifies that our translation file has the base name ``example`` and
+will be found in the source tree under ``locales``. The code will try
+to load a translation matching the current language.
+
+Messages to be translated look like:
+
+.. code-block:: python
+
+ file_menu = self.menuBar().addMenu(_("&File"))
+
+The status bar message shown in response to a selection change uses
+a plural form depending on a count:
+
+.. code-block:: python
+
+ count = len(self._list_widget.selectionModel().selectedRows())
+ message = ngettext("{0} language selected",
+ "{0} languages selected", count).format(count)
+
+The ``ngettext()`` function takes the singular form, plural form and the count.
+The returned string still contains the formatting placeholder, so it needs
+to be passed through ``format()``.
+
+In order to translate the messages to say German, a template file (``.pot``)
+is first created:
+
+.. code-block:: bash
+
+ mkdir -p locales/de_DE/LC_MESSAGES
+ xgettext -L Python -o locales/example.pot main.py
+
+This file has a few generic placeholders which can be replaced by the
+appropriate values. It is then copied to the ``de_DE/LC_MESSAGES`` directory.
+
+.. code-block:: bash
+
+ cd locales/de_DE/LC_MESSAGES/
+ cp ../../example.pot .
+
+Further adaptions need to be made to account for the German plural
+form and encoding:
+
+.. code-block::
+
+ "Project-Id-Version: PySide6 gettext example\n"
+ "POT-Creation-Date: 2021-07-05 14:16+0200\n"
+ "Language: de_DE\n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+Below, the translated messages can be given:
+
+.. code-block::
+
+ #: main.py:57
+ msgid "&File"
+ msgstr "&Datei"
+
+Finally, the ``.pot`` is converted to its binary form (machine object file,
+``.mo``), which needs to be deployed:
+
+.. code-block:: bash
+
+ msgfmt -o example.mo example.pot
+
+The example can then be run in German:
+
+.. code-block:: bash
+
+ LANG=de python main.py
+
+.. _GNU gettext: https://docs.python.org/3/library/gettext.html
diff --git a/sources/pyside6/doc/tutorials/basictutorial/treewidget.png b/sources/pyside6/doc/tutorials/basictutorial/treewidget.png
new file mode 100644
index 000000000..990fe977b
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/treewidget.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst b/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst
new file mode 100644
index 000000000..f431cb5c4
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst
@@ -0,0 +1,79 @@
+Displaying Data Using a Tree Widget
+===================================
+
+If you want to display data arranged in a tree, use a ``QTreeWidget`` to do so.
+
+Notice that using a ``QTreeWidget`` is not the only path to display
+information in trees. You can also create a data model and display it using a
+``QTreeView``, but that is not in the scope of this tutorial.
+
+.. note:: This Widget is a ready-to-use version of something you can customize
+ further on. To know more about the Model/View architecture in Qt, refer to
+ its `official documentation <https://doc.qt.io/qt-6/model-view-programming.html>`_.
+
+#. Import ``QTreeWidget`` and ``QTreeWidgetItem`` for this application:
+
+ .. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem
+
+#. Define a dictionary with project structures to display the information as a
+ tree, with files belonging to each project:
+
+ .. code-block:: python
+
+ data = {"Project A": ["file_a.py", "file_a.txt", "something.xls"],
+ "Project B": ["file_b.csv", "photo.jpg"],
+ "Project C": []}
+
+#. Initialize the ``QApplication`` singleton:
+
+ .. code-block:: python
+
+ app = QApplication()
+
+#. Configure the ``QTreeWidget`` to have two columns, one for the item name,
+ and the other for item type information of the files in the project
+ directories.
+ You can set the column name with the ``setHeaderLabels`` as described below:
+
+ .. code-block:: python
+
+ tree = QTreeWidget()
+ tree.setColumnCount(2)
+ tree.setHeaderLabels(["Name", "Type"])
+
+#. Iterate the data structure, create the ``QTreeWidgetItem`` elements, and add
+ the corresponding children to each parent.
+ We also extract the extension name for only the files and add them
+ into the second column.
+ In the constructor, you can see that each element (``QTreeWidgetItem``) is
+ added to different columns of the tree (``QTreeWidget``).
+
+ .. code-block:: python
+
+ items = []
+ for key, values in data.items():
+ item = QTreeWidgetItem([key])
+ for value in values:
+ ext = value.split(".")[-1].upper()
+ child = QTreeWidgetItem([value, ext])
+ item.addChild(child)
+ items.append(item)
+
+ tree.insertTopLevelItems(0, items)
+
+#. Show the tree and execute the ``QApplication``.
+
+ .. code-block:: python
+
+ tree.show()
+ sys.exit(app.exec())
+
+
+The final application will look like this:
+
+.. image:: treewidget.png
+ :alt: QTreeWidget example
+ :align: center
diff --git a/sources/pyside6/doc/tutorials/basictutorial/uifiles.png b/sources/pyside6/doc/tutorials/basictutorial/uifiles.png
new file mode 100644
index 000000000..918efec6d
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/uifiles.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst b/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst
new file mode 100644
index 000000000..cb945908d
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst
@@ -0,0 +1,304 @@
+.. _using_ui_files:
+
+Using ``.ui`` files from Designer or QtCreator with ``QUiLoader`` and ``pyside6-uic``
+*************************************************************************************
+
+This page describes the use of
+`Qt Widgets Designer <https://doc.qt.io/qt-6/qtdesigner-manual.html>`_ to create
+graphical interfaces based on Qt Widgets for your Qt for Python project.
+*Qt Widgets Designer* is a graphical UI design tool which is available as a
+standalone binary (``pyside6-designer``) or embedded into the
+`Qt Creator IDE <https://doc.qt.io/qtcreator>`_. Its use within *Qt Creator*
+is described at
+`Using Qt Widgets Designer <https://doc.qt.io/qtcreator/creator-using-qt-designer.html>`_.
+
+.. image:: uifiles.png
+ :alt: Designer and the equivalent code
+
+The designs are stored in ``.ui`` files, which is an XML-based format. It will
+be converted to Python or C++ code populating a widget instance at project build
+time by the `pyside6-uic <https://doc.qt.io/qt-6/uic.html>`_ tool.
+
+To create a new Qt Design Form in *Qt Creator*, choose
+``File/New File Or Project`` and "Main Window" for template. Save it as
+``mainwindow.ui``. Add a ``QPushButton`` to the center of the centralwidget.
+
+Your file ``mainwindow.ui`` should look something like this:
+
+.. code-block:: xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MainWindow</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <widget class="QPushButton" name="pushButton">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>80</y>
+ <width>201</width>
+ <height>81</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>20</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+ </ui>
+
+Now we are ready to decide how to use the **UI file** from Python.
+
+Option A: Generating a Python class
+===================================
+
+The standard way to interact with a **UI file** is to generate a Python
+class from it. This is possible thanks to the ``pyside6-uic`` tool.
+To use this tool, you need to run the following command on a console::
+
+ pyside6-uic mainwindow.ui -o ui_mainwindow.py
+
+We redirect all the output of the command to a file called ``ui_mainwindow.py``,
+which will be imported directly::
+
+ from ui_mainwindow import Ui_MainWindow
+
+Now to use it, we should create a personalized class for our widget
+to **setup** this generated design.
+
+To understand the idea, let's take a look at the whole code:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QMainWindow
+ from PySide6.QtCore import QFile
+ from ui_mainwindow import Ui_MainWindow
+
+ class MainWindow(QMainWindow):
+ def __init__(self):
+ super(MainWindow, self).__init__()
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ window = MainWindow()
+ window.show()
+
+ sys.exit(app.exec())
+
+What is inside the *if* statement is already known from the previous
+examples, and our new basic class contains only two new lines
+that are in charge of loading the generated python class from the UI
+file:
+
+.. code-block:: python
+
+ self.ui = Ui_MainWindow()
+ self.ui.setupUi(self)
+
+.. note::
+
+ You must run ``pyside6-uic`` again every time you make changes
+ to the **UI file**.
+
+Option B: Loading it directly
+=============================
+
+To load the UI file directly, we will need a class from the **QtUiTools**
+module:
+
+.. code-block:: python
+
+ from PySide6.QtUiTools import QUiLoader
+
+The ``QUiLoader`` lets us load the **ui file** dynamically
+and use it right away:
+
+.. code-block:: python
+
+ ui_file = QFile("mainwindow.ui")
+ ui_file.open(QFile.ReadOnly)
+
+ loader = QUiLoader()
+ window = loader.load(ui_file)
+ window.show()
+
+The complete code of this example looks like this:
+
+.. code-block:: python
+
+ # File: main.py
+ import sys
+ from PySide6.QtUiTools import QUiLoader
+ from PySide6.QtWidgets import QApplication
+ from PySide6.QtCore import QFile, QIODevice
+
+ if __name__ == "__main__":
+ app = QApplication(sys.argv)
+
+ ui_file_name = "mainwindow.ui"
+ ui_file = QFile(ui_file_name)
+ if not ui_file.open(QIODevice.ReadOnly):
+ print(f"Cannot open {ui_file_name}: {ui_file.errorString()}")
+ sys.exit(-1)
+ loader = QUiLoader()
+ window = loader.load(ui_file)
+ ui_file.close()
+ if not window:
+ print(loader.errorString())
+ sys.exit(-1)
+ window.show()
+
+ sys.exit(app.exec())
+
+Then to execute it we just need to run the following on a
+command prompt:
+
+.. code-block:: bash
+
+ python main.py
+
+.. note::
+
+ ``QUiLoader`` uses ``connect()`` calls taking the function signatures as string
+ arguments for signal/slot connections.
+ It is thus unable to handle Python types like ``str`` or ``list`` from
+ custom widgets written in Python since these types are internally mapped
+ to different C++ types.
+
+.. _designer_custom_widgets:
+
+Custom Widgets in Qt Widgets Designer
+=====================================
+
+*Qt Widgets Designer* is able to use user-provided (custom) widgets.
+They are shown in the widget box and can be dragged onto the form just like
+Qt's widgets (see
+`Using Custom Widgets with Qt Widgets Designer <https://doc.qt.io/qt-6/designer-using-custom-widgets.html>`_
+). Normally, this requires implementing the widget as a plugin to
+*Qt Widgets Designer* written in C++ implementing its
+`QDesignerCustomWidgetInterface`_ .
+
+Qt for Python provides a simple interface for this which is similar to
+:meth:`registerCustomWidget()<PySide6.QtUiTools.QUiLoader.registerCustomWidget>`.
+
+The widget needs to be provided as a Python module, as shown by
+the :ref:`widgetbinding-example` (file ``wigglywidget.py``) or
+the :ref:`task-menu-extension-example` (file ``tictactoe.py``).
+
+Registering this with *Qt Widgets Designer* is done by providing
+a registration script named ``register*.py`` and pointing
+the path-type environment variable ``PYSIDE_DESIGNER_PLUGINS``
+to the directory.
+
+The code of the registration script looks as follows:
+
+.. code-block:: python
+
+ # File: registerwigglywidget.py
+ from wigglywidget import WigglyWidget
+
+ import QtDesigner
+
+
+ TOOLTIP = "A cool wiggly widget (Python)"
+ DOM_XML = """
+ <ui language='c++'>
+ <widget class='WigglyWidget' name='wigglyWidget'>
+ <property name='geometry'>
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>200</height>
+ </rect>
+ </property>
+ <property name='text'>
+ <string>Hello, world</string>
+ </property>
+ </widget>
+ </ui>
+ """
+
+ QPyDesignerCustomWidgetCollection.registerCustomWidget(WigglyWidget, module="wigglywidget",
+ tool_tip=TOOLTIP, xml=DOM_XML)
+
+
+QPyDesignerCustomWidgetCollection provides an implementation of
+`QDesignerCustomWidgetCollectionInterface`_
+exposing custom widgets to *Qt Widgets Designer* with static convenience
+functions for registering types or adding instances of
+`QDesignerCustomWidgetInterface`_ .
+
+The function
+:meth:`registerCustomWidget()<PySide6.QtDesigner.QPyDesignerCustomWidgetCollection.registerCustomWidget>`
+is used to register a widget type with *Qt Widgets Designer*. In the simple case, it
+can be used like ``QUiLoader.registerCustomWidget()``. It takes the custom widget
+type and some optional keyword arguments passing values that correspond to the
+getters of
+`QDesignerCustomWidgetInterface`_ :
+
+When launching *Qt Widgets Designer* via its launcher ``pyside6-designer``,
+the custom widget should be visible in the widget box.
+
+For advanced usage, it is also possible to pass the function an implementation
+of the class QDesignerCustomWidgetInterface instead of the type to
+:meth:`addCustomWidget()<PySide6.QtDesigner.QPyDesignerCustomWidgetCollection.addCustomWidget>`.
+This is shown in taskmenuextension example, where a custom context menu
+is registered for the custom widget. The example is a port of the
+corresponding C++
+`Task Menu Extension Example <https://doc.qt.io/qt-6/qtdesigner-taskmenuextension-example.html>`_ .
+
+.. _QDesignerCustomWidgetCollectionInterface: https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html
+.. _QDesignerCustomWidgetInterface: https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html
+
+Troubleshooting the Qt Widgets Designer Plugin
+++++++++++++++++++++++++++++++++++++++++++++++
+
+- The launcher ``pyside6-designer`` must be used. The standalone
+ *Qt Widgets Designer* will not load the plugin.
+- The menu item **Help/About Plugin** brings up a dialog showing the plugins
+ found and potential load error messages.
+- Check the console or Windows Debug view for further error messages.
+- Due to the buffering of output by Python, error messages may appear
+ only after *Qt Widgets Designer* has terminated.
+- When building Qt for Python, be sure to set the ``--standalone`` option
+ for the plugin to be properly installed.
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgets.png b/sources/pyside6/doc/tutorials/basictutorial/widgets.png
new file mode 100644
index 000000000..de7a969f9
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgets.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgets.rst b/sources/pyside6/doc/tutorials/basictutorial/widgets.rst
new file mode 100644
index 000000000..ef14c7e99
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgets.rst
@@ -0,0 +1,52 @@
+Your First QtWidgets Application
+*********************************
+
+As with any other programming framework,
+you start with the traditional "Hello World" program.
+
+Here is a simple example of a Hello World application in PySide6:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtWidgets import QApplication, QLabel
+
+ app = QApplication(sys.argv)
+ label = QLabel("Hello World!")
+ label.show()
+ app.exec()
+
+
+When you execute it the code, the application will look like:
+
+.. image:: widgets.png
+ :alt: Simple Widget
+
+
+For a widget application using PySide6, you must always start by
+importing the appropriate class from the `PySide6.QtWidgets` module.
+
+After the imports, you create a `QApplication` instance. As Qt can
+receive arguments from command line, you may pass any argument to
+the QApplication object. Usually, you don't need to pass any
+arguments so you can leave it as is, or use the following approach:
+
+.. code-block:: python
+
+ app = QApplication([])
+
+After the creation of the application object, we have created a
+`QLabel` object. A `QLabel` is a widget that can present text
+(simple or rich, like html), and images:
+
+.. code-block:: python
+
+ # This HTML approach will be valid too!
+ label = QLabel("<font color=red size=40>Hello World!</font>")
+
+.. note:: After creating the label, we call `show()` on it.
+
+Finally, we call `app.exec()` to enter the Qt main loop and start
+to execute the Qt code. In reality, it is only here where the label
+is shown, but this can be ignored for now.
+
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-no.png b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-no.png
new file mode 100644
index 000000000..f8346533f
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-no.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-no.png b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-no.png
new file mode 100644
index 000000000..d510a80cd
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-no.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-yes.png b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-yes.png
new file mode 100644
index 000000000..e7a0c0ef7
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-simple-yes.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-yes.png b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-yes.png
new file mode 100644
index 000000000..9b83b8267
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling-yes.png
Binary files differ
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.py b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.py
new file mode 100644
index 000000000..106483b7b
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.py
@@ -0,0 +1,58 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+
+from PySide6.QtCore import Qt
+from PySide6.QtWidgets import (QApplication, QHBoxLayout, QLabel, QListWidget,
+ QListWidgetItem, QPushButton, QVBoxLayout,
+ QWidget)
+
+_placeholder = """
+Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum
+"""
+
+
+class Widget(QWidget):
+ def __init__(self, parent=None):
+ super(Widget, self).__init__(parent)
+
+ menu_widget = QListWidget()
+ for i in range(10):
+ item = QListWidgetItem(f"Item {i}")
+ item.setTextAlignment(Qt.AlignCenter)
+ menu_widget.addItem(item)
+
+ text_widget = QLabel(_placeholder)
+ button = QPushButton("Something")
+
+ content_layout = QVBoxLayout()
+ content_layout.addWidget(text_widget)
+ content_layout.addWidget(button)
+ main_widget = QWidget()
+ main_widget.setLayout(content_layout)
+
+ layout = QHBoxLayout()
+ layout.addWidget(menu_widget, 1)
+ layout.addWidget(main_widget, 4)
+ self.setLayout(layout)
+
+
+if __name__ == "__main__":
+ app = QApplication()
+
+ w = Widget()
+ w.show()
+
+ _style = None
+ with open("style.qss", "r") as f:
+ _style = f.read()
+ app.setStyleSheet(_style)
+
+ sys.exit(app.exec())
diff --git a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst
new file mode 100644
index 000000000..2fa51c0a8
--- /dev/null
+++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst
@@ -0,0 +1,171 @@
+.. _widgetstyling:
+
+Styling the Widgets Application
+===============================
+
+Qt Widgets application use a default theme depending on the platform.
+In some cases, there are system-wide configurations that modify the Qt theme,
+and applications are displayed differently.
+
+However, you can take care of your own widgets and provide a custom style
+to each component. As an example, look at the following simple snippet:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtCore import Qt
+ from PySide6.QtWidgets import QApplication, QLabel
+
+ if __name__ == "__main__":
+ app = QApplication()
+ w = QLabel("This is a placeholder text")
+ w.setAlignment(Qt.AlignCenter)
+ w.show()
+ sys.exit(app.exec())
+
+When you execute this code, you will see a simple ``QLabel`` aligned at the
+center, and with a placeholder text.
+
+.. image:: widgetstyling-simple-no.png
+ :alt: Simple Widget with no style
+
+You can style your application using the CSS-like syntax.
+For more information, see `Qt Style Sheets Reference`_.
+
+A ``QLabel`` can be styled differently by setting some of its CSS
+properties, such as ``background-color`` and ``font-family``,
+so let's see how does the code look like with these changes:
+
+.. code-block:: python
+
+ import sys
+ from PySide6.QtCore import Qt
+ from PySide6.QtWidgets import QApplication, QLabel
+
+ if __name__ == "__main__":
+ app = QApplication()
+ w = QLabel("This is a placeholder text")
+ w.setAlignment(Qt.AlignCenter)
+ w.setStyleSheet("""
+ background-color: #262626;
+ color: #FFFFFF;
+ font-family: Titillium;
+ font-size: 18px;
+ """)
+ w.show()
+ sys.exit(app.exec())
+
+Now when you run the code, notice that the ``QLabel`` looks different with your
+custom style:
+
+.. image:: widgetstyling-simple-yes.png
+ :alt: Simple Widget with Style
+
+
+.. note::
+
+ If you don't have the font ``Titillium`` installed, you can try with any
+ other you prefer.
+ Remember you can list your installed fonts using ``QFontDatabase``,
+ specifically the ``families()`` method.
+
+
+Styling each UI element separately like you did in the previous snippet is a
+lot of work. The easier alternative for this is to use Qt Style Sheets,
+which is one or more ``.qss`` files defining the style for the UI elements in
+your application.
+
+More examples can be found in the `Qt Style Sheet Examples`_ documentation
+page.
+
+
+.. _`Qt Style Sheets Reference`: https://doc.qt.io/qt-5/stylesheet-reference.html
+.. _`Qt Style Sheet Examples`: https://doc.qt.io/qt-5/stylesheet-examples.html
+
+Qt Style Sheets
+---------------
+
+.. warning::
+
+ Before starting modifying your application, keep in mind that you will be
+ responsible for all the graphical details of the application.
+ Altering margins, and sizes might end up looking strange or incorrect, so you
+ need to be careful when altering the style.
+ It's recommended to create a full new Qt style to cover all the possible
+ corner cases.
+
+A ``qss`` file is quite similar to a CSS file, but you need to specify the Widget
+component and optionally the name of the object::
+
+ QLabel {
+ background-color: red;
+ }
+
+ QLabel#title {
+ font-size: 20px;
+ }
+
+The first style defines a ``background-color`` for all ``QLabel`` objects in your
+application, whereas the later one styles the ``title`` object only.
+
+.. note::
+
+ You can set object names with the `setObjectName(str)` function to any Qt
+ object, for example: for a `label = QLabel("Test")`, you can write
+ `label.setObjectName("title")`
+
+
+Once you have a ``qss`` file for your application, you can apply it by reading
+the file and using the ``QApplication.setStyleSheet(str)`` function:
+
+.. code-block:: python
+
+ if __name__ == "__main__":
+ app = QApplication()
+
+ w = Widget()
+ w.show()
+
+ with open("style.qss", "r") as f:
+ _style = f.read()
+ app.setStyleSheet(_style)
+
+ sys.exit(app.exec())
+
+Having a general ``qss`` file allows you to decouple the styling aspects of
+the code, without mixing it in the middle of the general functionality, and you
+can simply enable it or disable it.
+
+Look at this new example, with more widgets components:
+
+.. literalinclude:: widgetstyling.py
+ :linenos:
+ :lines: 22-44
+
+This displays a two column widget, with a ``QListWidget`` on the left and a
+``QLabel`` and a ``QPushButton`` on the right. It looks like this when you run the
+code:
+
+.. image:: widgetstyling-no.png
+ :alt: Widget with no style
+
+If you add content to the previously described ``style.qss`` file, you can modify
+the look-n-feel of the previous example:
+
+.. literalinclude:: style.qss
+ :linenos:
+
+The style changes mainly the color of the different widgets, alter the
+alignment, and includes some spacing.
+You can also use state-based styling on the QListWidget *items* for example, to
+style them differently depending on whether they are *selected* or not.
+
+After applying all the styling alternatives you explored in this topic, notice
+that the ``QLabel`` example looks a lot different now.
+Try running the code to check its new look:
+
+.. image:: widgetstyling-yes.png
+ :alt: Widget with style
+
+You have the freedom to tune your style sheets and provide a really nice
+look-n-feel to all your applications.