{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Графический пользовательский интерфейс\n", "\n", "## Библиотеки для разработки графического интерфейса\n", "\n", "Существует множество инструментов, которые позволяют реализовать графический интерфейс в `python`. Среди них особняком стоит модуль встроенной библиотеки [tkinter](https://docs.python.org/3/library/tkinter.html): `tkinter` входит в стандартный дистрибутив `CPython`, а значит его использование не приводит к раздуванию зависимостей проекта. \n", "\n", "Остальные средства разработки графического интерфейса представлены в виде сторонних библиотек. Они, часто, предоставляют более функциональные и удобные инструменты нежели `tkinter`, но добавляют зависимостей к проекту, а также нередко требуют следовать лицензионному соглашению. Таких библиотек очень много, среди них:\n", "- Расширения для [Qt](https://www.qt.io/) на `python`: [PyQt](https://riverbankcomputing.com/software/pyqt/intro) и [PySide](https://www.qt.io/qt-for-python);\n", "- [Kivy](https://towardsdatascience.com/top-10-python-gui-frameworks-for-developers-adca32fbe6fc), [wxPython](https://www.wxpython.org/), [PySimpleGUI](https://pysimplegui.readthedocs.io/en/latest/) и другие.\n", "\n", "Здесь пойдет речь о `Qt`.\n", "\n", "## PySide vs PyQt\n", "\n", "Есть два распространенных расширения `Qt` для `Python`: `PtQt` и `PySide`. `PyQt` появился раньше и долгое время опережал `PySide`. На сегодня это отставание полностью сократилось (более того, `PySide6` вышел на месяц раньше `PyQt6`). Существование двух расширений объясняется различием в лицензировании: `PySide` распространяется под всеми теми же лицензиями, что и сам `Qt` (более того, его разрабатывает та же компания), а `PyQt` с несколько другим набором вариантов лицензирования.\n", "\n", "С точки зрения кода обе библиотеки почти эквиваленты. Оба расширения переносят имена объектов из `C++` в `python` без изменений. Миграция в обе стороны требует минимальных правок. \n", "\n", "Далее везде речь пойдет о `PySide6`, но большинство утверждений и примеров останутся корректными, если заменить в них `PySide` на `PyQt`. \n", "\n", "## Элементы графического интерфейса в `Jupyter`\n", "\n", "Но прежде чем перейти к изучению полноценного фреймворка для создания приложений с графическим интерфейсом `Qt`, упомянем способ воплотить интерфейс прямо в `Jupyter` ноутбуке.\n", "\n", "Библиотека [ipywidgets](https://ipywidgets.readthedocs.io/en/latest/index.html) позволяет добавлять элементы графического интерфейса прямо в `Jupyter` ноутбуке. С помощью этого инструмента можно быстро настроить интерактивное взаимодействие с кодом в блокноте. Например, это может быть полезно, чтобы пощупать какую-нибудь параметрическую модель: интерактивно изменяя параметры (например, ползунком), можно составить представления о том, как они влияют на модель.\n", "\n", "В качестве примера ниже приводится код, который предоставляет интерактивный интерфейс к построению графика\n", "функции $y=f(\\omega x)$: \n", "- выбор функции $f$, \n", "- значение параметра функции $\\omega$ \n", "- выбор цвета линии,\n", "- текст заголовка графика,\n", "- вывод сетки, \n", "- размера шрифта.\n", "\n", "```{note}\n", "Элементы графического интерфейса будут отображаться на сайте, но взаимодействие с ними не будет ни к чему приводить, т.к. на фоне нет запущенного ядра `python`. Чтобы попробовать пример, установите `ipywidgets` запустите этот код в `jupyter` ноутбуке. \n", "```" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "0e485b48dec04bf4ba29e5373d910fd7", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Dropdown(description='fname', options=('sin', 'cos'), value='sin'), FloatSlider(value=1.…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from IPython.display import display\n", "from ipywidgets import interact\n", "import ipywidgets as widgets\n", "\n", "import numpy as np\n", "from matplotlib import pyplot as plt\n", "\n", "def plot(fname, omega, color, title, grid, fontsize):\n", " plt.rcParams.update({\"font.size\":fontsize})\n", " \n", " x = np.linspace(0, 2 * np.pi, 200)\n", " fig, ax = plt.subplots(figsize=(10, 9))\n", " ax.set_ylim(-1, 1)\n", " ax.set_xlabel(\"$x$\")\n", " ax.set_ylabel(\"$y$\")\n", " \n", " f = eval(f\"np.{fname}\")\n", " y = f(omega * x)\n", " ax.plot(x, y, label=fname, color=color)\n", "\n", " ax.set_title(title)\n", " if grid:\n", " ax.grid()\n", "\n", "interactive_plot = interact(plot,\n", " fname=[\"sin\", \"cos\"],\n", " omega=widgets.FloatSlider(min=1., max=4., value=1.), \n", " color=widgets.ColorPicker(concise=False, description='pick a color', value='blue'),\n", " title=widgets.Text(value=\"Interactive plot\", placeholder=\"type the title\",\n", " disription=\"String:\"),\n", " grid=widgets.Checkbox(),\n", " fontsize=widgets.IntSlider(min=12, max=36, step=2, value=18)\n", " )" ] } ], "metadata": { "interpreter": { "hash": "cd49b4596bae9c980ff74fdf93e8fe80e447435ae307c062fad6c4f9ef2eb47f" }, "kernelspec": { "display_name": "Python 3.8.10 ('venv': venv)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }