Olá programadores e programadoras! Tudo bem com vocês? Espero que sim! Nessa aula veremos como criar e utilizar a barra de ferramentas em seu App para deixá-lo mais parecido com os programas que utilizamos em nosso dia a dia.
A seguir, veremos alguns dos elementos comuns da interface do usuário, que você provavelmente já viu em muitos outros aplicativos — barras de ferramentas e menus. Também exploraremos o sistema bacana que o Qt fornece para minimizar a duplicação entre diferentes áreas da IU: QAction.
Um dos elementos da interface do usuário mais comumente vistos é a barra de ferramentas. Barras de ferramentas são barras de ícones e/ou texto usadas para realizar tarefas comuns dentro de uma aplicação, para as quais o acesso através de um menu seria complicado. Eles são um dos recursos de UI mais comuns vistos em muitos aplicativos. Embora alguns aplicativos complexos, especialmente no pacote Microsoft Office, tenham migrado para interfaces contextuais de "faixa de opções", a barra de ferramentas padrão é suficiente para a maioria dos aplicativos que você criará.
As barras de ferramentas Qt suportam a exibição de ícones, texto e também podem conter qualquer widget Qt padrão. No entanto, para botões, a melhor abordagem é usar o sistema QAction para colocar botões na barra de ferramentas.
Vamos começar adicionando uma barra de ferramentas ao nosso aplicativo.
No Qt, as barras de ferramentas são criadas a partir da classe QToolBar. Para começar, você cria uma instância da classe e depois chama .addToolbar em QMainWindow. Passar uma string como primeiro parâmetro para QToolBar define o nome da barra de ferramentas, que será usado para identificar a barra de ferramentas na UI:
# --- Importar as bibliotecas --- #
import sys
from Pyside2.QtCore import Qt
from PySide2.QtWidgets import QApplication, QLabel, QMainWindow, QToolBar
class MeuApp(QMainWindow):
"""Classe responsável por criar o app."""
def __init__(self):
"""Função responsável por inicializar a classe."""
# --- Herdar a classe pai --- #
super().__init__()
# --- Título do app --- #
self.setWindowTitle('Meu app')
# --- Criar uma label --- #
label = QLabel('Olá')
label.setAlignment(Qt.AlignCenter)
# --- Centralizar a label --- #
self.setCentralWidget(label)
# --- Criar e adicionar à barra de ferramentas --- #
barra = QToolBar('Barra de ferramentas')
self.addToolBar(barra)
# --- Criar a instância do app --- #
app = QApplication(sys.argv)
# --- Criar a janela do app --- #
janela = MeuApp()
janela.show()
# --- Executar o loop de eventos --- #
app.exec_()
Você verá uma barra cinza fina na parte superior da janela. Esta é a sua barra de ferramentas. Clique com o botão direito e clique no nome para desativá-lo:
Infelizmente, depois de remover uma barra de ferramentas, não há mais lugar para clicar com o botão direito para adicioná-la novamente. Portanto, como regra geral, se você deseja manter uma barra de ferramentas irremovível ou fornecer uma interface alternativa para ativar e desativar as barras de ferramentas.
Vamos tornar a barra de ferramentas um pouco mais interessante. Poderíamos simplesmente adicionar um widget QButton, mas há uma abordagem melhor no Qt que oferece alguns recursos interessantes - e isso é via QAction. QAction é uma classe que fornece uma maneira de descrever interfaces de usuário abstratas. O que isso significa em inglês é que você pode definir vários elementos de interface dentro de um único objeto, unificados pelo efeito que a interação com esse elemento tem. Por exemplo, é comum ter funções representadas na barra de ferramentas, mas também no menu — pense em algo como Editar→Cortar que está presente tanto no menu Editar, mas também na barra de ferramentas como uma tesoura, e também através do atalho de teclado Ctrl+X (Cmd+X no macOS).
Sem QAction você teria que definir isso em vários lugares. Mas com QAction você pode definir uma única QAction, definindo a ação acionada e, em seguida, adicionar essa ação ao menu e à barra de ferramentas. Cada QAction tem nomes, mensagens de status, ícones e sinais aos quais você pode se conectar (e muito mais).
Veja o código abaixo para saber como adicionar sua primeira QAction:
# --- Importar as bibliotecas --- #
import sys
from Pyside2.QtCore import Qt
from PySide2.QtWidgets import (
QAction,
QApplication,
QLabel,
QMainWindow,
QToolBar
)
class MeuApp(QMainWindow):
"""Classe responsável por criar o app."""
def __init__(self):
"""Função responsável por inicializar a classe."""
# --- Herdar a classe pai --- #
super().__init__()
# --- Título do app --- #
self.setWindowTitle('Meu app')
# --- Criar uma label --- #
label = QLabel('Olá')
label.setAlignment(Qt.AlignCenter)
# --- Centralizar a label --- #
self.setCentralWidget(label)
# --- Criar e adicionar a barra de ferramentas --- #
barra = QToolBar('Barra de ferramentas')
self.addToolBar(barra)
# --- Adicionar um botão à barra de ferramentas --- #
botao = QAction('Botão', self)
botao.setStatusTip('Isso é um botão')
botao.triggered.connect(self.botao_barra_clique)
barra.addAction(botao)
def botao_barra_clique(self, estado):
"""
Função responsável por retornar se o botão da barra de ferramentas foi clicado.
:param estado: Estado do botão.
"""
print('clique', estado)
# --- Criar a instância do app --- #
app = QApplication(sys.argv)
# --- Criar a janela do app --- #
janela = MeuApp()
janela.show()
# --- Executar o loop de eventos --- #
app.exec_()
Para começar criamos a função que aceitará o sinal do QAction para que possamos ver se está funcionando. Em seguida, definimos o próprio QAction. Ao criar a instância podemos passar um rótulo para a ação e/ou um ícone. Você também deve passar qualquer QObject para atuar como pai da ação — aqui estamos passando self como referência para nossa janela principal. Estranhamente para QAction o elemento pai é passado como parâmetro final.
A seguir, podemos optar por definir uma dica de status – este texto será exibido na barra de status assim que tivermos uma. Finalmente, conectamos o sinal .triggered à função personalizada. Este sinal será acionado sempre que QAction for "acionado" (ou ativado).
Você deverá ver seu botão com o rótulo que você definiu. Clique nele e nossa função personalizada emitirá “clique” e o status do botão:
Por que o sinal é sempre falso? O sinal passado indica se a ação está verificada, e como nosso botão não é verificável — apenas clicável — ele é sempre falso. É exatamente como o QPushButton que vimos anteriormente.
Vamos adicionar uma barra de status.
Criamos um objeto de barra de status chamando QStatusBar e passando o resultado para .setStatusBar. Como não precisamos alterar as configurações da barra de status, podemos simplesmente passá-lo à medida que o criamos. Podemos criar e definir a barra de status em uma única linha, adicione o serguinte código ao final da função __init__:
# --- Definir a barra de status --- #
self.setStatusBar(QStatusBar(self))
Passe o mouse sobre o botão da barra de ferramentas e você verá o texto de status aparecer na barra de status na parte inferior da janela:
Em seguida, vamos tornar nosso QAction alternável – então clicar irá ativá-lo, clicar novamente irá desligá-lo. Para fazer isso, simplesmente chamamos setCheckable(True) no objeto QAction:
# --- Adicionar um botão a barra de ferramentas --- #
botao = QAction('Botão', self)
botao.setStatusTip('Isso é um botão')
botao.triggered.connect(self.botao_barra_clique)
botao.setCheckable(True)
barra.addAction(botao)
Clique no botão para vê-lo alternar do estado marcado para o estado desmarcado. Observe que a função de slot personalizada que criamos agora alterna a saída de True e False:
Há também um sinal .toggled, que só emite um sinal quando o botão é alternado. Mas o efeito é idêntico, por isso é praticamente inútil.
A nossa GUI parece bem simples e feia; então vamos adicionar um ícone ao nosso botão. Para isso recomendo que você baixe os ícones de GUI criado pelo designer Yusuke Kamiyamane. É um ótimo conjunto de lindos ícones 16x16 que podem dar aos seus aplicativos uma aparência profissional agradável. Ele está disponível gratuitamente, apenas com atribuição necessária quando você distribui seu aplicativo - embora eu tenha certeza de que o designer também apreciaria algum dinheiro se você tiver algum sobrando.
Selecione uma imagem do conjunto (nos exemplos aqui selecionei o arquivo bug.png) e copie-o para a mesma pasta do seu código-fonte. Para adicionar o ícone ao QAction (e portanto ao botão), simplesmente o passamos como primeiro parâmetro ao criar o QAction. Se o ícone estiver na mesma pasta do seu código-fonte, basta passar o nome com a extensão da imagem.
Você também precisa informar à barra de ferramentas o tamanho dos seus ícones, caso contrário, seu ícone ficará cercado por muito preenchimento. Você pode fazer isso chamando .setIconSize() com um objeto QSize:
# --- Importar as bibliotecas --- #
import sys
from PySide2.QtGui import QIcon
from Pyside2.QtCore import Qt, QSize
from PySide2.QtWidgets import (
QAction,
QApplication,
QLabel,
QMainWindow,
QStatusBar,
QToolBar
)
class MeuApp(QMainWindow):
"""Classe responsável por criar o app."""
def __init__(self):
"""Função responsável por inicializar a classe."""
# --- Herdar a classe pai --- #
super().__init__()
# --- Título do app --- #
self.setWindowTitle('Meu app')
# --- Criar uma label --- #
label = QLabel('Olá')
label.setAlignment(Qt.AlignCenter)
# --- Centralizar a label --- #
self.setCentralWidget(label)
# --- Criar e adicionar a barra de ferramentas --- #
barra = QToolBar('Barra de ferramentas')
barra.setIconSize(QSize(16, 16))
self.addToolBar(barra)
# --- Adicionar um botão à barra de ferramentas --- #
botao = QAction(QIcon('bug.png'), 'Botão', self)
botao.setStatusTip('Isso é um botão')
botao.triggered.connect(self.botao_barra_clique)
botao.setCheckable(True)
barra.addAction(botao)
# --- Definir a barra de status --- #
self.setStatusBar(QStatusBar(self))
def botao_barra_clique(self, estado):
"""
Função responsável por retornar se o botão da barra de ferramentas foi clicado.
:param estado: Estado do botão.
"""
print('clique', estado)
# --- Criar a instância do app --- #
app = QApplication(sys.argv)
# --- Criar a janela do app --- #
janela = MeuApp()
janela.show()
# --- Executar o loop de eventos --- #
app.exec_()
O QAction agora é representado por um ícone. Tudo deve funcionar exatamente como antes:
Note que o Qt usa as configurações padrão do seu sistema operacional para determinar se deve mostrar um ícone, texto ou um ícone e texto na barra de ferramentas. Mas você pode substituir isso usando .setToolButtonStyle. Este slot aceita qualquer um dos seguintes sinalizadores do Qt:
Tabela 1: Sinalizadores e comportamentos da barra de ferramentas.
O valor padrão é Qt.ToolButtonFollowStyle, o que significa que seu aplicativo seguirá por padrão a configuração padrão/global para o sistema operacional no qual o aplicativo é executado. Geralmente, isso é recomendado para fazer com que seu aplicativo pareça o mais nativo possível.
A seguir, adicionaremos mais alguns detalhes à barra de ferramentas. Adicionaremos um segundo botão e um widget de caixa de seleção. Como mencionado, você pode literalmente colocar qualquer widget aqui, então fique à vontade para testar. Não se preocupe com o tipo QCheckBox, abordaremos isso mais tarde:
# --- Importar as bibliotecas --- #
import sys
from PySide2.QtGui import QIcon
from Pyside2.QtCore import Qt, QSize
from PySide2.QtWidgets import (
QAction,
QApplication,
QCheckBox,
QLabel,
QMainWindow,
QStatusBar,
QToolBar
)
class MeuApp(QMainWindow):
"""Classe responsável por criar o app."""
def __init__(self):
"""Função responsável por inicializar a classe."""
# --- Herdar a classe pai --- #
super().__init__()
# --- Título do app --- #
self.setWindowTitle('Meu app')
# --- Criar uma label --- #
label = QLabel('Olá')
label.setAlignment(Qt.AlignCenter)
# --- Centralizar a label --- #
self.setCentralWidget(label)
# --- Criar e adicionar a barra de ferramentas --- #
barra = QToolBar('Barra de ferramentas')
barra.setIconSize(QSize(16, 16))
self.addToolBar(barra)
# --- Adicionar um botão à barra de ferramentas --- #
botao_1 = QAction(QIcon('bug.png'), 'Botão', self)
botao_1.setStatusTip('Isso é um botão')
botao_1.triggered.connect(self.botao_barra_clique)
botao_1.setCheckable(True)
barra.addAction(botao_1)
# -- Criar um separador para os botões --- #
barra.addSeparator()
# --- Adicionar um botão à barra de ferramentas --- #
botao_2 = QAction('Botão 2', self)
botao_2.setStatusTip('Isso é um botão 2')
botao_2.triggered.connect(self.botao_barra_clique)
botao_2.setCheckable(True)
botao_2.addAction(botao_2)
# --- Adicionar widgets à barra de ferramentas --- #
barra.addWidget(QLabel('Olá'))
barra.addWidget(QCheckBox())
# --- Definir a barra de status --- #
self.setStatusBar(QStatusBar(self))
def botao_barra_clique(self, estado):
"""
Função responsável por retornar se o botão da barra de ferramentas foi clicado.
:param estado: Estado do botão.
"""
print('clique', estado)
# --- Criar a instância do app --- #
app = QApplication(sys.argv)
# --- Criar a janela do app --- #
janela = MeuApp()
janela.show()
# --- Executar o loop de eventos --- #
app.exec_()
Agora você verá vários botões e uma caixa de seleção:
Os menus são outro componente padrão das UIs. Normalmente, eles estão na parte superior da janela ou na parte superior da tela no macOS. Eles permitem acesso a todas as funções padrão do aplicativo. Existem alguns menus padrão – por exemplo Arquivo, Editar, Ajuda. Os menus podem ser aninhados para criar árvores hierárquicas de funções e geralmente suportam e exibem atalhos de teclado para acesso rápido às suas funções.
Para criar um menu, criamos uma barra de menu que chamamos de .menuBar() no QMainWindow. Adicionamos um menu em nossa barra de menu chamando .addMenu(), passando o nome do menu. Eu chamei isso de '&Arquivo'. O e comercial define uma tecla rápida para pular para este menu ao pressionar Alt.
É aqui que entra em jogo o poder das ações. Podemos reutilizar o QAction já existente para adicionar a mesma função ao menu. Para adicionar uma ação você chama .addAction passando uma de nossas ações definidas. Adicione ao final da função __init__ o seguinte código:
# --- Criar a barra de menu --- #
menu = self.menuBar()
# --- Adicionar um botão ao menu --- #
menu_arquivo = menu.addMenu('&Arquivo')
menu_arquivo.addAction(botao_1)
Clique no item no menu e você notará que ele pode ser alternado — ele herda os recursos do QAction:
Vamos adicionar mais algumas coisas ao menu. Aqui adicionaremos um separador ao menu, que aparecerá como uma linha horizontal no menu, e depois adicionaremos a segunda QAction que criamos. Adicione o seguinte código ao final da função __init__:
# --- Criar a barra de menu --- #
menu = self.menuBar()
# --- Adicionar um botão ao menu --- #
menu_arquivo = menu.addMenu('&Arquivo')
menu_arquivo.addAction(botao_1)
# --- Adicionar um separador no menu --- #
menu_arquivo.addSeparator()
# --- Adicionar mais uma ação ao menu --- #
menu_arquivo.addAction(botao_2)
Você deverá ver dois itens de menu com uma linha entre eles:
Você também pode usar o E comercial para adicionar teclas aceleradoras ao menu para permitir que uma única tecla seja usada para pular para um item de menu quando ele estiver aberto. Novamente, isso não funciona no macOS.
Para adicionar um submenu, basta criar um novo menu chamando addMenu() no menu pai. Você pode então adicionar ações normalmente. Adicione o seguinte código ao final da função __init__:
# --- Criar a barra de menu --- #
menu = self.menuBar()
# --- Adicionar um botão ao menu --- #
menu_arquivo = menu.addMenu('&Arquivo')
menu_arquivo.addAction(botao_1)
# --- Adicionar um separador no menu --- #
menu_arquivo.addSeparator()
# --- Criar um submenu --- #
submenu_arquivo = menu_arquivo.addMenu('Submenu')
# --- Adicionar uma ação ao submenu --- #
submenu_arquivo.addAction(botao_2)
Veja que agora temos um menu dentro de outro menu:
Por fim, adicionaremos um atalho de teclado ao QAction. Você define um atalho de teclado passando setKeySequence() e passando a sequência de teclas. Quaisquer sequências de teclas definidas aparecerão no menu.
Observe que o atalho de teclado está associado ao QAction e ainda funcionará independentemente de o QAction ser adicionado ou não a um menu ou barra de ferramentas.
As sequências de teclas podem ser definidas de várias maneiras - passando como texto, usando nomes de chaves do Qt ou usando as sequências de teclas definidas do Qt. Use este último sempre que puder para garantir a conformidade com os padrões do sistema operacional.
Se seus usuários não conseguirem encontrar as ações do seu aplicativo, eles não poderão usar seu aplicativo em todo o seu potencial. Tornar as ações detectáveis é fundamental para criar um aplicativo fácil de usar. É um erro comum tentar resolver isso adicionando ações em todos os lugares e acabar sobrecarregando e confundindo seus usuários.
Coloque as ações comuns e necessárias em primeiro lugar, certificando-se de que sejam fáceis de encontrar e lembrar. Pense em Arquivo › Salvar na maioria dos aplicativos de edição. Rapidamente acessível na parte superior do menu Arquivo e vinculado a um simples atalho de teclado Ctrl + S . Se Salvar arquivo… estava acessível através de Arquivo › Operações comuns › Operações de arquivo › Documento ativo › Salvar ou o atalho Ctrl + Alt + J, os usuários teriam mais dificuldade em encontrá-lo, mais dificuldade em usá-lo e teriam menos probabilidade de salvar seus documentos.
Organize as ações em grupos lógicos. É mais fácil encontrar algo entre um pequeno número de alternativas do que numa longa lista. É ainda mais fácil descobrir se está entre coisas semelhantes.
Evite replicar ações em vários menus, pois isso introduz uma ambiguidade de "fazem a mesma coisa?" mesmo que tenham uma etiqueta idêntica. Por último, não fique tentado a simplificar os menus ocultando/removendo entradas dinamicamente. Isso gera confusão, pois os usuários procuram algo que não existe "...estava aqui há um minuto". Estados diferentes devem ser indicados desabilitando itens de menu ou janelas e caixas de diálogo separadas.
Faça:
Organize seus menus em uma hierarquia lógica;
Replique as funções mais comuns em suas barras de ferramentas;
Agrupe ações da barra de ferramentas logicamente e;
Desative itens nos menus quando eles não puderem ser usados.
Não faça:
Adicione a mesma ação a vários menus;
Adicione todas as ações do menu à barra de ferramentas;
Use nomes ou ícones diferentes para a mesma ação em locais diferentes e;
Remova itens dos seus menus – em vez disso, desative-os.