Text

مكون أساسي لعرض النصوص بأنماط مختلفة

مكون Text هو العنصر الأساسي لعرض النصوص في واجهة المستخدم. يمكن تخصيص النص بخصائص متعددة مثل الحجم واللون والخط والمحاذاة وغيرها.

متى تستخدمه؟

  • لعرض العناوين الرئيسية والفرعية
  • لعرض فقرات النصوص والمحتوى النصي
  • لعرض التسميات التوضيحية مع عناصر أخرى
  • لعرض رسائل تنبيه أو معلومات للمستخدم

المثال الأساسي

basic_text.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text(value="نص عادي بالخصائص الافتراضية"),
        ft.Text(
            value="نص بحجم وخصائص مخصصة",
            size=30,
            color="blue",
            weight="bold",
            italic=True,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

نص عادي بالخصائص الافتراضية

نص بحجم وخصائص مخصصة

الخصائص

الخاصية النوع الوصف القيمة الافتراضية
value str محتوى النص الذي سيتم عرضه ""
size float حجم الخط بالبكسل 14.0
color str لون النص (اسم أو قيمة hex) None
weight str وزن الخط (bold, normal, w100-w900) "normal"
italic bool جعل النص مائلًا False
font_family str نوع الخط المستخدم None
text_align TextAlign محاذاة النص (CENTER, LEFT, RIGHT...) None
selectable bool السماح للمستخدم بتحديد النص False
no_wrap bool منع النص من الالتفاف للسطر التالي False
max_lines int الحد الأقصى لعدد الأسطر None

أمثلة متقدمة

محاذاة النص

text_alignment.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text(
            value="هذا نص بمحاذاة لليمين (الافتراضي في RTL)",
            size=16,
            width=300,
            bgcolor="#f0f0f0",
            text_align=ft.TextAlign.RIGHT,
        ),
        ft.Text(
            value="هذا نص بمحاذاة للوسط",
            size=16,
            width=300,
            bgcolor="#e0e0e0",
            text_align=ft.TextAlign.CENTER,
        ),
        ft.Text(
            value="هذا نص بمحاذاة لليسار",
            size=16,
            width=300,
            bgcolor="#d0d0d0",
            text_align=ft.TextAlign.LEFT,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

هذا نص بمحاذاة لليمين (الافتراضي في RTL)
هذا نص بمحاذاة للوسط
هذا نص بمحاذاة لليسار

نص متعدد الأسطر مع تقييد

text_lines.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text(
            "هذا نص طويل يمتد على عدة أسطر وسيتم عرضه بالكامل مع التفاف تلقائي للسطور لملاءمة العرض المتاح. يمكنك استخدام هذا النوع من النصوص لعرض فقرات طويلة من المعلومات.",
            width=300,
        ),
        ft.Divider(),
        ft.Text(
            "هذا نص طويل لكن محدود بسطرين فقط. ستلاحظ قطع النص الزائد واستبداله بنقاط الحذف (...) لإشارة إلى وجود نص إضافي.",
            width=300,
            max_lines=2,
        ),
        ft.Divider(),
        ft.Text(
            "هذا نص بدون التفاف سيستمر أفقيًا ولن يتم قطعه إلى سطر جديد حتى لو تجاوز حدود العرض المتاح.",
            no_wrap=True,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

هذا نص طويل يمتد على عدة أسطر وسيتم عرضه بالكامل مع التفاف تلقائي للسطور لملاءمة العرض المتاح. يمكنك استخدام هذا النوع من النصوص لعرض فقرات طويلة من المعلومات.


هذا نص طويل لكن محدود بسطرين فقط. ستلاحظ قطع النص الزائد واستبداله بنقاط الحذف (...) لإشارة إلى وجود نص إضافي.


هذا نص بدون التفاف سيستمر أفقيًا ولن يتم قطعه إلى سطر جديد حتى لو تجاوز حدود العرض المتاح.

نص تفاعلي (قابل للتحديث)

dynamic_text.py
import flet as ft

def main(page: ft.Page):
    # إنشاء عنصر نص سيتم تحديثه
    text_output = ft.Text(
        value="انقر على الزر لتحديث النص",
        size=20,
        color="blue",
    )
    
    counter = 0
    
    def update_text(e):
        nonlocal counter
        counter += 1
        # تحديث قيمة النص
        text_output.value = f"تم النقر على الزر {counter} مرات"
        # تغيير لون النص
        text_output.color = "green" if counter % 2 == 0 else "purple"
        # يجب استدعاء page.update() لتحديث الواجهة
        page.update()
    
    page.add(
        text_output,
        ft.ElevatedButton(
            text="تحديث النص",
            on_click=update_text,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

انقر على الزر لتحديث النص

* في التطبيق الفعلي، سيتغير النص واللون عند النقر

اعتبارات ونصائح

  • للحصول على أفضل دعم للغة العربية، تأكد من تعيين page.rtl = True لإعداد التطبيق للعمل من اليمين إلى اليسار.
  • استخدم خطوطًا عربية مناسبة عن طريق تعيين font_family مثل "Cairo" أو "Tajawal".
  • استخدم selectable=True للنصوص التي قد يرغب المستخدم في نسخها.
  • يمكن استخدام overflow للتحكم في كيفية عرض النص الزائد عن المساحة المتاحة.
  • للنصوص التي تتغير ديناميكيًا، احتفظ بمرجع للعنصر وقم بتحديث خاصية value ثم استدعي page.update().

TextField

حقل إدخال نصي للحصول على بيانات المستخدم

مكون TextField هو عنصر إدخال يسمح للمستخدمين بكتابة نص. يمكن تخصيصه بالعديد من الخصائص مثل التسمية والنص التلميحي وأيقونات وأنماط مختلفة من الإدخال.

متى تستخدمه؟

  • لجمع المدخلات النصية من المستخدم (اسم، بريد إلكتروني، ملاحظات)
  • لإنشاء نماذج جمع البيانات والاستمارات
  • للبحث وحقول التصفية
  • لإدخال كلمات المرور مع إخفاء النص

المثال الأساسي

basic_textfield.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.TextField(
            label="الاسم",
            hint_text="أدخل اسمك هنا",
            width=400,
        ),
        ft.TextField(
            label="البريد الإلكتروني",
            hint_text="[email protected]",
            width=400,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

أمثلة متقدمة

أنواع مختلفة من حقول الإدخال

textfield_types.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("أنواع مختلفة من حقول الإدخال:", size=16, weight="bold"),
        
        # حقل نص عادي
        ft.TextField(
            label="نص عادي",
            width=400,
        ),
        
        # حقل كلمة مرور
        ft.TextField(
            label="كلمة المرور",
            password=True,  # إخفاء النص
            can_reveal_password=True,  # السماح بإظهار كلمة المرور
            width=400,
        ),
        
        # حقل متعدد الأسطر
        ft.TextField(
            label="ملاحظات متعددة الأسطر",
            multiline=True,  # تفعيل تعدد الأسطر
            min_lines=3,  # الحد الأدنى من الأسطر
            max_lines=5,  # الحد الأقصى من الأسطر
            width=400,
        ),
        
        # حقل مع عدد
        ft.TextField(
            label="العمر",
            keyboard_type=ft.KeyboardType.NUMBER,  # لوحة مفاتيح رقمية
            prefix_text="عمر: ",  # نص قبل الإدخال
            suffix_text=" سنة",  # نص بعد الإدخال
            width=400,
        ),
        
        # حقل بأيقونات
        ft.TextField(
            label="البحث",
            prefix_icon=ft.icons.SEARCH,  # أيقونة في البداية
            suffix_icon=ft.icons.CLEAR,  # أيقونة في النهاية
            width=400,
        ),
    )

ft.app(target=main)

التحقق من المدخلات والاستجابة للأحداث

textfield_validation.py
import flet as ft
import re

def main(page: ft.Page):
    # عنصر لعرض رسائل التحقق
    validation_text = ft.Text(color="red")
    
    # نص للعرض
    output_text = ft.Text(size=16)
    
    # التحقق من البريد الإلكتروني
    def validate_email(e):
        email_value = email_field.value
        if not email_value:
            validation_text.value = "الرجاء إدخال البريد الإلكتروني"
        elif not re.match(r"[^@]+@[^@]+\.[^@]+", email_value):
            validation_text.value = "البريد الإلكتروني غير صالح"
            email_field.border_color = "red"
        else:
            validation_text.value = ""
            email_field.border_color = "green"
            output_text.value = f"مرحباً {name_field.value}! تم تسجيل بريدك الإلكتروني: {email_value}"
        
        page.update()
    
    # تحديث مباشر مع كل تغيير
    def on_name_change(e):
        name = e.control.value
        if name:
            output_text.value = f"مرحباً {name}!"
        else:
            output_text.value = ""
        page.update()
    
    # حقول الإدخال
    name_field = ft.TextField(
        label="الاسم",
        on_change=on_name_change,
        width=400,
    )
    
    email_field = ft.TextField(
        label="البريد الإلكتروني",
        width=400,
        helper_text="أدخل بريدك الإلكتروني بصيغة صحيحة",
    )
    
    # إضافة العناصر للصفحة
    page.add(
        name_field,
        email_field,
        ft.ElevatedButton("تحقق", on_click=validate_email),
        validation_text,
        output_text,
    )

ft.app(target=main)

الخصائص الأساسية

الخاصية النوع الوصف
value str قيمة الحقل النصية
label str تسمية الحقل
hint_text str نص تلميحي يظهر عندما يكون الحقل فارغًا
helper_text str نص مساعد يظهر أسفل الحقل
password bool جعل الحقل مخصص لكلمات المرور (إخفاء النص)
multiline bool السماح بإدخال نص متعدد الأسطر
prefix_icon / suffix_icon str أيقونة تظهر في بداية/نهاية الحقل
prefix_text / suffix_text str نص يظهر في بداية/نهاية الحقل
on_change callable دالة تستدعى عند تغيير قيمة الحقل
on_submit callable دالة تستدعى عند الضغط على Enter

اعتبارات ونصائح

  • استخدم keyboard_type لتحديد نوع لوحة المفاتيح المناسب (رقمية، بريد إلكتروني، الخ).
  • وفر تعليمات واضحة باستخدام helper_text لمساعدة المستخدم في فهم المطلوب.
  • استخدم on_change للاستجابة الفورية لمدخلات المستخدم، وon_submit للإجراءات عند الانتهاء.
  • تأكد من التحقق من صحة البيانات المدخلة وتوفير تغذية راجعة واضحة للمستخدم.
  • استخدم disabled لتعطيل الحقل في سيناريوهات معينة.
  • للتعامل مع اللغة العربية بشكل أفضل، استخدم text_align=TextAlign.RIGHT و page.rtl=True.

Buttons

أزرار متنوعة لتنفيذ الإجراءات وتفاعل المستخدم

الأزرار هي عناصر واجهة المستخدم الأساسية للتفاعل. توفر مكتبة Flet أنواعًا مختلفة من الأزرار لتناسب احتياجات التصميم المختلفة.

متى تستخدمها؟

  • لتنفيذ إجراءات مثل الحفظ، الحذف، الإرسال
  • للتنقل بين الصفحات والشاشات
  • لفتح حوارات وقوائم منسدلة
  • لتفعيل أو تعطيل خيارات معينة

الأنواع الأساسية للأزرار

basic_buttons.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("أنواع الأزرار الأساسية:", size=16, weight="bold"),
        
        # زر مرتفع
        ft.ElevatedButton(
            text="زر مرتفع",
            icon=ft.icons.SEND,
            on_click=lambda e: print("تم النقر على الزر المرتفع")
        ),
        
        # زر مسطح
        ft.FilledButton(
            text="زر مسطح",
            icon=ft.icons.ADD,
            on_click=lambda e: print("تم النقر على الزر المسطح")
        ),
        
        # زر مخطط
        ft.OutlinedButton(
            text="زر مخطط",
            icon=ft.icons.EDIT,
            on_click=lambda e: print("تم النقر على الزر المخطط")
        ),
        
        # زر نصي
        ft.TextButton(
            text="زر نصي",
            icon=ft.icons.INFO,
            on_click=lambda e: print("تم النقر على الزر النصي")
        ),
        
        # زر أيقونة
        ft.IconButton(
            icon=ft.icons.FAVORITE,
            icon_color="pink",
            tooltip="زر أيقونة",
            on_click=lambda e: print("تم النقر على زر الأيقونة")
        ),
        
        # زر عائم
        ft.FloatingActionButton(
            icon=ft.icons.ADD,
            bgcolor=ft.colors.GREEN,
            on_click=lambda e: print("تم النقر على الزر العائم")
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

أنواع الأزرار الأساسية:

أمثلة متقدمة

أزرار تغير حالتها

state_buttons.py
import flet as ft

def main(page: ft.Page):
    # زر حالة التحميل
    loading_button = ft.ElevatedButton("تحميل البيانات")
    
    # زر معطل
    disabled_button = ft.ElevatedButton("زر معطل", disabled=True)
    
    # زر متغير اللون
    color_button = ft.ElevatedButton(
        text="تغيير اللون",
        bgcolor="blue",
        color="white",
    )
    
    # زر اعجاب
    like_button = ft.IconButton(
        icon=ft.icons.FAVORITE_BORDER,
        selected_icon=ft.icons.FAVORITE,
        icon_color="black",
        selected_icon_color="pink",
        tooltip="إعجاب",
    )
    
    # التبديل بين حالة التحميل
    def toggle_loading(e):
        loading_button.text = "جاري التحميل..." if loading_button.text == "تحميل البيانات" else "تحميل البيانات"
        loading_button.icon = ft.icons.PENDING if loading_button.text == "جاري التحميل..." else None
        loading_button.disabled = loading_button.text == "جاري التحميل..."
        page.update()
    
    # تغيير لون الزر
    def change_color(e):
        colors = ["blue", "green", "red", "purple", "orange"]
        current_index = colors.index(color_button.bgcolor) if color_button.bgcolor in colors else 0
        next_index = (current_index + 1) % len(colors)
        color_button.bgcolor = colors[next_index]
        page.update()
    
    # تبديل حالة الإعجاب
    def toggle_like(e):
        like_button.selected = not like_button.selected
        page.update()
    
    # ربط الأحداث بالأزرار
    loading_button.on_click = toggle_loading
    color_button.on_click = change_color
    like_button.on_click = toggle_like
    
    page.add(
        ft.Text("أزرار تغير حالتها:", size=16, weight="bold"),
        loading_button,
        disabled_button,
        color_button,
        ft.Row([like_button, ft.Text("أنقر للإعجاب")]),
    )

ft.app(target=main)

مجموعات الأزرار

button_groups.py
import flet as ft

def main(page: ft.Page):
    # مجموعة أزرار أفقية
    horizontal_group = ft.Row(
        controls=[
            ft.ElevatedButton("الصفحة الرئيسية", icon=ft.icons.HOME),
            ft.ElevatedButton("المنتجات", icon=ft.icons.SHOPPING_BAG),
            ft.ElevatedButton("اتصل بنا", icon=ft.icons.CONTACT_MAIL),
        ],
        spacing=10,
    )
    
    # مجموعة أزرار رأسية
    vertical_group = ft.Column(
        controls=[
            ft.OutlinedButton("خيار 1", width=200),
            ft.OutlinedButton("خيار 2", width=200),
            ft.OutlinedButton("خيار 3", width=200),
        ],
        spacing=5,
    )
    
    # شريط أدوات
    toolbar = ft.Row(
        controls=[
            ft.IconButton(icon=ft.icons.FORMAT_BOLD, tooltip="غامق"),
            ft.IconButton(icon=ft.icons.FORMAT_ITALIC, tooltip="مائل"),
            ft.IconButton(icon=ft.icons.FORMAT_UNDERLINE, tooltip="تحته خط"),
            ft.VerticalDivider(width=1, thickness=1),
            ft.IconButton(icon=ft.icons.FORMAT_ALIGN_RIGHT, tooltip="محاذاة لليمين"),
            ft.IconButton(icon=ft.icons.FORMAT_ALIGN_CENTER, tooltip="توسيط"),
            ft.IconButton(icon=ft.icons.FORMAT_ALIGN_LEFT, tooltip="محاذاة لليسار"),
        ],
        spacing=0,
    )
    
    # مفاتيح تبديل متعددة
    toggle_buttons = ft.Row(
        controls=[
            ft.ElevatedButton(
                "يومي",
                bgcolor="blue" if page.data.get("view") == "daily" else "transparent",
                color="white" if page.data.get("view") == "daily" else "black",
                data="daily",
            ),
            ft.ElevatedButton(
                "أسبوعي",
                bgcolor="blue" if page.data.get("view") == "weekly" else "transparent",
                color="white" if page.data.get("view") == "weekly" else "black",
                data="weekly",
            ),
            ft.ElevatedButton(
                "شهري",
                bgcolor="blue" if page.data.get("view") == "monthly" else "transparent",
                color="white" if page.data.get("view") == "monthly" else "black",
                data="monthly",
            ),
        ],
        spacing=1,
    )
    
    # تعيين العرض الافتراضي
    if not hasattr(page, "data"):
        page.data = {}
    
    page.data["view"] = "daily"
    
    # تبديل العرض المحدد
    def toggle_view(e):
        page.data["view"] = e.control.data
        for btn in toggle_buttons.controls:
            is_selected = btn.data == page.data["view"]
            btn.bgcolor = "blue" if is_selected else "transparent"
            btn.color = "white" if is_selected else "black"
        page.update()
    
    # ربط الأحداث بالأزرار
    for btn in toggle_buttons.controls:
        btn.on_click = toggle_view
    
    # إضافة المجموعات للصفحة
    page.add(
        ft.Text("مجموعة أزرار أفقية:", size=16, weight="bold"),
        horizontal_group,
        ft.Divider(),
        
        ft.Text("مجموعة أزرار رأسية:", size=16, weight="bold"),
        vertical_group,
        ft.Divider(),
        
        ft.Text("شريط أدوات:", size=16, weight="bold"),
        ft.Container(toolbar, border=ft.border.all(1, ft.colors.GREY_400), border_radius=5, padding=5),
        ft.Divider(),
        
        ft.Text("أزرار تبديل:", size=16, weight="bold"),
        toggle_buttons,
    )

ft.app(target=main)

الخصائص الشائعة للأزرار

الخاصية النوع الوصف
text str النص الظاهر على الزر
icon str أيقونة تظهر بجانب النص أو بدلاً منه
on_click callable دالة تستدعى عند النقر على الزر
disabled bool تعطيل الزر ومنع التفاعل معه
tooltip str نص تلميحي يظهر عند تمرير المؤشر فوق الزر
bgcolor / color str لون خلفية الزر / لون النص
width / height number عرض وارتفاع الزر
style ButtonStyle أنماط متقدمة للزر (شكل الحدود، تأثير الضغط، الخ)
autofocus bool تحديد الزر تلقائيًا عند تحميل الصفحة

اعتبارات ونصائح

  • اختر نوع الزر الذي يناسب أهمية الإجراء (ElevatedButton للإجراءات الرئيسية، TextButton للإجراءات الثانوية).
  • استخدم الألوان بحكمة لتوجيه المستخدم (أخضر للتأكيد، أحمر للحذف، إلخ).
  • أضف أيقونات للأزرار لتحسين الفهم البصري للإجراء.
  • استخدم تلميحات tooltip لشرح وظيفة الزر خاصة إذا كان يحتوي على أيقونة فقط.
  • عطل الأزرار التي لا تنطبق في سياق معين بدلاً من إخفائها لتوفير سياق أفضل للمستخدم.
  • عند استخدام العديد من الأزرار، قم بتجميعها في Row أو Column لتنظيم الواجهة.
  • قدم تغذية راجعة بصرية عند الضغط على الأزرار بتحديث حالتها (مثل أيقونة تحميل أو تغيير النص).

Image

عرض الصور وتخصيصها في تطبيقات Flet

مكون الصور في Flet يتيح عرض الصور من مصادر مختلفة مثل الملفات المحلية، عناوين URL، أو البيانات الثنائية. يمكن تخصيص الصور بالعديد من الخيارات مثل التدوير، الحجم، والتأثيرات.

متى تستخدمه؟

  • لعرض الصور والرسومات في واجهة المستخدم
  • لعرض أيقونات وشعارات المشروع
  • لعرض صور المستخدمين والملفات الشخصية
  • لتقديم مواد بصرية داعمة للمحتوى النصي

المثال الأساسي

basic_image.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("أنواع الصور الأساسية:", size=16, weight="bold"),
        
        # صورة من URL
        ft.Image(
            src="https://picsum.photos/300/200",
            width=300,
            height=200,
            fit=ft.ImageFit.COVER,
        ),
        
        ft.Text("صورة من URL", italic=True, size=12),
        
        # صورة من أصول المشروع (assets)
        ft.Image(
            src="/images/logo.png",  # هنا يجب وضع مسار نسبي لصورة في مجلد assets
            width=200,
            height=100,
        ),
        
        ft.Text("صورة من ملفات المشروع", italic=True, size=12),
    )

ft.app(target=main)

نتيجة التنفيذ:

أنواع الصور الأساسية:

صورة عشوائية

صورة من URL

[صورة من ملفات المشروع]

صورة من ملفات المشروع

خيارات ملاءمة الصور

image_fit.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("خيارات ملاءمة الصور (ImageFit):", size=16, weight="bold"),
        
        ft.Row([
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/300/300",
                        width=150,
                        height=150,
                        fit=ft.ImageFit.NONE,
                    ),
                    width=150,
                    height=150,
                    border=ft.border.all(1, ft.colors.BLACK),
                ),
                ft.Text("NONE", size=14),
                ft.Text("الحجم الأصلي", size=10),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/300/300",
                        width=150,
                        height=150,
                        fit=ft.ImageFit.CONTAIN,
                    ),
                    width=150,
                    height=150,
                    border=ft.border.all(1, ft.colors.BLACK),
                ),
                ft.Text("CONTAIN", size=14),
                ft.Text("تناسب مع الحفاظ على النسبة", size=10),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/300/300",
                        width=150,
                        height=150,
                        fit=ft.ImageFit.COVER,
                    ),
                    width=150,
                    height=150,
                    border=ft.border.all(1, ft.colors.BLACK),
                ),
                ft.Text("COVER", size=14),
                ft.Text("تغطية كاملة مع قص", size=10),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/300/300",
                        width=150,
                        height=150,
                        fit=ft.ImageFit.FILL,
                    ),
                    width=150,
                    height=150,
                    border=ft.border.all(1, ft.colors.BLACK),
                ),
                ft.Text("FILL", size=14),
                ft.Text("ملء كامل (تشويه)", size=10),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
        ], wrap=True, spacing=20),
    )

