Imagem de destaque do blog justcode.com.br.

PySide6 e PyQt6 os bindings para o framework gráfico Qt 6

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

RADs

Softwares

Outros binding