Python com Flet: Widgets

Widgets, propriedades e eventos

Vimos no primeiro artigo dessa série que um aplicativo Python com Flet consiste em código Python para a realização da lógica do aplicativo, usando o Flet como camada de exibição. Mais tarde nos preocuparemos em fazer uma separação explícita das camadas. Por enquanto basta notar que o Flet cria uma árvore de widgets cujas propriedades são controladas pelo código. Widgets também podem estar associados à ações ligadas a funções. Portanto, para construir aplicativos com Flet, precisamos conhecer esses widgets, suas propriedades e eventos que respondem.

Alguns controles tem a função principal de obter informações do usuário, como botões, menus dropdown ou caixas de texto, para inserção de dados. Outros servem para a exibição de informações calculadas pelo código, mostrando gráficos, figuras ou textos. As caixas de textos podem ser usadas em ambos os casos.

Figura 10: Estrutura de árvore de um aplicativo Flet

A interface do Flet é montada como uma composição de controles, arranjados em uma hierarquia sob forma de árvore que se inicia com uma Page. Dentro dela são dispostos os demais controles, sendo que alguns deles são também conteineres, abrigando outros controles. Todos os controles, portanto, possuem um pai, exceto a Page. Controles como Column, Row e Dropdown podem conter controles filhos, como mostrado na figura 10.

Categorias de Controles

🔘 Controles Categoria Itens
🔘 Layout diagramação 16 itens
🔘 Navigation navegação 3 itens
🔘 Information Displays exibição de informação 8 itens
🔘 Buttons botões 8 itens
🔘 Input and Selections entrada e seleções 6 itens
🔘 Dialogs, Alerts, Panels dialogo e paineis 4 itens
🔘 Charts gráficos 5 itens
🔘 Animations animações 1 item
🔘 Utility utilidades 13 itens

Propriedades comuns a vários controles

Algumas propriedades são comuns a todos (ou quase todos) os controles. Vamos primeiro listá-las e depois apresentar alguns exemplos de uso. As propriedades marcadas com o sinal ≜ só são válidas quando estão dentro de uma controle Stack, que será descrito após a tabela.

bottom Distância entre a borda inferior do filho e a borda inferior do Stack.
data Um campo auxiliar de dados arbitrários que podem ser armazenados junto a um controle.
disabled Desabilitação do controle. Por padrão disabled = False. Um controle desabilitado fica sombreado e não reage a nenhum evento. Todos os filhos de um controle desabilitado ficam desabilitados.
expand Um controle dentro de uma coluna ou linha pode ser expandido para preencher o espaço disponível. expand=valor, onde valor pode ser booleano ou inteiro, um fator de expansão, usado para dividir o espaço entre vários controles.
hight Altura do controle, em pixeis.
left Distância da borda esquerda do filho à borda esquerda do Stack.
right Distância da borda direita do filho à borda direita do Stack.
top Distância da borda superior do filho ao topo do Stack.
visible Visibilidade do controle e seus filhos. vivible = True por padrão. Controles invisíveis não recebem foco, não podem ser selecionados nem respondem a eventos.
widht Largura de controle em pixeis.

Um Stack é um controle usado para posicionar controles em cima de outros (empilhados). Veremos mais sobre ele na seção sobre layouts.

Transformações (Transformations)

Transformações são operações realizadas sobre os controles

