Sobre o Qt
O Qt possui uma arquitetura flexível e modular, o que permite aos desenvolvedores criar aplicativos personalizados de acordo com suas necessidades específicas.
Ele fornece uma ampla gama de componentes de interface do usuário pré-construídos, como botões, caixas de diálogo, barras de ferramentas e gráficos, facilitando a criação de interfaces atraentes e funcionais.
Uma das principais vantagens do Qt é sua abordagem de desenvolvimento orientada a objetos.
Ele utiliza a linguagem C++ como base, mas também oferece suporte para outras linguagens de programação, como Python e JavaScript (QML).
Isso permite que os desenvolvedores criem aplicativos de alta qualidade com um código limpo e bem estruturado, facilitando a manutenção e aprimoramento do software ao longo do tempo.
Além disso, o Qt oferece recursos avançados, como suporte a multi-threading, bancos de dados embutidos, integração com serviços da web, conectividade de rede e suporte a internacionalização.
Ele também possui uma extensa documentação e uma comunidade ativa de desenvolvedores, o que facilita a aprendizagem e a resolução de problemas durante o processo de desenvolvimento.
O Qt é amplamente adotado em várias indústrias, como automotiva, aeroespacial, jogos, eletrônicos de consumo e automação industrial.
Sua capacidade de criar aplicativos que podem ser executados em diferentes plataformas com uma única base de código reduz o tempo e os custos de desenvolvimento, permitindo que as empresas atinjam um público mais amplo.
Em resumo, o Qt é um framework poderoso e versátil para o desenvolvimento de aplicativos multiplataforma.
Com sua ampla gama de recursos, facilidade de uso e suporte ativo da comunidade, ele se tornou uma escolha popular para desenvolvedores que desejam criar interfaces gráficas de usuário ricas e funcionais.
Sobre os bindings
🚨 Alguns bindings para outras linguagens de programação estão no final deste artigo.
A linguagem de programação Python possui 2 para para o framework gráfico Qt 6.
PySide6
O PySide6 é o binding oficial do Qt Group para a linguagem de programação Python, ele foi lançado em dezembro de 2020 e também é conhecido como Qt for Python.
- Data de lançamento: Dezembro de 2020.
- Licença: LGPL.
- Mantenedor: Qt.
Versões:
- PySide: Utilizado para a construção de interfaces gráficas com Qt 4.
- PySide2: Utilizado para a construção de interfaces gráficas com Qt 5.
- PySide6: Utilizado para a construção de interfaces gráficas com Qt 6.
PyQt6
O PyQt6 é o binding desenvolvido pela Riverbank computing.
- Data de lançamento: Janeiro de 2021.
- Licença: GPL ou comercial.
- Mantenedor: Riverbank Computing Ltd.
Versões:
- PyQt4: Utilizado para a construção de interfaces gráficas com Qt 4.
- PyQt5: Utilizado para a construção de interfaces gráficas com Qt 5.
- PyQt6: Utilizado para a construção de interfaces gráficas com Qt 6.
Instalação
Existem diversas formas de realizar a instalação dos bindings PySide6 e PyQt6
Acredito que a forma recomendada para uma boa gestão de dependências seja utilizando um ambiente virtual (venv, Poetry, PDM, etc).
PySide6
PIP
pip install PySide6
📝 Lembre-se de realizar a instalação em um ambiente virtual (venv, poetry, pdm, etc).
Arch Linux
sudo pacman -S \
pyside6 \
pyside6-tools
PyQt6
PIP
pip install PyQt6
📝 Lembre-se de realizar a instalação em um ambiente virtual (venv, poetry, pdm, etc).
Arch Linux
sudo pacman -S \
python-pyqt6
Ubuntu
sudo apt install \
python3-pyqt6
Criando uma janela
No geral o Qt 6 nos fornece 3 formas para a criação das telas.
Uma dessas formas é utilizando a própria linguagem de programação e nas outras 2 formas utilizamos os arquivos de interface (*.ui
) gerados pelo Qt Creator ou Qt Designer.
Como referencia foi utilizado o seguinte arquivo de interface (MainWindow.ui
):
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>683</width>
<height>384</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>683</width>
<height>384</height>
</size>
</property>
<property name="windowTitle">
<string>Olá Mundo</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Olá Mundo</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>683</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
PySide6
Declarativo
Essa é a forma em que utilizamos a própria linguagem de programação para criar a interface e seus componentes:
# -*- coding: utf-8 -*-
"""MainWindow.py."""
from PySide6 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, application):
super().__init__()
self.setObjectName('MainWindow')
self.application = application
self.setGeometry(0, 0, 683, 384)
self.setMinimumSize(683, 384)
self.setWindowTitle('Olá Mundo')
vbox = QtWidgets.QVBoxLayout()
central_widget = QtWidgets.QWidget()
central_widget.setLayout(vbox)
self.setCentralWidget(central_widget)
label = QtWidgets.QLabel()
label.setText('Olá Mundo')
vbox.addWidget(label)
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
window.show()
sys.exit(application.exec())
Vantagens:
- Organização do código.
- Os componentes (widget) pode ser separados em scripts e importados posteriormente.
Desvantagens:
- A equipe precisa ter conhecimento da linguagem de programação Python.
- A equipe precisa conhecer o nome dos componentes do Qt.
Pyside6-uic
O comando pyside6-uic
irá converter o arquivo de interface (*.ui
) em um script Python que será importado.
Para gerar o arquivo de interface convertido é utilizado o comando:
pyside6-uic MainWindow.ui -o Ui_MainWindow.py
Após converter o arquivo o mesmo deve ser importado:
# -*- coding: utf-8 -*-
"""Compilando arquivo de interface com PySide6.
pyside6-uic MainWindow.ui -o Ui_MainWindow.py.
"""
from PySide6 import QtWidgets
from Ui_MainWindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, application):
super().__init__()
self.application = application
self.setupUi(self)
print(self.label.text())
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
window.show()
sys.exit(application.exec())
Vantagens:
- Equipe de designe não precisa ter um conhecimento prévio da linguagem de programação.
- Criação da interface e visualização do resultado em tempo real.
- Processo de configuração dos componentes se torna mais simples.
Desvantagens:
- Cada vez que houver uma alteração no arquivo de interface o mesmo dever ser convertido novamente.
- Deve ser ter cuidado com o nome (
ObjectName
) de cada componente. - Processo de organização do código Python pode não ser tão simples.
PySide6.QtUiTools.QUiLoader()
Ao utilizar o QUiLoader
não precisamos compilar o arquivo de interface, isso será feito de forma automática pela própria biblioteca:
# -*- coding: utf-8 -*-
"""PyQt6 lendo arquivo de interface com PySide6.QtUiTools.QUiLoader()."""
from pathlib import Path
from PySide6 import QtCore, QtWidgets, QtUiTools
BASE_DIR = Path(__file__).resolve().parent
UI_FILE = BASE_DIR.joinpath('MainWindow.ui')
LOADER = QtUiTools.QUiLoader()
class MainWindow(QtCore.QObject):
def __init__(self, application):
super().__init__()
self.application = application
self.ui = LOADER.load(UI_FILE)
print(self.ui.label.text())
self.ui.show()
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
sys.exit(application.exec())
Vantagens:
- Não é necessário compilar o arquivo de interface.
Desvantagens:
- Cada vez que o código for executado o arquivo de interface será compilado novamente.
- Overhead da aplicação, visto que o arquivo de interface será compilado a cada execução.
PyQt6
📝 As vantagens e desvantagens são praticamente as mesmas do PySide6.
Declarativo
Assim como no PySide6 podemos utilizar a própria linguagem de programação para criar a interface e seus componentes:
# -*- coding: utf-8 -*-
"""MainWindow.py."""
from PyQt6 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, application):
super().__init__()
self.setObjectName('MainWindow')
self.application = application
self.setGeometry(0, 0, 683, 384)
self.setMinimumSize(683, 384)
self.setWindowTitle('Olá Mundo')
vbox = QtWidgets.QVBoxLayout()
central_widget = QtWidgets.QWidget()
central_widget.setLayout(vbox)
self.setCentralWidget(central_widget)
label = QtWidgets.QLabel()
label.setText('Olá Mundo')
vbox.addWidget(label)
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
window.show()
sys.exit(application.exec())
Pyuic6
No PyQt6 devemos utilizar o comando pyuic6
para converter o arquivo de interface em um script Python
pyuic6 MainWindow.ui -o Ui_MainWindow.py
Após a conversão basta importar o script Python que foi gerado:
# -*- coding: utf-8 -*-
"""Compilando arquivo de interface com PyQt6.
pyuic6 MainWindow.ui -o Ui_MainWindow.py.
"""
from PyQt6 import QtWidgets
from Ui_MainWindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, application):
super().__init__()
self.application = application
self.setupUi(self)
print(self.label.text())
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
window.show()
sys.exit(application.exec())
PyQt6.uic.loadUi()
Ao utilizar o loadUi
não precisamos compilar o arquivo de interface, isso será feito de forma automática pela própria biblioteca:
No PyQt6 a leitura do arquivo de interface funciona de forma totalmente diferente do PySide6.
No PyQt6 ao invés de atribuir os componentes da interface gráfica a uma variável os mesmos são carregado na classe
:
# -*- coding: utf-8 -*-
"""PyQt6 lendo arquivo de interface com PyQt6.uic.loadUi()."""
from pathlib import Path
from PyQt6 import QtWidgets, uic
BASE_DIR = Path(__file__).resolve().parent
UI_FILE = BASE_DIR.joinpath('MainWindow.ui')
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, application):
super().__init__()
self.application = application
uic.loadUi(UI_FILE, self)
print(self.label.text())
if __name__ == "__main__":
import sys
application = QtWidgets.QApplication(sys.argv)
window = MainWindow(application=application)
window.show()
sys.exit(application.exec())
PySide6 ou PyQt6?
Bom aqui temos o clássico depende.
Código
A nível de código (API) ambos os bindings são extremamente parecidos.
Acredito que a maior diferença entre eles esteja em alguns enums
, flag groups
e na forma com que eles fazem a leitura ou compilação de um arquivo de interface gráfica (*.ui
).
No geral ambos chegam ao mesmo resultado a nível de interface gráfica e lógica de negocio.
Recursos
Atualmente considero o binding PySide6 o mais completo no quesito recursos.
Junto com a sua instalação temos as seguintes ferramenta:
pyside6-android-deploy
.pyside6-genpyi
.pyside6-metaobjectdump
.pyside6-qmlformat
.pyside6-qmltyperegistrar
.pyside6-assistant
.pyside6-linguist
.pyside6-project
.pyside6-qmlimportscanner
.pyside6-qtpy2cpp
.pyside6-deploy
.pyside6-lrelease
.pyside6-qml
.pyside6-qmllint
.pyside6-rcc
.pyside6-designer
.pyside6-lupdate
.pyside6-qmlcachegen
.pyside6-qmlls
.pyside6-uic
.
Acredito que dentre os destaques temos o Qt Desiger para elaboração de interfaces gráficas de forma visual e o Qt Linguist que é uma ferramenta que permite a edição de arquivos de tradução (*.ts
).
Licenciamento
A principal diferença entre esses bindings está no seu licenciamento.
O PyQt6 disponível sob uma licença GPL ou comercial e o PySide6 sob uma licença LGPL.
Posso usar o PyQt6 para aplicações comerciais?
Sim!
A GPL não impede a venda do software, ela apenas exige você compartilhe o código fonte com as pessoas que o compram.
Caso não queira compartilhar o código fonte será necessário realizar a aquisição da licença comercial da Riverbank.
Posso usar o PySide6 para aplicações comerciais?
Sim novamente e não é necessário de libertar o seu código fonte para os clientes.
A LGPL requer apenas que você libere quaisquer mudanças que você faça no próprio PySide6.
Conclusão
Independente do binding escolhido você conseguirá realizar o desenvolvimento do aplicativo.
O que irá determinar a escolha é:
- Uma boa analise do tipo de software que se está desenvolvendo.
- A experiência da equipe com um ou outro binding.
- E claro o tipo de licença que o software precisa.
Extra
Erros
Se ao executar o código for exibido o alerta:
qt.qpa.plugin: Could not find the Qt platform plugin "wayland" in ""
instale o pacote qt6-wayland
na sua distribuição Linux.
Qt
KDE
Ícones
- Cuttlefish. O Cuttlefish pode ser instalado através do pacote
plasma-sdk
. - Breeze (CDN).
RADs
Softwares
Outros binding
- Qt for Ring (RingQt).
- Qt for Java and Kotlin (QtJambi).
- Qt for Rust (CXX-Qt).
- Qt for Rust (Rust-Qt).
- Qt Quick for Rust (qmetaobject-rs).
- Qt Quick for Rust (qml-rust).
- Qt Quick for Rust (qmlrs).
- Qt Quick for Zig (qml_zig).
- Qt Quick for Zig (zqml).
- Qt for Crystal.
- qt5.cr.
- Qt for Nim (nimqt).
- Qt Quick for Nim (nimqml).
- Qt for Go (qt).
- Qt for Java (javacpp-presets).
- Qt for C#/Mono/.Net (QtSharp).
- Qt for C#/Mono/.Net
- Qml.Net.
- Qt for D (QtE5).
- Qt for Haskell (qtHaskell).
- Qtah.
- Qt for Julia (QML.jl).
- Qt Quick for Haskell (HsQML).
- Qt Quick for OCaml (lablqml).
- Node.js and Qt Widgets (NodeGui).
- Qt Quick for Node.js (Brig).
- QML bindings for Nelson language.