├── .gitignore ├── images ├── .DS_Store ├── 1.hello.png ├── 2.button.png ├── 3.grid_layout.png ├── 3.nested_layout.png ├── 3.vertical_layout.png ├── 3.horizontal_layout.png ├── 4.updating_gui_after.png └── 4.updating_gui_before.png ├── README.md ├── examples ├── 1.hello.py ├── 2.button.py ├── 3.horizontal_layout.py ├── 3.vertical_layout.py ├── 4.updating_gui.py ├── 3.grid_layout.py ├── 6.ui.py ├── 3.nested_layout.py ├── 5.matplotlib.py ├── 7.class.py └── mywidget.ui ├── installing.rst ├── Makefile ├── 4.updating_gui.rst ├── index.rst ├── make.bat ├── 2.button.rst ├── 1.hello.rst ├── 3.layout.rst └── conf.py /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/.DS_Store -------------------------------------------------------------------------------- /images/1.hello.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/1.hello.png -------------------------------------------------------------------------------- /images/2.button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/2.button.png -------------------------------------------------------------------------------- /images/3.grid_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/3.grid_layout.png -------------------------------------------------------------------------------- /images/3.nested_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/3.nested_layout.png -------------------------------------------------------------------------------- /images/3.vertical_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/3.vertical_layout.png -------------------------------------------------------------------------------- /images/3.horizontal_layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/3.horizontal_layout.png -------------------------------------------------------------------------------- /images/4.updating_gui_after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/4.updating_gui_after.png -------------------------------------------------------------------------------- /images/4.updating_gui_before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/astrofrog/python-qt-tutorial/HEAD/images/4.updating_gui_before.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Qt Tutorial 2 | 3 | This is the source code for a tutorial for using Qt from Python. It is a work in progress, and I welcome any contributions (fixes or additions). 4 | 5 | The tutorial can be found at https://python-qt-tutorial.readthedocs.io 6 | -------------------------------------------------------------------------------- /examples/1.hello.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import QApplication, QLabel 2 | 3 | # Initialize application 4 | app = QApplication([]) 5 | 6 | # Create label widget 7 | label = QLabel('Hello, world!') 8 | label.show() 9 | 10 | # Start 'event loop' 11 | app.exec_() 12 | -------------------------------------------------------------------------------- /examples/2.button.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import QApplication, QPushButton 2 | 3 | # Initialize application 4 | app = QApplication([]) 5 | 6 | # Define a function to connect to the button 7 | def say_hello(event): 8 | print('Hello, world!') 9 | 10 | # Create button widget and connect to 'say_hello' 11 | button = QPushButton('Say hello') 12 | button.clicked.connect(say_hello) 13 | button.show() 14 | 15 | # Start 'event loop' 16 | app.exec_() 17 | -------------------------------------------------------------------------------- /installing.rst: -------------------------------------------------------------------------------- 1 | Installing 2 | ========== 3 | 4 | conda 5 | ----- 6 | 7 | If you use conda to manage your Python environment (for example as part of 8 | Anaconda or Miniconda), you can easily install Qt, PyQt5, and QtPy (a common 9 | interface to all Python Qt bindings) using:: 10 | 11 | conda install pyqt qtpy 12 | 13 | pip 14 | --- 15 | 16 | If you don't make use of conda, an easy way to install Qt, PyQt5, and QtPy is 17 | to do:: 18 | 19 | pip install pyqt5 qtpy 20 | -------------------------------------------------------------------------------- /examples/3.horizontal_layout.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import QApplication, QLabel, QWidget, QHBoxLayout, QPushButton 2 | 3 | # Initialize application 4 | app = QApplication([]) 5 | 6 | # Create label and button 7 | label = QLabel('Hello, world!') 8 | button = QPushButton('test') 9 | 10 | # Create layout and add widgets 11 | layout = QHBoxLayout() 12 | layout.addWidget(label) 13 | layout.addWidget(button) 14 | 15 | # Apply layout to widget 16 | widget = QWidget() 17 | widget.setLayout(layout) 18 | 19 | # Show widget 20 | widget.show() 21 | 22 | # Start event loop 23 | app.exec_() 24 | -------------------------------------------------------------------------------- /examples/3.vertical_layout.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import (QApplication, QLabel, QWidget, 2 | QVBoxLayout, QPushButton) 3 | 4 | # Initialize application 5 | app = QApplication([]) 6 | 7 | # Create label and button 8 | label = QLabel('Hello, world!') 9 | button = QPushButton('test') 10 | 11 | # Create layout and add widgets 12 | layout = QVBoxLayout() 13 | layout.addWidget(label) 14 | layout.addWidget(button) 15 | 16 | # Apply layout to widget 17 | widget = QWidget() 18 | widget.setLayout(layout) 19 | 20 | # Show widget 21 | widget.show() 22 | 23 | # Start event loop 24 | app.exec_() 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = PythonQttutorial 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /examples/4.updating_gui.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import (QApplication, QLabel, QWidget, QVBoxLayout, 2 | QPushButton) 3 | 4 | # Initialize application 5 | app = QApplication([]) 6 | 7 | # Create label 8 | label = QLabel('Zzzzz') 9 | 10 | def say_hello(event): 11 | label.setText('Hello, world!') 12 | 13 | # Create button 14 | button = QPushButton('Press me!') 15 | button.clicked.connect(say_hello) 16 | 17 | # Create layout and add widgets 18 | layout = QVBoxLayout() 19 | layout.addWidget(label) 20 | layout.addWidget(button) 21 | 22 | # Apply layout to widget 23 | widget = QWidget() 24 | widget.setLayout(layout) 25 | 26 | widget.show() 27 | 28 | app.exec_() 29 | -------------------------------------------------------------------------------- /4.updating_gui.rst: -------------------------------------------------------------------------------- 1 | Part 4 - Dynamically updating widgets 2 | ===================================== 3 | 4 | Now that we know how to show multiple widgets in a single window, we can make 5 | use of what we learned in :doc:`2.button.py` to connect different widgets 6 | together. For example, we can make it so that pressing a button changes the 7 | text in one of the widgets: 8 | 9 | .. literalinclude:: examples/4.updating_gui.py 10 | 11 | Try running this script, and you should see something like: 12 | 13 | .. image:: images/4.updating_gui_before.png 14 | :align: center 15 | :scale: 60% 16 | 17 | Now press the button, and the label text should change: 18 | 19 | .. image:: images/4.updating_gui_after.png 20 | :align: center 21 | :scale: 60% 22 | -------------------------------------------------------------------------------- /examples/3.grid_layout.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import (QApplication, QLabel, QWidget, 2 | QGridLayout, QPushButton) 3 | 4 | # Initialize application 5 | app = QApplication([]) 6 | 7 | # Create label and button 8 | label1 = QLabel('Label 1') 9 | label2 = QLabel('Label 2') 10 | label3 = QLabel('Label 3') 11 | button = QPushButton('Press me!') 12 | 13 | # Create layout and add widgets 14 | layout = QGridLayout() 15 | layout.addWidget(label1, 0, 0) 16 | layout.addWidget(label2, 1, 0) 17 | layout.addWidget(label3, 0, 1) 18 | layout.addWidget(button, 1, 1) 19 | 20 | # Apply layout to widget 21 | widget = QWidget() 22 | widget.setLayout(layout) 23 | 24 | # Show widget 25 | widget.show() 26 | 27 | # Start event loop 28 | app.exec_() 29 | -------------------------------------------------------------------------------- /examples/6.ui.py: -------------------------------------------------------------------------------- 1 | from qtpy.uic import loadUi 2 | from qtpy.QtWidgets import QApplication, QLabel 3 | 4 | # Initialize application 5 | app = QApplication([]) 6 | 7 | # Load file made using Qt Designer 8 | widget = loadUi('mywidget.ui') 9 | 10 | 11 | def add_star(event): 12 | widget.list.addItem('A star') 13 | 14 | 15 | def add_planet(event): 16 | widget.list.addItem('A planet') 17 | 18 | 19 | def add_galaxy(event): 20 | if widget.option.isChecked(): 21 | widget.list.addItem('A BIG galaxy') 22 | else: 23 | widget.list.addItem('A galaxy') 24 | 25 | 26 | # Connect events to buttons 27 | widget.add_star.clicked.connect(add_star) 28 | widget.add_planet.clicked.connect(add_planet) 29 | widget.add_galaxy.clicked.connect(add_galaxy) 30 | 31 | widget.show() 32 | 33 | # Start 'event loop' 34 | app.exec_() 35 | -------------------------------------------------------------------------------- /examples/3.nested_layout.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import (QApplication, QLabel, QWidget, 2 | QHBoxLayout, QVBoxLayout, QPushButton) 3 | 4 | # Initialize application 5 | app = QApplication([]) 6 | 7 | # Set up individual widgets 8 | label1 = QLabel('My wonderful application') 9 | label2 = QLabel('The button:') 10 | button = QPushButton('Press me!') 11 | 12 | # Combine label2 and button into a single widget 13 | bottom_widget = QWidget() 14 | bottom_layout = QHBoxLayout() 15 | bottom_layout.addWidget(label2) 16 | bottom_layout.addWidget(button) 17 | bottom_widget.setLayout(bottom_layout) 18 | 19 | # Combine this widget with label1 to form the main window 20 | widget = QWidget() 21 | layout = QVBoxLayout() 22 | layout.addWidget(label1) 23 | layout.addWidget(bottom_widget) 24 | widget.setLayout(layout) 25 | 26 | # Show main widget 27 | widget.show() 28 | 29 | # Start event loop 30 | app.exec_() 31 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | Python Qt tutorial 2 | ================== 3 | 4 | This is a short tutorial on using Qt from Python. There are two main versions of 5 | Qt in use (Qt4 and Qt5) and several Python libraries to use Qt from Python (PyQt 6 | and PySide), but rather than picking one of these, this tutorial makes use of 7 | the `QtPy `_ package which provides a way to 8 | use whatever Python Qt package is available. 9 | 10 | This is not meant to be a completely exhaustive tutorial but just a place to 11 | start if you've never done Qt development before, and it will be expanded over 12 | time. 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | 17 | installing 18 | 1.hello 19 | 2.button 20 | 3.layout 21 | 4.updating_gui 22 | 23 | If you are interested in helping maintain these pages and/or add new pages, head 24 | over to the `GitHub repository `_! 25 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=PythonQttutorial 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /examples/5.matplotlib.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton 2 | 3 | import numpy as np 4 | 5 | from matplotlib.figure import Figure 6 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg 7 | 8 | # Initialize application 9 | app = QApplication([]) 10 | 11 | # Create Matplotlib figure and canvas 12 | fig = Figure() 13 | ax = fig.add_subplot(1, 1, 1) 14 | canvas = FigureCanvasQTAgg(fig) 15 | 16 | 17 | def plot_points(event): 18 | x = np.random.random(1000) 19 | y = np.random.random(1000) 20 | ax.cla() 21 | ax.plot(x, y, '.') 22 | fig.canvas.draw() 23 | 24 | 25 | # Create button 26 | button = QPushButton('test') 27 | button.clicked.connect(plot_points) 28 | 29 | # Create layout and add widgets 30 | layout = QVBoxLayout() 31 | layout.addWidget(canvas) 32 | layout.addWidget(button) 33 | 34 | # Apply layout to widget 35 | widget = QWidget() 36 | widget.setLayout(layout) 37 | 38 | widget.show() 39 | 40 | # Start 'event loop' 41 | app.exec_() 42 | -------------------------------------------------------------------------------- /examples/7.class.py: -------------------------------------------------------------------------------- 1 | from qtpy.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton 2 | 3 | import numpy as np 4 | 5 | from matplotlib.figure import Figure 6 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg 7 | 8 | 9 | class MyMatplotlibWidget(QWidget): 10 | 11 | def __init__(self, parent=None): 12 | 13 | super(MyMatplotlibWidget, self).__init__(parent=parent) 14 | 15 | # Create Matplotlib figure and canvas 16 | self.fig = Figure() 17 | self.ax = self.fig.add_subplot(1, 1, 1) 18 | self.canvas = FigureCanvasQTAgg(self.fig) 19 | 20 | # Create button 21 | self.button = QPushButton('test') 22 | self.button.clicked.connect(self.plot_points) 23 | 24 | # Create layout and add widgets 25 | layout = QVBoxLayout() 26 | layout.addWidget(self.canvas) 27 | layout.addWidget(self.button) 28 | 29 | self.setLayout(layout) 30 | 31 | def plot_points(self, event): 32 | x = np.random.random(1000) 33 | y = np.random.random(1000) 34 | self.ax.cla() 35 | self.ax.plot(x, y, '.') 36 | self.fig.canvas.draw() 37 | 38 | 39 | app = QApplication([]) 40 | 41 | widget = MyMatplotlibWidget() 42 | widget.show() 43 | 44 | app.exec_() 45 | -------------------------------------------------------------------------------- /examples/mywidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 463 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Add Star 23 | 24 | 25 | 26 | 27 | 28 | 29 | Add Planet 30 | 31 | 32 | 33 | 34 | 35 | 36 | Add Galaxy 37 | 38 | 39 | 40 | 41 | 42 | 43 | big galaxy mode 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /2.button.rst: -------------------------------------------------------------------------------- 1 | Part 2 - Buttons and events 2 | =========================== 3 | 4 | Let's be honest - the application we wrote in :doc:`1.hello` wasn't the most 5 | exciting one ever. In this section, we're going to look at how to use buttons, 6 | and we will learn about events in Qt. 7 | 8 | First, let's create a button (remember that as mentioned in :doc:`1.hello`, 9 | you should always set up a ``QApplication`` first):: 10 | 11 | from qtpy.QtWidgets import QPushButton 12 | button = QPushButton('Say hello') 13 | 14 | Qt widgets often have different kinds of *events* you can connect to. An event 15 | is just something that happens for example (but not limited to) something the 16 | user does. For instance, ``button`` has an event called ``clicked`` that 17 | gets triggered when the user clicks on the button. The normal way to use events 18 | is to write functions that can then do something as a result of the event 19 | being triggered. 20 | 21 | Let's write a function that will get executed when the user clicks on the button:: 22 | 23 | def say_hello(event): 24 | print('Hello, world!') 25 | 26 | Such a function typically takes the event as its only positional argument. 27 | 28 | We can then connect this function to the ``clicked`` event:: 29 | 30 | button.clicked.connect(say_hello) 31 | 32 | Finally, we can show the button with:: 33 | 34 | button.show() 35 | 36 | Let's take a look at the full example: 37 | 38 | .. literalinclude:: examples/2.button.py 39 | 40 | Copy this into a Python script, and run it with e.g.:: 41 | 42 | python 2.button.py 43 | 44 | You should see a small window pop up with a button inside: 45 | 46 | .. image:: images/2.button.png 47 | :align: center 48 | :scale: 60% 49 | 50 | Now click on the button and you should see the following message appear in the 51 | terminal:: 52 | 53 | Hello, world! 54 | 55 | Such fun! 56 | -------------------------------------------------------------------------------- /1.hello.rst: -------------------------------------------------------------------------------- 1 | Part 1 - Hello, World! 2 | ====================== 3 | 4 | To start off, we need to create a ``QApplication`` object, which represents the 5 | overall application:: 6 | 7 | from qtpy.QtWidgets import QApplication 8 | app = QApplication([]) 9 | 10 | You will always need to ensure that a ``QApplication`` object exists, otherwise 11 | your Python script will terminate with an error if you try and use any other Qt 12 | objects. The above won't open any window - the term *application* here doesn't 13 | refer to a specific window that will open, but instead to a windowless object 14 | that forms the basis for anything else we will build. 15 | 16 | Building blocks in Qt (and other similar frameworks) are called *widgets*. One 17 | of the simplest widgets is a text label. We can create a label widget by doing:: 18 | 19 | from qtpy.QtWidgets import QLabel 20 | label = QLabel('Hello, world!') 21 | label.show() 22 | 23 | Note that this should be done after creating a ``QApplication`` object. We need 24 | to explicitly tell Qt that we want to show the widget as a graphical window 25 | using ``.show()``, otherwise it will not be shown (this will come in handy once 26 | we want to use widgets as building blocks for windows). 27 | 28 | If you were to run the two code blocks above, the label would appear and 29 | disappear straight away because the script would finish running. The final step 30 | is to start the event loop. In graphical user interface (GUI) programming, an 31 | *event loop* is a common concept - the idea is to basically have an infinite 32 | loop that will continuously check for user interaction with the interface, such 33 | as clicking on buttons, entering text, and moving or closing windows. 34 | The infinite loop can be terminated in various ways depending on the 35 | configuration in ``QApplication`` - by default it will terminate once the 36 | visible windows are closed. To start the event loop, we can do:: 37 | 38 | app.exec_() 39 | 40 | This is equivalent to doing:: 41 | 42 | while True: 43 | app.processEvents() 44 | 45 | Let's take a look at the complete example: 46 | 47 | .. literalinclude:: examples/1.hello.py 48 | 49 | Copy this into a Python script, and run it with e.g.:: 50 | 51 | python 1.hello.py 52 | 53 | You should see a small window pop up with 'Hello, world!' 54 | inside: 55 | 56 | .. image:: images/1.hello.png 57 | :align: center 58 | :scale: 60% 59 | 60 | Close the window, and the Python script should stop running. 61 | 62 | Congratulations, you've written your first Qt application! 63 | -------------------------------------------------------------------------------- /3.layout.rst: -------------------------------------------------------------------------------- 1 | Part 3 - Laying out widgets 2 | =========================== 3 | 4 | Vertical layout 5 | --------------- 6 | 7 | Let's now take a look at how to construct more interesting application windows 8 | by combining different widgets together. Qt widgets can all include a 'layout', 9 | which defines combinations of children widgets. A simple example is the 10 | ``QVBoxLayout`` class, which allows widgets to be stacked vertically. Let's 11 | use a label and a button widget and stack these vertically into a layout:: 12 | 13 | from qtpy.QtWidgets import QLabel, QVBoxLayout, QPushButton 14 | 15 | # Create label and button 16 | label = QLabel('Hello, world!') 17 | button = QPushButton('test') 18 | 19 | # Create layout and add widgets 20 | layout = QVBoxLayout() 21 | layout.addWidget(label) 22 | layout.addWidget(button) 23 | 24 | However, note that a layout is not a widget, so we can't simply do 25 | ``layout.show()`` at this point. Instead, we need to add this layout to a parent 26 | widget. For this, we'll use ``QWidget``, which is the most basic kind of a 27 | widget - it contains nothing by default:: 28 | 29 | widget = QWidget() 30 | widget.setLayout(layout) 31 | 32 | We can now show this widget using:: 33 | 34 | widget.show() 35 | 36 | Note that in this kind of situation, it's clear why we don't want widgets to be 37 | shown by default and to have to specify ``widget.show()``. If we were to instead 38 | run ``button.show()``, only the button widget would be shown. 39 | 40 | Here is the complete example: 41 | 42 | .. literalinclude:: examples/3.vertical_layout.py 43 | 44 | Copy this into a Python script, and run it with e.g.:: 45 | 46 | python 3.vertical_layout.py 47 | 48 | You should see a small window pop up with the two widgets: 49 | 50 | .. image:: images/3.vertical_layout.png 51 | :align: center 52 | :scale: 60% 53 | 54 | Other layouts 55 | ------------- 56 | 57 | There are other types of layout besides vertical stacking. As you might expect, 58 | there is a corresponding ``QHBoxLayout`` class that will stack widgets 59 | horizontally:: 60 | 61 | from qtpy.QtWidgets import QHBoxLayout 62 | 63 | layout = QHBoxLayout() 64 | layout.addWidget(label) 65 | layout.addWidget(button) 66 | 67 | which will look like: 68 | 69 | .. image:: images/3.horizontal_layout.png 70 | :align: center 71 | :scale: 60% 72 | 73 | Another example is ``QGridLayout`` which allows widgets to be places in a grid. 74 | To add widgets to this kind of layout, you need to specify the row and column:: 75 | 76 | # Create label and button 77 | label1 = QLabel('Label 1') 78 | label2 = QLabel('Label 2') 79 | label3 = QLabel('Label 3') 80 | button = QPushButton('Press me!') 81 | 82 | # Create layout and add widgets 83 | layout = QGridLayout() 84 | layout.addWidget(label1, 0, 0) 85 | layout.addWidget(label2, 1, 0) 86 | layout.addWidget(label3, 0, 1) 87 | layout.addWidget(button, 1, 1) 88 | 89 | which will look like: 90 | 91 | .. image:: images/3.grid_layout.png 92 | :align: center 93 | :scale: 60% 94 | 95 | Nesting layouts 96 | --------------- 97 | 98 | In practice, you may need to use more complex layouts - for this, you can start 99 | to nest layouts. You can do this by adding a layout to a widget which is itself 100 | in a layout. Let's take a look at the following example: 101 | 102 | .. literalinclude:: examples/3.nested_layout.py 103 | 104 | This will result in the following window: 105 | 106 | .. image:: images/3.nested_layout.png 107 | :align: center 108 | :scale: 60% 109 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/stable/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'Python Qt tutorial' 23 | copyright = '2018, Thomas P. Robitaille' 24 | author = 'Thomas P. Robitaille' 25 | 26 | # The short X.Y version 27 | version = '' 28 | # The full version, including alpha/beta/rc tags 29 | release = '0.0' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.intersphinx', 43 | ] 44 | 45 | # Add any paths that contain templates here, relative to this directory. 46 | templates_path = ['_templates'] 47 | 48 | # The suffix(es) of source filenames. 49 | # You can specify multiple suffix as a list of string: 50 | # 51 | # source_suffix = ['.rst', '.md'] 52 | source_suffix = '.rst' 53 | 54 | # The master toctree document. 55 | master_doc = 'index' 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | # 60 | # This is also used if you do content translation via gettext catalogs. 61 | # Usually you set "language" from the command line for these cases. 62 | language = None 63 | 64 | # List of patterns, relative to source directory, that match files and 65 | # directories to ignore when looking for source files. 66 | # This pattern also affects html_static_path and html_extra_path . 67 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 68 | 69 | # The name of the Pygments (syntax highlighting) style to use. 70 | pygments_style = 'sphinx' 71 | 72 | 73 | # -- Options for HTML output ------------------------------------------------- 74 | 75 | # The theme to use for HTML and HTML Help pages. See the documentation for 76 | # a list of builtin themes. 77 | # 78 | # html_theme = 'alabaster' 79 | 80 | # Theme options are theme-specific and customize the look and feel of a theme 81 | # further. For a list of options available for each theme, see the 82 | # documentation. 83 | # 84 | # html_theme_options = {} 85 | 86 | # Add any paths that contain custom static files (such as style sheets) here, 87 | # relative to this directory. They are copied after the builtin static files, 88 | # so a file named "default.css" will overwrite the builtin "default.css". 89 | html_static_path = ['_static'] 90 | 91 | # Custom sidebar templates, must be a dictionary that maps document names 92 | # to template names. 93 | # 94 | # The default sidebars (for documents that don't match any pattern) are 95 | # defined by theme itself. Builtin themes are using these templates by 96 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 97 | # 'searchbox.html']``. 98 | # 99 | # html_sidebars = {} 100 | 101 | 102 | # -- Options for HTMLHelp output --------------------------------------------- 103 | 104 | # Output file base name for HTML help builder. 105 | htmlhelp_basename = 'PythonQttutorialdoc' 106 | 107 | 108 | # -- Options for LaTeX output ------------------------------------------------ 109 | 110 | latex_elements = { 111 | # The paper size ('letterpaper' or 'a4paper'). 112 | # 113 | # 'papersize': 'letterpaper', 114 | 115 | # The font size ('10pt', '11pt' or '12pt'). 116 | # 117 | # 'pointsize': '10pt', 118 | 119 | # Additional stuff for the LaTeX preamble. 120 | # 121 | # 'preamble': '', 122 | 123 | # Latex figure (float) alignment 124 | # 125 | # 'figure_align': 'htbp', 126 | } 127 | 128 | # Grouping the document tree into LaTeX files. List of tuples 129 | # (source start file, target name, title, 130 | # author, documentclass [howto, manual, or own class]). 131 | latex_documents = [ 132 | (master_doc, 'PythonQttutorial.tex', 'Python Qt tutorial Documentation', 133 | 'Thomas P. Robitaille', 'manual'), 134 | ] 135 | 136 | 137 | # -- Options for manual page output ------------------------------------------ 138 | 139 | # One entry per manual page. List of tuples 140 | # (source start file, name, description, authors, manual section). 141 | man_pages = [ 142 | (master_doc, 'pythonqttutorial', 'Python Qt tutorial Documentation', 143 | [author], 1) 144 | ] 145 | 146 | 147 | # -- Options for Texinfo output ---------------------------------------------- 148 | 149 | # Grouping the document tree into Texinfo files. List of tuples 150 | # (source start file, target name, title, author, 151 | # dir menu entry, description, category) 152 | texinfo_documents = [ 153 | (master_doc, 'PythonQttutorial', 'Python Qt tutorial Documentation', 154 | author, 'PythonQttutorial', 'One line description of project.', 155 | 'Miscellaneous'), 156 | ] 157 | 158 | 159 | # -- Extension configuration ------------------------------------------------- 160 | 161 | # -- Options for intersphinx extension --------------------------------------- 162 | 163 | # Example configuration for intersphinx: refer to the Python standard library. 164 | intersphinx_mapping = {'https://docs.python.org/': None} 165 | --------------------------------------------------------------------------------