如何将kivy中的下拉小部件与python类一起使用

如何将kivy中的下拉小部件与python类一起使用,python,class,drop-down-menu,kivy,query-by-example,Python,Class,Drop Down Menu,Kivy,Query By Example,所以,我认为至少有两种方法可以在这个页面上设置一个下拉菜单,但这两种方法都不能工作。我对kivy和编程一般来说都是新手,但我已经阅读了文档,似乎我根本不懂 我创建了以下示例: import kivy kivy.require('1.7.2') # replace with your current kivy version ! from kivy.app import App from kivy.uix.screenmanager import ScreenManager, Screen fr

所以,我认为至少有两种方法可以在这个页面上设置一个下拉菜单,但这两种方法都不能工作。我对kivy和编程一般来说都是新手,但我已经阅读了文档,似乎我根本不懂

我创建了以下示例:

import kivy
kivy.require('1.7.2') # replace with your current kivy version !

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown

class CustomDropDown(DropDown):
    pass

class HomeScreen(Screen):
    translateInput = ObjectProperty(None)
    translateButton = ObjectProperty(None)
    translateLabel = ObjectProperty(None)
    top_layout = ObjectProperty(None)
    dd_btn = ObjectProperty(None)
    drop_down = CustomDropDown()
    #notes_dropdown = ObjectProperty(None)


    dropdown = DropDown()
    notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
    for note in notes:
        # when adding widgets, we need to specify the height manually (disabling
        # the size_hint_y) so the dropdown can calculate the area it needs.
        btn = Button(text='%r' % note, size_hint_y=None, height=30)

        # for each button, attach a callback that will call the select() method
        # on the dropdown. We'll pass the text of the button as the data of the
        # selection.
        btn.bind(on_release=lambda btn: dropdown.select(btn.text))

        # then add the button inside the dropdown
        dropdown.add_widget(btn)

    # create a big main button
    mainbutton = Button(text='Usage Notes 2', size_hint=(1, 1))

    # show the dropdown menu when the main button is released
    # note: all the bind() calls pass the instance of the caller (here, the
    # mainbutton instance) as the first argument of the callback (here,
    # dropdown.open.).
    mainbutton.bind(on_release=dropdown.open)
    #dd_btn.bind(on_release=dropdown.open)

    # one last thing, listen for the selection in the dropdown list and
    # assign the data to the button text.
    dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
    #dropdown.bind(on_select=lambda instance, x: setattr(dd_btn, 'text', x))

    #top_layout.add_widget(mainbutton)


class dropdApp(App):

    def build(self):

        return HomeScreen()



if __name__ == '__main__':
    dropdApp().run()
这是相应的.kv文件:

#:kivy 1.7.2

<CustomDropDown>:
    Button:
        text: 'My first Item'
        size_hint_y: None
        height: 44
        on_release: root.select('item1')
    Label:
        text: 'Unselectable item'
        size_hint_y: None
        height: 44
    Button:
        text: 'My second Item'
        size_hint_y: None
        height: 44
        on_release: root.select('item2')

<HomeScreen>:
    id: home_screen
    translateInput: translateInputID
    translateButton: translateButtonID
    translateLabel: labelID
    top_layout: topLayoutID
    #notes_dropdown: notesDropDownID
    dd_btn: btn_ddID

    orientation: 'vertical'
    FloatLayout:
        size_hint: 1, .95
        TextInput:
            id: translateInputID
            text: 'cove'
            #text: 'ﻰﺸَﻣ'
            font_name: "data/fonts/DejaVuSans.ttf"
            background_color: 1, 1, 1, 1
            size_hint: .75, .1
            multiline: False
            pos_hint: {'x': .125, 'y': .45}
            text_size: self.size
            valign: 'middle'
            halign: 'center'
            padding: 5

        Button:
            id: translateButtonID
            text: 'Translate'
            pos_hint: {'x': .35, 'y': .35}
            size_hint: .3, .08
            valign: 'middle'
            halign: 'center'
            text_size: self.size
            on_release: root.translateButtonPressed()
            #on_press: root.manager.current = 'resultsscreen'

        Label:
            id: labelID
            text: 'Translator'
            text_size: self.size
            valign: 'middle'
            halign: 'center'
            pos_hint: {'x': .3, 'y': .75}
            size_hint: .4, .2
            #font_name: "simpo.ttf"
            #font_name: "5thgradecursive.ttf"
            #font_name: "AGA-Rasheeq-Regular.ttf"
            font_name: "data/fonts/DejaVuSans.ttf"
            font_size: 50

    BoxLayout:
        id: topLayoutID
        #cols: 2
        size_hint: 1, .05
        pos_hint: {'x': 0, 'y': .95}
        Button:
            #id: notesDropDownID 
            id: btn_ddID
            text: 'Usage Notes'
            on_release: root.drop_down.open
        Button:
            text: 'About'