ft.app(target=main)

نتيجة التنفيذ:

خيارات ملاءمة الصور (ImageFit):

مثال NONE

NONE

الحجم الأصلي

مثال CONTAIN

CONTAIN

تناسب مع الحفاظ على النسبة

مثال COVER

COVER

تغطية كاملة مع قص

مثال FILL

FILL

ملء كامل (تشويه)

تأثيرات متقدمة للصور

advanced_image.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("تأثيرات متقدمة للصور:", size=16, weight="bold"),
        
        ft.Row([
            ft.Column([
                ft.Image(
                    src="https://picsum.photos/200/200",
                    width=200,
                    height=200,
                    border_radius=10,  # تدوير زوايا الصورة
                ),
                ft.Text("زوايا دائرية", size=12),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Image(
                    src="https://picsum.photos/200/200",
                    width=200,
                    height=200,
                    border_radius=100,  # دائرة كاملة
                    fit=ft.ImageFit.COVER,
                ),
                ft.Text("صورة دائرية", size=12),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/200/200",
                        width=200,
                        height=200,
                        color=ft.colors.BLUE,  # تطبيق لون
                        color_blend_mode=ft.BlendMode.COLOR,  # وضع المزج
                    ),
                    border_radius=10,
                    shadow=ft.BoxShadow(
                        spread_radius=1,
                        blur_radius=15,
                        color=ft.colors.BLUE_GREY_300,
                        offset=ft.Offset(0, 5),
                    )
                ),
                ft.Text("تأثير اللون مع ظل", size=12),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
            
            ft.Column([
                ft.Container(
                    ft.Image(
                        src="https://picsum.photos/200/200",
                        width=200,
                        height=200,
                        fit=ft.ImageFit.COVER,
                        color=ft.colors.BLACK,
                        opacity=0.5,  # شفافية 50%
                    ),
                    gradient=ft.LinearGradient(
                        begin=ft.alignment.top_center,
                        end=ft.alignment.bottom_center,
                        colors=[ft.colors.TRANSPARENT, ft.colors.BLACK],
                    ),
                    border_radius=10,
                ),
                ft.Text("تدرج شفافية", size=12),
            ], horizontal_alignment=ft.CrossAxisAlignment.CENTER),
        ], wrap=True, spacing=20),
        
        ft.Divider(height=30),
        
        ft.Text("صورة تفاعلية:", size=16, weight="bold"),
        
        ft.Container(
            content=ft.Image(
                src="https://picsum.photos/300/200",
                width=300,
                height=200,
                fit=ft.ImageFit.COVER,
                border_radius=10,
            ),
            ink=True,  # تفعيل تأثير الحبر عند النقر
            tooltip="انقر لعرض صورة أكبر",
            on_click=lambda e: page.show_dialog(
                ft.AlertDialog(
                    content=ft.Image(
                        src="https://picsum.photos/600/400",
                        fit=ft.ImageFit.CONTAIN,
                    ),
                    actions=[
                        ft.TextButton("إغلاق", on_click=lambda e: page.dialog.open = False),
                    ],
                    actions_alignment=ft.MainAxisAlignment.END,
                )
            ),
        ),
    )

