diff options
Diffstat (limited to 'sources/pyside6/doc/tutorials/basictutorial')
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst | 6 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/dialog.rst | 43 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/icons.zip | bin | 0 -> 6156 bytes | |||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst | 34 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst | 214 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/translations.rst | 168 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/treewidget.rst | 12 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/uifiles.rst | 88 | ||||
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst | 36 |
9 files changed, 326 insertions, 275 deletions
diff --git a/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst index 2221858bc..c5464640b 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/clickablebutton.rst @@ -60,7 +60,8 @@ signal to the `say_hello()` 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() @@ -68,9 +69,8 @@ Finally, we show the button and start the Qt main loop: app.exec() Here is the complete code for this example: -:: - #!/usr/bin/python +.. code-block:: python import sys from PySide6.QtWidgets import QApplication, QPushButton diff --git a/sources/pyside6/doc/tutorials/basictutorial/dialog.rst b/sources/pyside6/doc/tutorials/basictutorial/dialog.rst index bc06d6d9b..b7712672b 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/dialog.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/dialog.rst @@ -3,8 +3,8 @@ 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`. +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 @@ -31,24 +31,24 @@ tutorial, but you can use this stub as is if you need to: 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. +``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 +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 +``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: +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 @@ -62,8 +62,8 @@ 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, +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: :: @@ -72,40 +72,41 @@ after creating the widgets: layout.addWidget(self.edit) layout.addWidget(self.button) -So, we create the layout, add the widgets with `addWidget()`. +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: +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 +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. +``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: +``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 +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, diff --git a/sources/pyside6/doc/tutorials/basictutorial/icons.zip b/sources/pyside6/doc/tutorials/basictutorial/icons.zip Binary files differnew file mode 100644 index 000000000..e279e37b8 --- /dev/null +++ b/sources/pyside6/doc/tutorials/basictutorial/icons.zip diff --git a/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst b/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst index 477c5b738..858293beb 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/qrcfiles.rst @@ -1,7 +1,7 @@ .. _using_qrc_files: -Using `.qrc` Files (`pyside6-rcc`) -********************************** +Using ``.qrc`` Files (``pyside6-rcc``) +************************************** The `Qt Resource System`_ is a mechanism for storing binary files in an application. @@ -17,7 +17,7 @@ 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 +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. @@ -25,29 +25,27 @@ default icons meant for such actions. :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, `download the following set`_ -and use them. +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 +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. -.. _`download the following set`: icons/ - -The `.qrc` file -================ +The ``.qrc`` file +================= -Before running any command, add information about the resources to a `.qrc` +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` +In the following example, notice how the resources are listed in ``icons.qrc`` :: - </ui> <!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>icons/play.png</file> @@ -62,15 +60,15 @@ In the following example, notice how the resources are listed in `icons.qrc` Generating a Python file ========================= -Now that the `icons.qrc` file is ready, use the `pyside6-rcc` tool to generate +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.rc -o rc_icons.py + 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. +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:: @@ -167,7 +165,7 @@ Now, the constructor of your class should look like this: Executing the example ===================== -Run the application by calling `python main.py` to checkout the new icon-set: +Run the application by calling ``python main.py`` to checkout the new icon-set: .. image:: player-new.png :alt: New Multimedia Player Qt Example diff --git a/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst index 470b4ab70..0bfd9e276 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/signals_and_slots.rst @@ -43,101 +43,104 @@ 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: +``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 +.. code-block:: python - button = QToolButton() - line_edit = QLineEdit() - button.clicked.connect(line_edit.clear) + 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. +``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 +.. code-block:: python - import sys - from PySide6.QtWidgets import QApplication, QPushButton + import sys + from PySide6.QtWidgets import QApplication, QPushButton - def function(): - print("The 'function' has been called!") + def function(): + print("The 'function' has been called!") - app = QApplication() - button = QPushButton("Call function") - button.clicked.connect(func) - button.show() - sys.exit(app.exec()) + 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 Designer. +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 +that emits a ``clicked()`` signal could look as follows: - .. code-block:: python +.. code-block:: python - from PySide6.QtCore import Qt, Signal - from PySide6.QtWidgets import QWidget + from PySide6.QtCore import Qt, Signal + from PySide6.QtWidgets import QWidget - class Button(QWidget): + class Button(QWidget): - clicked = Signal(Qt.MouseButton) + clicked = Signal(Qt.MouseButton) - ... + ... - def mousePressEvent(self, event): - self.clicked.emit(event.button()) + 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 +.. 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 + 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 +.. code-block:: python - # TODO - signal5 = Signal(int, name='rangeChanged') - # ... - rangeChanged.emit(...) + # 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 +.. code-block:: python - sumResult = Signal(int, arguments=['sum']) + sumResult = Signal(int, arguments=['sum']) - .. code-block:: javascript +.. code-block:: javascript - Connections { - target: ... - function onSumResult(sum) { - // do something with 'sum' - } + Connections { + target: ... + function onSumResult(sum) { + // do something with 'sum' + } + + +.. _slot-decorator: The Slot Class -------------- @@ -146,11 +149,11 @@ 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 +.. code-block:: python - @Slot(str) - def slot_function(self, s): - ... + @Slot(str) + def slot_function(self, s): + ... ``Slot()`` also accepts a ``name`` and a ``result`` keyword. @@ -159,6 +162,19 @@ 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: @@ -172,62 +188,76 @@ 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 +.. code-block:: python - import sys - from PySide6.QtWidgets import QApplication, QPushButton - from PySide6.QtCore import QObject, Signal, Slot + 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,)) + 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__(self, parent) + def __init__(self, parent=None): + super().__init__(parent) - self.speak[int].connect(self.say_something) - self.speak[str].connect(self.say_something) + 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) + # 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() - 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!") - # 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: +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 +.. code-block:: python - from PySide6.QtCore import SIGNAL, SLOT + wizard.registerField("text", line_edit, "text", + SIGNAL("textChanged(QString)")) - button.connect(SIGNAL("clicked(Qt::MouseButton)"), - action_handler, SLOT("action1(Qt::MouseButton)")) +The signature strings can be found by querying ``QMetaMethod.methodSignature()`` +when introspecting ``QMetaObject``: -This is not recommended for connecting signals, it is mostly -used to specify signals for methods like `QWizardPage::registerField()`: +.. code-block:: python - .. code-block:: python + mo = widget.metaObject() + for m in range(mo.methodOffset(), mo.methodCount()): + print(mo.method(m).methodSignature()) - wizard.registerField("text", line_edit, "text", - SIGNAL("textChanged(QString)")) +Slots should be decorated using :ref:`@Slot <slot-decorator>`. diff --git a/sources/pyside6/doc/tutorials/basictutorial/translations.rst b/sources/pyside6/doc/tutorials/basictutorial/translations.rst index 31cd004a3..21c16cdcd 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/translations.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/translations.rst @@ -9,10 +9,10 @@ Translating Applications Qt Linguist ----------- -`Qt Linguist <https://doc.qt.io/qt-6/qtlinguist-index.html>`_ and +`Qt Linguist`_ and its related tools can be used to provide translations for applications. -The ``examples/widgets/linguist`` example illustrates this. The example is +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. @@ -28,18 +28,18 @@ 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 +.. code-block:: python - count = len(self._list_widget.selectionModel().selectedRows()) - message = self.tr("%n language(s) selected", "", count) + 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 +.. code-block:: bash - pyside6-lupdate main.py -ts example_de.ts + 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. @@ -52,15 +52,29 @@ they should be passed to the ``pyside6-lupdate`` tool as well: 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. +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 +.. 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: - mkdir translations - pyside6-lrelease example_de.ts -qm translations/example_de.qm +.. 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 @@ -68,43 +82,45 @@ applications resources (see :ref:`using_qrc_files`). The resource file ``linguist.qrc`` provides the ``example_de.qm`` under ``:/translations``: - .. code-block:: xml +.. code-block:: xml - <!DOCTYPE RCC><RCC version="1.0"> - <qresource> - <file>translations/example_de.qm</file> - </qresource> - </RCC> + <!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 +.. 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) + 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 +.. code-block:: bash + + LANG=de python main.py - LANG=de python main.py +.. _Qt Linguist: https://doc.qt.io/qt-6/qtlinguist-index.html GNU gettext ----------- -The `GNU gettext <https://docs.python.org/3/library/gettext.html>`_ module +The `GNU gettext`_ module can be used to provide translations for applications. -The ``examples/widgets/gettext`` example illustrates this. The example is +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. @@ -116,29 +132,29 @@ aliased to ``ngettext``. Those functions are defined at the top: - .. code-block:: python +.. code-block:: python - import gettext - ... - _ = None - ngettext = None + 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 +.. 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 @@ -146,18 +162,18 @@ to load a translation matching the current language. Messages to be translated look like: - .. code-block:: python +.. code-block:: python - file_menu = self.menuBar().addMenu(_("&File")) + 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 +.. code-block:: python - count = len(self._list_widget.selectionModel().selectedRows()) - message = ngettext("{0} language selected", - "{0} languages selected", count).format(count) + 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 @@ -172,43 +188,45 @@ is first created: 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. +appropriate values. It is then copied to the ``de_DE/LC_MESSAGES`` directory. - .. code-block:: bash +.. code-block:: bash - cd locales/de_DE/LC_MESSAGES/ - cp ../../example.pot . + 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:: +.. 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" + "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:: +.. code-block:: - #: main.py:57 - msgid "&File" - msgstr "&Datei" + #: 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 +.. code-block:: bash - msgfmt -o example.mo example.pot + msgfmt -o example.mo example.pot The example can then be run in German: - .. code-block:: bash +.. code-block:: bash + + LANG=de python main.py - LANG=de python main.py +.. _GNU gettext: https://docs.python.org/3/library/gettext.html diff --git a/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst b/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst index b286de507..f431cb5c4 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/treewidget.rst @@ -11,14 +11,14 @@ information in trees. You can also create a data model and display it using a 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 ``QTreeWidget`` and ``QTreeWidgetItem`` for this application: +#. Import ``QTreeWidget`` and ``QTreeWidgetItem`` for this application: .. code-block:: python import sys from PySide6.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem -2. Define a dictionary with project structures to display the information as a +#. Define a dictionary with project structures to display the information as a tree, with files belonging to each project: .. code-block:: python @@ -27,13 +27,13 @@ information in trees. You can also create a data model and display it using a "Project B": ["file_b.csv", "photo.jpg"], "Project C": []} -3. Initialize the ``QApplication`` singleton: +#. Initialize the ``QApplication`` singleton: .. code-block:: python app = QApplication() -4. Configure the ``QTreeWidget`` to have two columns, one for the item name, +#. 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: @@ -44,7 +44,7 @@ information in trees. You can also create a data model and display it using a tree.setColumnCount(2) tree.setHeaderLabels(["Name", "Type"]) -5. Iterate the data structure, create the ``QTreeWidgetItem`` elements, and add +#. 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. @@ -64,7 +64,7 @@ information in trees. You can also create a data model and display it using a tree.insertTopLevelItems(0, items) -7. Show the tree and execute the ``QApplication``. +#. Show the tree and execute the ``QApplication``. .. code-block:: python diff --git a/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst b/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst index cd1057c97..cb945908d 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/uifiles.rst @@ -1,27 +1,27 @@ .. _using_ui_files: -Using `.ui` files from Designer or QtCreator with `QUiLoader` and `pyside6-uic` -******************************************************************************* +Using ``.ui`` files from Designer or QtCreator with ``QUiLoader`` and ``pyside6-uic`` +************************************************************************************* This page describes the use of -`Qt Designer <https://doc.qt.io/qt-6/qtdesigner-manual.html>`_ to create +`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 Designer** is a graphical UI design tool which is available as a +*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** +`Qt Creator IDE <https://doc.qt.io/qtcreator>`_. Its use within *Qt Creator* is described at -`Using Qt Designer <https://doc.qt.io/qtcreator/creator-using-qt-designer.html>`_. +`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 +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. +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: @@ -88,12 +88,12 @@ 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. +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 > ui_mainwindow.py + pyside6-uic mainwindow.ui -o ui_mainwindow.py -We redirect all the output of the command to a file called `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 @@ -136,7 +136,7 @@ file: .. note:: - You must run `pyside6-uic` again every time you make changes + You must run ``pyside6-uic`` again every time you make changes to the **UI file**. Option B: Loading it directly @@ -149,7 +149,7 @@ module: from PySide6.QtUiTools import QUiLoader -The `QUiLoader` lets us load the **ui file** dynamically +The ``QUiLoader`` lets us load the **ui file** dynamically and use it right away: .. code-block:: python @@ -192,40 +192,41 @@ The complete code of this example looks like this: Then to execute it we just need to run the following on a command prompt: -.. code-block:: python +.. code-block:: bash python main.py .. note:: - `QUiLoader` uses connect() calls taking the function signatures as string + ``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 + 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 Designer -============================= +Custom Widgets in Qt Widgets Designer +===================================== -**Qt 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 Designer <https://doc.qt.io/qt-6/designer-using-custom-widgets.html>`_ -). Normally, this requires implementing the widget as a plugin to Qt Designer -written in C++ implementing its -`QDesignerCustomWidgetInterface <https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html>`_ . +*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 widgetbinding example (file ``wigglywidget.py``) or -the taskmenuextension example (file ``tictactoe.py``). +the :ref:`widgetbinding-example` (file ``wigglywidget.py``) or +the :ref:`task-menu-extension-example` (file ``tictactoe.py``). -Registering this with Qt Designer is done by providing +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`` +the path-type environment variable ``PYSIDE_DESIGNER_PLUGINS`` to the directory. The code of the registration script looks as follows: @@ -262,20 +263,20 @@ The code of the registration script looks as follows: QPyDesignerCustomWidgetCollection provides an implementation of -`QDesignerCustomWidgetCollectionInterface <https://doc.qt.io/qt-6/qdesignercustomwidgetcollectioninterface.html>`_ -exposing custom widgets to **Qt Designer** with static convenience functions -for registering types or adding instances of -`QDesignerCustomWidgetInterface <https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html>`_ . +`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 Designer**. In the simple case, it -can be used like `QUiLoader.registerCustomWidget()`. It takes the custom widget +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 <https://doc.qt.io/qt-6/qdesignercustomwidgetinterface.html>`_ : +`QDesignerCustomWidgetInterface`_ : -When launching **Qt Designer** via its launcher ``pyside6-designer``, +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 @@ -286,15 +287,18 @@ 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>`_ . -Troubleshooting the Qt Designer Plugin -++++++++++++++++++++++++++++++++++++++ +.. _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 Designer** will not load the plugin. + *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 Designer** has terminated. + 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/widgetstyling.rst b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst index e1af8b8a9..2fa51c0a8 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/widgetstyling.rst @@ -23,7 +23,7 @@ to each component. As an example, look at the following simple snippet: w.show() sys.exit(app.exec()) -When you execute this code, you will see a simple `QLabel` aligned at the +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 @@ -32,8 +32,8 @@ center, and with a placeholder text. 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`, +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 @@ -55,7 +55,7 @@ so let's see how does the code look like with these changes: w.show() sys.exit(app.exec()) -Now when you run the code, notice that the `QLabel` looks different with your +Now when you run the code, notice that the ``QLabel`` looks different with your custom style: .. image:: widgetstyling-simple-yes.png @@ -64,15 +64,15 @@ custom style: .. note:: - If you don't have the font `Titillium` installed, you can try with any + 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. + 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 +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 @@ -94,7 +94,7 @@ Qt Style Sheets 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 +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 { @@ -105,8 +105,8 @@ component and optionally the name of the object:: 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. +The first style defines a ``background-color`` for all ``QLabel`` objects in your +application, whereas the later one styles the ``title`` object only. .. note:: @@ -115,8 +115,8 @@ application, whereas the later one styles the `title` object only. `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: +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 @@ -132,7 +132,7 @@ the file and using the `QApplication.setStyleSheet(str)` function: sys.exit(app.exec()) -Having a general `qss` file allows you to decouple the styling aspects of +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. @@ -142,14 +142,14 @@ Look at this new example, with more widgets components: :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 +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 +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 @@ -161,7 +161,7 @@ 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. +that the ``QLabel`` example looks a lot different now. Try running the code to check its new look: .. image:: widgetstyling-yes.png |