Flet 03 - Python Rehberi

Python Rehberi

Python'da Flet uygulamaları oluşturma

Bir Flet uygulaması yazmak için front-end gurusu olmanız gerekmez, ancak temel Python bilgisine ve Nesne Yönelimli Programlama (OOP) bilgisine sahip olmanız önerilir.

Bu kılavuzda (rehberde), bir Flet uygulamasının yapısını inceleyeceğiz, Flet kontrollerini kullanarak veri çıktısını almayı, bir kullanıcıdan veri istemeyi ve temel sayfa düzenleri oluşturmayı öğreneceğiz. Kullanıcılarınıza hazır bir uygulama sunmak için bazı paketleme ve dağıtım seçeneklerini de ele alacağız.

Flet modülünü yükleme

Flet, Python 3.7 veya üst sürümünü gerektirir. Flet ile arabirim oluşturmak için önce flet modülünü kurmanız gerekir:

pip install flet

Flet modülünü yükseltmek için aşağıdaki kodu çalıştırmalısınız:

pip install flet --upgrade

Flet ön-sürümünü (pre-release) yüklemek için (ileri düzey kullanıcılar için) aşağıdaki kodu çalıştırın:

pip install flet --pre

Dikkat!

Ön-sürüm (pre-release) yapılarını, bir sanal ortama yüklemenizi öneririz.

Linux

Flet uygulamalarını Linux ve WSL'de çalıştırmak için GStreamer kitaplıklarının kurulu olması gerekir. Büyük olasılıkla zaten sisteminizde vardır, ancak Flet uygulamasını çalıştırırken error while loading shared libraries: libgstapp-1.0.so.0: cannot open shared object file: No such file or directory şeklinde hata alıyorsanız, GStreamer'ı yüklemeniz gerekir .

GStreamer'ı Ubuntu/Debian'a yüklemek için aşağıdaki komutları çalıştırın:

sudo apt-get update
sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio

GStreamer'ı, diğer Linux dağıtımlarına yüklemek için bu kılavuza göz atın.

WSL

Flet uygulamaları WSL2'de çalıştırılabilir. cannot open display (ekran açılamıyor) hatası alıyorsanız, sorun giderme için bu kılavuza göz atın.

Temel uygulama yapısı

Çok minimal bir Flet uygulaması aşağıdaki yapıya sahiptir:

import flet as ft

def main(page: ft.Page):
    # add/update controls on Page
    pass

ft.app(target=main)

basic-app-structure

NOT:

Bu bölüm kasıtlı olarak "temel" olarak adlandırılmıştır, çünkü bu kılavuzun ilerleyen bölümlerinde yeniden kullanılabilir kontrollerle uygulama yapısına yönelik daha gerçekçi yaklaşımlara bakacağız.

Tipik bir Flet programı, uygulamanın yeni kullanıcı oturumlarını beklemeye başladığı flet.app() çağrısıyla sona erer. main() fonksiyonu, bir Flet uygulamasındaki giriş noktasıdır. Page (Sayfa) örneğinin aktarıldığı her kullanıcı oturumu için yeni bir iş parçacığı çağrılıyor. Flet uygulamasını tarayıcıda çalıştırırken, açılan her sekme veya sayfa için yeni bir kullanıcı oturumu başlatılır. Bir masaüstü uygulaması olarak çalışırken oluşturulan yalnızca bir oturum vardır.

Page (Sayfa), kullanıcıya özgü bir "canvas (tuval)" gibidir, kullanıcı oturumunun görsel halidir. Bir uygulama arabirimi oluşturmak için bir sayfaya (page) kontroller ekler ve kaldırırsınız, kontrollerin özelliklerini güncellersiniz. Yukarıdaki kod örneği, içerisine hiçbir kontrol eklenmediği için her kullanıcıya sadece boş bir sayfa (page) görüntüleyecektir.

Flet uygulaması varsayılan olarak, yerel işletim sistemi penceresinde (uygulama/yazılım olarak) başlar. Ancak, flet.app çağrısını aşağıdaki gibi değiştirerek onu yeni bir tarayıcı penceresinde açabilirsiniz:

ft.app(target=main, view=ft.WEB_BROWSER)

NOT:

Dahili olarak, her Flet uygulaması bir web uygulamasıdır ve yerel bir işletim sistemi penceresinde açılsa bile yerleşik bir web sunucusu arka planda başlatılır. Flet web sunucusuna "Fletd" adı verilir ve varsayılan olarak rastgele bir TCP bağlantı noktasını dinler. Özel bir TCP bağlantı noktası belirtebilir ve ardından uygulamayı masaüstü görünümüyle birlikte tarayıcıda açabilirsiniz:

python flet.app(port=8550, target=main)

Flet uygulamanızın web sürümünü görmek için tarayıcınızda http://localhost:<port> öğesini açın.

Kontroller (controls)

