Код этикетки Kivy с языка Kivy на Python - PullRequest
0 голосов
/ 17 января 2019

У меня есть следующее простое приложение, созданное с помощью фреймворка kivy gui. Он не самый простой, поскольку label_1 имеет цвет фона, а его размер изменяется в соответствии с текстом метки. Это мой самый первый опыт общения с KIVY. К сожалению, документация kivy и большинство примеров, доступных через Google, интенсивно используют язык kivy. Мой вопрос: как я могу получить тот же результат без языка программирования, используя только Python 3?

Код:

from kivy.config import Config
from kivy.core.window import Window

from kivy.app import App

from kivy.lang import Builder


MainScreen = Builder.load_string('''
BoxLayout:
    orientation: 'vertical'
    Label:
        text: 'label_1'
        font_size: 18
        color: (0, 0, 0, 1)
        size_hint: None, None
        size: self.texture_size
        canvas.before:
            Color:
                rgba: 1, .5, 0, 1
            Rectangle:
                pos: self.pos
                size: self.size
    Label:
        text: 'label_2'
        color: (0, 0, 0, 1)
''')


class MyApp(App):
    def build(self):
        return MainScreen


if __name__ == '__main__':

    Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
    Window.clearcolor = (1, 1, 1, 1)

    MyApp().run()

Как это выглядит:

enter image description here

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Еще один способ решить мою проблему - решение, основанное на ответе @ eyllanesc и видео с киви-курсом . Я публикую это здесь по двум причинам: (1) с этой версией ясно видно, что происходит - как и когда фон нарисован на самом деле - без другого синтаксического слоя (язык kivy) и без bind и setter, которые полностью Новый для меня, (2) eyllanesc предоставил немного грязный код Python.

Код:

from kivy.config import Config
from kivy.core.window import Window

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label

from kivy.graphics import Color, Rectangle

from kivy.app import App


class LabelWithBackground(Label):

    def __init__(self, bgcolor, **kwargs):
        super().__init__(**kwargs)
        self.bgcolor = bgcolor
        self.draw_background()

    def draw_background(self):
        if self.canvas is not None:
            self.canvas.before.clear()
            with self.canvas.before:
                Color(*self.bgcolor)
                Rectangle(pos=self.pos, size=self.size)

    def on_size(self, *args):
        self.draw_background()

    def on_pos(self, *args):
        self.size = self.texture_size
        self.draw_background()


class MyApp2(App):

    def __init__(self):

        super().__init__()

        self.layout = BoxLayout()
        self.layout.orientation = 'vertical'

        self.labels = [
            Label(text='label_0', color=(0, 0, 0, 1)),
            LabelWithBackground(text='label_1', color=(0, 0, 0, 1), size_hint=(.5, None), bgcolor=(1, .5, 0, 1)),
            Label(text='label_2', color=(0, 0, 0, 1)),
            LabelWithBackground(text='label_3', color=(0, 0, 0, 1), size_hint=(None, .25), bgcolor=(1, .5, 0, 1)),
            Label(text='label_4', color=(0, 0, 0, 1)),
            LabelWithBackground(text='label_5', color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))]

        for lbl in self.labels:
            self.layout.add_widget(lbl)

    def build(self):
        return self.layout


if __name__ == '__main__':

    Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
    Window.clearcolor = (1, 1, 1, 1)

    MyApp2().run()

Как это выглядит:

enter image description here

0 голосов
/ 17 января 2019

Реализация кода, который вам требуется:

from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color

mainscreen = BoxLayout(orientation='vertical')

label1 = Label(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None))
label1.bind(texture_size=label1.setter('size'))
def update_rect(instance, *args):
    rect.pos = instance.pos
    rect.size = instance.size
with label1.canvas.before:
    Color(1, .5, 0, 1)
    rect = Rectangle(pos=label1.pos, size=label1.size)
label1.bind(pos=update_rect, size=update_rect)

label2 = Label(text='label_2', color=(0, 0, 0, 1))

mainscreen.add_widget(label1)
mainscreen.add_widget(label2)

class MyApp(App):
    def build(self):
        return mainscreen

if __name__ == '__main__':
    Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
    Window.clearcolor = (1, 1, 1, 1)
    MyApp().run()

ИМХО реализация в kv более читабельна и более гибка, когда выполняется связывание, как в случае метки, которая соответствует размеру.


from kivy.config import Config
from kivy.core.window import Window
from kivy.app import App

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color

from kivy.properties import ListProperty


class CustomLabel(Label):
    bgcolor = ListProperty([0, 0, 0, 1])
    def __init__(self, **kwargs):
        if kwargs.get('bgcolor'):
            self.bgcolor = kwargs['bgcolor']
            kwargs.pop('bgcolor')
        super(CustomLabel, self).__init__(**kwargs)
        self.bind(texture_size=self.setter('size'))

        with self.canvas.before:
            self.p = Color(*self.bgcolor)
            self.rect = Rectangle(pos=self.pos, size=self.size)

        self.on_bgcolor()
        self.bind(pos=self.geometry_bind, size=self.geometry_bind)

    def on_bgcolor(self, *args):
        self.p.rgba = self.bgcolor

    def geometry_bind(self, *args):
        self.rect.pos = self.pos
        self.rect.size = self.size


class MyApp(App):
    def build(self):
        mainscreen = BoxLayout(orientation='vertical')
        label1 = CustomLabel(text='label_1', font_size=18, color=(0, 0, 0, 1), size_hint=(None, None), bgcolor=(1, .5, 0, 1))
        label2 = Label(text='label_2', color=(0, 0, 0, 1))
        mainscreen.add_widget(label1)
        mainscreen.add_widget(label2)
        return mainscreen

if __name__ == '__main__':
    Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
    Window.clearcolor = (1, 1, 1, 1)
    MyApp().run()

Пояснение:

  • bind: функция bind(foo_property = callback) отвечает за вызов обратного вызова при изменении foo_property.

  • setter: функция setter('foo_property') генерирует обратный вызов, который позволяет вам установить значение.

Если вы присоединитесь к обеим функциям:

class FooClass(Foo_EventDispatcher):
    property_a = FooProperty(initial_value_a)
    property_b = FooProperty(initial_value_b)

    def __init__(self, **kwargs):
       super(FooClass, self).__init__(**kwargs)
       self.bind(property_a=self.setter('property_b'))

эквивалентно следующей инструкции в .kv:

<FooClass>:
    property_b: self.property_a
...