Flet: CircleAvatar, CupertinoActivityIndicator, Icon


Controle CircleAvatar

O controle CircleAvatar desenha um círculo que pode conter imagens, ícones ou texto. Geralmente é usado para representar o avatar de um usuário. Um texto alternativo pode ser usado para exibição caso a imagem declarada não esteja acessível.

Propriedades e evento de CircleAvatar

As seguintes propriedades e evento existem no controle CircleAvatar:

Descrição
background_image_src recurso de imagem (local ou URL) a ser renderizado no fundo do círculo. Se essa imagem é alterada uma animação será mostrada na troca de imagens. Alterar a imagem de fundo fará com que o avatar anime para a nova imagem. Essa imagem serve como fallback para foreground_image_src. Caso as iniciais do usuário devem ser exibidas (ou qualquer outro texto curto), informe a imagem na propriedade content.
bgcolor cor de fundo do círculo. Alteração na cor provocará uma animação no avatar para a nova cor.
color cor do texto padrão. Default O padrão é a cor do tema de texto primário se a cor de fundo não for especificada.
content normalmente, um controle de texto. Para apresentar uma imagem em CircleAvatar use background_image_src.
foreground_image_src A fonte (arquivo de ativo local ou URL) da imagem de primeiro plano no círculo. Normalmente usada como imagem de perfil. Para fallback, use background_image_src.
max_radius O tamanho máximo do avatar, expresso como o raio (metade do diâmetro). Se maxRadius for especificado, o raio também não deve ser especificado. O padrão é “infinito”.
min_radius O tamanho mínimo do avatar, expresso como o raio (metade do diâmetro). Se minRadius for especificado, o raio não deve ser especificado também. O padrão é zero.
radius O tamanho do avatar, expresso como o raio (metade do diâmetro). Se radius for especificado, nem minRadius nem maxRadius podem ser especificados.
tooltip O texto exibido ao passar o mouse sobre o botão.
Evento Descrição
on_image_error dispara quando ocorre um erro ao carregar imagens em background_image_src ou foreground_image_src.
Os evento tem a propriedade e.data que contém uma string com valor “background” ou “foreground”, indicando a origem do erro.

Exemplo de uso do CircleAvatar

import flet as ft

def main(page):
    page.bgcolor=ft.colors.WHITE
    foto="https://phylos.net/wp-content/uploads/2017/12/GuilhermeRoundPequeno.png"
    ico=ft.Icon(ft.icons.BEDROOM_BABY)

    a1 = ft.CircleAvatar(foreground_image_src=foto, content=ft.Text("autor"))

    a2 = ft.Stack([a1, ft.CircleAvatar(bgcolor="green", radius=7)], width=40, height=40)

    a3 = ft.CircleAvatar(content=ico, bgcolor="red", color="black")

    a4 = ft.CircleAvatar(content=ico, color="red", bgcolor="black")

    a5 = ft.CircleAvatar(content=ft.Text("@", size=20))

    page.add(ft.Row([a1, a2, a3, a4, a5]))

ft.app(target=main)
Figura 1: resultado do código de CircleAvatar

Os controles CircleAvatar nesse código são:

  • a1: um avatar comum com imagem de fundo,
  • a2: um avatar com círculo de status,
  • a3: um avatar avatar com ícon, e cores customizadas,
  • a4: um avatar avatar com ícon, e cores customizadas invertidas, e
  • a5: um avatar com imagem de fundo e texto fallback.

Controle CupertinoActivityIndicator

O controle CupertinoActivityIndicator é uma imagem indicadora de atividade no estilo Cupertino (iOS) que pode ou não ser animado. Se animado a imagem gira no sentido horário.

Propriedades de CupertinoActivityIndicator

Descrição
animating booleano, default=True. Se o indicador deve ser animado.
color a cor do indicator
radius raio do indicador de atividade (tamanho).

Exemplo de uso do CupertinoActivityIndicator

import flet as ft

def main(page):
    page.bgcolor=ft.colors.WHITE

    act0=ft.CupertinoActivityIndicator(radius=20, color=ft.colors.GREEN, animating=True)
    act1=ft.CupertinoActivityIndicator(radius=50, color=ft.colors.BLUE, animating=True)
    act2=ft.CupertinoActivityIndicator(radius=30, color=ft.colors.RED)

    page.add(ft.Row([act0, act1, act2]))

ft.app(target=main)
Figura 2: resultado do código de ActivityIndicator

Controle Icon

O controle Icon desenha um ícone no estilo Material na página do aplicativo.

Uma página interativa na web pode ser usada para buscar nomes dos ícones desejados, em Flet: Icons Browser.

Propriedades de Icon

Propriedade Descrição
color cor do ícone.
name nome do ícone.
semantics_label nome semântico do ícone. Não é exibido na página mas pode ser acionado em modos de acessibilidade.
size tamanho do ícone. Defaul = 24.
tooltip texto da “dica”, exibido com a passar do mouse (hovering).

Exemplo de uso do Controle Icon

import flet as ft

def main(page: ft.Page):
    page.theme_mode = ft.ThemeMode.LIGHT

    def cor_original():
        ico1.color=ft.colors.PINK
        ico2.color=ft.colors.YELLOW
        ico3.color=ft.colors.GREEN
        ico4.color=ft.colors.BLUE

    def mudar_cor(e):
        if ico1.color==ft.colors.PINK:
            arr_Icons=page.controls[0].controls
            for i in arr_Icons:
                i.color=ft.colors.GREY
        else:
            cor_original()
        page.update()

    def tamanho(e):
        arr_Icons=page.controls[0].controls
        for i in arr_Icons:
            i.size+=5
        page.update()

    ico1=ft.Icon(name=ft.icons.SD_CARD, size=15)
    ico2=ft.Icon(name="sd_card", size=15)
    ico3=ft.Icon(name=ft.icons.ANCHOR, size=30)
    ico4=ft.Icon(name=ft.icons.ELECTRIC_CAR, size=50)
    cor_original()
    bt_cor=ft.ElevatedButton("Mudar Cor", icon="arrow", on_click=mudar_cor, width=150)
    bt_tamanho=ft.ElevatedButton("Tamanho", icon="arrow", on_click=tamanho, width=150)

    page.add(ft.Row([ico1, ico2, ico3, ico4]), ft.Row([bt_cor, bt_tamanho]))

ft.app(target=main)
Figura 3: resultado do código de exemplo de Icon

A figura 3 mostra o resultado do código. A Figura 3-A é o estado inicial do aplicativo. Figura 3-B é o estado após 5 cliques no botão “Tamanho”. O  botão “Muda Cor” alterna entre as cores originais e um tom de cinza, para todos os ícones.

Um comentário pode ser útil aqui: como a propriedade de cores dos ícones é usada mais de uma vez, é interessante atribuir essas propriedades em um mesmo bloco de código, o que é feito na função cor_original().

Percorrer todos os ícones para mudar de tamanho ou atribuir a cor cinza foi feita da seguinte forma: foram capturados todos os ícones em um array arr_Icons. Observe que:

  • page.controls[] é uma lista com 2 linhas,
  • page.controls[0] é a primeira linha da lista,
  • page.controls[0].controls é lista de ícones existentes na 1a linha,
  • page.controls[0].controls[i] é cada um dos ícones, (i=0,1, 2, 3),
  • page.controls[0].controls[i].size é o tamanho de cada ícone, e
  • page.controls[0].controls[i].color é a cor de cada ícone.

Flet, Exemplos: Controles Badge e Canvas

Exemplos: Badge e Canvas

Exemplo 1: uso do Controle Badge

import flet as ft

def main(page: ft.Page):

    def clicou(e):
        badge.text=str(int(badge.text)+1)
        page.update()

    badge=ft.Badge(
        text="1",
        content=ft.Icon(ft.icons.PHONE, size=40),
        bgcolor="#ff0000",
        text_color="#000000",
    )

    page.navigation_bar = ft.NavigationBar(
        destinations=[ft.NavigationBarDestination(icon_content=badge, label="Soma Um")],
        on_change=clicou
    )
    page.add()

ft.app(main)
Figura 1

A figura 1-A mostra o estado inicial do Badge e 1-B mostra o estado final, após 4 cliques sobre o controle.

Exemplo 2: uso do Canvas.Shapes

O exemplo abaixo mostra casos simples de uso de Color, Circle, Arc, Rect e Line.

import flet as ft
import flet.canvas as cv
import math

def main(page: ft.Page):
    risco = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE)
    pintar = ft.Paint(style=ft.PaintingStyle.FILL)
    cnv = cv.Canvas(
        [
            cv.Color(ft.colors.GREEN_50),                             # A
            cv.Circle(100, 100, 40, risco),                           # B
            cv.Circle(100, 100, 30, risco),                           # C
            cv.Circle(100, 100, 10, pintar),                          # D
            cv.Arc(180, 90, 60, 40, 0, 2*math.pi, paint=risco),       # E
            cv.Arc(180, 80, 60, 20, math.pi, math.pi, paint=risco),   # F
            cv.Rect(165, 60, 90, 80, 15, risco),                      # G
            cv.Line(280, 70, 340, 130, risco),                        # H
            cv.Line(280, 130, 340, 70, risco),                        # I
            cv.Oval(267, 70, 90, 60, risco)                           # J
        ],
    )
    page.add(cnv)

ft.app(main)
Figura 2: representação das curvas marcadas no código

Exemplo 3: uso do Canvas.Path, LineTo, MoveTo

O exemplo abaixo mostra casos simples de uso de Paint, Path, MoveTo, LineTo e Close.

import flet as ft
import flet.canvas as cv
import math

def main(page: ft.Page):
    page.bgcolor=ft.colors.AMBER_100

    def mudar(e):
        caminho1.paint=preenche if caminho1.paint==risco else risco
        caminho2.paint=preenche if caminho2.paint==risco else risco
        caminho1.update()
        caminho2.update()

    risco=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE)
    preenche=ft.Paint(style=ft.PaintingStyle.FILL)
    caminho1=cv.Path(
        [
            cv.Path.MoveTo(25, 25),
            cv.Path.LineTo(105, 25),
            cv.Path.LineTo(25, 105),
            cv.Path.Close()
        ],
        paint=risco
    )
    caminho2=cv.Path(
        [
            cv.Path.MoveTo(125, 125),
            cv.Path.LineTo(125, 45),
            cv.Path.LineTo(45, 125),
            cv.Path.Close()
        ],
        paint=preenche
    )
    page.add(
        ft.ElevatedButton("Mudar estilo de Paint", on_click=mudar),
        cv.Canvas([caminho1, caminho2])
    )
ft.app(main)
Figura 3: Estado inicial e após um clique

Exemplo 3: uso do Canvas.Circle, Rect

O exemplo abaixo mostra casos simples de uso de canvas.Circle, canvas.Rect, canvas.Path, canvas.Path.MoveTo, canvas.QuadraticTo e rotações.

import flet as ft
import flet.canvas as cv

def main(page: ft.Page):
    page.bgcolor=ft.colors.GREEN_200

    gr1=ft.PaintRadialGradient((60, 90), 50, colors=[ft.colors.YELLOW, ft.colors.BLUE])
    grad1=ft.Paint(gradient=gr1, style=ft.PaintingStyle.FILL)
    gr2=ft.PaintRadialGradient((250, 90), 50, colors=[ft.colors.BLACK, ft.colors.RED])
    grad2=ft.Paint(gradient=gr2, style=ft.PaintingStyle.FILL)
    risco=ft.Paint(stroke_width=4, style=ft.PaintingStyle.STROKE)

    fig1=cv.Circle(60, 90, 50, grad1)
    fig2=cv.Path([cv.Path.MoveTo(110, 130), cv.Path.QuadraticTo(160, 1, 210, 130, 1)], paint=risco)
    fig3=cv.Rect(230, 50, 70, 60, 1, grad2)
    fig4=cv.Rect(240, 60, 70, 60, 1, risco)

    page.add(cv.Canvas([fig1,fig2, fig3, fig4]))

