В фреймворке PyQt (и PySide тоже) часто встречается настройка чего-либо с помощью так называемых флагов.
Несколько флагов можно указать с помощью оператора "|"
#qt
widget.setWindowFlags(Qt.Window)
Взаимодействие нескольких флагов делается с помощью бинарных (или побитовых) операторов. Несколько флагов можно указать с помощью оператора "|"
list_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
исключить флаг из уже имеющегося набора можно такlist_item.setFlags(list_item.flags() ^ Qt.ItemIsEnabled)
Добавить новый флаг к имеющимся можно такlist_item.setFlags(list_item.flags() | Qt.ItemIsEnabled)
А проверка наличия делается такis_enabled = item.flags() & Qt.ItemIsEnabled > 0
Почему именно так? Всё дело в том как именно работают побитовые операторы. Но об этом в следующем посте.#qt
Когда разрабатываете свой GUI с помощью PyQt для какого-либо софта бывает необходимо позаимствовать цвета из текущего стиля интерфейса. Например, чтобы правильно раскрасить свои виджеты, подогнав их по цвету. Ведь бывает, что ваш GUI используется в разных софтах. Причём некоторые со светлой темой а другие с тёмной.
По умолчанию стили наследуются, но если вы задаёте какую-либо раскраску для части виджета через свой styleSheet, то требуется ссылаться на цвета текущего стиля.
Как это сделать? Как получить нужный цвет из палитры имеющегося стиля? Это достаточно просто, нужно использовать класс QPalette и его роли.
Например, мне нужно достать цвет текста из одного виджета и применить его в другом как цвет фона (не важно зачем именно так, просто захотелось😊).
Получаем палитру виджета и сразу достаём нужный цвет, указав его роль.
На самом деле есть запись покороче, в одну строку и без лишних переменных. Не очень-то по правилам CSS, но Qt это понимает.
Зато он прекрасно сработает в файле .qss, то есть не придётся в коде прописывать раскраску отдельных элементов через ссылки на палитру, всё красиво сохранится в отдельном файле .qss!
#qt #tricks
По умолчанию стили наследуются, но если вы задаёте какую-либо раскраску для части виджета через свой styleSheet, то требуется ссылаться на цвета текущего стиля.
Как это сделать? Как получить нужный цвет из палитры имеющегося стиля? Это достаточно просто, нужно использовать класс QPalette и его роли.
Например, мне нужно достать цвет текста из одного виджета и применить его в другом как цвет фона (не важно зачем именно так, просто захотелось😊).
Получаем палитру виджета и сразу достаём нужный цвет, указав его роль.
from PySide2.QtGui import QPaletteтеперь можем использовать этот цвет в стилях
color = main_window.palette().color(QPalette.Text)
my_widget.setStyleSheet(f'background-color: {color.name()};')
Готово, мы динамически переопределили дефолтный стиль используя текущий стиль окна! На самом деле есть запись покороче, в одну строку и без лишних переменных. Не очень-то по правилам CSS, но Qt это понимает.
my_widget.setStyleSheet('background-color: palette(Text);')
Этот способ не подходит если вам нужно как-то модифицировать цвет перед применением в своих стилях. В этом случае потребуется первый способ. Зато он прекрасно сработает в файле .qss, то есть не придётся в коде прописывать раскраску отдельных элементов через ссылки на палитру, всё красиво сохранится в отдельном файле .qss!
QListView#my_widget::item:selected {
background: palette(Midlight);
}
Про имеющиеся роли можно почитать здесь 🌍#qt #tricks
Ещё немного про base64.
Собрал пример со встроенной в код картинкой. Это иконка для окна на PySide2. Файл кодирован в base64 и просто сохранён в переменной.
Для использования этих данных даже не пришлось сохранять их в новый файл. Иконка создаётся на лету с помощью метода QPixmap.loadFromData()
#libs #tricks #qt
Собрал пример со встроенной в код картинкой. Это иконка для окна на PySide2. Файл кодирован в base64 и просто сохранён в переменной.
Для использования этих данных даже не пришлось сохранять их в новый файл. Иконка создаётся на лету с помощью метода QPixmap.loadFromData()
...
raw_data = base64.decodebytes(ico_encoded)
ico = QPixmap()
ico.loadFromData(raw_data, "PNG")
...
🌎 Полный пример смотрите в gists.#libs #tricks #qt
This media is not supported in your browser
VIEW IN TELEGRAM
Есть у QLabel есть одна особенность. Её минимальный размер определяется текстом, который в неё записан. Это приводит к тому что длинный текст принудительно увеличивает ширину интерфейса.
В большинстве случаев это выглядит плохо.
Как с этим бороться?
🔸 Обрезать текст заранее, задав лимит по длине строки. В этом случае мы теряем часть визуальной информации. Не всегда угадаешь нужный размер. В разных OS шрифт используется разный.
🔸 Делать перенос строки. Тогда мы получим изменение размера в другую сторону, что тоже поломает интерфейс.
🔸 Переопределить paintEvent() и сделать кастомный рендеринг текста. Можно, но слишком сложно для такой задачи.
Проще всего обрезать текст под текущий размер виджета используя класс QFontMetrics.
Он имеет готовый метод elidedText(), который просто вызываем по событию resizeEvent.
Я также добавил установку ToolTip чтобы всегда можно было увидеть полный текст при наведении курсора.
🌎 Код здесь
#qt #source
В большинстве случаев это выглядит плохо.
Как с этим бороться?
🔸 Обрезать текст заранее, задав лимит по длине строки. В этом случае мы теряем часть визуальной информации. Не всегда угадаешь нужный размер. В разных OS шрифт используется разный.
🔸 Делать перенос строки. Тогда мы получим изменение размера в другую сторону, что тоже поломает интерфейс.
🔸 Переопределить paintEvent() и сделать кастомный рендеринг текста. Можно, но слишком сложно для такой задачи.
Проще всего обрезать текст под текущий размер виджета используя класс QFontMetrics.
Он имеет готовый метод elidedText(), который просто вызываем по событию resizeEvent.
Я также добавил установку ToolTip чтобы всегда можно было увидеть полный текст при наведении курсора.
🌎 Код здесь
#qt #source
This media is not supported in your browser
VIEW IN TELEGRAM
Опубликовал для вас один из своих учебных проектов моего курса про PySide2 — LaunchPanel.
Это панель, которая выезжает сверху экрана когда к ней подводишь курсор. Содержит кнопки для запуска любых команд.
🔸 можно добавить любые команды
🔸 одна кнопка может содержать много вариантов одной команды. Доступ к ним через контекстное меню
🔸 панель настраивается через файлы конфига
Но самое главное в этом проекте то, что почти каждая строка задокументирована! 😱
Что используется в проекте?
🔸 стилизация виджетов через StyleSheet
🔸 настройка отображения окна как панели без рамок, заголовка и всего остального
🔸 использование файлов конфига
🔸 HTML текст в виджетах
🔸 анимация свойств виджета (позиция и прозрачность)
🔸 реакция виджета на курсор
🔸 запуск подпроцессов
🌎 Исходники забираем здесь
Смотрите, изучайте, пользуйтесь 😉
#qt #source
Это панель, которая выезжает сверху экрана когда к ней подводишь курсор. Содержит кнопки для запуска любых команд.
🔸 можно добавить любые команды
🔸 одна кнопка может содержать много вариантов одной команды. Доступ к ним через контекстное меню
🔸 панель настраивается через файлы конфига
Но самое главное в этом проекте то, что почти каждая строка задокументирована! 😱
Что используется в проекте?
🔸 стилизация виджетов через StyleSheet
🔸 настройка отображения окна как панели без рамок, заголовка и всего остального
🔸 использование файлов конфига
🔸 HTML текст в виджетах
🔸 анимация свойств виджета (позиция и прозрачность)
🔸 реакция виджета на курсор
🔸 запуск подпроцессов
🌎 Исходники забираем здесь
Смотрите, изучайте, пользуйтесь 😉
#qt #source
А вы ждёте Qt6 как жду его я? )))
Наверняка, те кто ждёт, уже в курсе, но я уточню даты релизов.
- Qt 6.0 Feature freeze - 31.8.2020
- Qt 6.0 Alpha - 2.10.2020
- Qt 6.0 Beta 1 - 15.10.2020
- Qt 6.0.0 RC - 17.11.2020
- Qt 6.0.0 Final - 1.12.2020
Полный список https://wiki.qt.io/Qt_6.0_Release
Между тем, библиотеки PySide3 ждать не стоит. Дело в том, что разработчики решили синхронизировать версии библиотек C++ и Qt for Python.
Так что ждём сразу PySide6!
#qt
Наверняка, те кто ждёт, уже в курсе, но я уточню даты релизов.
- Qt 6.0 Feature freeze - 31.8.2020
- Qt 6.0 Alpha - 2.10.2020
- Qt 6.0 Beta 1 - 15.10.2020
- Qt 6.0.0 RC - 17.11.2020
- Qt 6.0.0 Final - 1.12.2020
Полный список https://wiki.qt.io/Qt_6.0_Release
Между тем, библиотеки PySide3 ждать не стоит. Дело в том, что разработчики решили синхронизировать версии библиотек C++ и Qt for Python.
Так что ждём сразу PySide6!
#qt
🙄 Разминка для ума!
Треугольник Серпинского, интересная фигура которую построить достаточно просто.
Алгоритм такой:
1. создаём любые 3 точки на плоскости
2. из этих точек случайно выбираем любую, как начальную
3. случайно выбираем любую точку из этих же трёх точек как цель
4. перемещаемся в сторону цели на половину расстояния
5. повторяем бесконечно с пункта 3
Если сделать достаточно много итераций то вырисовывается интересная фигура. Треугольник, в который вписаны более мелкие треугольники. Это самый настоящий фрактал!
Я собрал пример построения такой фигуры на базе Qt.
🌎 Код можно посмотреть здесь.
С помощью paintEvent я рисую точки по озвученному алгоритму. Каждые 10 секунд либо по клику на виджете строится следующий треугольник.
Особенности примера:
🔸 Атрибут Qt.WA_OpaquePaintEvent позволяет сохранить то, что было нарисовано в прошлой итерации. Таким образом мы видим постепенное наполнение точек а не мелькающую одну точку.
🔸 QTimer позволяет создавать отложенные вызовы один раз или с повторением через интервал.
🔸 QColor.fromHsv() позволяет создать рандомный но предсказуемый цвет с помощью HSV схемы. Не слишком светлый и не слишком тёмный но всегда с разный. Рандомизации подвергается только смещение по цветовому кругу (Hue), яркость (Value) и насыщенность (Saturation) можно контролировать отдельно в своих пределах или оставить статичными. Обычный рандом цвета по RGB не даёт такой предсказуемый результат.
🔸 Каждый новый цикл с новым треугольником предварительно затемняет предыдущие через этот вызов
Если сделать виджет фулскрин, то у нас получится некий ScreenSaver)))
🔸 Да, я знаю, что рисование в Qt не самый лучший способ сделать этот пример) Скорее всего самый НЕподходящий. Попробуйте сделать тоже самое но другими средствами.
#qt #source #tricks
Треугольник Серпинского, интересная фигура которую построить достаточно просто.
Алгоритм такой:
1. создаём любые 3 точки на плоскости
2. из этих точек случайно выбираем любую, как начальную
3. случайно выбираем любую точку из этих же трёх точек как цель
4. перемещаемся в сторону цели на половину расстояния
5. повторяем бесконечно с пункта 3
Если сделать достаточно много итераций то вырисовывается интересная фигура. Треугольник, в который вписаны более мелкие треугольники. Это самый настоящий фрактал!
Я собрал пример построения такой фигуры на базе Qt.
🌎 Код можно посмотреть здесь.
С помощью paintEvent я рисую точки по озвученному алгоритму. Каждые 10 секунд либо по клику на виджете строится следующий треугольник.
Особенности примера:
🔸 Атрибут Qt.WA_OpaquePaintEvent позволяет сохранить то, что было нарисовано в прошлой итерации. Таким образом мы видим постепенное наполнение точек а не мелькающую одну точку.
🔸 QTimer позволяет создавать отложенные вызовы один раз или с повторением через интервал.
🔸 QColor.fromHsv() позволяет создать рандомный но предсказуемый цвет с помощью HSV схемы. Не слишком светлый и не слишком тёмный но всегда с разный. Рандомизации подвергается только смещение по цветовому кругу (Hue), яркость (Value) и насыщенность (Saturation) можно контролировать отдельно в своих пределах или оставить статичными. Обычный рандом цвета по RGB не даёт такой предсказуемый результат.
🔸 Каждый новый цикл с новым треугольником предварительно затемняет предыдущие через этот вызов
painter.fillRect(rec, QColor(0, 0, 0, 100))
То есть полупрозрачный цвет. Таким образом, чем старше треугольник, тем он темней. Если сделать виджет фулскрин, то у нас получится некий ScreenSaver)))
🔸 Да, я знаю, что рисование в Qt не самый лучший способ сделать этот пример) Скорее всего самый НЕподходящий. Попробуйте сделать тоже самое но другими средствами.
#qt #source #tricks
Для тех кто пишет расширения на PyQt/PySide для CG-софтов.
Когда я только начинал писать тулзы под Maya (тогда еще версия 2010-2011) мне приходилось ручками ставить PyQt4 под Maya. Даже написал мануалы по установке на своём сайте. Но потом стал доступен из коробки PySide и позже он обновится до PySide2. Для некоторых систем была поддержка PyQt5.
И как простому разработчику поддерживать этот зоопарк? Ведь хочется чтобы тул работал на любой версии (вы тоже делали модуль что-то типа import_qt.py? 😁)
На помощь приходит проект Qt.py который поставил себе цель унифицировать использование Qt-биндингов вне зависимости от среды где запускается код. Те, кто давно пишут на Qt, скорее всего знают этот проект.
Он стал стандартом для CG-индустрии и используется в топовых студиях и проектах.
Qt․py помогает запускать один и тот же код на разных платформах с разными вариантами Qt-библиотек. Это может быть как интеграция в CG-софт, так и переносимость стендалонов между разными платформами с разными версиями Python.
Я решил рассказать о некоторых особенностях работы с этой библиотекой.
Сегодня о том, как установить и использовать Qt․py и что это вам даёт.
Установка
При этом не потребуется использовать if-else конструкции под разные версии. Все вызовы теперь одинаковы.
Всё что нужно сделать, это написать его по правилам PySide2. Именно эта версия была взята за основу.
Приоритет импорта такой:
1. PySide2
2. PyQt5
3. PySide
4. PyQt4
Что именно загрузилось можно посмотреть в переменной
#qt #libs
Когда я только начинал писать тулзы под Maya (тогда еще версия 2010-2011) мне приходилось ручками ставить PyQt4 под Maya. Даже написал мануалы по установке на своём сайте. Но потом стал доступен из коробки PySide и позже он обновится до PySide2. Для некоторых систем была поддержка PyQt5.
И как простому разработчику поддерживать этот зоопарк? Ведь хочется чтобы тул работал на любой версии (вы тоже делали модуль что-то типа import_qt.py? 😁)
На помощь приходит проект Qt.py который поставил себе цель унифицировать использование Qt-биндингов вне зависимости от среды где запускается код. Те, кто давно пишут на Qt, скорее всего знают этот проект.
Он стал стандартом для CG-индустрии и используется в топовых студиях и проектах.
Qt․py помогает запускать один и тот же код на разных платформах с разными вариантами Qt-библиотек. Это может быть как интеграция в CG-софт, так и переносимость стендалонов между разными платформами с разными версиями Python.
Я решил рассказать о некоторых особенностях работы с этой библиотекой.
Сегодня о том, как установить и использовать Qt․py и что это вам даёт.
Установка
pip install Qt.pyЧтобы начать использовать Qt․py в коде достаточно заменить импорт вашего варианта Qt-биндинга на Qt․py
from [PySide|PyQt4|PySide2|PyQt5] import QtWidgetsТеперь ваш код будет поддерживать любой вариант биндинга Qt в Python.
=>
from Qt import QtWidgets
При этом не потребуется использовать if-else конструкции под разные версии. Все вызовы теперь одинаковы.
Всё что нужно сделать, это написать его по правилам PySide2. Именно эта версия была взята за основу.
Приоритет импорта такой:
1. PySide2
2. PyQt5
3. PySide
4. PyQt4
Что именно загрузилось можно посмотреть в переменной
__binding__
>>> import QtПриоритет имопрта можно изменить через переменные
>>> Qt.__binding__
'PySide2'
QT_PREFERRED_BINDING и QT_PREFERRED_BINDING_JSON. Причем под каждый проект оверрайды можно настраивать индивидеально.#qt #libs
GitHub
GitHub - mottosso/Qt.py: Minimal Python 2 & 3 shim around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5.
Minimal Python 2 & 3 shim around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5. - mottosso/Qt.py
В прошлом посте говоря "Все вызовы теперь одинаковы" я несколько слукавил. Всё-таки есть в этом зоопарке версий некоторая несовместимость вызов которой просто так не унифицировать. Эти моменты вынесены в отдельный модуль QtCompat (compatibility). Там не так много функций но они довольно полезны.
Этот модуль содержит унификаци модуля shiboken2, функций loadUi, translate и несколько переименованных функций классов или изменённую сигнатуру аргументов и возвращаемых значений. Это единственное исключение из правила когда вам потребуется где-то изменить свой код кроме импортов и этот код не похож на обычный код PySide2.
Например, в PyQt4 и PySide есть метод
Полный список можно посмотреть в таблице.
#qt #tricks
Этот модуль содержит унификаци модуля shiboken2, функций loadUi, translate и несколько переименованных функций классов или изменённую сигнатуру аргументов и возвращаемых значений. Это единственное исключение из правила когда вам потребуется где-то изменить свой код кроме импортов и этот код не похож на обычный код PySide2.
Например, в PyQt4 и PySide есть метод
QHeaderView.setResizeModeДля PyQt5 и PySide2 они были благополучно переименованы в
QHeaderView.setSectionResizeModeЧтобы применить этот метод следует использовать такой код
from Qt import QtCompathУнификация загрузки UI файлов:
header = self.horizontalHeader()
QtCompat.QHeaderView.setSectionResizeMode(header, QtWidgets.QHeaderView.Fixed)
# PySide2Хорошо что таких моментов не много и их легко запомнить.
from PySide2.QtUiTools import QUiLoader
loader = QUiLoader()
widget = loader.load(ui_file)
# PyQt5
from PyQt5 import uic
widget = uic.loadUi(ui_file)
# Qt.py
from Qt import QtCompat
widget = QtCompat.loadUi(ui_file)
Полный список можно посмотреть в таблице.
#qt #tricks
GitHub
GitHub - mottosso/Qt.py: Minimal Python 2 & 3 shim around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5.
Minimal Python 2 & 3 shim around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5. - mottosso/Qt.py
Модуль Qt․py это не просто текстовый модуль, его компоненты генерируются на лету в зависимости от ситуации.
Поэтому ваша любимая IDE не сможет качественно сообразить автокомплиты под этот модуль.
Решение здесь более чем очевидно, надо сделать stubs-файлы. Это файлы с расширением .pyi, описывающие содержимое модуля но не имеющие рабочего кода.
Ну что, готовы потратить пару месяцев своей жизни чтобы описать все классы Qt и их методы? 😭
Расслабьтесь, за вас это уже сделали добрые люди.
Спасибо Fredrik Averpil !
Качаем здесь ⬇️
https://github.com/fredrikaverpil/Qt.py/tree/stubs/stubs/Qt
Не думаю что стоит устанавливать Qt․py из этого репозитория. Он там не обновляется. Так что забираем только файлы .pyi.
За актуальность этих файлов тоже не ручаюсь, но большинство методов там имеются.
Установка:
🔸 Вариант 1:
- находим куда установлен сам модуль Qt․py, это будет одинокий файл который так и называется Qt․py
- кидаем директорию рядом с ним (если есть доступ на запись). Должно получиться так:
- копируем директорию Qt куда угодно
- пробиваем путь к ней в настройках энвайронмента в переменную PATH так, чтобы путь был ДО директории Qt.
Закинуть можно и в свою домашнюю директорию. Если скопируете сюда:
#qt #libs #tricks
Поэтому ваша любимая IDE не сможет качественно сообразить автокомплиты под этот модуль.
Решение здесь более чем очевидно, надо сделать stubs-файлы. Это файлы с расширением .pyi, описывающие содержимое модуля но не имеющие рабочего кода.
Ну что, готовы потратить пару месяцев своей жизни чтобы описать все классы Qt и их методы? 😭
Расслабьтесь, за вас это уже сделали добрые люди.
Спасибо Fredrik Averpil !
Качаем здесь ⬇️
https://github.com/fredrikaverpil/Qt.py/tree/stubs/stubs/Qt
Не думаю что стоит устанавливать Qt․py из этого репозитория. Он там не обновляется. Так что забираем только файлы .pyi.
За актуальность этих файлов тоже не ручаюсь, но большинство методов там имеются.
Установка:
🔸 Вариант 1:
- находим куда установлен сам модуль Qt․py, это будет одинокий файл который так и называется Qt․py
- кидаем директорию рядом с ним (если есть доступ на запись). Должно получиться так:
📁 site-packages\🔸 Вариант 2
📄 Qt.py
📁 Qt\
...
- копируем директорию Qt куда угодно
- пробиваем путь к ней в настройках энвайронмента в переменную PATH так, чтобы путь был ДО директории Qt.
Закинуть можно и в свою домашнюю директорию. Если скопируете сюда:
~/stubs/QtТо переменную пишем так
export PATH=~/stubs:${PATH}
После этого IDE должна распарсить stubs-файлы и автокомплиты появятся 😎#qt #libs #tricks
GitHub
Qt.py/stubs/Qt at stubs · fredrikaverpil/Qt.py
Python 2 & 3 compatibility wrapper around all Qt bindings - PySide, PySide2, PyQt4 and PyQt5. - Qt.py/stubs/Qt at stubs · fredrikaverpil/Qt.py