Kivy中奇怪的滚动行为

时间:2016-05-27 19:17:27

标签: python python-3.x kivy

我有一个getDirTree和一个ScrollView,它与它部分重叠并包含Bubble
问题:

  • 如何在不移除小部件的情况下隐藏小部件?

我已经阅读了关于该主题的question的答案,建议要么合并GridLayoutdisabled属性,这是我最终使用的属性,或者暂时将小部件移出屏幕。使用第一种隐藏opacity的方法,我发现即使它被禁用,它也会阻止其后面的视图滚动,即使文档说明了这个属性

  

指示此窗口小部件是否可以与输入进行交互

所以我认为它不应该阻止滚动。有趣的是,当它没有被隐藏(Bubble)时,滚动正好通过它,这更加令人困惑

我之前还有disabled=False包含Bubble,而ScrollView又持有GridLayout。以下问题不再是问题,但仍然是一个有趣的行为:

  • 为什么Bubble通过向上滚动,但没有通过向下滚动?

要理解我的意思,请运行代码,将鼠标移到Bubble上,然后尝试使用鼠标滚轮向不同方向滚动。这是考虑到GridLayout中的ScrollView不包含任何内容,即使它不会影响行为

以下是两个问题的代码以及获得所需行为的一些说明:

from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.bubble import Bubble
from kivy.properties import ListProperty

Builder.load_string('''
<SmileBubble>:
    size_hint: None, None
    pos: 220, 90
    size: 175, 250

    #ScrollView:
        #GridLayout:
            #rows: 8        # To see the second question's example, uncomment this section
                            # and comment out the one below
    GridLayout:
        rows: 8

<MessageView>:
    canvas:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            pos: self.pos
            size: self.size

<Message>:
    BoxLayout:
        pos: root.pos
        height: self.height
        TextInput:
            pos: root.pos
            size: root.size
            id: msg

''')

class Message(Widget):
    bg_color = ListProperty([0.99, 0.99, 0.99, 1])

class SmileBubble(Bubble):
    def hide(self):
        self.disabled = True

    def show(self):
        self.disabled = False

class MessageView(ScrollView):
    pass

class TestApp(App):
    def msg_in(self, text):
        msg = Message()
        msg.ids['msg'].text = text
        msg.size_hint = [None, None]
        msg.width = 160
        self.msg_layout.add_widget(msg)

    def build(self):
        self.scr = Screen()
        self.sv1_main = MessageView()
        self.msg_layout = GridLayout(cols = 1,
                                     size_hint_y = None)
        self.msg_layout.bind(minimum_height = self.msg_layout.setter('height'))

        self.smile_bbl = SmileBubble()
        for i in range(10):
            self.msg_in("test")

        self.smile_bbl.hide()      # To hide/show the Bubble, comment out this line. For the second question, comment out this line

        self.scr.add_widget(self.sv1_main)
        self.sv1_main.add_widget(self.msg_layout)
        self.scr.add_widget(self.smile_bbl)

        return self.scr

TestApp().run()

如果重要,我会使用Kivy v1.9.2-dev0

1 个答案:

答案 0 :(得分:1)

如果你不想要不透明度和禁用技巧(很好的)或类似y = 5000之类的东西,例如ScrollView不能正常工作BoxLayout - 并明确使用它会导致你的canvas.clear拉伸,我看到“两个”简单的选项,虽然不是没有删除 - 但保留!

首先,如果你可以访问它们,可以获取所有画布说明,将它们复制到某处from kivy.lang import Builder from kivy.base import runTouchApp from kivy.uix.boxlayout import BoxLayout Builder.load_string(''' <Test>: orientation: 'vertical' Button: on_release: root.move_me() BoxLayout: id: box Button: text: 'Hi %s!' % self.parent Button: id: box2 ''') class Test(BoxLayout): def move_me(self): if self.ids.box.children: button = self.ids.box.children[0] self.ids.box.remove_widget(button) self.ids.box2.add_widget(button) else: button = self.ids.box2.children[0] self.ids.box2.remove_widget(button) self.ids.box.add_widget(button) runTouchApp(Test()) ,但如果出现问题,可以找到错误。

第二个基本上是第一个,但是在三个命令中,除非你忘记了小部件的去向(hehe),否则你不能搞砸了什么:

  • 复制小部件
  • 从不应该看到的小部件中移除小部件
  • 添加以后可以访问的地方

button.<something>

您可以看到小部件仍然存在于变量中,您可以通过text访问其属性,如Boxlayout中所示。

现在,如果你在例如GridLayoutpos以错误的方式:父级中的小部件[1, 2, 3].remove(2)得到更新,与列表[1, 3]完全相同,最终列表为BoxLayout,其中my_widgets = <parent>.children[<widget you want to hide>:len(<parent>.children)-1] 表示将大小分成两半而不是三分之一。

如何解决这个问题?简单地说,再次使用上面的技巧,但现在保存更多小部件 - 您要隐藏的小部件+稍后添加到父的每个小部件

Widget

它将为您提供一个对象列表,即再次按原样保留所有内容,您只会“弹出”您不想看到的小部件。最后使用相同的size(甚至可能是pos制作占位符(例如for child in my_widgets: <parent>.add_widget(child) 或透明的任何内容),但这是自动计算的,因此...)您想要的小部件隐藏和:

disabled=True

这种方法(或者更确切地说是我的解释)可能看起来很难,但比从父母的边界框中丢弃一个小部件或尝试Bubble更简单,这对你来说导致无法滚动(否则我肯定会那样做。)将Widget替换为Color,您就可以滚动了。它会被放置到[0,0],但这不是一个参数,好像你用Rectangle&amp; Widget看到它,滚动光标放在master上(至少对我来说from kivy.lang import Builder from kivy.base import runTouchApp from kivy.uix.boxlayout import BoxLayout from kivy.uix.widget import Widget Builder.load_string(''' <Test>: orientation: 'vertical' Button: text: 'hide' on_release: root.hide(box) BoxLayout: id: box Button: text: 'Hi %s!' % self.parent Button text: 'Retrieve' on_release: root.hide(root.placeholder, root.saved) ''') class Test(BoxLayout): def hide(self, what, retrieve=None): # you'll need that object accessible and ".parent" will disappear parent = what.parent children = what.parent.children[:] # check for position in children list place = children.index(what) # save the widget you want to hide self.saved = children[place] # save children from the latest added to the removed one saved_children = children[0:place+1] # sizes are optional here self.placeholder = Widget(size_hint=[None, None], size=saved_children[0].size) for child in saved_children: parent.remove_widget(child) # here you still can use what.parent # here the ".parent" is not available - the reason for "parent" var. # add Widget instead of whatever you will "hide" # pass to "retrieve" the saved widget if you want it back parent.add_widget(self.placeholder if not retrieve else retrieve) # add widgets in order they were originally added to the parent for child in list(reversed(saved_children[:place])): parent.add_widget(child) # cleanup mess ^^ del children, saved_children runTouchApp(Test()) 使用你的代码)。

最后:从中创建一个函数

NSTextFieldDelegate