ft.app(target=main)

الخصائص الأساسية

الخاصية النوع الوصف
src str مصدر الصورة (URL أو مسار محلي)
width / height number عرض وارتفاع الصورة
fit ImageFit طريقة ملاءمة الصورة في المساحة المتاحة
repeat ImageRepeat إعادة الصورة في حال كانت أصغر من مساحة العرض
border_radius number تدوير زوايا الصورة
color str لون يتم تطبيقه على الصورة
color_blend_mode BlendMode طريقة مزج اللون مع الصورة
opacity float شفافية الصورة (0.0 إلى 1.0)

اعتبارات ونصائح

  • استخدم fit=ft.ImageFit.COVER للحصول على صورة تملأ المساحة بشكل كامل مع الحفاظ على نسبة الأبعاد.
  • استخدم gapless_playback=True لتجنب وميض الصورة عند تغيير المصدر.
  • ضع الصور داخل Container مع ink=True لإضافة تأثيرات عند النقر.
  • استخدم semantic_label لوصف الصورة لتحسين إمكانية الوصول.
  • تجنب الصور الكبيرة دون داعي للحفاظ على أداء التطبيق.
  • عند استخدام ImageFit.CONTAIN مع خلفية، استخدم Container للتحكم في لون الخلفية.
  • وفر صور بديلة باستخدام error_content للعرض في حالة فشل تحميل الصورة.