Kullanıcı arayüzü, Kontrollerden (Controls) (widget olarak da bilinir) yapılmıştır. Kontrollerin bir kullanıcı tarafından görülebilmesi için bir Sayfaya (Page) veya diğer kontrollerin içine eklenmesi gerekir. Page (Sayfa), en üstteki denetimdir. İç içe geçmiş denetimler, kök olarak Page (Sayfa) ile bir ağaç yapısı olarak temsil edilebilir.

Kontroller, temelde normal Python sınıflarıdır. Özellikleriyle eşleşen parametreleri kullanarak, yapıcılar (constructors) aracılığıyla kontrol örnekleri oluşturulur. örneğin:

t = ft.Text(value="Hello, world!", color="green")

Bir sayfada kontrolü görüntülemek istiyorsanız, o kontrolü sayfanın kontroller (controls) listesine eklemeli ve sayfa değişikliklerini bir tarayıcıya veya masaüstü istemcisine göndermek / güncellemek için page.update() öğesini çağırmalısınız:

import flet as ft

def main(page: ft.Page):    
    t = ft.Text(value="Hello, world!", color="green")    
    page.controls.append(t)    
    page.update()

ft.app(target=main)

controls-text

NOT:

Aşağıdaki örneklerde sadece ana (main) fonksiyonun içeriğini göstereceğiz.

Kontrol özelliklerini değiştirebilirsiniz ancak yaptığınız değişiklikler kullanıcı arayüzünde bir sonraki page.update(): komutu ile güncellenecektir.

t = ft.Text()
page.add(t) # it's a shortcut for page.controls.append(t) and then page.update()

for i in range(10):
    t.value = f"Step {i}"
    page.update()
    time.sleep(1)

Bazı kontroller, diğer kontrolleri içerebilen "kapsayıcı (container)" kontrollerdir ( Page (Sayfa) gibi ). Örneğin, Row (Satır) kontrolü, diğer kontrollerin bir satırda tek tek düzenlenmesine izin verir:

page.add(
    ft.Row(controls=[
        ft.Text("A"),
        ft.Text("B"),
        ft.Text("C")
    ])
)

row

veya TextField (metin alanı) ve yanında ElevatedButton (Yükseltilmiş Düğme):

page.add(
    ft.Row(controls=[
        ft.TextField(label="Your name"),
        ft.ElevatedButton(text="Say my name!")
    ])
)

row_2

page.update() yalnız son çağrısından bu yana yapılan değişiklikleri güncelleyecek kadar akıllıdır. Bir sayfaya birkaç yeni kontrol ekleyebilir, bazılarını kaldırabilir, diğer kontrollerin özelliklerini değiştirebilirsiniz ancak bu değişikliklerin topluca güncellenmesi için page.update()'i çağırabilirsiniz. , örneğin:

for i in range(10):
    page.controls.append(ft.Text(f"Line {i}"))
    if i > 4:
        page.controls.pop(0)
    page.update()
    time.sleep(0.3)

Düğmeler (Butonlar) gibi bazı kontroller (denetimler), bir kullanıcı girişine tepki veren "olay işleyicilere (fonksiyonlara) sahip olabilir, örneğin ElevatedButton.on_click: (butona tıklamak sonucunda bir işlemin gerçekleşmesi gibi)

def button_clicked(e):
    page.add(ft.Text("Clicked!"))

page.add(ft.ElevatedButton(text="Click me", on_click=button_clicked))

ve basit bir Yapılacaklar Lisesi (To-Do) için daha gelişmiş bir örnek:

import flet as ft

def main(page):
    def add_clicked(e):
        page.add(ft.Checkbox(label=new_task.value))
        new_task.value = ""
        new_task.focus()
        new_task.update()

    new_task = ft.TextField(hint_text="Whats needs to be done?", width=300)
    page.add(ft.Row([new_task, ft.ElevatedButton("Add", on_click=add_clicked)]))

ft.app(target=main)

to-do

NOT: Flet, kullanıcı arayüzünü durum bilgisi olan kontrollerle "manuel" oluşturduğunuz ve ardından kontrol özelliklerini güncelleyerek değişikliğe uğrattığınız zorunlu kullanıcı arayüzü modelini uygular. Flutter, kullanıcı arayüzünün uygulama verisi değişikliklerine göre otomatik olarak yeniden oluşturulduğu bildirime dayalı modeli uygular. Modern front-end uygulamalarında, uygulama durumunu yönetmek, doğası gereği karmaşık bir görevdir ve Flet'in "eski usul" yaklaşımı, front-end deneyimi olmayan programcılar için daha çekici olabilir.

visible (görünürlük) özelliği;