ft.app(main)
Figura 4: Curvas no código

Exemplo 5: uso do Canvas.Text

O exemplo abaixo mostra casos simples de uso de canvas.Text, estilos e rotações.

import flet as ft, flet.canvas as cv, math

def main(page: ft.Page):
    page.bgcolor=ft.colors.WHITE

    estilo1=ft.TextStyle(weight=ft.FontWeight.BOLD, color=ft.colors.GREEN, size=40)
    estilo2=ft.TextStyle(weight=ft.FontWeight.BOLD, color=ft.colors.RED, size=30)

    texto1=cv.Text(0, 0, "Um texto comum", ft.TextStyle(color=ft.colors.BLUE, size=30))
    texto2=cv.Text(180, 100, "Um texto", estilo1, alignment=ft.alignment.top_center, rotate=math.pi/4)
    texto3=cv.Text(130, 140, "rotacionado", estilo2, alignment=ft.alignment.top_center, rotate=math.pi/4)

    page.add(cv.Canvas([texto1, texto2, texto3]))

ft.app(main)
Figura 5: texto rotacionado de Canvas

Exemplo 5: uso do Canvas.Point

O código do próximo exemplo coleta pares de pontos em duas listas, representando seno e cosseno mas as mesmas amplitudes e diferentes comprimentos de onda. As duas listas são representados por meio do canvas.Points.

import flet as ft, flet.canvas as cv, math

def main(page: ft.Page):
    page.bgcolor=ft.colors.WHITE
    risco1=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE, color=ft.colors.BLUE_ACCENT)
    risco2=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE, color=ft.colors.RED)

    seno1=[]
    seno2=[]
    for x in range(500):
        seno1.append((x,50+50*math.sin(.05*x)))
        seno2.append((x,50+50*math.cos(.5*x)))

    cnv=cv.Canvas(
        [
            cv.Points(points=seno1, paint=risco1, point_mode=cv.PointMode.POLYGON),
            cv.Points(points=seno2, paint=risco2, point_mode=cv.PointMode.POLYGON)
        ]
    )
    page.add(cnv)

ft.app(main)
Figura 6: Canvas.Point

Flet: Badge e Canvas

Controle Badge

O controle Badge (um distintivo ou emblema) é uma marca posta acima de outro controle, usada ​​para mostrar notificações, contagens ou informações de status sobre o aplicativo. O controle que recebe um Badge é normalmente um ícone, parte de um NavigationBar ou um destino de NavigationRail, ou um ícone de botão. O controle tem a propriedade text onde as informações podem ser exibidas. Se text é fornecido, o rótulo será um emblema em forma de StadiumBorder com altura large_size. Se nenhum texto for fornecido, o emblema será exibido como um círculo preenchido de diâmetro small_size.

Propriedades de Badge

As seguintes propriedades existem no controle Badge:

Propriedade Descrição
alignment alinhamento do label em relação ao conteúdo do controle. Este valor só é usado se a propriedade text for especificada. Por exemplo: badge.alignment = ft.alignment.top_left. O valor é do tipo Alignment.
bgcolor cor de fundo do label.
content um controle filho contido pelo Badge, normalmente um ícone parte de um destino de NavigationBar ou NavigationRail. O valor é do tipo Control.
label_visible booleano, default True. Se label_visible=False, o Badge não é exibido.
large_size altura do Badge se nenhum text for fornecido. O valor é do tipo OptionalNumber com default 16.
offset combinado com o alinhamento para determinar a localização do Badge. Só tem efeito se text for fornecido. O valor é do tipo OffsetValue.
padding preenchimento aplicado ao label. Esse valor só é usado se text for fornecido. O padrão é 4 pixels à esquerda e à direita. O valor é do tipo PaddingValue.
small_size O diâmetro do label se o text não for fornecido. O valor é do tipo OptionalNumber com default 6.
text texto mostrado no label, normalmente de 1 a 4 caracteres. Se o text for fornecido, o label terá a forma de StadiumBorder com altura igual a large_size. Se não for fornecido, o emblema será exibido como um disco diâmetro small_size. O valor é do tipo string.
text_color cor do texto no label. Substitui a cor especificada em text_style.
text_style estilo usado para texto em label. O valor é do tipo TextStyle.

Você pode ver um exemplo de uso do controle Bagde.

Controle Canvas

O controle Canvas serve para que sejam desenhados gráficos arbitrários, usando um conjunto de formas primitivas como line, arc, path e text, respectivamente linha, arco, caminho, e texto.

Propriedades do Canvas

As seguintes propriedades estão definidas do controle Canvas:

Propriedade Descrição
resize_interval intervalo de amostragem (em milissegundos) para coleta do evento on_resize. O default é 0 (on_resize ocorre imediatamente após a alteração).
shapes lista de objetos Shape (listados abaixo) a serem desenhados no canvas.

Evento do Canvas

O seguinte evento pode ser acionado no Canvas:

Evento Descrição
on_resize dispara quando o tamanho do canvas é alterado. O objeto de evento e é uma instância de CanvasResizeEvent.

Propriedades das Formas (Shapes)

Nesse contexto chamamos as Shapes de formas, Path de caminhos, as partes de um caminho de subcaminhos.

As formas básicas (Shapes) usadas pelo Canvas são: Arc, Circle, Color, Fill, Line, Oval, Path, Points, Rect, Shadow, Text, respectivamente: Arco, círculo, cor, preenchimento, linha, oval, caminho, ponto, retângulo, sombra, texto.

Propriedades de Arc

Um Arc é o elemento que desenha um arco dimensionado para caber dentro do retângulo disponível. O arco vai no sentido horário de start_angle até start_angle + sweep_angle (em radianos, com zero mostrado na figura 2). Se use_center=True, o arco é fechado de volta ao centro. Caso contrário, o arco fica aberto.

Figura 2

Uso: canvas.Arc(x, y, width, height, start_angle, sweep_angle, use_center, paint)

height altura do retângulo que contém o arco.
paint estilo de desenho do arco. O valor é uma instância da classe Paint.
start_angle ângulo inicial (em radianos) no desenho do arco. Veja figura.
sweep_angle acréscimo sobre o ângulo inicial (em radianos) no desenho do arco. Veja figura.
use_center se use_center=True o arco será fechado de volta ao centro. Caso contrário, o arco fica aberto.
width largura do retângulo que contém o arco.
x, y coordenadas (x,y) do ponto superior esquerdo do arco.
Propriedades de Circle

Um Circle desenha um círculo dentro do canvas.
Uso: canvas.Circle(x,y,radius, paint)

paint estilo de desenho do círculo. O valor é instância da classe Paint.
radius raio do círculo.
x, y coordenadas do centro do círculo.
Propriedades de Color

Color pinta uma cor na tela, usando o blend_mode fornecido. A cor fornecida é a origem e o fundo o destino.
Uso: canvas.Color(color, blend_mode)

blend_mode modo de mesclagem a ser aplicado. O valor é do tipo BlendMode.
color cor usada para pintar a tela.
Propriedades de Fill

Um Fill preenche a tela com o Paint dado (definido abaixo). Para preencher a tela com cor sólida e modo de mesclagem, considere usar forma Color.
Uso: canvas.Fill(paint)

paint estilo de preenchimento da tela. O valor é instância da classe Paint.
Propriedades de Line

Line desenha uma linha entre os pontos dados usando paint. A linha é traçada e o valor do Paint.style é ignorado.
Uso: canvas.Line(x1, y1, x2, y2, paint)

paint estilo de desenho da linha. O valor é instância da classe Paint.
x1, y1 coordenadas (x, y) do ponto inicial da linha.
x2, y2 coordenadas (x, y) do ponto final da linha.
Propriedades de Oval

Oval desenha uma figura oval (uma elipse) usando o Paint dado. A oval pode ser preenchida ou traçada (ou ambos), o que é controlado por Paint.style.

Uso: canvas.Oval(x, y, width, height, paint)

height altura do retângulo contendo a oval.
paint estilo para desenhar uma oval. O valor é instância da classe Paint.
width largura do retângulo contendo a oval.
x, y coordenadas (x, y) do ponto superior esquerdo da oval.
Propriedades de Path

Path desenha um caminho com elementos fornecidos por Paint. A forma pode ser preenchida ou traçada (ou ambos), e isso é controlado por Paint.style. Se Path for preenchido, os subcaminhos serão implicitamente fechados (veja Path.Close).
Uso: canvas.Path(elements, paint)

elements lista de elementos do caminho. Os elementos possíveis estão listados abaixo.
paint estilo para desenhar o caminho. O valor é instância da classe Paint.
Elementos de Path

A tabela abaixo lista os possíveis elementos de Path:

Path.MoveTo(x, y) inicia um novo subcaminho no ponto (x,y).
Path.LineTo(x, y) adiciona um segmento de reta do ponto atual ao ponto (x,y) dado.
Path.QuadraticTo(cp1x, cp2y, x, y, w) adiciona um segmento bezier do ponto atual até (x,y) dado, usando os pontos de controle (cp1x,cp1y). O peso w define o tipo de curva: se w> 1, hipérbole; w = 1, parábola; w < 1, elipse.
Path.CubicTo(cp1x, cp1y, cp2x, cp2y, x, y) adiciona um segmento cúbico bezier do ponto atual para (x,y), usando os pontos de controle (cp1x,cp1y) e (cp2x,cp2y).
Path.SubPath(elements, x, y) adiciona subcaminho descrito por elements até (x,y).
Path.Arc(x, y, width, height, start_angle, sweep_angle) adiciona subcaminho com um segmento de arco que segue a borda do oval delimitado por um retângulo. O retângulo tem canto superior esquerdo em (x, y) e dimensões width e height. O arco vai de start_angle radianos até start_angle + sweep_angle, crescendo no sentido horário.
Path.ArcTo(x, y, radius, rotation, large_arc, clockwise) adiciona até quatro curvas cônicas ponderadas. radius é o raio; rotation a rotação dos eixos (em graus e sentido horário). A primeira curva começa no ponto atual, e a última termina em (x, y). O sentido do arco é definido por clockwise e large_arc. clockwise=True é sentido horário e o ângulo de varredura é sempre menor que 360 ​​graus. Uma linha simples é acrescentada se radius=0.
Path.Oval(x, y, width, height) adiciona um novo subcaminho que consiste em uma curva que forma a elipse que preenche o retângulo fornecido.
Path.Rect(x, y, width, height, border_radius) adiciona um retângulo como um novo subcaminho.
Path.Close fecha o último subcaminho, ligando o ponto atual até o primeiro ponto do subcaminho.

Nota: †: Uma curva de Bezier é uma curva parametrizada que representa a interpolação linear entre os chamados pontos de controle. Normalmente, ela tem como objetivo aproximar uma forma que não tem representação matemática explícita ou com representação desconhecida ou complicada. Ela é usada principalmente em aplicações gráficas computadorizadas.

Figura 3: curva de Bezier
Propriedades de Points

Points é o elemento que desenha uma sequência de pontos de acordo com o point_mode dado.

paint estilo para desenhar pontos. O valor é instância da classe Paint.
points lista de ft.Offset descrevendo pontos.
point_mode define como a lista de pontos é interpretada ao desenhar um conjunto de pontos. O valor é do tipo PointMode.
Propriedades de Rect

Rect desenha um retângulo.

Uso: canvas.Rect(x, y, width, height, border_radius, paint)

border_radius raio da borda do retângulo. O valor é do tipo BorderRadius.
height altura do retângulo.
paint estilo para desenhar o retângulo. O valor é a instância da classe Paint.
width largura do retângulo.
x, y coordenadas (x,y) do ponto superior esquerdo do retângulo.
Propriedades de Shadow