Layout

تنظيم وتخطيط عناصر واجهة المستخدم

توفر مكتبة Flet عدة مكونات للتخطيط تساعدك على تنظيم عناصر واجهة المستخدم بطرق مختلفة. هذه المكونات تتيح إنشاء واجهات مستخدم معقدة ومتجاوبة بسهولة.

مكونات التخطيط الأساسية:

  • Row: لترتيب العناصر أفقيًا جنبًا إلى جنب
  • Column: لترتيب العناصر رأسيًا من أعلى لأسفل
  • Container: لتغليف العناصر مع خيارات التنسيق المتقدمة
  • Stack: لوضع العناصر فوق بعضها البعض
  • Grid: لترتيب العناصر في صفوف وأعمدة

Row و Column

row_column.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("Row - ترتيب أفقي:", size=16, weight="bold"),
        
        # صف أساسي
        ft.Row(
            controls=[
                ft.Container(width=50, height=50, bgcolor="blue", border_radius=5),
                ft.Container(width=50, height=50, bgcolor="green", border_radius=5),
                ft.Container(width=50, height=50, bgcolor="red", border_radius=5),
            ],
            spacing=10,  # المسافة بين العناصر
        ),
        
        # صف مع محاذاة
        ft.Text("Row مع محاذاة مختلفة:", size=14),
        ft.Row(
            controls=[
                ft.Container(width=50, height=50, bgcolor="blue", border_radius=5),
                ft.Container(width=50, height=100, bgcolor="green", border_radius=5),
                ft.Container(width=50, height=70, bgcolor="red", border_radius=5),
            ],
            alignment=ft.MainAxisAlignment.SPACE_BETWEEN,  # توزيع المساحة بين العناصر
            vertical_alignment=ft.CrossAxisAlignment.CENTER,  # محاذاة عمودية في المنتصف
            height=150,
            bgcolor="#f0f0f0",
            padding=10,
        ),
        
        ft.Divider(height=30),
        
        ft.Text("Column - ترتيب رأسي:", size=16, weight="bold"),
        
        # عمود أساسي
        ft.Column(
            controls=[
                ft.Container(width=200, height=30, bgcolor="blue", border_radius=5),
                ft.Container(width=200, height=30, bgcolor="green", border_radius=5),
                ft.Container(width=200, height=30, bgcolor="red", border_radius=5),
            ],
            spacing=10,  # المسافة بين العناصر
        ),
        
        # عمود مع محاذاة
        ft.Text("Column مع محاذاة مختلفة:", size=14),
        ft.Column(
            controls=[
                ft.Container(width=50, height=30, bgcolor="blue", border_radius=5),
                ft.Container(width=100, height=30, bgcolor="green", border_radius=5),
                ft.Container(width=150, height=30, bgcolor="red", border_radius=5),
            ],
            alignment=ft.MainAxisAlignment.CENTER,  # محاذاة رأسية في المنتصف
            horizontal_alignment=ft.CrossAxisAlignment.CENTER,  # محاذاة أفقية في المنتصف
            width=300,
            bgcolor="#f0f0f0",
            padding=10,
            spacing=15,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

Row - ترتيب أفقي:

Row مع محاذاة مختلفة:


Column - ترتيب رأسي:

Column مع محاذاة مختلفة:

Container

container.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("Container - حاوية العناصر:", size=16, weight="bold"),
        
        # حاوية بسيطة
        ft.Container(
            content=ft.Text("حاوية بسيطة", color="white", text_align=ft.TextAlign.CENTER),
            width=200,
            height=60,
            bgcolor="blue",
            border_radius=10,
            alignment=ft.alignment.center,
            margin=10,
            padding=10,
        ),
        
        # حاوية بتدرج لوني
        ft.Container(
            content=ft.Text("حاوية بتدرج لوني", color="white", text_align=ft.TextAlign.CENTER),
            width=200,
            height=60,
            gradient=ft.LinearGradient(
                begin=ft.alignment.top_left,
                end=ft.alignment.bottom_right,
                colors=["#4CAF50", "#2196F3"],
            ),
            border_radius=10,
            alignment=ft.alignment.center,
            margin=10,
        ),
        
        # حاوية مع حدود وظل
        ft.Container(
            content=ft.Text("حاوية مع حدود وظل", text_align=ft.TextAlign.CENTER),
            width=200,
            height=60,
            border=ft.border.all(2, "blue"),
            border_radius=10,
            shadow=ft.BoxShadow(
                spread_radius=1,
                blur_radius=10,
                color=ft.colors.BLUE_GREY_300,
                offset=ft.Offset(0, 5),
            ),
            alignment=ft.alignment.center,
            margin=10,
        ),
        
        # حاوية عند التمرير فوقها (محاكاة)
        ft.Container(
            content=ft.Text("مرر المؤشر فوق الحاوية", text_align=ft.TextAlign.CENTER),
            width=200,
            height=60,
            bgcolor="#f5f5f5",
            border_radius=10,
            ink=True,  # تأثير الحبر عند النقر
            on_hover=lambda e: setattr(e.control, "bgcolor", "#e0e0e0" if e.data == "true" else "#f5f5f5") or page.update(),
            alignment=ft.alignment.center,
            margin=10,
        ),
        
        # حاوية متداخلة
        ft.Container(
            content=ft.Column([
                ft.Text("حاوية خارجية", color="white", size=16),
                ft.Container(
                    content=ft.Text("حاوية داخلية", size=14),
                    bgcolor="white",
                    padding=10,
                    border_radius=5,
                    width=150,
                ),
            ], spacing=20, alignment=ft.MainAxisAlignment.CENTER),
            width=250,
            height=150,
            bgcolor="purple",
            border_radius=10,
            padding=20,
            margin=10,
            alignment=ft.alignment.center,
        ),
    )

