Basic

  • Introducció

    NiceGUI és una llibreria de Python de codi obert per escriure interfícies gràfiques d’usuari que s’executen al navegador. Té una corba d’aprenentatge suau i, alhora, ofereix opcions per a personalitzacions avançades. NiceGUI segueix una filosofia “backend-first”: s’encarrega de tots els detalls del desenvolupament web. Tu et pots centrar en escriure codi Python. Això la fa ideal per a una àmplia gamma de projectes, incloent scripts curts, quadres de comandament, robòtica, solucions IoT, domòtica i aprenentatge automàtic.

    NiceGUI s’implementa amb components HTML servits per un servidor HTTP (FastAPI), fins i tot per a finestres natives.

    NiceGUI utilitza Vue i Quasar per al frontend, i està construïda sobre FastAPI

    Entorn de treball

    Crea un projecte amb UV amb el nom gui:

    uv unit gui

    Obre el projecte amb PyCharm.

    Obre el terminal i afegeix una dependència amb nicegui:

    uv add nicegui

    Modifica el fitxer main.py:

    from nicegui import ui
    
    ui.label('Hello World!')
    ui.run()

    Executa el projecte:

    run main.py

    Obre el navegador i veu el resultat: http://localhost:8080

    Text

    ui.label

    ui.label displays some text.

    ui.element

    Aquesta classe és la base de tots els altres elements de la UI. Però es pot utilitzar per crear elements amb etiquetes HTML arbitràries.

    Estil

    Tailwind

    Pots aplicar classes utilitàries de Tailwind amb el mètode classes.

    ui.label("Tailwind!").classes("text-blue text-2xl font-bold")

    NiceGUI ofereix una interfície fluida i amigable amb l’autocompletat per afegir classes de Tailwind als elements de la UI.

    ui.label('Auto-Complete').tailwind.font_weight('extrabold').text_color('blue-600').background_color('orange-200')

    Pots descobrir les classes disponibles navegant pels mètodes de la propietat tailwind. El patró de “builder” permet encadenar múltiples classes.

    També pots cridar la propietat tailwind amb una llista de classes.

    from nicegui import ui
    
    ui.label("List of classes").tailwind("font-extrabold","text-red-500")
    
    ui.run()

    Encara que això és molt similar a utilitzar el mètode classes, és més còmode per a classes de Tailwind gràcies a l’autocompletat.

    Finalment, també pots predefinir un estil i aplicar-lo a múltiples elements:

    from nicegui import Tailwind, ui
    
    style = Tailwind().font_weight("extrabold").text_color("red-500")
    
    ui.label("Mercury").tailwind(style)
    
    venus = ui.label("Venus")
    style.apply(venus)
    
    ui.run()

    CSS

    Si realment necessites aplicar CSS, pots utilitzar el mètode style. Aquí el delimitador és ; en lloc d’un espai en blanc.

    ui.label('Stylish!').style('color: #6E93D6; font-size: 200%; font-weight: 300')

    Disseny

    Per tal de permetre descripcions de UI intuïtives, NiceGUI fa un seguiment automàtic del context en què es creen els elements. Això vol dir que no hi ha cap paràmetre “pare” explícit. En lloc d’això, el context pare es defineix amb una instrucció with.

    Aquesta decisió de disseny facilita la creació de components modulars que continuen funcionant encara que els moguis dins la UI.

    ui.row

    ui.row ofereix un contenidor que disposa els fills en una fila.

    style = Tailwind().border_width("2").padding("p-2")
    
    ui.label("ui.row")
    with ui.row(align_items="end"):
        ui.label("Carps are deep-bodied freshwater fishes, typically with barbels around the mouth").tailwind(style)
        ui.label("Perch are small freshwater fish known for their distinctive greenish-yellow bodies that feature vertical dark stripes.").tailwind(style)
        ui.label("Salmon").tailwind(style)
    wrapsi s’ha d’ajustar el contingut (per defecte: False)
    align_itemsalineació dels ítems a la columna (“start”, “end”, “center”, “baseline” o “stretch”; per defecte: None)

    ui.column

    ui.column ofereix un contenidor que disposa els fills en una columna.

    with ui.column(align_items="center"):
        ui.label("Cows are herbivorous mammals with cloven hoofs and two horns.")
        ui.label("Rabbits are small, furry mammals with long ears, short fluffy tails, and strong, large hind legs.")
        ui.label("Cats are small domesticated carnivorous mammals.")
    wrapsi s’ha d’ajustar el contingut (per defecte: False)
    align_itemsalineació dels ítems a la columna (“start”, “end”, “center”, “baseline” o “stretch”; per defecte: None)

    ui.grid

    ui.grid ofereix un contenidor que disposa els fills en una graella.

    rowsnombre de files de la graella o una cadena amb la propietat CSS grid-template-rows (p. ex. ‘auto 1fr’)
    columnsnombre de columnes de la graella o una cadena amb la propietat CSS grid-template-columns (p. ex. ‘auto 1fr’)
        with ui.grid(columns=2):
            ui.label('Name:')
            ui.label('Tom')
    
            ui.label('Age:')
            ui.label('42')
    
            ui.label('Height:')
            ui.label('1.80m')

    Disseny de graella personalitzat

    Aquesta demo mostra com crear un disseny de graella personalitzat passant una cadena amb la propietat CSS grid-template-columns. Pots utilitzar qualsevol dimensió CSS vàlida, com ‘auto’, ‘1fr’, etc.

    • auto fa que la columna tingui l’amplada del seu contingut.
    • 1fr o 2fr fa que les columnes corresponents omplin l’espai restant, amb fraccions en una proporció 1:2.
    with ui.grid(columns='auto 1fr 2fr').classes('w-full gap-0'):
        for _ in range(3):
            ui.label('auto').classes('border p-1')
            ui.label('1fr').classes('border p-1')
            ui.label('2fr').classes('border p-1'

    Cel·les que abasten múltiples columnes

    Aquesta demo mostra com fer que les cel·les abastin múltiples columnes.

    with ui.grid(columns=16).classes('w-full gap-0'):
        ui.label('full').classes('col-span-full border p-1')
        ui.label('8').classes('col-span-8 border p-1')
        ui.label('8').classes('col-span-8 border p-1')
        ui.label('12').classes('col-span-12 border p-1')
        ui.label('4').classes('col-span-4 border p-1')
        ui.label('15').classes('col-[span_15] border p-1')
        ui.label('1').classes('col-span-1 border p-1')

    ui.list

    ui.list ofereix un contenidor que disposa els fills en una llista.

    Es basa en el component QList de Quasar.

    with ui.list().props('dense separator'):
        ui.item('3 Apples')
        ui.item('5 Bananas')
        ui.item('8 Strawberries')
        ui.item('13 Walnuts')

    Pàgina

    @ui.page

    Aquest decorador marca una funció com a generadora de pàgina.

    Cada usuari que accedeixi a la ruta indicada veurà una nova instància de la pàgina. Això significa que és privada per a l’usuari i no es comparteix amb altres (com passa quan es col·loquen elements fora d’un decorador de pàgina).

    pathruta de la nova pàgina (la ruta ha de començar amb ’/‘)
    titletítol opcional de la pàgina
    viewportcontingut opcional de la metaetiqueta viewport
    faviconcamí relatiu o URL absoluta opcional a un favicon (per defecte: None, s’utilitza la icona de NiceGUI)
    darksi s’ha d’utilitzar el mode fosc de Quasar (per defecte: l’argument dark de la comanda run)
    languageidioma de la pàgina (per defecte: l’argument language de la comanda run)
    response_timeouttemps màxim perquè la funció decorada construeixi la pàgina (per defecte: 3.0 segons)
    reconnect_timeouttemps màxim que el servidor espera que el navegador es reconnecti (per defecte: l’argument reconnect_timeout de la comanda run)
    api_routerinstància d’APIRouter a utilitzar; es pot deixar None per usar la predeterminada
    kwargsarguments addicionals que es passen al @app.get de FastAPI
    from nicegui import ui
    
    @ui.page('/other_page')
    def other_page():
        ui.label('Welcome to the other side')
    
    @ui.page('/dark_page', dark=True)
    def dark_page():
        ui.label('Welcome to the dark side')
    
    ui.link('Visit other page', other_page)
    ui.link('Visit dark page', dark_page)
    
    ui.run()

    ui.link crea un enllaç a una altra pàgina.

    Per saltar a una ubicació específica dins d’una pàgina, pots col·locar àncores enllaçables amb ui.link_target("name") i enllaçar-hi amb ui.link(target="#name").

    Paràmetres a la ruta

    Les rutes de pàgina poden contenir paràmetres com a FastAPI.

    from nicegui import ui
    
    @ui.page('/repeat/{word}/{count}')
    def page(word: str, count: int):
        ui.label(word * count)
    
    ui.link('Say hi to Santa!', '/repeat/Ho! /3')
    
    ui.run()

    Si tenen anotacions de tipus, es converteixen automàticament a valors bool, int, float i complex.

    Si la funció de pàgina espera un argument request, l’objecte de la petició es proporciona automàticament. L’argument client dona accés a la connexió websocket, el layout, etc.

    Pàgina d’índex automàtica

    Les pàgines creades amb el decorador @ui.page són “privades”. El seu contingut es torna a crear per a cada client. Per tant, a la demo de la dreta, l’ID que es mostra a la pàgina privada canvia quan el navegador recarrega la pàgina.

    Els elements de la UI que no estan dins d’una funció de pàgina decorada es col·loquen en una pàgina d’índex generada automàticament a la ruta “/”. Aquesta pàgina d’auto-índex es crea una vegada a l’inici i es comparteix entre tots els clients que s’hi connectin. Així, cada client veurà els mateixos elements. A la demo de la dreta, l’ID que es mostra a la pàgina d’auto-índex es manté constant quan el navegador es recarrega.

    from nicegui import ui
    from uuid import uuid4
    
    @ui.page('/private_page')
    async def private_page():
        ui.label(f'private page with ID {uuid4()}')
    
    ui.label(f'shared auto-index page with ID {uuid4()}')
    ui.link('private page', private_page)
    
    ui.run()

    ui.run

    ui.run

    Pots cridar ui.run() amb arguments opcionals. La majoria només apliquen després d’aturar i reiniciar completament l’aplicació i no s’apliquen amb recàrrega automàtica.

    Consulta la documentació ui.run

    Canvia el títol per defecte de les pàgines:

    NiceGUI On Air

    Amb ui.run(on_air=True) pots compartir la teva app local amb altres per Internet 🧞.

    En accedir a l’URL “on-air”, totes les llibreries (com Vue, Quasar, …) es carreguen des del CDN de NiceGUI. Així, només cal transmetre el contingut cru i els esdeveniments des de la teva app local. Això ho fa molt ràpid, fins i tot si la teva app només té una connexió a Internet pobra (p. ex. un robot mòbil al camp).

    En establir on_air=True obtindràs una URL aleatòria vàlida durant 1 hora. Si et registres a https://on-air.nicegui.io, pots configurar una organització i un nom de dispositiu per obtenir una URL fixa: https://on-air.nicegui.io/<my-org>/<my_device_name>.

    El dispositiu s’identifica amb un testimoni únic i privat que pots utilitzar en lloc del booleà: ui.run(on_air='<your token>').

    Si patrocines NiceGUI, habilitaran la gestió multidispositiu i proporcionaran protecció integrada amb contrasenya per a cada dispositiu.

    Actualment On Air està disponible com a “tech preview” i es pot utilitzar gratuïtament.

    TODO