Desenha uma sombra sob um caminho, representada com uma elevação elevation.

Uso: canvas.Shadow(color, elevation, path, transparent_occluder)

color cor da sombra.
elevation elevação da sombra.
path lista de objetos Path.PathElement que descrevem o caminho.
transparent_occluder True se o objeto oclusivo não for opaco. Default é False.
Propriedades de Text

Text renderiza elemento de texto com style dado no ponto (x, y).

Uso: canvas.Text(x, y, text, alignment, rotate)

alignment ponto dentro de um retângulo de texto que define sua posição e centro de rotação. O valor é do tipo Alignment e o default é align.top_left.
ellipsis String que define elipsis (três pontos: ) usados em texto maiores que o espaço disponível.
max_lines número máximo de linhas exibidas. Além desse número as linhas são silenciosamente descartadas. Ex.: se max_lines = 1, só uma linha é renderizada. Se max_lines = None e ellipsis != None as linhas que seguem a primeira a ultrapassar as restrições de largura são descartadas.
max_width largura máxima do texto renderizado. Default None (infinito).
rotate rotação do texto em radianos, em torno do ponto determinado pelo alinhamento.
spans lista de objetos TextSpan para criar um parágrafo de rich text.
style estilo de texto para rederizar text e spans. O valor é instância da classe TextStyle.
text texto a ser exibido.
text_align alinhamento horizontal do texto. O valor é do tipo TextAlign com default TextAlign.LEFT.
x, y coordenadas (x,y) do ponto de alinhamento do texto.

Flet: NavigationDrawer

Controle NavigationDrawer

O controle NavigationDrawer é um componente no estilo Material Design que desenha um painel similar ao NavigationBar mas que desliza horizontalmente da borda, da esquerda para a direita ou o inverso. Ela serve para apresentar destinos primários em um aplicativo. Uma NavigationDrawer é adicionada e removida da página com as propriedades page.drawer e page.end_drawer. Um controle NavigationDrawer pode ser adicionado a uma View, usando as propriedades View.drawer ou View.end_drawer.

Nesse texto chamaremos a drawer (literalmente, gaveta) de aba. Portanto o controle de navegação contem diversos controles de destinos que são abas.

Propriedades do NavigationDrawer

Propriedade Descrição
bgcolor cor de fundo do controle.
controls lista de itens de menu que são os filhos do NavigationDrawer. Esses filhos são controles NavigationDrawerDestination ou alguns outros, como títulos e divisores.
elevation elevação do controle.
indicator_color cor do indicador de destino selecionado.
indicador_shape forma do indicador de destino selecionado. O valor é do tipo OutlinedBorder.
position posição dessa aba. O valor é do tipo NavigationDrawerPosition com default NavigationDrawerPosition.START.
selected_index índice do NavigationDrawerDestination selecionado, ou nulo se nenhuma seleção foi feita.Se esse número for inválido (como -1), nenhum destino será selecionado.
shadow_color cor da sombra usada para indicar elevação.
surface_tint_color tom de cor da superfície (Material) que abriga o conteúdo do NavigationDrawer.
tile_padding preenchimento para controles NavigationDrawerDestination.

Eventos do NavigationDrawer

Evento Descrição
on_change dispara na seleção de um destino.
on_dismiss dispara quando a aba é descartada por ação de alhum outro controle ou clique fora da aba.

Uma NavigationDrawer recebe outros controles em sua propriedade NavigationDrawer.controls, que é um array. Em particular vários controles NavigationDrawerDestination podem ser inseridos, contendo ícones e labels. A seleção dos destinos é realizada no evento NavigationDrawer.on_change e a captura do índice do controlel clicado. Um evento também é disparado no fechamento da aba, com NavigationDrawer.on_change.

Propriedades de NavigationDrawerDestination

Propriedade Descrição
bgcolor cor do controle de destino.
icon ícone do destino.
icon_content controle dentro do ícone de destino. Geralmente é um controle Icon e é usado no lugar da propriedade icon.
Se um selected_icon_content for fornecido ele só será exibido se o destino não for selecionado.
label rótulo de texto abaixo do ícone deste NavigationDrawerDestination.
selected_icon ícone alternativo exibido quando o destino é selecionado.
selected_icon_content controle de ícone alternativo exibido quando o destino é selecionado. Se este ícone não for fornecido, o NavigationDrawer exibe icon_content em qualquer estado.

† Nota: O manual do Flet sugere a escolha de um ícone com uma versão com traço e preenchida, como icons.CLOUD e icons.CLOUD_QUEUE, para tornar o NavigationDrawer mais acessível. O ícone deve ser definido para a versão com traço e selected_icon para a versão preenchida.

Exemplo de Uso do NavigationDrawer

import flet as ft

def main(page: ft.Page):
    page.bgcolor=ft.colors.BLUE_500

    def fechar_painel(e):
        mensagem.value+="\nAba dispensada"
        page.update()

    def clicar_destino(e):
        mensagem.value+=f"\nFoi selecionado o índice: {e.control.selected_index}"
        if e.control.selected_index==3:
            page.close(aba)
        page.update()

    aba=ft.NavigationDrawer(
        bgcolor=ft.colors.BLUE_600,
        on_dismiss=fechar_painel,
        on_change=clicar_destino,
        controls=[
            ft.Container(height=12),
            ft.NavigationDrawerDestination(
                label="Item 1",
                icon=ft.icons.AIRPLANEMODE_ON,
                selected_icon_content=ft.Icon(ft.icons.AIRPLANEMODE_INACTIVE),
            ),
            ft.NavigationDrawerDestination(
                icon_content=ft.Icon(ft.icons.AIRPLANE_TICKET),
                label="Item 2",
                selected_icon=ft.icons.AIRPLANE_TICKET_OUTLINED,
            ),
            ft.NavigationDrawerDestination(
                icon_content=ft.Icon(ft.icons.AIRPORT_SHUTTLE),
                label="Item 3",
                selected_icon=ft.icons.DEBLUR_SHARP,
            ),
            ft.Divider(thickness=2),
            ft.NavigationDrawerDestination(
                icon_content=ft.Icon(ft.icons.CHALET),
                label="Fechar Aba",
                selected_icon=ft.icons.PHONE,
            ),
            ft.NavigationDrawerDestination(
                label="Feche a aba clicando no ícone\n ou fora da aba"
            ),
        ],
    )
    mensagem=ft.Text("Suas ações serão vistas aqui:\n", color=ft.colors.BLACK)
    centro=ft.Container(
        content=mensagem,
        margin = ft.margin.only(left=300, top=0, right=0, bottom=0),
        padding=30,
        width=300,
        height=230,
        border_radius=10,
        bgcolor=ft.colors.AMBER_100,
    )
    page.add(
        ft.ElevatedButton("Exibir drawer", on_click=lambda e: page.open(aba)),
        centro
    )

ft.app(main)

A figura 1 mostra o estado do aplicativo em execução. 1 (A) é o estado inicial, antes de qualquer ação do usuário. 1 (B) exibe a aba após o clique sobre Exibir drawer. 1 (C) é o estado após um clique sobre os três itens, seguido do clique sobre Fechar Aba ou em qualquer ponto da página fora da aba.

Flet: NavigationBar


Controle NavigationBar

NavigationBar é um componente da barra de navegação no estilo Material 3. Barras de navegação são dispostas ao fundo da página do aplicativo e podem conter diversos controles de seleção, chamados NavigationBarDestination que podem ser selecionados com um clique. Essa é uma forma conveniente de alternar entre destinos em um aplicativo.

Propriedades de NavigationBar

As seguintes propriedades estão definidas para o controle NavigationBar:

Propriedade Descrição
adaptive booleano, default False. Se adaptive=True uma barra adaptável será criada. No iOS/MacOS uma CupertinoNavigationBar é criada, com funcionalidade e apresentação correspondentes ao padrão do iOS. Em outras plataformas a barra tem a apresentação do estilo Material.
animation_duration tempo de transição para os ícones de destino para mudar de selecionado para não selecionado.
bgcolor cor da barra de navegação.
destinations define os botões dispostos dentro da barra de navegação, inclusive sua aparência. Deve ser uma lista de duas ou mais
instâncias de NavigationBarDestination.
elevation elevação da barra de navegação.
indicator_color cor do indicador de destino selecionado.
indicator_shape formato do indicador de destino selecionado. O valor é do tipo OutlinedBorder.
label_behavior define a disposição dos rótulos de destinos e quando serão exibidos.É possível exibir ou ocultar todos os rótulos, ou mostrar apenas aquele selecionado. O valor é do tipo NavigationBarLabelBehavior e o padrão é NavigationBarLabelBehavior.ALWAYS_SHOW (sempre exibido).
overlay_color cor de destaque do NavigationDestination em vários estados ControlState. Os seguintes valores de ControlState são suportados: PRESSED, HOVERED e FOCUSED.
selected_index índice do destino selecionado (o último NavigationBarDestination selecionado), ou None se nenhum destino foi selecionado.
shadow_color cor usada na sombra que indica elevação.
surface_tint_color tonalidade da superfície Material que contém o conteúdo do NavigationDrawer.

Nota † ControlState é um enum com os valores: DEFAULT, DISABLED, DRAGGED, ERROR, FOCUSED, HOVERED, PRESSED, SELECTED, SCROLLED_UNDER.

Eventos da NavigationBar

Os controles NavigationBarDestination não possuem nenhum evento associado. O único evento do conjunto está na troca de seleção entre as opções dispostas na NavigationBar.

Evento Descrição
on_change dispara quando o destino é alterado, por exemplo por meio de um clique nos botões de destino.

Propriedades de NavigationBarDestination

 

Propriedade Descrição
bgcolor cor do botão de destino.
icon nome do ícone do botão de destino.
icon_content ícone usado dentro do destino (em vez da propriedade icon). Se selected_icon_content for fornecido essa propriedade só será exibida quando o destino não estiver selecionado.
label rótulo (texto) que aparece abaixo do ícone do NavigationBarDestination.
selected_icon ícone alternativo para exibição quando o destino é selecionado.
selected_icon_content um controle de ícone alternativo exibido quando este destino é selecionado. Se este controle não for fornecido, a NavigationBar exibirá icon_content em qualquer estado.

Exemplo de Uso da NavigationBar e NavigationBarDestination

import flet as ft

def main(page: ft.Page):
    page.horizontal_alignment = "center"
    page.bgcolor=ft.colors.BLUE_100
    page.title = "Exemplo de NavigationBar"
    controle=["Explorar", "Carona", "Ônibus", "Apagar"]

    def mostrar_barra(e):
        nav_barra.visible=not nav_barra.visible
        bt.text=f"{'Ocultar' if nav_barra.visible else 'Exibir'} Barra de Navegação"
        mensagem.value += f"\nVocê {'exibiu' if nav_barra.visible else 'ocultou'} a Barra de Navegação"
        page.update()

    def mudou_destino(e):
        if e.control.selected_index==3:
            mensagem.value="Suas ações serão vistas aqui:\n"
        else:
            mensagem.value += f"\nVocê selecionou o botão {controle[e.control.selected_index]}"
        page.update()

    nav_barra=ft.NavigationBar(
        visible=False,
        destinations=[
            ft.NavigationBarDestination(icon=ft.icons.EXPLORE, label="Explorar"),
            ft.NavigationBarDestination(icon=ft.icons.PERSON, label="Carona"),
            ft.NavigationBarDestination(icon=ft.icons.DIRECTIONS_BUS, label="Ônibus"),
            ft.NavigationBarDestination(
                icon=ft.icons.HIDE_IMAGE,
                selected_icon=ft.icons.HIDE_SOURCE,
                label="Apagar"
            ),
        ],
        on_change=mudou_destino
    )
    page.navigation_bar = nav_barra
    mensagem=ft.Text("Suas ações serão vistas aqui:\n", color=ft.colors.BLACK)
    bt=ft.ElevatedButton("Exibir NavigationBar", on_click=mostrar_barra)
    page.add(bt, mensagem)