它在python和kivy方面都给了我一个句柄来操作它,但是当您运行它并单击“用法说明”时,您可能会注意到,什么都没有发生

  • 第二个下拉菜单也是在kivy文档之后用python创建的。我认为它会在应用程序顶部创建第三个按钮,标题为“用法说明2”。我只是在尝试添加时出错。现在,行(我的文件中有53行):

    被注释掉或应用程序甚至无法运行,导致错误:

    AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'add_widget'
    
    我意识到这是我设定的

    top_layout = ObjectProperty(None)
    
    但这正是kivy建议对许多小部件所做的,我对许多其他小部件所做的都没有这个错误

  • 我相信这两个问题中的一个或两个对外面的人来说都很简单。我错过了什么

    第一个下拉菜单应附在kv文件底部已创建的按钮“用法说明”上。它附加到python中的类“CustomDropDown”,并在kv文件中附加相应的

    对于这一部分,您有正确的基本想法,但犯了两个主要错误

    首先,您的类定义错误,您通常不希望将代码放在类级别,它应该放在类方法中。如果希望在实例化类时运行它,则应将其放入
    \uuuu init\uuu
    方法中。下面粘贴的代码显示了执行此操作所需的简单更改。您还需要将
    drop\u down
    更改为
    self.drop\u down
    ,以便设置class属性,而不仅仅是生成局部变量

    有时您确实希望在类变量处创建变量,该变量可用于类的所有实例。Kivy属性就是一个例子,它们有特殊的行为来控制它们在实际类实例中的行为。尽管如此,这是一个例外,而不是您希望对大多数代码执行的操作

    实际上,我不完全确定代码失败的细节(不确定执行顺序/时间),但最终代码没有正确运行,小部件也没有正确初始化。如果遵循正常的
    \uuuuu init\uuuu
    过程,这一切都很好

    第二个错误是您的kv文件在发布时有
    :root.drop\u down.open
    。问题是kv冒号右边的所有内容都是纯python,在本例中,您不调用该函数,只需声明其名称,因此不会发生任何事情。您需要将其替换为
    root.drop\u down.open(self)
    ,以获得正确的行为,因为open方法需要一个小部件作为参数

    第二个下拉菜单也是在kivy文档之后用python创建的。我认为它会在应用程序顶部创建第三个按钮,标题为“用法说明2”。我只是在尝试添加时出错。现在,行(我的文件中有53行):

    这是代码在类级别而不是在
    \uuuu init\uuu
    方法中错误的另一个症状。问题是top_layout是一个ObjectProperty,在kv类中只显示为普通对象,因为该属性在类实例中管理其接口的特殊方式。当代码处于类级别时,它看不到特殊接口,因为它不是从类实例运行的(这与导致所有其他问题的原因相同),所以它会抛出错误,因为它看到的是ObjectProperty,而不是它的内容

    在如下更改代码的情况下,添加小部件可以正常工作,因为
    \uuuu init\uuuu
    从类实例运行,并且可以像普通属性一样与属性交互

    我做了以下更改,两个下拉列表似乎都正常工作:

    import kivy
    kivy.require('1.7.2') # replace with your current kivy version !
    
    from kivy.app import App
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import ObjectProperty
    from kivy.uix.button import Button
    from kivy.uix.dropdown import DropDown
    
    class CustomDropDown(DropDown):
        for i in range(5):
            print i 
    
    
    class HomeScreen(Screen):
        translateInput = ObjectProperty(None)
        translateButton = ObjectProperty(None)
        translateLabel = ObjectProperty(None)
        top_layout = ObjectProperty(None)
        dd_btn = ObjectProperty(None)
    
        def __init__(self, *args, **kwargs):
            super(HomeScreen, self).__init__(*args, **kwargs)
            self.drop_down = CustomDropDown()
            #notes_dropdown = ObjectProperty(None)
    
    
            dropdown = DropDown()
            notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
            for note in notes:
                # when adding widgets, we need to specify the height manually (disabling
                # the size_hint_y) so the dropdown can calculate the area it needs.
                btn = Button(text='%r' % note, size_hint_y=None, height=30)
    
                # for each button, attach a callback that will call the select() method
                # on the dropdown. We'll pass the text of the button as the data of the
                # selection.
                btn.bind(on_release=lambda btn: dropdown.select(btn.text))
    
                # then add the button inside the dropdown
                dropdown.add_widget(btn)
    
            # create a big main button
            mainbutton = Button(text='Usage Notes 2', size_hint=(1, 1))
            print 'yay' 
    
            # show the dropdown menu when the main button is released
            # note: all the bind() calls pass the instance of the caller (here, the
            # mainbutton instance) as the first argument of the callback (here,
            # dropdown.open.).
            mainbutton.bind(on_release=dropdown.open)
            #dd_btn.bind(on_release=dropdown.open)
    
            # one last thing, listen for the selection in the dropdown list and
            # assign the data to the button text.
            dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
            #dropdown.bind(on_select=lambda instance, x: setattr(dd_btn, 'text', x))
    
            self.top_layout.add_widget(mainbutton)
    
    class dropdApp(App):
    
        def build(self):
    
            return HomeScreen()
    
    
    
    if __name__ == '__main__':
        dropdApp().run()
    
    千伏:

    :
    按钮:
    文本:“我的第一项”
    尺寸提示:无
    身高:44
    发布时:root.select('item1')
    标签:
    文本:“不可选择项”
    尺寸提示:无
    身高:44
    按钮:
    文本:“我的第二项”
    尺寸提示:无
    身高:44
    发布时:root.select('item2')
    :
    id:主屏幕
    translateInput:translateInputID
    translateButton:translateButtonID
    翻译标签:labelID
    top_布局:topLayoutID
    #notes_下拉列表:notesDropDownID
    dd_btn:btn_ddID
    方向:“垂直”
    浮动布局:
    尺寸提示:1.95
    文本输入:
    id:translateInputID
    文字:“海湾”
    #正文:'ﻰﺸَﻣ' 
    字体名称:“data/fonts/DejaVuSans.ttf”
    背景颜色:1,1,1,1
    大小提示:.75,.1
    多行:False
    位置提示:{'x':.125,'y':.45}
    文本大小:self.size
    valign:“中间”
    哈利恩:“中心”
    填充:5
    按钮:
    id:translateButtonID
    文本:“翻译”
    位置提示:{'x':.35,'y':.35}
    大小提示:.3,.08
    valign:“中间”
    哈利恩:“中心”
    文本大小:self.size
    发布时:root.translateButtonPressed()
    #按:root.manager.current='resultsscreen'
    标签:
    id:labelID
    文本:“译者”
    文本大小:self.size
    valign:“中间”
    哈利恩:“中心”
    位置提示:{'x':.3,'y':.75}
    大小提示:.4,.2
    #字体名称:“simpo.ttf”
    #字体名称:“5thgrade草书.ttf”
    #字体名称:“AGA Rasheeq Regular.ttf”
    字体名称:“data/fonts/DejaVuSans.ttf”
    字体大小:50
    
    top_layout = ObjectProperty(None)
    
    import kivy
    kivy.require('1.7.2') # replace with your current kivy version !
    
    from kivy.app import App
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import ObjectProperty
    from kivy.uix.button import Button
    from kivy.uix.dropdown import DropDown
    
    class CustomDropDown(DropDown):
        for i in range(5):
            print i 
    
    
    class HomeScreen(Screen):
        translateInput = ObjectProperty(None)
        translateButton = ObjectProperty(None)
        translateLabel = ObjectProperty(None)
        top_layout = ObjectProperty(None)
        dd_btn = ObjectProperty(None)
    
        def __init__(self, *args, **kwargs):
            super(HomeScreen, self).__init__(*args, **kwargs)
            self.drop_down = CustomDropDown()
            #notes_dropdown = ObjectProperty(None)
    
    
            dropdown = DropDown()
            notes = ['Features', 'Suggestions', 'Abreviations', 'Miscellaneous']
            for note in notes:
                # when adding widgets, we need to specify the height manually (disabling
                # the size_hint_y) so the dropdown can calculate the area it needs.
                btn = Button(text='%r' % note, size_hint_y=None, height=30)
    
                # for each button, attach a callback that will call the select() method
                # on the dropdown. We'll pass the text of the button as the data of the
                # selection.
                btn.bind(on_release=lambda btn: dropdown.select(btn.text))
    
                # then add the button inside the dropdown
                dropdown.add_widget(btn)
    
            # create a big main button
            mainbutton = Button(text='Usage Notes 2', size_hint=(1, 1))
            print 'yay' 
    
            # show the dropdown menu when the main button is released
            # note: all the bind() calls pass the instance of the caller (here, the
            # mainbutton instance) as the first argument of the callback (here,
            # dropdown.open.).
            mainbutton.bind(on_release=dropdown.open)
            #dd_btn.bind(on_release=dropdown.open)
    
            # one last thing, listen for the selection in the dropdown list and
            # assign the data to the button text.
            dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
            #dropdown.bind(on_select=lambda instance, x: setattr(dd_btn, 'text', x))
    
            self.top_layout.add_widget(mainbutton)
    
    class dropdApp(App):
    
        def build(self):
    
            return HomeScreen()
    
    
    
    if __name__ == '__main__':
        dropdApp().run()
    
    <CustomDropDown>:
        Button:
            text: 'My first Item'
            size_hint_y: None
            height: 44
            on_release: root.select('item1')
        Label:
            text: 'Unselectable item'
            size_hint_y: None
            height: 44
        Button:
            text: 'My second Item'
            size_hint_y: None
            height: 44
            on_release: root.select('item2')
    
    <HomeScreen>:
        id: home_screen
        translateInput: translateInputID
        translateButton: translateButtonID
        translateLabel: labelID
        top_layout: topLayoutID
        #notes_dropdown: notesDropDownID
        dd_btn: btn_ddID 
    
        orientation: 'vertical'
        FloatLayout: 
            size_hint: 1, .95
            TextInput:
                id: translateInputID
                text: 'cove'
                #text: 'ﻰﺸَﻣ' 
                font_name: "data/fonts/DejaVuSans.ttf"
                background_color: 1, 1, 1, 1
                size_hint: .75, .1
                multiline: False
                pos_hint: {'x': .125, 'y': .45} 
                text_size: self.size
                valign: 'middle'
                halign: 'center'
                padding: 5
    
            Button:
                id: translateButtonID
                text: 'Translate'
                pos_hint: {'x': .35, 'y': .35}
                size_hint: .3, .08
                valign: 'middle'
                halign: 'center'
                text_size: self.size
                on_release: root.translateButtonPressed()
                #on_press: root.manager.current = 'resultsscreen'
    
            Label:
                id: labelID
                text: 'Translator'
                text_size: self.size
                valign: 'middle'
                halign: 'center'
                pos_hint: {'x': .3, 'y': .75}
                size_hint: .4, .2
                #font_name: "simpo.ttf"
                #font_name: "5thgradecursive.ttf"
                #font_name: "AGA-Rasheeq-Regular.ttf"
                font_name: "data/fonts/DejaVuSans.ttf"
                font_size: 50
    
        BoxLayout:
            id: topLayoutID
            #cols: 2
            size_hint: 1, .05
            pos_hint: {'x': 0, 'y': .95}
            Button:
                #id: notesDropDownID
                id: btn_ddID
                text: 'Usage Notes'
                on_release: root.drop_down.open(self)
            Button:
                text: 'About'
    
    class DropBut(Button):
        def __init__(self, **kwargs):
            super(DropBut, self).__init__(**kwargs)
            self.drop_list = None
            self.drop_list = DropDown()
    
            types = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6']
    
            for i in types:
                btn = Button(text=i, size_hint_y=None, height=50)
                btn.bind(on_release=lambda btn: self.drop_list.select(btn.text))
               
                self.drop_list.add_widget(btn)
    
            self.bind(on_release=self.drop_list.open)
            self.drop_list.bind(on_select=lambda instance, x: setattr(self, 'text', x))