Skip to main content

2 posts tagged with "how-to"

View All Tags

Control Refs

· 3 min read
Feodor Fitsner
Flet founder and developer

Flet controls are objects and to access their properties we need to keep references (variables) to those objects.

Consider the following example:

import flet as ft

def main(page):

first_name = ft.TextField(label="First name", autofocus=True)
last_name = ft.TextField(label="Last name")
greetings = ft.Column()

def btn_click(e):
greetings.controls.append(ft.Text(f"Hello, {first_name.value} {last_name.value}!"))
first_name.value = ""
last_name.value = ""
page.update()
first_name.focus()

page.add(
first_name,
last_name,
ft.ElevatedButton("Say hello!", on_click=btn_click),
greetings,
)

ft.app(target=main)

In the very beginning of main() method we create three controls which we are going to use in button's on_click handler: two TextField for first and last names and a Column - container for greeting messages. We create controls with all their properties set and in the end of main() method, in page.add() call, we use their references (variables).

When more and mode controls and event handlers added it becomes challenging to keep all control definitions in one place, so they become scattered across main() body. Glancing at page.add() parameters it's hard to imagine (without constant jumping to variable definitions in IDE) what would the end form look like:

    page.add(
first_name,
last_name,
ft.ElevatedButton("Say hello!", on_click=btn_click),
greetings,
)

Is first_name a TextField, does it have autofocus set? Is greetings a Row or a Column?

Ref class

Flet provides Ref utility class which allows to define a reference to the control, use that reference in event handlers and set the reference to a real control later, while building a tree. The idea comes from React.

To define a new typed control reference:

first_name = ft.Ref[ft.TextField]()

To access referenced control (control de-reference) use Ref.current property:

# empty first name
first_name.current.value = ""

To assign control to a reference set Control.ref property to a reference:

page.add(
ft.TextField(ref=first_name, label="First name", autofocus=True)
)
note

All Flet controls have ref property.

We could re-write our program to use references:

import flet as ft


def main(page):

first_name = ft.Ref[ft.TextField]()
last_name = ft.Ref[ft.TextField]()
greetings = ft.Ref[ft.Column]()

def btn_click(e):
greetings.current.controls.append(
ft.Text(f"Hello, {first_name.current.value} {last_name.current.value}!")
)
first_name.current.value = ""
last_name.current.value = ""
page.update()
first_name.current.focus()

page.add(
ft.TextField(ref=first_name, label="First name", autofocus=True),
ft.TextField(ref=last_name, label="Last name"),
ft.ElevatedButton("Say hello!", on_click=btn_click),
ft.Column(ref=greetings),
)

ft.app(target=main)

Now we can clearly see in page.add() the structure of the page and all the controls it's built of.

Yes, the logic becomes a little bit more verbose as you need to add .current. to access ref's control, but it's a matter of personal preference :)

Give Flet a try and let us know what you think!

Using custom fonts in a Flet app

· 2 min read
Feodor Fitsner
Flet founder and developer

You can now use your own fonts in a Flet app!

The following font formats are supported:

  • .ttc
  • .ttf
  • .otf

Use page.fonts property to import fonts.

Set page.fonts property to a dictionary where key is the font family name to refer that font and the value is the URL of the font file to import:

def main(page: ft.Page):
page.fonts = {
"Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf",
"Aleo Bold Italic": "https://raw.githubusercontent.com/google/fonts/master/ofl/aleo/Aleo-BoldItalic.ttf"
}
page.update()

# ...

Font can be imported from external resource by providing an absolute URL or from application assets by providing relative URL and assets_dir.

Specify assets_dir in flet.app() call to set the location of assets that should be available to the application. assets_dir could be a relative to your main.py directory or an absolute path. For example, consider the following program structure:

/assets
/fonts
/OpenSans-Regular.ttf
main.py

Code sample

The following program loads "Kanit" font from GitHub and "Open Sans" from the assets. "Kanit" is set as a default app font and "Open Sans" is used for a specific Text control:

import flet as ft

def main(page: ft.Page):
page.title = "Custom fonts"

page.fonts = {
"Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf",
"Open Sans": "fonts/OpenSans-Regular.ttf",
}

page.theme = Theme(font_family="Kanit")

page.add(
ft.Text("This is rendered with Kanit font"),
ft.Text("This is Open Sans font example", font_family="Open Sans"),
)

ft.app(target=main, assets_dir="assets")

Static vs Variable fonts

At the moment only static fonts are supported, i.e. fonts containing only one specific width/weight/style combination, for example "Open Sans Regular" or "Roboto Bold Italic".

Variable fonts support is still work in progress.

However, if you need to use a variable font in your app you can create static "instantiations" at specific weights using fonttools, then use those:

fonttools varLib.mutator ./YourVariableFont-VF.ttf wght=140 wdth=85

To explore available font features (e.g. possible options for wght) use Wakamai Fondue online tool.

Give Flet a try and let us know what you think!