ft.app(target=main)
Figura 1

A figura 1 mostra o estado do aplicativo em execução. A primeira imagem é o estado após a exibição da barra de navegação e clique no botão Explorar. Ao lado o resultado do clique no botão Apagar.

Flet: MenuBar

Controle MenuBar

Um controle MenuBar é uma barra que normalmente é posta acima da página principal do aplicativo para abrigar um sistema de menus e outros controles usados para as ações principais do usuário. Ela pode conter um sistema de menus composto por submenus e, se desejado, pode ser colocado em qualquer parte do aplicativo.

Propriedades de MenuBar

O controle MenuBar possui poucas propriedades. Como ele pode conter diversos outros controles filhos as formatação e coleta de eventos se dá, em geral, nesses filhos. As seguintes propriedades estão definidas para o controle MenuBar:

Propriedade Descrição
clip_behavior informa de o conteúdo deste controle deve ser cortado (clipped); O valor é do tipo ClipBehavior com default ClipBehavior.NONE.
controls a lista de itens de menu que são os filhos do MenuBar.
style estilização do controle, com valor do tipo MenuStyle.

Exemplo de Uso do MenuBar

import flet as ft

def main(page: ft.Page):
    page.horizontal_alignment = "center"

    def delete(e):
        mensagem.value=""
        page.open(ft.SnackBar(ft.Text("Você apagou as mensagens!")))
        page.update()

    def hover_submenu(e):
        page.open(ft.SnackBar(ft.Text(f"Hover em {e.control.content.value}!")))
        page.update()

    def clique_menu(e):
        mensagem.value+=f"\nClicou em {e.control.content.value}"
        page.update()

    def abre_submenu(e):
        mensagem.value+=f"\nAbrir {e.control.content.value}"
        page.update()

    def fecha_submenu(e):
        mensagem.value+=f"\nFechar {e.control.content.value}"
        page.update()

    icone=[ft.icons.HELP, ft.icons.SAVE, ft.icons.DOOR_BACK_DOOR,
           ft.icons.TEXT_INCREASE , ft.icons.TEXT_DECREASE]

    class MenuItem(ft.MenuItemButton):
        def __init__(self, texto, ico):
            super().__init__()
            self.content=ft.Text(texto)
            self.leading=ft.Icon(icone[ico])
            self.style=ft.ButtonStyle(bgcolor={ft.ControlState.HOVERED: ft.colors.BLUE_100})
            self.on_click=clique_menu

    class SubMenu(ft.SubmenuButton):
        def __init__(self, texto, controles):
            super().__init__()
            self.content=ft.Text(texto)
            self.on_open=abre_submenu
            self.on_close=fecha_submenu
            self.on_hover=hover_submenu
            self.controls=controles

    page.appbar = ft.AppBar(
        title=ft.Text("Demonstração do Controle MenuBar e SnackBar"),
        center_title=True,
        bgcolor=ft.colors.BLUE
    )

    mensagem=ft.Text("", size=20)
    estilo=ft.MenuStyle(alignment=ft.alignment.top_left, bgcolor=ft.colors.RED_300)
    bt_apagar=ft.IconButton(ft.icons.DELETE, icon_color="white", on_click=delete)
    subMenu1=SubMenu("Arquivo",[MenuItem("Sobre", 0), MenuItem("Gravar", 1), MenuItem("Terminar", 2)])
    subMenu2=SubMenu("Visualizar", [SubMenu("Zoom", [MenuItem("Ampliar", 3),MenuItem("Diminuir", 4)])])
    menu_bar=ft.MenuBar(expand=True, style=estilo, controls=[bt_apagar, subMenu1, subMenu2])
    coluna = ft.Column(
        controls=[mensagem],
        height=700,
        alignment=ft.MainAxisAlignment.CENTER
    )

    page.add(ft.Row([menu_bar]), coluna)

ft.app(main)
Figura 1

O resultado desse código está mostrado na figura 1. A primeira imagem mostra o estado ao abrir o aplicativo e passar o cursor do mouse sobre o Menu Arquivo. A segundo mostra o estado após alguns cliques nos submenus de Arquivo. Um clique na lixeira apaga o texto no corpo da página.

Esse exemplo usa o controle SnackBar, que é uma barra de exibição de informações que se abre, temporariamente, no fundo da página do aplicativo.

Duas classes foram definidas:

  • MenuItem, que herda de ft.MenuItemButton e recebe apenas o texto e o ícone a exibir,
  • SubMenu, que herda de ft.SubmenuButton e recebe o texto e o array de controles que serão exibidos.

Esse é um recurso para evitar a declaração repetida de controles que possuem a maioria das propriedades comuns.

Estilo de formatação do código

Nota: adotei nesse bloco de código a prática de declarar os objetos antes de seu uso dentro das propriedades dos controles. Também é possível definir os blocos no ambiente em que são usados. A primeira opção foi usada buscando dar mais clareza ao código. Alguns programadores provavelmente preferem fazer do segundo modo. Esses estilos estão ilustrados abaixo:

# o estilo usado no texto:
    mensagem=ft.Text("", size=20)
    estilo=ft.MenuStyle(alignment=ft.alignment.top_left, bgcolor=ft.colors.RED_300)
    subMenu=SubMenu("Visualizar", [SubMenu("Zoom", [MenuItem("Ampliar"),MenuItem("Diminuir")])])
    menu_bar=ft.MenuBar(expand=True, style=estilo, controls=[subMenu])
    coluna=ft.Column(controls=[mensagem])
    linha=ft.Row([menu_bar])

    page.add(linha, coluna)
    
# alternativamente:

    mensagem=ft.Text("", size=20)
    page.add(
        ft.Row(
            ft.MenuBar(
                expand=True,
                style=ft.MenuStyle(
                    alignment=ft.alignment.top_left,
                    bgcolor=ft.colors.RED_300
                ),
                controls=[
                    SubMenu("Visualizar",
                        [SubMenu("Zoom", [MenuItem("Ampliar"), MenuItem("Diminuir")])]
                    )
                ]
            )
        ),
        ft.Column(controls=[mensagem])
    )


Se essa segunda forma de formatação for adotada é importante manter um sistema coerente de indentação (notando que não se trata da indentação obrigatória do Python para definir blocos).
Observe que a variávelmensagem (um flet.Text) continua sendo definida em separado para poder ser referenciada em uma função fora desse bloco.

Flet: AppBar e BottomAppBar

Controle Appbar

O controle AppBar insere uma barra de aplicativos, às vezes chamada de barra de ação, na parte superior da página do Flet. Essa barra pode conter botões, menus dropdown e outros widgets que acionam ações desejados pelo usuário. A barra de aplicativos tem uma estrutura visual e elementos interativos familiares para os usuários.

Exemplo de Uso da Appbar

Um controle AppBar é aplicado à propriedade da página, page.appbar = app_barra. O código a seguir mostra um pequeno aplicativo que faz uso da Appbar.

import flet as ft

def main(page: ft.Page):
    page.bgcolor="#72BFDE"
    page.horizontal_alignment=ft.CrossAxisAlignment.CENTER

    def clicou_botao(e):
        texto.value += f"\nO ícone \"{e.control.icon}\" foi clicado"
        page.update()

    def clicou_check(e):
        e.control.checked = not e.control.checked
        insere = f"\nO {e.control.text} {'' if e.control.checked else 'não'} está selecionado!"
        texto.value += insere
        page.update()

    class Pop(ft.PopupMenuItem):
        def __init__(self, texto):
            super().__init__()
            self.text=texto
            self.checked=False
            self.on_click=clicou_check

    app_barra = ft.AppBar(
        leading=ft.IconButton(ft.icons.SOUTH_AMERICA, icon_color="white", on_click=clicou_botao),
        leading_width=40,
        title=ft.Text("AppBar: Barra de Aplicativo", color="white"),
        center_title=False,
        bgcolor="#8FD0DA",
        actions=[
            ft.IconButton(ft.icons.PODCASTS, icon_color="white", on_click=clicou_botao),
            ft.IconButton(ft.icons.CAR_REPAIR, icon_color="white", on_click=clicou_botao),
            ft.PopupMenuButton(
                items=[Pop("Item 1"), Pop("Item 2"), Pop(""), Pop("Item 3")],
                bgcolor="#A88413", icon_color="#ffffff"
            ),
        ],
    )

    titulo = ft.Text("Clique nos ícones ou menu dropdown", size=15, color="#333333")
    texto = ft.Text("", size=20, color=ft.colors.BLACK)

    page.appbar = app_barra
    page.add(
        ft.Text(
            "Lista de ações executadas:",
            size=30,
            color=ft.colors.BLACK
        ),
        ft.Container(
            content=ft.Column([titulo, texto]),
            padding=20,
            width=500, height=500,
            bgcolor=ft.colors.BLUE_100,
            border=ft.border.all(1, "#aaaaff")
        )
    )

ft.app(target=main)

A variável app_barra contém uma AppBar com ícones e um menu dropdown. Um clique em cada ícone ativa a função clicou_botao(e) que acrescenta uma linha de texto à variável texto que é um controle dentro do container na página.

Os cliques ativam as funções clicou_botao(e) e clicou_check(e) que recebem os objetos de eventos e (da classe ControlEvent). Esse objeto possui a propriedade .control que, por sua vez possui um dicionárioiconbutton, no caso do IconButton e popupmenuitem, no caso do PopupMenuButton. Os dois dicionários estão listados abaixo (para algum momento da execução):

  • iconbutton = {‘icon’: ‘podcasts’, ‘iconcolor’: ‘white’, ‘n’: ‘action’}
  • popupmenuitem = {‘text’: ‘Item 1’, ‘checked’: False}

Em execução o aplicativo é renderizado de acordo com a figura 1. A figura 1(a) mostra o estado inicial, com o PopupMenuButton clicado. A figura 1(b) representa o estado após um clique nos três ícones, seguidos de 2 cliques no item 1 do menu.

Figura 1: AppBar

Propriedades de AppBar

As seguintes propriedades estão definidas para o controle AppBar:

Propriedade Descrição
actions uma lista de controles a exibir na linha, depois do título.
Normalmente são IconButtons mas pode ser usado um PopupMenuButton.
Se AppBar.adaptive=True em dispositivo iOS ou macOS, apenas o primeiro elemento da lista será exibido.
adaptive booleano, default=False. Se True, o controle será adaptável à plataforma de destino. No iOS e macOS, uma barra CupertinoAppBar é criada, com funcionalidade e aparência esperadas no iOS. Nas demais plataformas, um Material AppBar é criado.
automatically_imply_leading booleano, válida apenas se leading = null. Se False aloca o espaço inicial para o título. Se True tenta deduzir automaticamente será o controle na primeira posição.
bgcolor cor de fundo da AppBar. A cor do tema atual é o default.
center_title booleano, default=False. Se o título deve ser centralizado.
clip_behavior O comprtamento de recorte (clipping) do conteúdo. O valor é do tipo ClipBehavior.
color definição de cor para os controles de texto e ícones na barra. A cor padrão é definida pelo tema atual.
elevation elevação da barra de aplicativos. Observação: o efeito só é visível quando o design Material 2 é usado (Theme.use_material3=False). O valor é do tipo OptionalNumber com default 4.
elevation_on_scroll elevação usada se houver algum controle rolado sob a barra. O valor é do tipo OptionalNumber.
exclude_header_semantics booleano, default=False. Se o título deve envolver um controle Semantics.
force_material_transparency booleano. Torna a barra transparente (em vez do padrão Material). Também remove a exibição visual de bgcolor e elevation (e outras características).
is_secondary booleano, default=False. Se a barra não é exibida na parte superior da tela.
leading controle exibido antes do título na barra. Normalmente é um Icon ou um IconButton. O valor é do tipo Control.
leading_width largura do controle leading. O valor é do tipo OptionalNumber com default 56,0.
shadow_color cor da sombra abaixo da barra, só visível se a elevation > 0.
shape A forma da barra e de sua sombra. O valor é do tipo OutlinedBorder.
surface_tint_color cor da sobreposição entre tom da superfície e da barra para indicar elevação. Default: nenhuma sobreposição é aplicada.
title controle principal exibido na barra, normalmente, um controle de texto. Se AppBar.adaptive=True no iOS ou macOS, o controle é centralizado automaticamente. O valor é do tipo Control.
title_spacing Espaçamento do título no eixo horizontal, aplicado mesmo se não não existirem controles leading ou action.
Se title_spacing = 0.0 o título ocupa todo o espaço disponível. O valor é do tipo OptionalNumber.
title_text_style estilo usado nos controles de texto do título. O valor é do tipo TextStyle.
toolbar_height altura do componente toolbar na AppBar. O valor é do tipo OptionalNumber, com default 56.0.
toolbar_opacity opacidade da barra, variando de 0.0 (transparente) a 1.0 (totalmente opaco). O valor é do tipo OptionalNumber com default 1.0.
toolbar_text_style estilo usado nos controles de texto leading ou action, exceto no título. O valor é do tipo TextStyle.