Her kontrolün (denetimin), Sayfa (Page) oluşturulurken, varsayılan değeri true (doğru) olan visible (görünür) özelliği vardır. visible (görünür) değerini false (yanlış / hayır) olarak ayarlamak, kontrolün (ve varsa tüm alt öğelerinin) bir sayfa tuvalinde oluşturulmasını tamamen engeller. Gizli kontrollere klavye veya fare ile odaklanılamaz veya seçilemez ve herhangi bir olay (event) belirtemez.

disabled (devre dışı / engelli) özelliği;

Her kontrol (denetim), varsayılan olarak false (yanlış) değerini barındıran disabled (devre dışı) özelliğine sahiptir. Yani kontrol (denetim) ve tüm alt öğeleri etkindir. disabled özelliği çoğunlukla TextField, Dropdown, Checkbox ve butonlar gibi veri giriş kontrolleri ile kullanılır. Bununla birlikte, bir üst denetim (Parent Control) disabled (devre dışı) olarak ayarlanabilir ve değeri, yinelemeli olarak tüm alt kontrollere (çocuklara) yayılır / uygulanır.

Örneğin, çoklu giriş kontrolüne sahip bir formunuz varsa, her kontrol için disabled (devre dışı) bırakılan özelliği ayrı ayrı ayarlayabilirsiniz:

first_name = ft.TextField()
last_name = ft.TextField()
first_name.disabled = True
last_name.disabled = True
page.add(first_name, last_name)

veya form kontrollerini bir kapsayıcı (container) içerisine koyabilirsiniz, ör.kontrolleri Column (Sütun) içerisine koyun ve ardından Column (sütun)'un disabled (devre dışı) özelliğinini True (Doğru/Aktif) olarak ayarlayın:

first_name = ft.TextField()
last_name = ft.TextField()
c = ft.Column(controls=[
    first_name,
    last_name
])
c.disabled = True
page.add(c)

Kontrol Referansları (Değişkenler)

Flet kontrolleri nesnelerdir ve özelliklerine erişmek için bu nesnelere, referanslar (değişkenler) tutmamız gerekir.

Aşağıdaki örneği göz önünde bulundurun:

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)

control-refs

main() metodunun en başında, butonun on_click fonksiyonunda (işleyicisinde) kullanacağımız üç adet kontrol oluşturuyoruz. Bunlar ad (first name) ve soyad (lastname) için iki TextField kontrolü ile karşılama (greetings) mesajı için bir Column (Sütun) konteyneri (container) kullanılıyor. Kontrolleri, tüm özellikleri ayarlanmış olarak oluşturuyoruz ve main() metodunun sonundaki page.add() çağrısında, bunların referanslarını kullanıyoruz.

Giderek daha fazla denetim ve olay işleyicisi eklendiğinde, tüm denetim tanımlarını (ad, soyad, karşılama,...vb) tek bir yerde tutmak zorlaşır, bu nedenle ana gövdeye (main) dağılırlar. page.add() parametrelerine bakarak (IDE'deki değişken tanımlarına sürekli bakıp tekrar geri dönmeden) formun nasıl görüneceğini hayal etmek zordur:

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

Yani kapsamlı bir çalışma içerisinde, yukarıdaki kod parçasına bakarak first_name 'in bir TextField olup olmadığı, otomatik odaklanma ayarının varlığı ya da yokluğu, greetings (Karşılama) kontrolünün Satırı mı (Row) yoksa Sütunu mu (Column)? ifade ettiği gibi kontrollerin ne olduğuna dair doğru karar vermek zordur, doğru teşhis için kod sayfası içinde aşağı yukarı gezmemiz gerekir ki bu da bize vakit kaybettirir.

Flet, kontrole bir referans tanımlamaya (kontrolü bir değişkene atamaya), bu referansı olay işleyicilerinde (fonksiyonlarda) kullanmaya ve daha sonra bir ağaç (yapısı) oluştururken referansı gerçek bir kontrole ayarlamaya izin veren Ref yardımcı sınıfı sağlar. Fikir React'tan gelmektedir.

Yeni yazılan bir kontrol referansını (Referanslı kontrol) tanımlamak için:

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

Referanslı kontrole erişmek için Ref.current özelliğini kullanın:

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

Kontrolü bir referansa atamak için Control.ref özelliğini bir referansa ayarlayın:

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

NOT:

Tüm Flet kontrolleri ref özelliğine sahiptir.

Referansları kullanacak şekilde programımızı yeniden yazabiliriz:

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)

control-refs-rewritten

Artık kodlarımızı incelerken page.add() içinde sayfanın yapısını ve oluşturduğu tüm kontrolleri açıkça görebiliriz.

Evet, referanslı kontrolün özelliklerine erişmek için .current. ibaresinin eklenmesi gerektiğinden, mantık biraz daha ayrıntılı hale geliyor, ancak referanslı kontrol kullanma konusu, kişisel tercih meselesi :)

Önceki Bölüm Sonraki Bölüm
<<< 02 Giris 04 Kullanicidan Girdi Almak >>>