En este tutorial le mostraremos, paso a paso, cómo crear una aplicación de calculadora en Python usando el marco Flet y empaquetarla como un ejecutable independiente para Windows, macOS y Linux, o implementarla como una aplicación web. La aplicación es un programa de consola simple, pero es una aplicación multiplataforma con una interfaz de usuario similar a la de la aplicación de calculadora de iPhone:
Puedes encontrar la demostración en vivo aquí.
En este tutorial, cubriremos todos los conceptos básicos para crear una aplicación de escritorio multiplataforma: creación de un diseño de página, adición de controles, control de eventos y opciones de empaquetado e implementación.
El tutorial consta de los siguientes pasos:
- Paso 1: Primeros pasos con Flet
- Paso 2: Agregar controles de página
- Paso 3: Creación del diseño de la página
- Paso 4: Control de eventos
- Paso 5: Empaquetar como una aplicación de escritorio
- Paso 6: Implementación de una aplicación web
- Resumen
Paso 1: Primeros pasos con Flet
Para escribir una aplicación web de Flet no es necesario saber HTML, CSS o JavaScript, pero sí conocimientos básicos de Python y programación orientada a objetos.
Flet requiere Python 3.7 o superior. Para crear una aplicación web en Python con Flet, primero debe instalar el módulo:flet
pip install flet
Para empezar, vamos a crear una sencilla aplicación hello-world.
Crea con los siguientes contenidos:hello.py
import flet
from flet import Page, Text
def main(page: Page):
page.add(Text(value="Hello, world!"))
flet.app(target=main)
Ejecute esta aplicación y verá una nueva ventana con un saludo:
Paso 2: Agregar controles de página
Ahora está listo para crear una aplicación de calculadora.
Para empezar, necesitará un control Text para mostrar el resultado del cálculo y algunos ElevatedButtons con todos los números y acciones en ellos.
Crea con los siguientes contenidos:calc.py
import flet
from flet import ElevatedButton, Page, Text
def main(page: Page):
page.title = "Calc App"
result = Text(value="0")
page.add(
result,
ElevatedButton(text="AC"),
ElevatedButton(text="+/-"),
ElevatedButton(text="%"),
ElevatedButton(text="/"),
ElevatedButton(text="7"),
ElevatedButton(text="8"),
ElevatedButton(text="9"),
ElevatedButton(text="*"),
ElevatedButton(text="4"),
ElevatedButton(text="5"),
ElevatedButton(text="6"),
ElevatedButton(text="-"),
ElevatedButton(text="1"),
ElevatedButton(text="2"),
ElevatedButton(text="3"),
ElevatedButton(text="+"),
ElevatedButton(text="0"),
ElevatedButton(text="."),
ElevatedButton(text="="),
)
flet.app(target=main)
Ejecute la aplicación y debería ver una página como esta:
Paso 3: Creación del diseño de la página
Ahora organicemos el texto y los botones en 6 filas horizontales.
Reemplace el contenido por lo siguiente:calc.py
import flet
from flet import ElevatedButton, Page, Row, Text
def main(page: Page):
page.title = "Calc App"
result = Text(value="0")
page.add(
Row(controls=[result]),
Row(
controls=[
ElevatedButton(text="AC"),
ElevatedButton(text="+/-"),
ElevatedButton(text="%"),
ElevatedButton(text="/"),
]
),
Row(
controls=[
ElevatedButton(text="7"),
ElevatedButton(text="8"),
ElevatedButton(text="9"),
ElevatedButton(text="*"),
]
),
Row(
controls=[
ElevatedButton(text="4"),
ElevatedButton(text="5"),
ElevatedButton(text="6"),
ElevatedButton(text="-"),
]
),
Row(
controls=[
ElevatedButton(text="1"),
ElevatedButton(text="2"),
ElevatedButton(text="3"),
ElevatedButton(text="+"),
]
),
Row(
controls=[
ElevatedButton(text="0"),
ElevatedButton(text="."),
ElevatedButton(text="="),
]
),
)
flet.app(target=main)
Ejecute la aplicación y debería ver una página como esta:
Uso de contenedores para la decoración
Para agregar un fondo negro con borde redondeado alrededor de la calculadora, usaremos el control Contenedor. El contenedor puede decorar solo un control, por lo que tendremos que envolver las 6 filas en una sola columna vertical que se usará como :content
Para completar la parte de la interfaz de usuario del programa, actualice y las propiedades del texto y las propiedades de los botones. Para una alineación uniforme de los botones dentro de las filas, usaremos la propiedad como se muestra en el diagrama anterior. color
size
color
bgcolor
expand
Reemplace el contenido por lo siguiente:calc.py
import flet
from flet import (
Column,
Container,
ElevatedButton,
Page,
Row,
Text,
border_radius,
colors,
)
def main(page: Page):
page.title = "Calc App"
result = Text(value="0", color=colors.WHITE, size=20)
page.add(
Container(
width=300,
bgcolor=colors.BLACK,
border_radius=border_radius.all(20),
padding=20,
content=Column(
controls=[
Row(controls=[result], alignment="end"),
Row(
controls=[
ElevatedButton(
text="AC",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="+/-",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="%",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="/",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="7",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="8",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="9",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="*",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="4",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="5",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="6",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="-",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="1",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="2",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="3",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="+",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="0",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=2,
),
ElevatedButton(
text=".",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="=",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
]
),
)
)
flet.app(target=main)
Run the app and you should see a page like this:
Just what we wanted!
Reusable UI components
While you can continue writing your app in the function, the best practice would be to create a reusable UI component. main
Imagine you are working on an app header, a side menu, or UI that will be a part of a larger project (for example, at Flet we will be using this Calculator app in a bigger "Gallery" app that will show all the examples for Flet framework).
Even if you can't think of such uses right now, we still recommend creating all your web apps with composability and reusability in mind.
To make a reusable Calc app component, we are going to encapsulate its state and presentation logic in a separate class.CalculatorApp
Replace contents with the following:calc.py
import flet
from flet import (
Column,
Container,
ElevatedButton,
Page,
Row,
Text,
UserControl,
border_radius,
colors,
)
class CalculatorApp(UserControl):
def build(self):
result = Text(value="0", color=colors.WHITE, size=20)
# application's root control (i.e. "view") containing all other controls
return Container(
width=300,
bgcolor=colors.BLACK,
border_radius=border_radius.all(20),
padding=20,
content=Column(
controls=[
Row(controls=[result], alignment="end"),
Row(
controls=[
ElevatedButton(
text="AC",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="+/-",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="%",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
),
ElevatedButton(
text="/",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="7",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="8",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="9",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="*",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="4",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="5",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="6",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="-",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="1",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="2",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="3",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="+",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
Row(
controls=[
ElevatedButton(
text="0",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=2,
),
ElevatedButton(
text=".",
bgcolor=colors.WHITE24,
color=colors.WHITE,
expand=1,
),
ElevatedButton(
text="=",
bgcolor=colors.ORANGE,
color=colors.WHITE,
expand=1,
),
]
),
]
),
)
def main(page: Page):
page.title = "Calc App"
# create application instance
calc = CalculatorApp()
# add application's root control to the page
page.add(calc)
flet.app(target=main)
Read more about creating user controls.
Try something
Try adding two components to the page:CalculatorApp
# create application instance
calc1 = CalculatorApp()
calc2 = CalculatorApp()
# add application's root control to the page
page.add(calc1, calc2)
Step 4: Handling events
Now let's make the calculator do its job. We will be using the same event handler for all the buttons and use property to differentiate between the actions depending on the button clicked. For each ElevatedButton control, specify event and set property equal to button's text, for example:data
on_click=self.button_clicked
data
ElevatedButton(
text="AC",
bgcolor=colors.BLUE_GREY_100,
color=colors.BLACK,
expand=1,
on_click=self.button_clicked,
data="AC",
)
Below is event handler that will reset the Text value when "AC" button is clicked:on_click
def button_clicked(self, e):
if e.data == "AC":
self.result.value = "0"
With similar approach, specify event and property for each button and add expected action to the event handler depending on value. Copy the entire code for this step from here.on_click
data
button_clicked
e.data
Run the app and see it in the action:
Step 5: Packaging as a desktop app
Congratulations! You have created your Calculator app with Flet, and it looks awesome! Now it's time to share your app with the world!
Flet Python app and all its dependencies can be packaged into an executable and user can run it on their computer without installing a Python interpreter or any modules.
PyInstaller is used to package Flet Python app and all its dependencies into a single package for Windows, macOS and Linux. To create Windows package, PyInstaller must be run on Windows; to build Linux app, it must be run on Linux; and to build macOS app - on macOS.
Start from installing PyInstaller:
pip install pyinstaller
Navigate to the directory where your file is located and build your app with the following command:.py
pyinstaller your_program.py
Your bundled Flet app should now be available in folder. Try running the program to see if it works.dist/your_program
On macOS/Linux:
./dist/your_program/your_program
on Windows:
dist\your_program\your_program.exe
Now you can just zip the contents of folder and distribute to your users! They don't need Python or Flet installed to run your packaged program - what a great alternative to Electron!dist/your_program
You'll notice though when you run a packaged program from macOS Finder or Windows Explorer a new console window is opened and then a window with app UI on top of it.
You can hide that console window by rebuilding the package with switch:--noconsole
pyinstaller your_program.py --noconsole --noconfirm
Bundling to one file
Contents of directory is an app executable plus supporting resources: Python runtime, modules, libraries.dist/your_program
You can package all these in a single executable by using switch:--onefile
pyinstaller your_program.py --noconsole --noconfirm --onefile
Obtendrá un ejecutable más grande en la carpeta. Ese ejecutable es un archivo autoejecutable con su programa y recursos de tiempo de ejecución que se desempaqueta en el directorio temporal cuando se ejecuta, es por eso que se tarda más en iniciar el paquete "onefile".dist
Nota:
Para macOS, puede distribuir uno u otro paquete de aplicaciones.dist/your_program
dist/your_program.app
Personalización del icono del paquete
El icono predeterminado de la aplicación del paquete es un disquete, lo que puede resultar confuso para los desarrolladores más jóvenes que se perdieron esos tiempos antiguos en los que se usaban disquetes para almacenar datos de la computadora.
Puede reemplazar el icono con el suyo propio agregando el argumento:--icon
pyinstaller your_program.py --noconsole --noconfirm --onefile --icon <your-image.png>
PyInstaller convertirá el PNG proporcionado a un formato específico de la plataforma (para Windows y para macOS), pero debe instalar el módulo Pillow para eso:.ico
.icns
pip install pillow
Activos de embalaje
Tu aplicación Flet puede incluir activos. Los activos de la aplicación proporcionados están en la carpeta junto a que se pueden agregar a un paquete de aplicación con argumento, en macOS/Linux:assets
your_program.py
--add-data
pyinstaller your_program.py --noconsole --noconfirm --onefile --add-data "assets:assets"
En Windows debe estar delimitado con:assets;assets
;
pyinstaller your_program.py --noconsole --noconfirm --onefile --add-data "assets;assets"
Nota:
Aquí puede encontrar todas las opciones de línea de comandos de PyInstaller
Uso de CI para el empaquetado multiplataforma
Para crear un paquete de aplicación con PyInstaller para un sistema operativo específico, debe ejecutarse en ese sistema operativo.
Si no tiene acceso a Mac o PC, puede agrupar su aplicación para las tres plataformas con AppVeyor - Servicio de integración continua para Windows, Linux y macOS. En resumen, la integración continua (CI) es un proceso automatizado de creación, prueba e implementación de aplicaciones (entrega continua - CD) en cada envío a un repositorio.
AppVeyor es gratuito para proyectos de código abierto alojados en GitHub, GitLab y Bitbucket. Para usar AppVeyor, inserte la aplicación en un repositorio dentro de uno de esos proveedores de control de código fuente.
Para comenzar con AppVeyor regístrese para obtener una cuenta gratuita.
Click "New project" button, authorize AppVeyor to access your GitHub, GitLab or Bitbucket account, choose a repository with your program and create a new project.
Now, to configure packaging of your app for Windows, Linux and macOS, add file with the following contents into the root of your repository . is a build configuration file, or CI workflow, describing build, test, packaging and deploy commands that must be run on every commit.appveyor.yml
appveyor.yml
Note:
You can just fork flet-dev/python-ci-example repository and customize it to your needs.
When you push any changes to GitHub repository, AppVeyor will automatically start a new build:
What that CI workflow does on every push to the repository:
- Clones the repository to a clean virtual machine.
- Installs app dependencies using .
pip
- Runs to package Python app into "onefile" bundle for Windows, macOS and Ubuntu.
pyinstaller
- Zip/Tar packages and uploads them to "Artifacts".
- Uploads packages to GitHub releases when a new tag is pushed. Just push a new tag to make a release!
GITHUB_TOKEN
in is a GitHub Personal Access Token (PAT) used by AppVeyor to publish created packages to repository "Releases". You need to generate your own token and replace it in . Login to your GitHub account and navigate to Personal access token page. Click "Generate new token" and select "public_repo" or "repo" scope for public or private repository respectively. Copy generated token to a clipboard and return to AppVeyor Portal. Navigate to Encrypt configuration data page and paste token to "Value to encrypt" field, click "Encrypt" button. Put encrypted value under in your .GITHUB_TOKEN
appveyor.yml
appveyor.yml
GITHUB_TOKEN
appveyor.yml
Configure AppVeyor para su proyecto de Python, envíe una nueva etiqueta a un repositorio y obtenga "automáticamente" el paquete de escritorio para las tres plataformas en las versiones de GitHub. 🎉
Además de las versiones de GitHub, también puede configurar la liberación de artefactos en el bucket de Amazon S3 o en Azure Blob Storage.
Paso 6: Implementación de una aplicación web
La aplicación Flet se puede implementar como una aplicación web "independiente", lo que significa que tanto la aplicación Python como el servidor web Flet se implementan juntos como un paquete.
Las aplicaciones de Flet usan WebSockets para actualizaciones parciales en tiempo real de su interfaz de usuario y para enviar eventos de vuelta a su programa.
A la hora de elegir un proveedor de alojamiento para tu aplicación Flet, debes prestar atención a su compatibilidad con WebSockets. A veces, los WebSockets no están permitidos o forman parte de una oferta más costosa, a veces hay un proxy que interrumpe periódicamente la conexión de WebSocket por un tiempo de espera (Flet implementa la lógica de reconexión, pero de todos modos podría ser un comportamiento desagradable para los usuarios de la aplicación).
Otro factor importante a la hora de elegir un proveedor de alojamiento para la aplicación Flet es la latencia. Cada acción del usuario en la interfaz de usuario envía un mensaje a la aplicación Flet y la aplicación envía la interfaz de usuario actualizada al usuario. Asegúrese de que su proveedor de alojamiento tenga varios centros de datos, para que pueda ejecutar su aplicación más cerca de la mayoría de sus usuarios.
Nota:
No estamos afiliados a proveedores de alojamiento en esta sección, simplemente usamos su servicio y nos encanta.
Fly.io
Fly.io tiene una sólida compatibilidad con WebSocket y puede implementar la aplicación en un centro de datos cercano a los usuarios. Tienen precios muy atractivos con un generoso nivel gratuito que le permite alojar hasta 3 aplicaciones de forma gratuita.
Para empezar a usar Fly, instale flyctl y, a continuación, autentique:
flyctl auth login
Para implementar la aplicación, debe agregar los siguientes 3 archivos a la carpeta con su aplicación de Python.flyctl
Cree con una lista de dependencias de la aplicación. Como mínimo, debe contener el módulo:requirements.txt
flet
flet>=0.1.33
Cree la aplicación Fly que describa:fly.toml
app = "<your-app-name>"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []
[env]
FLET_SERVER_PORT = "8080"
[experimental]
allowed_public_ports = []
auto_rollback = true
[[services]]
http_checks = []
internal_port = 8080
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"
[[services.ports]]
force_https = true
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
Reemplácelo con el nombre de la aplicación deseado que también se utilizará en la URL de la aplicación, como .<your-app-name>
https://<your-app-name>.fly.dev
Tenga en cuenta que estamos estableciendo el valor de la variable de entorno en la que se ejecutará un puerto TCP interno de la aplicación web Flet.FLET_SERVER_PORT
8080
Create que contiene los comandos para compilar el contenedor de la aplicación:Dockerfile
FROM python:3-alpine
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD ["python", "./main.py"]
main.py
es un archivo con su programa Python.
Nota:
Fly.io implementa todas las aplicaciones como un contenedor Docker, pero una gran ventaja de Fly es que proporciona un generador de Docker remoto gratuito, por lo que no necesita instalar Docker en su máquina.
A continuación, cambie la línea de comandos a una carpeta con la aplicación y ejecute el siguiente comando para crear e inicializar una nueva aplicación Fly:
flyctl apps create --name <your-app-name>
Para implementar la aplicación, ejecute:
flyctl deploy
¡Eso es todo! Para abrir la aplicación en el navegador, ejecute:
flyctl apps open
Replit
Replit es un IDE en línea y una plataforma de alojamiento para aplicaciones web escritas en cualquier idioma. Su nivel gratuito permite ejecutar cualquier número de aplicaciones con algunas limitaciones de rendimiento.
Para ejecutar tu app en Replit:
- Regístrate en Replit.
- Haga clic en el botón "Nuevo repl".
- Seleccione el lenguaje "Python" de una lista y proporcione el nombre de repl, por ejemplo, .
my-app
- Haga clic en la pestaña "Paquetes" y busque el paquete; Seleccione su última versión.
flet
- Haga clic en la pestaña "Secretos" y agregue una variable con valor.
FLET_SERVER_PORT
5000
- Vuelve a la pestaña "Archivos" y copia y pega tu aplicación en .
main.py
- Ejecuta la aplicación. Disfruta.
Resumen
En este tutorial has aprendido a:
- Crea una aplicación Flet sencilla;
- Trabajar con componentes de interfaz de usuario reutilizables;
- Diseñe el diseño de la interfaz de usuario mediante y controles;
Column
Row
Container
- Manejar eventos;
- Empaqueta tu aplicación Flet en un ejecutable;
- Implemente su aplicación Flet en la web;
Para obtener más información, puede explorar el repositorio de controles y ejemplos.
¡Nos encantaría escuchar sus comentarios! Envíanos un correo electrónico, únete a la discusión en Discord y síguenos en Twitter.
0 comentarios:
Publicar un comentario