Notas †:Semantics Um controle que leva uma anotação descrendo o significado do widget. Usado para acessibilidade, search engines e ferramentas de análise semântica.

Controle BottomAppBar

O controle BottomAppBar é similar ao AppBar mas disposto no fundo da página do aplicativo.

Propriedades de BottomAppBar

As seguintes propriedades estão definidas para o controle BottomAppBar:

Propriedade Descrição
bgcolor cor de fundo para o BottomAppBar. A cor default é definida pelo tema atual.
clip_behavior O conteúdo será recortado (ou não) de acordo com esta opção. O valor é do tipo ClipBehavior e o default é ClipBehavior.NONE.
content Um controle filho contido pelo BottomAppBar.
elevation controla a elevação (e portanto a sombra abaixo do BottomAppBar). O default é 4.
height altura do BottomAppBar. O default é 80,0 no material 3.
notch_margin margem entre o FloatingActionButton e o entalhe (notch) do BottomAppBar. Só visível se shape=None.
padding margens internas na decoração (fundo, borda). É uma instância da classe Padding, e o default é padding.symmetric(vertical=12.0, horizontal=16.0).
shadow_color cor da sombra abaixo da BottomAppBar.
shape entalhe (notch) para o botão de ação flutuante. O valor é do tipo NotchShape.
surface_tint_color cor usada como sobreposição de bgcolor para indicar elevação. Se for None, nenhuma sobreposição será aplicada. Caso contrário, a cor será composta em cima de bgcolor com opacidade relacionada à elevação e a cor de fundo da BottomAppBar. O default é None.

Nota: †: Notch ou entalhe é o recorte usado para acomodar componentes na parte superior frontal na tela dos smartphones.

Exemplo de Uso da BottomAppbar

Um controle BottomAppBar é aplicado à propriedade da página, page.bottom_appbar = barra_fundo. O código a seguir mostra um pequeno aplicativo que faz uso da BottomAppbar.

import flet as ft

def main(page: ft.Page):
    def clicou(e):
        texto.visible = not texto.visible
        page.update()

    page.horizontal_alignment = page.vertical_alignment = "center"
    page.floating_action_button = ft.FloatingActionButton(icon=ft.icons.ADD, on_click=clicou)
    page.floating_action_button_location = ft.FloatingActionButtonLocation.CENTER_DOCKED

    page.bottom_appbar = ft.BottomAppBar(
        bgcolor=ft.colors.BLUE,
        shape=ft.NotchShape.CIRCULAR,
        content=ft.Row(
            controls=[
                ft.IconButton(icon=ft.icons.MENU, icon_color=ft.colors.WHITE),
                ft.Container(expand=True),
                ft.IconButton(icon=ft.icons.SEARCH, icon_color=ft.colors.WHITE),
                ft.IconButton(icon=ft.icons.FAVORITE, icon_color=ft.colors.WHITE),
            ]
        ),
    )

    texto = ft.Text(
        (
        'Lorem ipsum dolor sit amet, consectetur adipisicing elit,\n'
        'sed do eiusmod tempor incididunt ut labore et dolore magna\n'
        'aliqua. Ut enim ad minim veniam, quis nostrud exercitation\n'
        'ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n'
        'Duis aute irure dolor in reprehenderit in voluptate velit\n'
        'esse cillum dolore eu fugiat nulla pariatur. Excepteur sint\n'
        'occaecat cupidatat non proident, sunt in culpa qui officia\n'
        'deserunt mollit anim id est laborum.'
        ),
        size=15, color=ft.colors.WHITE
    )

    page.add(texto)

ft.app(target=main)
Figura 2: BottomAppBar

A figura 2 mostra a execução do aplicativo. Cliques no botão FloatingActionButton (com o ícone +) ocultam / exibem a texto centralizado na página.

Versões Estilizadas para IOS

Dois controles análogos estão disponíveis com o estilo iOS:

Um exemplo breve de uso está descrito a seguir:

import flet as ft

def main(page: ft.Page):
    page.theme_mode = ft.ThemeMode.LIGHT
    page.horizontal_alignment = page.vertical_alignment = "center"
    page.bgcolor="#F4F0BD"
    icone = ["Bússula", "Carros", "Bandeira"]

    def clicou(e):
        texto2.value += f"\nClicou no ícone {icone[e.control.selected_index]}"
        page.update()

    page.appbar = ft.CupertinoAppBar(
        leading=ft.Icon(ft.icons.PALETTE),
        bgcolor="#976A4E",
        trailing=ft.Icon(ft.icons.WB_SUNNY_OUTLINED),
        middle=ft.Text("Exemplo de CupertinoAppBar e CupertinoNavigationBar")
    )

    page.navigation_bar = ft.CupertinoNavigationBar(
        bgcolor="#4E7B97",
        inactive_color=ft.colors.GREY,
        active_color=ft.colors.BLACK,
        on_change=clicou,
        destinations=[
            ft.NavigationBarDestination(icon=ft.icons.EXPLORE, label="Bússula"),
            ft.NavigationBarDestination(icon=ft.icons.COMMUTE, label="Carros"),
            ft.NavigationBarDestination(
                icon=ft.icons.BOOKMARK_BORDER,
                selected_icon=ft.icons.BOOKMARK,
                label="Bandeira",
            ),
        ]
    )
    texto1 = ft.Text("Exemplo de Uso dos controles:\n\nCupertinoAppBar e CupertinoNavigationBar", size=18)
    texto2 = ft.Text("", size=20)
    page.add(texto1, texto2)

ft.app(target=main)

O Material Design é desenvolvido pelo Google e pode ser usado para desenvolver aplicativos Android, iOS, web e desktop.O Cupertino é desenvolvido pela Apple. Ele é baseado nas Diretrizes de Interface Humana da Apple, que implementam a linguagem de design atual do iOS.

O Flutter e o Flet vem com bibliotecas de widgets Material e Cupertino para desenvolver um aplicativo que pareça e seja nativo para qualquer plataforma.

Figura 3: Controles estilizados Cupertino

A figura 3 mostra a execução do aplicativo após cliques nos botões na barra de fundo.

Flet: Controles personalizados

Personalizando Controles

O Flet inclui muitos controles prontos para uso, como já listamos nessas páginas. Mesmo assim é sempre possível que o desenvolvedor pense em um controle diferente, personalizado para fim específico. No Flet podemos partir dos controles embutidos e modificá-los, usando os conceitos de programação orientada a objetos do Python. Os controles definidos dessa forma podem ser armazenados e reutilizados posteriormente em outros projetos.

Controles estilizados

A personalização mais simples consiste em usar um controle existente e o estilizar, gerando nova aparência e acrescentando funcionalidades (métodos). Para fazer isso você cria uma nova classe em Python que herda do controle Flet que se deseja personalizar. No exemplo seguinte modificamos um botão ElevatedButton:

class NovoBotao(ft.ElevatedButton)
    def __init__(self, texto):
        super().__init__()
        self.bgcolor = ft.colors.ORANGE_300
        self.color = ft.colors.GREEN_800
        self.text = texto

O controle assim personalizado possui um construtor que define propriedades e eventos, além de passar dados, no caso através da variável texto. A chamada a super().__init__() no construtor dá o acesso às propriedades e métodos originais do controle Flet usado na herança. Uma vez criada essa classe esse controle pode ser usado no aplicativo:

import flet as ft

def main(page: ft.Page):
    page.add(NovoBotao(text="Sim"), NovoBotao(text="Não"))

ft.app(target=main)

Um exemplo de uso pode ser visto no código abaixo:


import flet as ft

def clicou_sim(e):
    e.control.text = "Clicou sim!"
    e.control.update()

def clicou_nao(e):
    e.control.text = "Clicou não!"
    e.control.update()

class NovoBotao(ft.ElevatedButton):
    def __init__(self, clicou, texto="Não"):
        super().__init__()
        self.bgcolor = ft.colors.BLUE_800
        self.color = ft.colors.YELLOW_100
        self.icon="chair_outlined"
        self.icon_color="GREEN_100"
        self.text = texto
        self.on_click = clicou

def main(page: ft.Page):
    page.bgcolor=ft.colors.BLUE_50

    page.add(
        NovoBotao(texto="Sim", clicou = clicou_sim),
        NovoBotao(clicou = clicou_nao)
    )

ft.app(target=main)
Figura 1

No exemplo acima vemos que a classe estende um ElevatedButton e seu construtor permite a alteração do texto e do nome da função executada sob o evento on_click. Essas funções devem estar definidas antes do ponto em que serão chamadas, e antes da definição da classe. Por default o texto no botão será “Não”. A execução do código gera a janela inicial com os botões ilustrados na figura 1 (a), que se alteram para 1 (b) quando o botão “Não” é clicado.

Controles Compostos