offset É uma translação aplicada sobre um controle, antes que ele seja renderizado. A translação é dada em uma escala relativa ao tamanho do controle. Um deslocamento de 0,25 realizará uma translação horizontal de 1/4 da largura do controle. Ex,: ft.Container(..., offset=ft.transform.Offset(-1, -1).
opacity Torna o controle parcialmente transparente. O default é opacity=1.0, nenhuma transparência. Se opacity=0.0controle é 100% transparente.
rotate Aplica uma rotação no controle em torno de seu centro. O parâmetro rotate pode receber um número, que é interpretado com o ângulo, em radianos, de rotação anti-horária. A rotação também pode ser especificada por meio de transform.Rotate, que permite estabelecer ângulo, alinhamento e posição de centro de rotação. Ex,: ft.Image(..., rotate=Rotate(angle=0.25 * pi, alignment=ft.alignment.center_left) representa uma rotação de 45° (π/4).
scale Controla a escala ao longo do plano 2D. O fator de escala padrão é 1,0. Por ex.: ft.Image(..., scale=Scale(scale_x=2, scale_y=0.5) multiplica as dimensões em x por 2 e em y por .5. Alternativamente Scale(scale=3) multiplica por 3 nas duas direções.

Exemplo de uso das Propriedades e Transformações

import flet as ft

def main(page: ft.Page):
    def mover_x(e):
        ct.left += 20
        page.update()

    def mover_y(e):
        ct.top += 20
        page.update()

    def mover(e):
        bt3.value += .2
        ct.offset=ft.transform.Offset(bt3.value, bt3.value)
        page.update()

    def sumir(e):
        ct.visible = not ct.visible
        page.update()

    def rodar(e):
        bt5.value+=.5
        ct.rotate=ft.Rotate(angle=bt5.value, alignment=ft.alignment.center)
        page.update()

    def opaco(e):
        ct.opacity -= .1
        page.update()

    def zerar(e):
        bt3.value=0
        bt5.value=0
        ct.left=0
        ct.top=0
        ct.offset=ft.transform.Offset(0, 0)
        ct.opacity = 1
        ct.visible = True
        ct.rotate=ft.Rotate(angle=0, alignment=ft.alignment.center)
        page.update()

    bt1 = ft.ElevatedButton(" ", icon="arrow_circle_right", on_click= mover_x, width=50)
    bt2 = ft.ElevatedButton(" ", icon="arrow_circle_down", on_click= mover_y, width=50)
    bt3 = ft.ElevatedButton(" ", icon="SUBDIRECTORY_ARROW_RIGHT", on_click= mover, width=50)
    bt3.value=0
    bt4 = ft.ElevatedButton("on/off", on_click= sumir, width=150)
    bt5 = ft.ElevatedButton("Rodar", on_click= rodar, width=150)
    bt5.value=0
    bt6 = ft.ElevatedButton("Opaco", on_click= opaco, width=150)
    bt7 = ft.ElevatedButton("Zerar", on_click= zerar, width=150)

    ct = ft.Container(bgcolor="red", width=50, height=50, left=0, top=0,
                      offset=ft.transform.Offset(0, 0))

    page.add(ft.Row([bt1, bt2, bt3, bt4, bt5, bt6, bt7]), ft.Stack([ct], width=1000, height=1000))

ft.app(target=main)

Os botões executam as funções:

  • bt1 ⇾ move para a direita, horizontalmente (ct.left += 20),
  • bt2 ⇾ move para baixo, na vertical (ct.top += 20),
  • bt3 ⇾ aumenta offset, nas duas direções (ct.offset=ft.transform.Offset(bt3.value, bt3.value)),
  • bt4 ⇾ torna a imagem invisível/visível (ct.visible = not ct.visible),
  • bt5 ⇾ gira imagem, anti-horário:
    ct.rotate=ft.Rotate(angle=bt5.value, alignment=ft.alignment.center),
  • bt6 ⇾ torna a cor mais translúcida (ct.opacity -= .1),
  • bt7 ⇾ retorna a imagem para o estado inicial,
Figura 12: Propriedades e Transformações

onde ct = ft.Container, é o container de cor vermelha, mostrado no figura 12.

Atalhos de Teclado

Qualquer pessoa que faz uso intensivo do computador sabe da importância dos Atalhos de Teclado (Keyboard shortcuts). A possibilidade de não mover a mão do teclado para acionar o mouse pode significar melhor usabilidade e aumento de produtividade. Para isso o Flet oferece para o programador a possibilidade de inserir atalhos em seus aplicativos para que seu usuário possa dinamizar seu uso.

Para capturar eventos produzidos pelo teclado o objeto page implementa o método on_keyboard_event, que gerencia o pressionamento de teclas de caracter, em combinação com teclas de controle. Esse evento passa o parâmetro eque é uma instância da classe KeyboardEvent, e tem as seguintes propriedades:

e.key Representação textual da tecla pressionada. Veja nota.
e.shift Booleano: True se a tecla “Shift” foi pressionada.
e.ctrl Booleano: True se a tecla “Control” foi pressionada.
e.alt Booleano: True se a tecla “Alt” foi pressionada.
e.meta Booleano: True se a tecla “Meta” foi pressionada††.

Nota: Além dos caracteres A … Z (todos apresentados em maiúsculas) também são representadas as teclas Enter, Backspace, F1 … F12, Escape, Insert … Page Down, Pause, etc. Alguns teclados permitem a reconfiguração de teclas, por exemplo fazendo F1 = Help, etc.
Nota††: A tecla Meta é representada em geral no Windows como tecla Windows e no Mac como tecla Command.

O seguinte código ilustra esse uso. A linha page.on_keyboard_event = on_teclado faz com que eventos de teclado acionem a função on_teclado. O objeto e leva as propriedades booleanas e.ctrl, e.alt, e.shift, e.meta e o texto e.key.

import flet as ft                                                          
                                                                            
def main(page: ft.Page):

    class BtControle(ft.TextField):
        def __init__(self, text):
            super().__init__()
            self.value = text
            self.width=100
            self.text_size=25
            self.bgcolor="blue"
            self.color="white"
            self.visible = False
            
    def on_teclado(e: ft.KeyboardEvent):
        c_ctrl.visible = e.ctrl
        c_alt.visible = e.alt
        c_shift.visible = e.shift
        c_meta.visible = e.meta
        c_key.visible = True
        c_key.value = e.key
        page.update()

    page.on_keyboard_event = on_teclado

    t1= ft.Text("Pressione qualquer tecla, combinada com \nCTRL, ALT, SHIFT ou META", size=25)
    c_ctrl = BtControle("Ctrl")
    c_alt = BtControle("Alt")
    c_shift = BtControle("Shift")
    c_meta = BtControle("Meta")
    c_key = BtControle("")

    page.add(t1)
    page.add(ft.Row(controls=[c_ctrl, c_alt, c_shift, c_meta, c_key]))

ft.app(target=main) 
Figura 13: Uso de “keyboards shortcuts”

O resultado desse código, quando executado e após o pressionamento simultaneo das teclas CTRL-ALT-SHIFT-J, está mostrado na figura 13.

O exemplo acima ilustra ainda uma característica da POO (programação orientada a objetos). Como temos que criar 5 caixas de texto iguais, exceto pelo seu valor, criamos uma classe BtControle (herdando de ft.TextField) e criamos cada botão como instância dessa classe. No código manipulamos a visibilidade desses botões.

Bibiografia


Python com Flet: Botões