Bahan Python. Kartu khusus dengan efek OpenGL


Salam, para kekasih dan pakar Python!

Pada artikel ini saya akan menunjukkan kepada Anda bagaimana menerapkan efek OpenGL ke kartu khusus Anda jika Anda menggunakan alat lintas platform seperti kerangka kerja Kivy dan pustaka desain bahan untuk kerangka kerja ini, KivyMD , dalam aplikasi Anda . Ayo pergi!

KivyMD memiliki komponen standar MDCard - kelas dasar untuk membuat berbagai kartu khusus ( Material Design spec, Cards ). Jika Anda tidak masuk ke rincian, kemudian di bawah kap MDCard adalah biasa BoxLayout - wadah yang memungkinkan Anda untuk menempatkan widget lain dalam orientasi vertikal atau horizontal. Artinya, jika Anda perlu membuat semacam kartu, misalnya, informasi tentang pengguna, Anda melakukannya sendiri. MDCard hanya mengimplementasikan ripple_behavior , touch_behavior dan cast shadows:

Contoh program yang menampilkan kartu kosong adalah sebagai berikut:

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()

Hasil:


Ini terlihat sangat sederhana. Tetapi bagaimana jika kita menginginkan kartu yang indah dengan efek Blur jika menerima fokus? Seperti, misalnya, dalam aplikasi Flutter UI Designs :


Harus melakukannya sendiri! Lagipula, tidak ada yang rumit tentang ini. Pertama, buat kelas dasar dari peta masa depan:

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

Gambar utama kartu:


Bayangan Gambar:


Sekarang kita akan mengisi peta dengan komponen yang propertinya telah kita tentukan menggunakan bahasa DSL Kv-Language khusus, yang dirancang untuk desain tata letak antarmuka yang nyaman:

<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

Kami menempatkan widget RelativeLayout di peta , yang memungkinkan kami untuk mencampur komponen satu di atas yang lain dengan cara ini:


Pertama, kami menempatkan gambar utama, meletakkan bayangan dan teks di atas. Sekarang jika kita menjalankan kode kita:

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()

... kami mendapatkan hasilnya:


Dan hasilnya, tentu saja, jauh dari yang diharapkan, karena kita tidak akan melihat efek blur atau ujung bundar pada kartu. Mari kita mulai dengan efek blur. Kivy memiliki widget EffectWidget standar yang dapat menerapkan berbagai efek grafis untuk anak-anaknya. Ini bekerja dengan merender instance Fbo menggunakan shader OpenGL kustom. Kita perlu menerapkan efek blur pada gambar utama dan gambar bayangan pada kartu. Karena itu, kita harus meletakkan komponen mereka di widget 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"

    ...    

Tambahkan bidang untuk nilai tingkat efek blur:

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

Kami mulai dan melihat:


Saat Anda mengarahkan kursor (jika itu desktop) atau mengetuk (jika itu seluler) tidak ada yang terjadi. Agar kartu merespons acara on_focus, kami harus mengaktifkan pembacaan acara ini di properti aturan RestaurantCard dan menetapkan metode yang akan dieksekusi ketika acara ini terdaftar:

#: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)

Sudah lebih baik:


Untuk memangkas sudut kartu, saya memutuskan untuk menerapkan Stensil (stensil) ke widget EffectWidget:

#:import Stencil kivymd.uix.graphics.Stencil


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


<RestaurantCard>
    ...

    RelativeLayout:

        Effect:
            ...

Dan sekarang semuanya berjalan sesuai rencana kami:


Kode contoh lengkap
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()


Yah, akhirnya, saya ingin menunjukkan video di mana dua program bekerja: Satu, ditulis menggunakan kerangka Flutter, dan yang kedua - menggunakan Kivy dan KivyMD. Di akhir artikel saya meninggalkan survei di mana Anda perlu menebak teknologi mana yang digunakan dan di mana.


All Articles