Alguns exemplos de widgets do Flet que são também containers (podem conter outros controles internamente, são: View, Page, Container, Column, Row e Stack.

Os controles personalizados compostos herdam de controles que podem ser também containers, como Page, Row ou Column, que por sua vez abrigam outros controles filhos. O controle criado dessa forma tem acesso às propriedades e métodos do container e também dos controles filhos.

O exemplo abaixo mostra um esqueleto de um aplicativo TODO simples, que define um controle personalizado que herda de ft.Row e acrescenta outros controles.

                                                                                   
import flet as ft

class Row_Tarefa(ft.Row):
    def __init__(self, texto):
        super().__init__()
        self.ver_texto = ft.Text(texto)
        self.editar_texto = ft.TextField(texto, visible=False)
        self.editar_botao = ft.IconButton(
            icon=ft.icons.EDIT,
            on_click=self.modificar
        )
        self.gravar_botao = ft.IconButton(
            icon=ft.icons.SAVE,
            on_click=self.modificar,
            visible=False
        )
        self.controls = [
            ft.Checkbox(),
            self.ver_texto,
            self.editar_texto,
            self.editar_botao,
            self.gravar_botao,
        ]

    def modificar(self, e):
        op = e.control.icon=="save"
        self.editar_botao.visible = op
        self.gravar_botao.visible = not op
        self.ver_texto.visible = op
        self.editar_texto.visible = not op
        if op:
            self.ver_texto.value = self.editar_texto.value
        self.update()

def main(page: ft.Page):

    page.add(
        Row_Tarefa(texto="Fazer Compras"),
        Row_Tarefa(texto="Terminar Código"),
        Row_Tarefa(texto="Enviar Projeto"),
    )

ft.app(target=main)

Figura 2

A execução desse código gera a janela mostrada na figura 2: (a) é a janela inicial; (b) o primeiro botão de editar foi clicado e o texto alterado; (c) a alteração foi transferida para o texto, com um clique no botão de gravar.

Observe que o controle herda de Row e acrescenta a ele os controles ft.Text, ft.TextField e dois controles ft.IconButton, que não existem no controle pai. Esses controle são inseridos nas propriedades personalizadas ver_texto, editar_texto, editar_botao e gravar_botao. Definidas essas propriedades elas são inseridas, juntas com um Checkbox, na lista de controles (controls) (que e nativa de Row). Três linhas com o objeto Row_Tarefa são inseridos na página.

Tanto o botão gravar_botao quanto editar_botao respondem ao evento on_click ativando a função modificar que recebe o parâmetro e que contém a propriedade e.control.icon=="save"/"edit". A função decide com ela quais controles devem ser exibidos ou ocultados, e altera a propriedade ver_texto.value quando o botão gravar foi clicado.

Nenhum evento foi definido associado aos botões Checkbox que, por isso, não executam nenhuma ação.

Métodos do ciclo de vida

Quando você cria controles personalizados, alguns métodos se tornam disponíveis para o gerenciamento do ciclo de vida do controle:

Método Efeito
build() chamado quando o controle está sendo criado e atribuído à página. Ele pode ser sobrescrito (override) para implementar uma lógica que não pode ser executada no construtor do controle porque necessita do acesso à self.page. Por exemplo: esse seria o local certo para escolher um ícone que depende qual é a plataforma em self.page.platform.
did_mount() chamado após a adição do controle à página e recebe um uid transitório. Por exemplo: o widget Wheather chama uma API (API Open Weather) a cada minuto para atualizar seus dados climáticos.
will_unmount() chamado antes que o controle seja removido da página. Pode ser usado para operação de limpeza.
before_update() chamado sempre que o controle está sendo atualizado. O método update() não deve ser chamado dentro de before_update(), ou um loop infinito seria gerado.

Controles isolados

Controles personalizados recebem automaticamente a propriedade is_isolated, que recebe um booleano com False. Se for ajustado is_isolated = True esse controle fica isolado do layout geral, o que significa que quando o método update() for chamado no controle pai, o próprio pai e seus filhos serão atualizados, exceto o controle isolado. Para atualizar controles isolados, seu próprio método self.update() deve ser chamado. É boa prática que, se self.update() for chamado em um controle personalizado, que ele seja isolado.

Por exemplo, nos códigos acima, o botão NovoBotao não precisa ser isolado, mas Row_Tarefa(ft.Row) deve ser:

class Row_Tarefa(ft.Row):
    def __init__(self, texto):
        super().__init__()
        self.isolated = True
        self.ver_texto = ft.Text(texto)
        self.editar_texto = ft.TextField(texto, visible=False)

DNF: Gerenciador de Pacotes


DNF: Gerenciador de Pacotes de Software no Linux

O que é DNF

DNF é um gerenciador de pacotes de software, usado para instalar, atualizar e remover pacotes no Fedora e outras distribuições do Linux. DNF (Dandified Yum) foi proposto como substituto do YUM (Yellowdog Updater Modified), ambos usados em sistemas operacionais que utilizam pacotes RPM.

Um gerenciador de pacotes é um conjunto de aplicativos usados para automatizar o processo de instalação, atualização, configuração e remoção de programas de computador de uma maneira consistente. Ele manipula pacotes, que são distribuições de software e dados, contendo metadados como o nome do software, descrição de propósito, versão, fornecedor, checksum e uma lista de dependências necessárias. Na instalação, os metadados são armazenados em um banco de dados local. Gerenciadores de pacotes usam esse banco de dados de dependências para evitar incompatibilidades de software e pré-requisitos ausentes. Eles trabalham em conjunto com os repositórios de software, algumas vezes acessados pelas lojas de aplicativos. Diversas distribuições Linus usam DNF (ou YUM), entre elas: RedHat Enterprise Linux, Fedora, CentOS, Oracle Enterprise Linux, SUSE, OpenSUSE, Mageia e Turbolinux.

O DNF facilita a manutenção de pacotes, verificando automaticamente as dependências e determinando as ações necessárias para instalar os pacotes. Este método elimina a necessidade de instalar ou atualizar manualmente o pacote e suas dependências usando o comando rpm.

Uso do dnf

Nesse artigo usamos as seguintes convenções:
# linhas de comentários
$ linhas de código (input)
➡ linhas de saída (output)

O dnf pode ser usado para buscar, instalar, atualizar ou remover pacotes. Por exemplo:

# para pesquisar nos repositórios um tipo de pacote:
$ dnf search nome_do_pacote

# para instalar o pacote:
$ dnf install nome_do_pacote

# para remover um pacote:
$ dnf remove nome_do_pacote

# em muitos casos pode ser necessário rodar o comando como superuser
$ sudo dnf comando

Outros comandos do dnf de uso comum são:

Comando, aliás Descrição
autoremove remove dependências instaladas que não são mais necessárias para os programas instalados.
check-update verifica se existem atualizações, sem baixar nem instalar os pacotes.
downgrade, dg reverte para a versão anterior de um pacote.
download baixa um pacote, sem instalar.
info, if fornece informações básicas sobre o pacote, incluindo nome, versão, lançamento e descrição.
reinstall, rei reinstala o pacote que já está instalado.
remove remove (desinstala) o pacote do sistema.
upgrade, up verifica os repositórios em busca de pacotes mais recentes e os atualiza.
search procura pelo pacote nos repositórios registrados.
system upgrade atualiza o sistema operacional para a sua versão mais atualizada.

Alguns manuais encontrados online descrevem o comando update como sendo diferente de upgrade. Mas, de acordo com as páginas de man dnf, update é apenas um aliás, além de ser obsoleto (deprecated), o que significa que será eventualmente removido. Um aliás válido é dnf up.Você pode encontrar os demais parâmetros usados com DNF digitando dnf -help para uma lista de parâmetros ou dnf --help para a ajuda completa. A página de manual pode ser vista com man dnf.

Exemplos de Uso

Como exemplo, procuraremos pelo aplicativo focuswriter, um editor de texto distraction free. Ele é instalado e, em seguida, desinstalado. A pesquisa é feita nos repositórios cadastrados.

# pesquisando pelo aplicativo
$ dnf search focuswriter

➡ ========= Name Exactly Matched: focuswriter ========================
➡ focuswriter.x86_64 : A full screen, distraction-free writing program

# instalando o focuswriter (superuser é exigido)
$ sudo dnf install focuswriter
# aparece o aplicativo e uma lista de dependências (Is this ok? [y/n])

# desinstalando um aplicativo
$ sudo dnf remove focuswriter
# aparece o aplicativo e uma lista de dependências (Is this ok? [y/n])

Instalando Pacotes

O comando dnf [options] install <spec>... instala pacotes e verifica se todas as dependências estão satisfeitas (instaladas no sistema). <spec> pode se referir a pacotes, módulos ou grupos. Uma mensagem de erro será emitida se o pacote não estiver disponível nos repósitórios declarados. Se a versão do pacote for especificada ela será instalada, independentemente de qual versão já está instalada ou qual é a mais recente. A versão previamente instalada será removida.

Alguns exemplos podem ajudar a explicar o uso de install:

# instala o pacote vlc (vlc é o nome do pacote)
$ dnf install vlc

# instala o arquivo rpm tito-0.6.2-1.fc22.noarch.rpm na pasta ~/Downloads
$ dnf install ~/Downloads/tito-0.6.2-1.fc22.noarch.rpm

# instala o pacote do repositório, na versão especificada
# Se o pacote já instalado ele será atualizado ou downgraded (tentativamente)
$ dnf install tito-0.5.6-1.fc22

# instala a última versão do pacote. Se já instalado o pacote será atualizado ou downgraded (tentativamente)
# a instalação falhará se o pacote atualizado não puder ser instalado
$ dnf --best instala tito

# nesse caso vim não é o nome do pacote mas de um grupo
# dnf instalará o conjunto de pacote e dependências necessárias
$ dnf install vim

# instala o pacote diretamente da URL
$ dnf install https://fedoraproject.org//packages/nome_do_pacote.rpm

# instale todos os perfis do módulo 'docker' e seus RPMs
$ dnf install '@docker'

# instala o grupo 'Web Server'
$ dnf install '@Web Server'

# instala o pacote que fornece o arquivo /usr/bin/rpmsign.
$ dnf install /usr/bin/rpmsign

# instala o pacote tito sem dependências fracas (não exigidas para o
# funcionamento básico do pacote, como documentação, plugins, funções adicionais, etc).
$ dnf -y install tito --setopt=install_weak_deps=False

# instala todos os pacotes do "FEDORA-2018-b7b99fe852".
$ dnf install --advisory=FEDORA-2018-b7b99fe852 \*

Listando Pacotes

Podemos listar os pacotes instalados com dnf list installed:

$ dnf list installed
# uma lista de apps instalados pelo sistema ou pelo usuário,
# é exibida (com nome, versão e repositório de origem).

# dica: se você quer analisar a lista em um editor de texto faça:
$ dnf list installed > apps_instalados.txt
# um arquivo de nome apps_instalados.txt é gravado no diretório atual

# para contar quantos pacotes estão instalados
$ dnf list installed | wc -l

O “pipe” | envia a saida em lista para o comando seguinte. O comando wc do BASH faz uma contagem das linhas emitidas na saída de list.

Todos os pacotes instalados em sistemas que usam RPM deixam informações armazenadas em um banco de dados SQLite. Existem mais de uma forma de consultar esse banco de dados e encontrar detalhes sobre pacotes instalados, por exemplo usando o comando rpm. No Fedora esse banco de dados fica no diretório /var/lib/rpm/rpmdb.sqlite.

dnf list é uma das formas de acessar essa tabela. Outros comandos são possíveis:

Comando, aliás Descrição
dnf list [–all] Lista os pacotes presentes no RPMDB, nos repositórios registrados ou ambos.
dnf list –installed Lista pacotes instalados.
dnf list –available Lista pacotes disponíveis.
dnf list –extras Lista pacotes extras, i.e. pacotes instalados mas não disponíveis nos repositórios registrados.
dnf list –obsoletes Lista pacotes instalados obsoletos, i.e., com atualização disponíveis nos repositórios registrados.
dnf list –recent Lista pacotes adicionados recentemente nos repositórios registrados.
dnf list –upgrades Lista as atualizações disponíveis para pacotes instalados.
dnf list –autoremove Lista os pacotes que serão removidos através do comando dnf autoremove.

Todos os comandos acima admitem a inclusão de opções e discriminação de tipos de pacote, na forma:
dnf [option] comando <especifica-pacote>. Confira as opções disponíveis na páginas do manual usando man dnf.

Gerenciando Repositórios

Repositórios são servidores onde estão armazenados os pacotes de software das distribuições do Linux. As grandes distribuições mantém os seus repositórios próprios, que são acessados por meio dos comandos de gerenciamento de pacotes como dnf (do Fedora), apt (do Ubuntu) ou pacman (do Arch).

No Fedora os repositórios cadastrados podem ser encontrados no diretório etc/yum.repos.d/. Esses repositórios podem ser gerenciados com dnf:

# para ver uma lista de repositórios disponíneis e habilitados
$ dnf repolist

# para ver uma lista de todos os repositórios, habilitados ou não
$ dnf repolist all

Novos repositórios podem ser inseridos e habilitados simplesmente acrescentando-se um arquivo .repo na pasta /etc/yum.repos.d. A mesma operação pode ser feita com o comando dnf config-manager. Por exemplo, podemos inserir o repositório que contém o Sublime Text (um editor de código). Em seguido usamos cat para listar o conteúdo do arquivo inserido:

# inserindo o repositório para Sublime Text (stable, no Fedora)
$ sudo dnf config-manager --add-repo https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo
➡ Adding repo from: https://download.sublimetext.com/rpm/stable/x86_64/sublime-text.repo

# o seguinte arquivo é inserido na pasta /etc/yum.repos.d/
$ cat /etc/yum.repos.d/sublime-text.repo
➡ [sublime-text]
➡ name=Sublime Text - x86_64 - Stable
➡ baseurl=https://download.sublimetext.com/rpm/stable/x86_64
➡ enabled=1
➡ gpgcheck=1
➡ gpgkey=https://download.sublimetext.com/sublimehq-rpm-pub.gpg

O arquivo *.repo tem a seguinte estrutura:

  • [ID do pacote]: id do repositório,
  • name: nome do repositório,
  • baseurl: URL do repositório,
  • enabled=1: 1 para habilitado, 0 para desabilitado,
  • gpgcheck=1: 1 para permitir verificação da assinatura gpg, 0 para impedir,
  • gpgkey: URL da chave GPG, usada para assinar os pacotes.

Feito isso o pacote para o Sublime Text pode ser instalado com sudo dnf install sublime-text.

Repositórios podem ser habilitados ou desabilitados com dnf --enablerepo. Essa operação pode ser útil, por exemplo quando um pacote está disponível em mais de um repositório mas desejamos instalar de um específico.

# para desabilitar um repositório
$ sudo dnf config-manager --set-disabled id_do_repositorio

# para habilitar um repositório
sudo dnf config-manager --set-enabled id_do_repositorio

Por exemplo, podemos encontrar o id do repositório Sublime Text (supondo que esteja instalado e habilitado) com dnf repolist --all, que é, como se vê abaixo, sublime-text. Em seguida vamos desabilitá-lo, e reabilitá-lo em seguida.

$ dnf repolist --all
➡ repo id repo name status
➡ docker-ce-nightly Docker CE Nightly - x86_64 disabled
➡ fedora Fedora 40 - x86_64 enabled
➡ google-chrome google-chrome enabled
➡ sublime-text Sublime Text - x86_64 enabled

# para desabilitar o repositório
$ sudo dnf config-manager --set-disabled sublime-text

# para habilitar o repositório
$ sudo dnf config-manager --set-enabled sublime-text

# para remover o repositório do sistema basta apagar o arquivo em /etc/yum.repos.d
$ sudo rm /etc/yum.repos.d/sublime-text.repo

Uma vez que o repositório tenha sido excluído o dnf não tentará instalar ou atualizar seus pacotes.

Opções

O comando dnf [options] install <spec>... pode receber parâmetros em [options]. Alguns opções são listadas abaixo. Veja a lista completa na documentação do dnf.

Opção, aliás Descrição
–assumeno Responder automaticamente “não” para todas as perguntas na execução de dnf.
-b, –best Tenta encontrar as melhores versões de pacotes disponíveis nas transações.
–bugfix Inclui pacotes que corrigem algum bug. Pode ser usado com install, repoquery, updateinfo, upgrade e offline-upgrade (dnf-plugins-core).
-C, –cacheonly Usa apenas o cache do sistema, não realizar nenhuma atualização, mesmo que o cache esteja expirado.
–color=<cor> Informa se cores são usadas na saída do terminal. Valores válidos: always, never e auto (default).
–comment=<comentário> Adiciona um comentário ao histórico de transações.
-c <arquivo de configuração>, –config=<arquivo de configuração> Indica a localização do arquivo de configuração.
–disable, –set-disable Desativa repositórios especificados. Deve ser usada com o comando config-manager (dnf-plugins-core).
–disableplugin=<nomes dos plug-ins> Desativa os plug-ins listados.
–disablerepo=<repoid> Desativa temporariamente os repositórios no comando dnf atual. Pode receber um ID, lista de IDs separados por vírgula ou um conjunto de IDs.
–downloaddir=<caminho>, –destdir=<caminho> Redireciona os pacotes baixados para o diretório fornecido. Deve ser usada em conjunto com a opção --downloadonly, com os comandos download, modulesync, reposync ou system-upgrade (dnf-plugins-core).
–downloadonly Baixa o conjunto de pacotes sem realizar nenhuma transação de instalar, atualizar ou apagar.
–enable, –set-enabled Habilita repositórios especificados. Deve ser usada junto com config-manager (dnf-plugins-core).
–enableplugin=<nomes dos plug-ins> Habilita os plug-ins especificados por nomes ou globs.
–enablerepo=<repoid> Habilita temporariamente repositórios. Aceita um ID, uma lista de IDs separados por vírgula ou um conjunto de IDs.
-x <especificação do arquivo de pacote>, –exclude=<especificação do arquivo de pacote> Exclui pacotes especificados por <package-file-spec>.
–forcearch=<arquitetura> Força o uso de uma arquitetura. Qualquer arquitetura pode ser especificada.
-h, –help, –help-cmd Mostra o texto da Ajuda.
–noautoremove Desabilita a remoção de dependências não usadas.
–nobest Ajusta como falsa a opção best para que as transações não sejam limitadas ao melhor candidato.
–nodocs Não instala a documentação.
–nogpgcheck Não faz o teste de assinaturas GPG dos pacotes, se permitido pela diretriz RPM.
–noplugins Disabilita todos os plugins.
-q, –quiet Se usada com comandos não interativos, exibe apenas conteúdo mais relevante. Suprime mensagens sobre o estado ou ações do DNF.
-R , –randomwait= Tempo máximo de espera.
–refresh Recarrega a metadata antes de executar o o comando.
–repofrompath ,<path/url> Especifica um repositório extra, indicado por <path/url>.
–repo=, –repoid= Habilita um repositório dado por id ou glob.
–security Inclui pacotes que fornecam ajustes de segurança. Pode ser usado com install, repoquery, updateinfo, upgrade e offline-upgrade (dnf-plugins-core).
–setopt== Sobrescreve uma opção de configuração definida no arquivo de configuração. A especificação de valor vazio (por ex., --setopt=tsflags=) reseta o opção.
–skip-broken Remove pacotes que estão causando problemas na transação. Permite que se execute uma ação mesmo que ela cause problemas de dependência.
–showduplicates Mostra pacotes duplicados nos repositórios. Aplicável aos comandos list e search.
-v, –verbose Operação exibindo todas as mensagens de debug.
–version Mostra a versão do DNF e termina.
-y, –assumeyes Responde automaticamente “yes” para todas as perguntas.

Histórico

O dnf armazena um histórico de transações realizadas, que permite a verificação de tudo o que foi feito. Isso é útil para identificar problemas e desfazer operações.

# para listar o histórico de transações usamos
$ dnf history

# ou
$ dnf history list

Esses comandos exibem uma tabela com quatro colunas: ID da transação, a linha de comando executada, data e hora, a ação executada e o número de pacotes alterados. Por default as transações mais recentes aparecem primeiro.

➡ ID  | Command line             | Date and time       | Action(s) | Altered
➡ --------------------------------------------------------------------------------
➡ 157 | upgrade                  | 2024-07-23 17:31    | Upgrade   | 16
➡ 156 | remove focuswriter       | 2024-07-23 11:58    | Removed   | 5
➡ 155 | install focuswriter      | 2024-07-23 11:55    | Install   | 5
➡ 154 | update                   | 2024-07-23 11:20    | Upgrade   | 1
➡ 153 | autoremove               | 2024-07-23 09:37    | Removed   | 1
➡ 152 | remove mpv*              | 2024-07-23 09:35    | Removed   | 75
➡ 151 | remove sublime-text      | 2024-07-23 09:33    | Removed   | 1

A coluna Actions pode listar as ações listadas (às vezes indicada por uma letra):

  • Install (I): pelo menos um pacote foi instalado,
  • Update (U): pelo menos um pacote foi atualizado,
  • Reinstall (R): pelo menos um pacote foi reinstalado,
  • Downgrade (D): pelo menos um pacote foi rebaixado para uma versão anterior,
  • Erase (E): pelo menos um pacote foi desinstalado ou removido do sistema,
  • Obsoleting (O): pelo menos um pacote foi marcado como obsoleto.

A coluna “Altered” lista quantas ações foram executadas na transação, e pode usar os seguintes símbolos:

  • >: O banco de dados RPM foi alterado após a transação,
  • <: O banco de dados RPM foi alterado antes da transação,
  • *: A transação foi abortada antes do término,
  • #: A transação foi completada mas com status não zero,
  • E: A transação foi completada com sucesso, mas emitiu mensagem de erro.

Alguns argumentos adicionais podem ser usados para se encontrar uma transação específica.

# listar a última transação
$ dnf history list last
➡ ID | Command line | Date and time | Action(s) | Altered
--------------------------------------------------------------------------------
➡ 157 | upgrade | 2024-07-23 17:31 | Upgrade | 16

# listar a n-ésima transação, sendo n=0 a última
$ dnf history list last-5
➡ ID | Command line | Date and time | Action(s) | Altered
➡ --------------------------------------------------------------------------------
➡ 152 | remove mpv* | 2024-07-23 09:35 | Removed | 75

# listar a transação por ID
$ dnf history list 155
➡ ID | Command line | Date and time | Action(s) | Altered
➡ --------------------------------------------------------------------------------
➡ 155 | install focuswriter | 2024-07-23 11:55 | Install | 5

# listar a transações dentro de uma faixa de IDs
$ dnf history list 101..104
➡ ID | Command line | Date and time | Action(s) | Altered
➡ --------------------------------------------------------------------------------
➡ 104 | install docker-ce | 2024-06-18 12:56 | Install | 9 <
➡ 103 | remove cosmic* | 2024-06-18 12:05 | Removed | 35 >>
➡ 102 | remove xournal* | 2024-06-18 11:30 | Removed | 5
➡ 101 | update | 2024-06-18 11:06 | Upgrade | 2

# listar a transações em ordem invertida:
$ dnf history list --reverse
# A saida é uma lista de transações iniciando pela mais antiga

# listar as transações de instalações executadas pelo usuário:
$ dnf history userinstalled

A saída do comando pode ser filtrada de alguns modos:

# dnf history list | grep nome_do_pacote
# por exemplo
$ dnf history list | grep sublime
➡ ID | Command line | Date and time | Action(s) | Altered
➡ --------------------------------------------------------------------------------
➡ 151 | remove sublime-text | 2024-07-23 09:33 | Removed | 1
➡ 120 | install sublime-text | 2024-07-02 14:58 | Install | 1 <

Obtendo informações mais detalhadas: para obter detalhes sobre uma transação específica passe a opção info.A saída inclui:

  1. duração (em tempo) da transação
  2. qual usuário executou a transação
  3. código de retorno
  4. versão
  5. qual comando foi executado
  6. pacotes alterados

Por exemplo:

# para ver detalhes da transação com ID=120
$ dnf history info 120
➡ Transaction ID : 120
➡ Begin time : Tue 02 Jul 2024 02:58:05 PM -03
➡ Begin rpmdb : 562f2fb16f16bf6744987e7ab94ef265d7e988c68995eb4ca7bf3ea9e1705337
➡ End time : Tue 02 Jul 2024 02:58:07 PM -03 (2 seconds)
➡ End rpmdb : d4583d3d187fc29fd02eb6e36847eda474f1e6097e60885543adfdb936446035
➡ User : Nome Completo do Usuário <usuario>
➡ Return-Code : Success
➡ Releasever : 40
➡ Command Line : install sublime-text
➡ Comment :
➡ Packages Altered:
➡ Install sublime-text-4169-1.x86_64 @sublime-text

Para desfazer uma transação listada no histórico usamos undo ID. No exemplo, a transação com ID=156 consistiu na remoção do Focus Writer. Além disso é possível fazer uma operação de rollback, desfazendo todas as transações realizadas após a transação de ID=n, fazendo sudo dnf history rollback 12. Todas as transações ocorridas depois da transação com ID=n, portanto as que aparecem primeiro na lista, são desfeitas.

$ sudo dnf history undo 156
# após essa operação o Focus Writer volta a estar instalado no sistema.

# para desfazer todas as transações até a de ID=12
$ sudo dnf history rollback 12

# para desfazer um rollback, as mesmas transações podem ser reexecutadas,
$ sudo dnf history redo 12

Mesmo após a execução da operação de reverter uma transação e de rollback (que reverte várias transações) as entradas no histórico não são removidas, mas uma nova entrada é acrescentada para armazenar a operação de desfazer.

Plugins

A funcionalidade do dnf pode ser ampliada por meio de plugins. Existem plugins oficiais e plugins de outros desenvolvedores. A instalação é feita com o próprio dnf.

# para instalar os plugins core
$ dnf install dnf-plugins-core-NOME_PLUGIN

# para instalar os plugins extras
$ dnf install dnf-plugins-core-NOME_PLUGIN

São exemplos de plugins nos repositórios oficiais:

$ dnf install dnf-plugin-kickstart
$ dnf install dnf-plugin-rpmconf
$ dnf install dnf-plugin-showvars
$ dnf install dnf-plugin-snapper
$ dnf install dnf-plugin-torproxy
$ dnf install dnf-plugin-tracer

Mais informações em Core DNF plugins e Extras DNF plugins.

Atualizações de Sistema


O comando dnf pode ser usado para a atualização do sistema, diretamente ou com o plugin de atualização dnf-plugin-system-upgrade. A atualização pode ser feita diretamente com DNF puro (sem plugins) ou com o plugin de atualização do sistema DNF. Consulte o documento de atualização do sistema DNF para obter mais detalhes, em Upgrading Fedora.

Para fazer uma atualização (upgrade) de sistema, fazemos primeiro a atualização da tabela do dnf com refresh.

# atualiza tabela dnf
$ sudo dnf upgrade --refresh
# em seguida reinicialie o sistema

# instala systema: substitua n pelo número da versão
$ sudo dnf system-upgrade download --releasever=n

# para disparar o processo (o computador reiniciará imediatamente)
$ sudo dnf system-upgrade reboot

Algumas tarefas são possíveis após uma atualização. A maioria dos arquivos de configuração são armazenados na pasta /etc. Se algum desses arquivos poi alterado o RPM cria novos arquivos com extensão .rpmnew (os novos arquivos) ou .rpmsave (os arquivos antigos). Você pode examinar manualmente esses arquivos ou usar a ferramenta rpmconf para simplificar esse processo.

# instala a ferramenta
$ sudo dnf install rpmconf

# use a ferramenta
$ sudo rpmconf -a

Mais informações nos manuais em man rpmconf.

Bibliografia

Flet: Pagelet


Layout

Controle Pagelet

O controle Pagelet permite a inserção de uma área no aplicativo usando o layout do Material Design. Com ele podemos criar uma barra de cabeçalho, uma área de conteúdo, uma barra inferior e um menu que surge quando requerido.

Um exemplo simples de uso mostra essas áreas e seus respectivos nomes.

import flet as ft

def main(page: ft.Page):
    page.bgcolor=ft.colors.LIGHT_BLUE_ACCENT_700

    titulo=ft.Text("Barra superior da Pagelet", color="BLACK")
    conteudo=ft.Text("Conteúdo do corpo da Pagelet", color="BLACK")
    icone_inferior=ft.IconButton(icon=ft.icons.SEARCH, icon_color=ft.colors.BLUE)
    txt_inferior=ft.Text("Texto na barra inferior da Pagelet", color="BLACK")
    barra_inferior=ft.Row([icone_inferior, txt_inferior])

    menu_direita=[
        ft.NavigationDrawerDestination(icon=ft.icons.HOME, label="Em casa"),
        ft.NavigationDrawerDestination(icon=ft.icons.HOME_WORK, label="No trabalho")
    ]

    pagelet = ft.Pagelet(
        appbar=ft.AppBar(title=titulo, bgcolor=ft.colors.DEEP_ORANGE_200),
        content=conteudo,
        bgcolor=ft.colors.AMBER_50,
        bottom_app_bar=ft.BottomAppBar(
            bgcolor=ft.colors.CYAN_ACCENT_700,
            content=barra_inferior,
        ),
        end_drawer=ft.NavigationDrawer(controls=menu_direita, bgcolor=ft.colors.BLUE_ACCENT),
        width=400,
        height=300
    )

    page.add(pagelet)

ft.app(target=main)

O resultado da execução do código está mostrado na figura 1.

Figura 1: componentes de um controle Pagelet.

Respectivamente as propriedades de Pagelet correspondem: appbar, a barra superior, cabeçalho do aplicativo;
content, o conteúdo central; bottom_app_bar, a barra inferior; end_drawer uma barra ocultável, normalmente usada para inserir um menu de opções.

Propriedades de Pagelet

Propriedade Descrição
appbar controle exibido na parte superior do aplicativo. Geralmente contém texto mas pode conter outros controles
bgcolor cor de fundo da Pagelet.
bottom_appbar controle BottomAppBar a ser exibido na parte inferior da Pagelet. Se as propriedades bottom_appbar e navigation_bar estão preenchidas uma barra de navegação NavigationBar também será exibida.
bottom_sheet uma folha de fundo persistente para exibir conteúdo adicional. Qualquer controle pode ser usado como bottom_sheet.
content o controle filho da Pagelet, para a exibição de conteúdo. Ele é posicionado em cima, à esquerda, no espaço disponível entre as barras superior e inferior da Pagelet.
drawer um controle NavigationDrawer a ser exibido como painel deslizante a partir da borda superior da Pagelet.
end_drawer um controle NavigationDrawer a ser exibido como painel deslizante a partir da borda lateral da Pagelet.
floating_action_button um controle FloatingActionButton a ser exibido em cima do conteudo da Pagelet.
floating_action_button_location define a posição do controle FloatingActionButton. O valor é um enum com os valores:

CENTER_DOCKED END_TOP MINI_END_TOP
CENTER_FLOAT MINI_CENTER_DOCKED MINI_START_DOCKED
CENTER_TOP MINI_CENTER_FLOAT MINI_START_FLOAT
END_CONTAINED MINI_CENTER_TOP MINI_START_TOP
END_DOCKED MINI_END_DOCKED START_DOCKED
END_FLOAT (default) MINI_END_FLOAT START_FLOAT
navigation_bar é um controle NavigationBar a ser exibido no fundo da página. Se as propriedades bottom_appbar e navigation_bar estão preenchidas uma barra de navegação NavigationBar também será exibida.

Métodos de Pagelet

close_drawer() fecha a gaveta ativa.
close_end_drawer() fecha a gaveta ativa na posição à direita.
show_drawer(drawer: NavigationDialog) exibe a gaveta
show_end_drawer(drawer: NavigationDialog) exibe a gaveta na posição à direita

† NotaTraduzi drawer por gaveta.

Uso de Pagelet

import flet as ft

def main(page: ft.Page):
    page.bgcolor=ft.colors.BLUE_50

    citacao=[(
        'Há três métodos para ganhar sabedoria: primeiro, por reflexão, '
        'que é o mais nobre; segundo, por imitação, que é o mais fácil; '
        'e terceiro, por experiência, que é o mais amargo. Confúcio'
    ),
    (
        'Todos os seres vivos temem a violência. Todos temem a morte,'
        'todos amam a vida. Projete você mesmo em todas as criaturas.'
        'Quem você poderia ferir? Que mal você poderia fazer? Buda'
    )]

    def clicou_algo(e):
        mensagem.content.value=e.control.tooltip
        page.update()

    def selecionar_sabedoria(e):
        conteudo.content.value=citacao[e.control.selected_index]
        pagelet.end_drawer.open = False
        page.update()

    def abrir_drawer(e):
        pagelet.end_drawer.open = True
        pagelet.end_drawer.update()

    def fecha_barra_direita(e):
        mensagem.content.value="Menu da direita fechado"
        page.update()

    class Botao(ft.IconButton):
        def __init__(self, icon, tip):
            super().__init__()
            self.icon=icon
            self.icon_color=ft.colors.WHITE
            self.tooltip=tip
            self.on_click=clicou_algo

    conteudo = ft.Container(
        content=ft.Text(citacao[0], size=19, color="BLACK"),
        padding=ft.padding.all(20),
        bgcolor=ft.colors.BLUE_300,
        border=ft.border.all(3, ft.colors.BLUE_400),
        border_radius=ft.border_radius.all(10),
        expand=True,
    )
    barra_inferior = ft.BottomAppBar(
        bgcolor=ft.colors.BLUE,
        shape=ft.NotchShape.CIRCULAR,
        content=ft.Row(
            controls=[
                Botao(ft.icons.SUNNY, "Escolha seu destino"),
                Botao(ft.icons.AIRPLANEMODE_ACTIVE, "Compre sua passagem"),
                ft.Container(expand=True),
                Botao(ft.icons.HOTEL, "Reserve o seu hotel"),
                Botao(ft.icons.ROCKET, "Viaje para mais longe"),
            ]
        )
    )
    barra_direita=ft.NavigationDrawer(
        controls=[
            ft.NavigationDrawerDestination(icon=ft.icons.SELECT_ALL, label="Confúcio"),
            ft.NavigationDrawerDestination(icon=ft.icons.ADD_COMMENT, label="Buda"),
        ],
        bgcolor=ft.colors.LIGHT_BLUE_ACCENT_700,
        on_change=selecionar_sabedoria,
        on_dismiss=fecha_barra_direita,
    )

    pagelet = ft.Pagelet(
        appbar=ft.AppBar(
            title=ft.Text("Clique no menu para selecionar", color=ft.colors.BROWN),
            bgcolor=ft.colors.LIGHT_BLUE_ACCENT_100,
            toolbar_height=60,
        ),
        content=conteudo,
        bottom_app_bar=barra_inferior,
        end_drawer=barra_direita,
        floating_action_button=ft.FloatingActionButton("Menu", on_click=abrir_drawer),
        floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED,
        bgcolor=ft.colors.BLUE_600,
        width=400,
        height=300,
    )
    mensagem=ft.Container(
        ft.Text("Eventos aparecem aqui...", size=17, color=ft.colors.BLACK),
        padding=ft.padding.all(20),
        bgcolor=ft.colors.BROWN_200,
        border=ft.border.all(3, ft.colors.BROWN_300),
        border_radius=ft.border_radius.all(10),
        width=400,
        height=70,
    )
    page.add(
        ft.Container(
            content=ft.Column([pagelet,mensagem]),
            padding=ft.padding.all(20),
            bgcolor=ft.colors.BLUE_300,
            border=ft.border.all(3, ft.colors.BLUE_400),
            border_radius=ft.border_radius.all(10),
        ),
    )

ft.app(target=main)
Figura 2: Aplicativo após um clique sobre o ícone de sol e após seleção do menu|Buda. Segunda imagem com o menu aberto.

O resultado da execução do código está mostrado na figura 2.

Nesse código alguns componentes da Pagelet foram definidos separadamente e inseridas depois no controle. Isso foi feito para tornar o código mais fácil de ser entendido. A definição da classe Botao tem apenas o objetivo de diminuir as repetições de código na montagem da barra_inferior.

Os cliques nos ícones na barra inferior transfere o conteúdo dos tooltips para o container inferior no aplicativo. Cliques no menu deslizante, nos itens Confúcio e Buda alteram o conteúdo de texto do controle central através da função selecionar_sabedoria. A mensagem é selecionada usando e.control.selected_index, que é o índice do controle NavigationDrawerDestination clicado.