【问题标题】:Kivy background in scroll view滚动视图中的 Kivy 背景
【发布时间】:2013-02-22 03:31:29
【问题描述】:

测试应用程序摘要: 我正在编写一个带有可滚动视图(名为 Scroller)的 Kivy 应用程序,其中包含许多要查看的字段(名为 Field)。这些单独的字段有时真的很难区分,所以我决定为每个字段使用交替的背景颜色来帮助区分彼此。我的测试应用程序使用 20 个单独的字段,每个字段在深灰色和深灰色之间交替。

测试试验: 启动应用程序,程序看起来很棒。交替的背景看起来很好。即使我向下滚动应用程序看起来也很好。但是,当我向上滚动应用程序时,应用程序似乎变得很奇怪。文本随应用程序滚动,但背景不滚动。更好的是(讽刺地),文本开始消失在他们的邻居背景中。当我再次向下滚动(通过最远向上滚动点的点)时,问题似乎消失了。

简单的问题描述Field 的“背景颜色”在向上滚动事件期间弄乱了应用程序。

旁注:我还注意到应用程序在滚动过多后变得有点迟钝。我对 Kivy 的绘制周期不是很熟悉,但是 blitting 背景不应导致过度减速。

测试应用:

import kivy
kivy.require('1.0.7')

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.graphics import Color, Rectangle

class Main(App):
    def build(self):
        self.root = GridLayout(rows = 1)
        self.root.add_widget(Scroller())
        return self.root

class Scroller(ScrollView):
    def __init__(self):
        ScrollView.__init__(self)
        self.view = GridLayout(cols = 1, size_hint = (1, None))
        self.add_widget(self.view)
        self.view.bind(minimum_height = self.view.setter('height'))

        for i in range(20):
            self.view.add_widget(Field('Test field {}'.format(i),i%2 is 0))

class Field(GridLayout):
    def __init__(self, name, bg):
        assert isinstance(name, str)
        assert isinstance(bg, bool)
        self.bg = bg
        GridLayout.__init__(self,
                            rows = 1,
                            padding = 10,
                            size = (0, 60),
                            size_hint = (1, None))
        self.add_widget(Label(text = name))
        self.add_widget(Button(text = 'Test button',
                               size = (200, 0),
                               size_hint = (None, 1)))
        self.bind(pos = self.change_background)
        self.bind(size = self.change_background)

    def change_background(self, *args):
        with self.canvas.before:
            if self.bg:
                Color(0.2, 0.2, 0.2, mode = 'rgb')
            else:
                Color(0.1, 0.1, 0.1, mode = 'rgb')
            Rectangle(pos = self.pos, size = self.size)

if __name__ in ('__main__', '__android__'):
    app = Main()
    app.run()

【问题讨论】:

    标签: python kivy


    【解决方案1】:
    def change_background(self, *args):
            self.canvas.before.clear()#<- clear previous instructions
            with self.canvas.before:
                if self.bg:
                    Color(0.2, 0.2, 0.2, mode = 'rgb')
                else:
                    Color(0.1, 0.1, 0.1, mode = 'rgb')
                Rectangle(pos = self.pos, size = self.size)
    

    每次字段的位置/大小发生变化时,您都在向画布添加/堆积指令,而无需清除先前的指令。

    您还应该考虑将 kv 用于除小型 sn-p 之外的任何东西,它最终会为您节省大量时间。您可以像这样使用 kv 转换代码 ::

    import kivy
    kivy.require('1.0.7')
    
    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.scrollview import ScrollView
    from kivy.properties import ObjectProperty, BooleanProperty
    from kivy.lang import Builder
    
    Builder.load_string('''
    <Scroller>
        # root is Scroller here
        # create a new ObjectProperty in kv that holds the ref to Gridlayout
        # so you can access the instance in python code
        view: glayout
        GridLayout:
            id: glayout
            cols: 1
            size_hint: (1, None)
            height: self.minimum_height
    
    <Field>
        canvas.before:
            Color:
                rgba: (0.2, 0.2, 0.2, 1) if self.bg else (0.1, 0.1, 0.1, 1)
            Rectangle:
                # binding properties is done implicitly and instructions aren't
                # piled up while doing that.
                pos: self.pos
                # self here refers to Field as `self` is supposed to refer to the
                # Widget not the drawing instruction
                size: self.size
        rows: 1
        padding: 10
        size: (0, 60)
        size_hint: (1, None)
        Label:
            text: root.name
        Button:
            text: 'test button'
            size: (200, 0)
            size_hint: (None, 1)
    ''')
    
    
    class Main(App):
    
        def build(self):
            self.root = GridLayout(rows = 1)
            self.root.add_widget(Scroller())
            return self.root
    
    
    class Scroller(ScrollView):
        def __init__(self, **kwargs):
            super(Scroller, self).__init__(**kwargs)
            for i in range(20):
                # access self.view that was set in kv
                self.view.add_widget(
                                    Field(
                                        name = 'Test field {}'.format(i),
                                        bg = i%2 is 0))
    
    class Field(GridLayout):
    
        # use  kivy's Properties so it becomes easier to observe and apply changes
        # as a plus these can also be directly used in kv. As a advantage of using this now
        # you can change name and bg dynamically and the changes should be reflected on
        # screen
        name = ObjectProperty('Test field uninitialized')
    
        bg = BooleanProperty(False)
    
    
    if __name__ in ('__main__', '__android__'):
        app = Main()
        app.run()
    

    【讨论】:

      猜你喜欢
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-15
      相关资源
      最近更新 更多