ft.app(target=main)

نتيجة التنفيذ:

Container - حاوية العناصر:

حاوية بسيطة

حاوية بتدرج لوني

حاوية مع حدود وظل

مرر المؤشر فوق الحاوية

حاوية خارجية

حاوية داخلية

Stack

stack.py
import flet as ft

def main(page: ft.Page):
    page.add(
        ft.Text("Stack - تكديس العناصر:", size=16, weight="bold"),
        
        # Stack أساسي
        ft.Container(
            content=ft.Stack(
                [
                    # الطبقة الخلفية (خلفية)
                    ft.Container(
                        width=300,
                        height=200,
                        bgcolor="blue",
                        border_radius=10,
                    ),
                    
                    # الطبقة المتوسطة (صورة)
                    ft.Container(
                        width=280,
                        height=180,
                        left=10,
                        top=10,
                        bgcolor="white",
                        border_radius=5,
                        alignment=ft.alignment.center,
                        content=ft.Image(
                            src="https://picsum.photos/250/150",
                            width=250,
                            height=150,
                            fit=ft.ImageFit.COVER,
                            border_radius=5,
                        ),
                    ),
                    
                    # الطبقة العلوية (نص)
                    ft.Container(
                        content=ft.Text("عنوان الصورة", color="white", weight="bold"),
                        bottom=0,
                        left=0,
                        right=0,
                        padding=10,
                        bgcolor=ft.colors.with_opacity(0.5, "black"),
                        border_radius=ft.border_radius.only(
                            bottom_left=10,
                            bottom_right=10,
                        ),
                    ),
                    
                    # زر في الزاوية العلوية
                    ft.Container(
                        content=ft.IconButton(
                            icon=ft.icons.FAVORITE_BORDER,
                            icon_color="red",
                        ),
                        top=0,
                        right=0,
                    ),
                ]
            ),
            width=300,
            height=200,
            margin=20,
        ),
        
        # مثال آخر (بطاقة معلومات)
        ft.Text("مثال آخر - بطاقة شخصية:", size=14),
        ft.Container(
            content=ft.Stack(
                [
                    # خلفية البطاقة
                    ft.Container(
                        width=350,
                        height=150,
                        bgcolor="#f0f0f0",
                        border_radius=10,
                    ),
                    
                    # نمط زخرفي
                    ft.Container(
                        width=150,
                        height=150,
                        right=0,
                        bgcolor=ft.colors.with_opacity(0.1, "blue"),
                        border_radius=ft.border_radius.only(
                            top_right=10,
                            bottom_right=10,
                        ),
                    ),
                    
                    # صورة شخصية
                    ft.Container(
                        content=ft.Container(
                            width=80,
                            height=80,
                            border_radius=40,
                            bgcolor="blue",
                            alignment=ft.alignment.center,
                            content=ft.Text("أ ب", size=30, color="white"),
                        ),
                        left=20,
                        top=35,
                    ),
                    
                    # معلومات الشخص
                    ft.Container(
                        content=ft.Column(
                            [
                                ft.Text("أحمد بن محمد", size=18, weight="bold"),
                                ft.Text("مطور تطبيقات", size=14, color="#666666"),
                                ft.Row(
                                    [
                                        ft.Icon(ft.icons.EMAIL, size=14, color="blue"),
                                        ft.Text("[email protected]", size=12),
                                    ],
                                    spacing=5,
                                ),
                                ft.Row(
                                    [
                                        ft.Icon(ft.icons.PHONE, size=14, color="blue"),
                                        ft.Text("+966 123 456 7890", size=12),
                                    ],
                                    spacing=5,
                                ),
                            ],
                            spacing=5,
                        ),
                        left=120,
                        top=30,
                    ),
                ]
            ),
            width=350,
            height=150,
            margin=10,
        ),
    )

