مادة بايثون. بطاقات مخصصة بتأثيرات OpenGL


تحية ومحبي الأعزاء والخبراء في بايثون!

في هذه المقالة سأوضح لك كيفية تطبيق تأثيرات OpenGL على بطاقاتك المخصصة إذا كنت تستخدم أدوات عبر الأنظمة الأساسية مثل إطار عمل Kivy ومكتبة تصميم المواد لهذا الإطار ، KivyMD ، في تطبيقاتك . لنذهب!

تحتوي KivyMD على مكون قياسي MDCard - الفئة الأساسية لإنشاء بطاقات مخصصة مختلفة ( مواصفات تصميم المواد ، بطاقات ). إذا كنت لا أخوض في التفاصيل، ثم تحت غطاء محرك السيارة من MDCard هو المعتاد BoxLayout - وعاء التي تسمح لك لوضع الحاجيات الأخرى في اتجاه عمودي أو أفقي. أي إذا كنت بحاجة إلى عمل نوع من البطاقة ، على سبيل المثال ، معلومات عن المستخدم ، فأنت تفعل ذلك بنفسك. تطبق MDCard فقط ripple_behavior و touch_behavior وظلال الإلقاء:

مثال لبرنامج يعرض بطاقة فارغة كما يلي:

from kivy.lang import Builder

from kivymd.app import MDApp

KV = '''
Screen:  #  

    MDCard:  # 
        #    
        size_hint: .6, .5
        pos_hint: {"center_x": .5, "center_y": .5}
'''


class TestCard(MDApp):
    def build(self):
        return Builder.load_string(KV)

TestCard().run()

نتيجة:


يبدو بسيطا جدا. ولكن ماذا لو أردنا بطاقة جميلة ذات تأثير طمس في حالة التركيز؟ على سبيل المثال ، في تطبيق Flutter UI Designs :


يجب أن تفعل ذلك بنفسك! علاوة على ذلك ، لا يوجد شيء معقد في هذا الشأن. أولاً ، أنشئ الفئة الأساسية للخريطة المستقبلية:

class RestaurantCard(MDCard):
    source = StringProperty()  #     
    shadow = StringProperty()  #    -
    text = StringProperty()  #  

الصورة الرئيسية للبطاقة:


صورة الظل:


الآن سنملأ الخريطة بمكونات حددنا خصائصها باستخدام لغة Kv-Language DSL الخاصة ، والمصممة للتصميم المريح لتخطيطات الواجهة:

<RestaurantCard>
    elevation: 12

    RelativeLayout:

        # ,       .
        FitImage:  #   
            source: root.source

        FitImage:  # -
            source: root.shadow
            size_hint_y: None
            height: "120dp"

        MDLabel:  #  
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1

نضع عنصر واجهة RelativeLayout على الخريطة ، مما يسمح لنا بخلط المكونات واحدًا فوق الآخر بهذه الطريقة:


أولاً ، وضعنا الصورة الرئيسية ، وضعنا الظل والنص في الأعلى. الآن إذا قمنا بتشغيل الكود الخاص بنا:

from kivy.lang import Builder
from kivy.properties import StringProperty

from kivymd.app import MDApp
from kivymd.uix.card import MDCard

KV = """
<RestaurantCard>
    elevation: 12

    RelativeLayout:

        FitImage:
            source: root.source

        FitImage:
            source: root.shadow
            size_hint_y: None
            height: "120dp"

        MDLabel:
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1


Screen:

    RestaurantCard:
        text: "[size=23][b]Restaurant[/b][/size]\\nTuborg Havnepark 15, Hellerup 2900 Denmark"
        shadow: "shadow-black.png"
        source: "restourant.jpg"
        pos_hint: {"center_x": .5, "center_y": .5}
        size_hint: .7, .5
"""


class RestaurantCard(MDCard):
    source = StringProperty()
    text = StringProperty()
    shadow = StringProperty()


class BlurCard(MDApp):
    def build(self):
        return Builder.load_string(KV)

BlurCard().run()

... نحصل على النتيجة:


والنتيجة ، بالطبع ، بعيدة عن النتيجة المتوقعة ، لأننا لن نرى أي تأثير ضبابي أو حواف مستديرة في البطاقة. لنبدأ بتأثير التمويه. يحتوي Kivy على عنصر واجهة مستخدم EffectWidget قياسي يمكنه تطبيق تأثيرات رسومية متنوعة على أطفاله. وهو يعمل عن طريق عرض مثيلات Fbo باستخدام تظليل OpenGL المخصص. نحتاج إلى تطبيق تأثير التمويه على الصورة الرئيسية وصورة الظل على البطاقة. لذلك ، يجب أن نضع مكوناتها في عنصر واجهة مستخدم EffectWidget:

#:import effect kivy.uix.effectwidget.EffectWidget
#:import HorizontalBlurEffect kivy.uix.effectwidget.HorizontalBlurEffect

<RestaurantCard>

    ...

    RelativeLayout:
        
        #   ,      .
        EffectWidget:
            #  .
            effects: (HorizontalBlurEffect(size=root.blur),)

            FitImage:
                source: root.source

            FitImage:
                source: root.shadow
                size_hint_y: None
                height: "120dp"

    ...    

أضف حقلاً لقيمة درجة تأثير التمويه:

class RestaurantCard(MDCard):
    ...
    blur = NumericProperty(8)

نبدأ ونرى:


عندما تحوم فوق (إذا كان سطح المكتب) أو اضغط (إذا كان الهاتف المحمول) لا يحدث شيء. لكي تستجيب البطاقة لحدث on_focus ، يجب علينا تمكين قراءة هذا الحدث في خصائص قاعدة RestaurantCard وتعيين الأساليب التي سيتم تنفيذها عند تسجيل هذا الحدث:

#:import Animation kivy.animation.Animation

<RestaurantCard>
    focus_behavior: True  #    on_focus
    # ,       .
    #   Animation,    .
    on_enter: Animation(blur=0, d=0.3).start(self)
    on_leave: Animation(blur=8, d=0.3).start(self)

أفضل بالفعل:


لقص أركان البطاقة ، قررت تطبيق استنسل (استنسل) على أداة EffectWidget:

#:import Stencil kivymd.uix.graphics.Stencil


#   ,   EffectWidget  Stencil.
<Effect@EffectWidget+Stencil>
    radius: [20,]


<RestaurantCard>
    ...

    RelativeLayout:

        Effect:
            ...

والآن كل شيء يعمل كما خططنا:


رمز المثال الكامل
from kivy.lang import Builder
from kivy.properties import StringProperty, NumericProperty

from kivymd.app import MDApp
from kivymd.uix.card import MDCard

KV = """
#:import Stencil kivymd.uix.graphics.Stencil
#:import Animation kivy.animation.Animation
#:import effect kivy.uix.effectwidget.EffectWidget
#:import HorizontalBlurEffect kivy.uix.effectwidget.HorizontalBlurEffect


<Effect@EffectWidget+Stencil>
    radius: [20,]


<RestaurantCard>
    md_bg_color: 0, 0, 0, 0
    elevation: 12
    focus_behavior: True
    on_enter: Animation(blur=0, d=0.3).start(self)
    on_leave: Animation(blur=8, d=0.3).start(self)
    radius: [20,]

    RelativeLayout:

        Effect:
            effects: (HorizontalBlurEffect(size=root.blur),)

            FitImage:
                source: root.source

            FitImage:
                source: root.shadow
                size_hint_y: None
                height: "120dp"

        MDLabel:
            text: root.text
            markup: True
            size_hint_y: None
            height: self.texture_size[1]
            x: "10dp"
            y: "10dp"
            theme_text_color: "Custom"
            text_color: 1, 1, 1, 1


FloatLayout:

    RestaurantCard:
        text: "[size=23][b]Restaurant[/b][/size]\\nTuborg Havnepark 15, Hellerup 2900 Denmark"
        shadow: "shadow-black.png"
        source: "restourant.jpg"
        pos_hint: {"center_x": .5, "center_y": .5}
        size_hint: .7, .5
"""


class RestaurantCard(MDCard):
    source = StringProperty()
    text = StringProperty()
    shadow = StringProperty()
    blur = NumericProperty(8)


class BlurCard(MDApp):
    def build(self):
        return Builder.load_string(KV)


BlurCard().run()


حسنًا ، أخيرًا ، أريد عرض مقطع فيديو يعمل فيه برنامجان: أحدهما مكتوب باستخدام إطار Flutter ، والثاني - باستخدام Kivy و KivyMD. في نهاية المقال ، أترك استطلاعًا تحتاج فيه إلى تخمين التكنولوجيا المستخدمة وأين.


All Articles