ft.app(target=main)

Grid

grid.py
import flet as ft

def main(page: ft.Page):
    # دالة لإنشاء بطاقة
    def create_card(title, color):
        return ft.Container(
            content=ft.Column(
                [
                    ft.Icon(ft.icons.FOLDER, size=40, color=color),
                    ft.Text(title, size=16, weight="bold"),
                ],
                spacing=5,
                horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                alignment=ft.MainAxisAlignment.CENTER,
            ),
            width=150,
            height=120,
            bgcolor="white",
            border_radius=10,
            border=ft.border.all(1, color),
            alignment=ft.alignment.center,
        )
    
    # إنشاء شبكة من البطاقات
    grid = ft.GridView(
        runs_count=3,  # عدد الصفوف أو الأعمدة
        max_extent=160,  # الحد الأقصى لحجم العنصر
        child_aspect_ratio=1.0,  # نسبة العرض للارتفاع
        spacing=10,  # المسافة بين العناصر
        run_spacing=10,  # المسافة بين الصفوف/الأعمدة
        padding=20,  # هامش الشبكة
        controls=[
            create_card("المستندات", "blue"),
            create_card("الصور", "green"),
            create_card("الموسيقى", "purple"),
            create_card("الفيديوهات", "red"),
            create_card("التنزيلات", "orange"),
            create_card("المشاريع", "teal"),
            create_card("التطبيقات", "indigo"),
            create_card("الألعاب", "pink"),
        ],
    )
    
    page.add(
        ft.Text("GridView - عرض شبكي:", size=16, weight="bold"),
        ft.Container(
            content=grid,
            bgcolor="#f5f5f5",
            border_radius=15,
            padding=10,
        ),
        
        ft.Divider(height=30),
        
        ft.Text("شبكة ديناميكية (حسب حجم النافذة):", size=16, weight="bold"),
        ft.Text("قم بتغيير حجم النافذة لرؤية تأثير التخطيط المتجاوب", size=12, italic=True),
    )
    
    # شبكة متجاوبة
    responsive_grid = ft.GridView(
        expand=1,  # ملء المساحة المتوفرة
        max_extent=200,  # كحد أقصى لحجم العنصر
        child_aspect_ratio=1.5,  # نسبة العرض للارتفاع
        spacing=10,
        run_spacing=10,
        padding=20,
    )
    
    # إضافة عناصر للشبكة المتجاوبة
    colors = ["#2196F3", "#4CAF50", "#FF9800", "#9C27B0", "#F44336", "#009688"]
    for i in range(12):
        responsive_grid.controls.append(
            ft.Container(
                content=ft.Text(f"عنصر {i+1}", color="white", weight="bold"),
                bgcolor=colors[i % len(colors)],
                alignment=ft.alignment.center,
                border_radius=5,
            )
        )
    
    page.add(
        ft.Container(
            content=responsive_grid,
            bgcolor="#f5f5f5",
            border_radius=15,
            padding=10,
            height=400,
        )
    )

ft.app(target=main)

اعتبارات ونصائح

  • استخدم Row و Column كعناصر تخطيط أساسية، مع خاصية spacing لإضافة مسافات بين العناصر.
  • استخدم خاصية alignment للتحكم في محاذاة العناصر داخل Row و Column.
  • استخدم Container لإضافة هامش، حشو، ألوان، حدود، وظلال للعناصر.
  • ضبط expand على True أو استخدم قيمة رقمية لتحديد كيفية توزيع المساحة المتاحة.
  • استخدم Stack لوضع العناصر فوق بعضها، مثل وضع نص فوق صورة.
  • استخدم GridView لعرض مجموعة من العناصر في شكل شبكة.
  • عند إنشاء واجهات متجاوبة، استفد من خاصية wrap=True مع Row لتمكين التفاف العناصر.
  • استخدم page.window_width و page.on_resize للاستجابة لتغييرات حجم الشاشة.