【问题标题】:Access python list in kivy file访问kivy文件中的python列表
【发布时间】:2021-06-22 00:04:04
【问题描述】:

我是一名物理学家,众所周知,我们喜欢我们的鸡尾酒。因此,我正在尝试建立一个自动调酒师。不幸的是,我在 python 中编程的唯一经验就是进行物理模拟,而且我对编码并不精通。

我的问题现在是这样的:我想在 kivy 文件中使用 BartenderApp 类中有一个 python 列表,特别是在 kivy 文件中的 LoadNewIngredients 中,供微调器使用选项来自。我已经寻找了很长一段时间的解决方案,但到目前为止还没有一个有效的解决方案。我知道我应该能够使用 for 循环将微调器和标签放入 python 文件中,但我更希望它更干净一些并将它们保存在 kivy 文件中。

因此,如果有人可以帮助我如何将列表传递给 kivy 文件,将不胜感激!

这是 .py 文件:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.clock import mainthread
from functools import partial
#Import drink list
from drinks import drink_list, drink_options

class drink:
    def __init__(self,name,ingredients,amount):
        self.name = name
        self.ingredients = ingredients
        self.amount = amount

#Define the different screens
class MainMenu(Screen):
    pass

class UseLastIngredients(Screen):
    pass

class DrinkMenu(Screen):

    #Mainthread will pause shortly to give script time, the rest adds the buttons
    @mainthread
    def on_enter(self):
        self.buttons = []
        self.ids.drinks.clear_widgets()
        for btn in range(len(drink_list)):
            self.buttons.append(Button(text=str(drink_list[btn]['name'])))
            self.buttons[btn].bind(on_press = self.pour_drink)
            self.ids.drinks.add_widget(self.buttons[btn])


    def pour_drink(self, button):
        print(button.text)


class LoadNewIngredients(Screen):
    def spinner_clicked(self, ident, value):
        if ident == 1:
            pass
        if ident == 2:
            pass
        if ident == 3:
            pass
        if ident == 4:
            pass
        if ident == 5:
            pass
        if ident == 6:
            pass
        if ident == 7:
            pass
        if ident == 8:
            pass


#Define the ScreenManager
class MenuManager(ScreenManager):
    pass

#Designate the .kv design file
kv = Builder.load_file('bartenderkv.kv')

class BartenderApp(App):

    #I want to use the ingredients list in the kivy file
    global ingredients
    ingredients = []
    for drink in range(len(drink_list)):
        ings = list(drink_list[drink]['ingredients'].keys())
        for ing in range(len(ings)):
            elem = ings[ing]
            if elem not in ingredients:
                ingredients.append(elem)

    def build(self):
        return kv

if __name__ == '__main__':
    BartenderApp().run()

这是 .kv 文件:

#:import Factory kivy.factory.Factory
#:import ScrollView kivy.uix.scrollview

MenuManager:
    MainMenu:
    LoadNewIngredients:
    DrinkMenu:

<MainMenu>:
    name: "MainMenu"
    GridLayout:
        rows: 3
        size: root.width, root.height
        padding: 10
        spacing: 10

        Label:
            text: "Main Menu"
            font_size: 32

        GridLayout:
            cols: 2
            size: root.width, root.height
            spacing: 10
            Button:
                text: "Use Last Ingredients"
                font_size: 32
                on_release: app.root.current = "DrinkMenu"
            Button:
                text: "Load New Ingredients"
                font_size: 32
                on_release: app.root.current = "LoadNewIngredients"
        Button:
            text: "See Permissable Ingredients"
            font_size: 32
            #on_press: print("It Works")
            on_release: Factory.PermissablePopup().open()

<LoadNewIngredients>:
    name: "LoadNewIngredients"
    GridLayout:
        cols: 2
        size: root.width, root.height
        padding: 10
        spacing: 10

        GridLayout:
            size: root.width, root.height
            size_hint_x: 0.4
            rows: 2
            Button:
                text: "Continue"
                font_size: 24
                on_release: app.root.current = "DrinkMenu"
            Button:
                text: "Main Menu"
                font_size: 24
                on_release: app.root.current = "MainMenu"
        GridLayout:
            
            #This is where I want the spinners to take in the ingredients list as options.

            id: choices
            rows: 4
            orientation: 'tb-lr'
            Label:
                id: pump_1
                text: "Pump 1"
                font_size: 24
            Label:
                id: pump_2
                text: "Pump 2"
                font_size: 24
            Label:
                id: pump_3
                text: "Pump 3"
                font_size: 24
            Label:
                id: pump_4
                text: "Pump 4"
                font_size: 24
            #Spinner is the easy drop down version in kivy, lets see how it looks.
            Spinner:
                id: spinner_id_1
                text: "Pump_1"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(1,spinner_id_1.text)

            Spinner:
                id: spinner_id_2
                text: "Pump_2"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(2,spinner_id_2.text)

            Spinner:
                id: spinner_id_3
                text: "Pump_3"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(3,spinner_id_3.text)

            Spinner:
                id: spinner_id_4
                text: "Pump_4"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(4,spinner_id_4.text)

            Label:
                id: pump_5
                text: "Pump 5"
                font_size: 24
            Label:
                id: pump_6
                text: "Pump 6"
                font_size: 24
            Label:
                id: pump_7
                text: "Pump 7"
                font_size: 24
            Label:
                id: pump_8
                text: "Pump 8"
                font_size: 24
            #Spinner is the drop down version, lets see how it looks.
            Spinner:
                id: spinner_id_5
                text: "Pump_5"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(5,spinner_id_5.text)

            Spinner:
                id: spinner_id_6
                text: "Pump_6"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(6,spinner_id_6.text)

            Spinner:
                id: spinner_id_7
                text: "Pump_7"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(7,spinner_id_7.text)

            Spinner:
                id: spinner_id_8
                text: "Pump_8"
                values: ["1", "2", "3"]
                on_text: root.spinner_clicked(8,spinner_id_8.text)

<DrinkMenu>:
    name: "DrinkMenu"
    GridLayout:
        cols: 2
        width: root.width
        height: self.minimum_height
        padding: 10
        spacing: 10
        GridLayout:
            height: root.height
            size_hint_x: 0.4
            rows: 2
            Button:
                text: "Top Up"
                font_size: 24
                on_release:
            Button:
                text: "Main Menu"
                font_size: 24
                on_release: app.root.current = "MainMenu"
        ScrollView:
            size_hint_y: 0.73
            pos_hint: {'x':0, 'y': 0.11}
            do_scroll_x: False
            do_scroll_y: True

            GridLayout:
                id: drinks
                orientation: 'lr-tb'
                size_hint_y: None
                size_hint_x: 1.0
                cols: 3
                height: self.minimum_height
                row_default_height: 180
                row_force_default: True

#Create a rounded button, the @Button is what it inherits
<RoundedButton@Button>
    background_color: (0,0,0,0)
    background_normal: ''
    canvas.before:
        Color:
            rgba:
                (48/255,84/255,150/255,1)\
                if self.state == 'normal' else (0.6,0.6,1,1) # Color is red if button is not pressed, otherwise color is green
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [58]

<PermissablePopup@Popup>
    auto_dismiss: False
    #size_hint: 0.6,0.2
    #pos_hint: {"x":0.2, "top":0.9}
    title: "Permissable Ingredients"
    GridLayout:
        rows: 2
        size: root.width, root.height
        spacing: 10
        GridLayout:
            cols: 2
            Label:
                text: "Sodas"
                font_size: 32
                #Add list of sodas
            Label:
                text: "Alcohol"
                font_size: 32
                #Add list of alcohols

        Button:
            text: "Done"
            font_size: 24
            on_release: root.dismiss()

【问题讨论】:

    标签: python user-interface kivy kivy-language


    【解决方案1】:

    尝试将 ListProperty (https://kivy.org/doc/stable/api-kivy.properties.html) 添加到您的 App 类。像这样:

    class BartenderApp(App):
    
        ingredients = ListProperty() 
        
        for drink in range(len(drink_list)):
            ings = list(drink_list[drink]['ingredients'].keys())
            for ing in range(len(ings)):
                elem = ings[ing]
                if elem not in self.ingredients:
                    self.ingredients.append(elem)
    

    列表属性可以在 Python 和 KV 文件中访问。更重要的是,它们可以绑定到回调,以便您可以创建自己的事件!

    在 KV 文件中,您现在可以引用 app.ingredients,并且当 app.ingredients 更改时,列表定义的任何对象都将自动更新。例如,如果您的 KV 文件中有以下标签:

    Label:
        text: app.ingredients[0]
    

    当您更改列表时,文本会自动更新。但请注意,如果您引用的索引中没有对象,您可能会遇到索引错误。

    让我知道你是如何处理这个问题的,以及它是否能解决你的问题。

    【讨论】:

    • 我明白了,我设法解决了它并发布了我的解决方案,但我也会尝试你的解决方案!我是否可以假设我可以从 kivy 文件中的任何位置使用 app.ingredients[0] 获取成分?
    • 没错,kv 文件中的每个小部件都有一个属性app,它允许它们访问App
    • 是否可以在 App 类中声明一个函数并使用 app.function_name() 调用它,在这种情况下返回列表?
    • 您好!我最终选择了自己的解决方案,因为列表也需要动态更新。
    【解决方案2】:

    我终于设法解决了它,也许不是最好的解决方案,但它确实有效。

    在 LoadNewIngredients 类中,我编写了一个函数来检查可用的成分并返回包含成分的列表。然后在 kivy 应用程序中使用 root.function_name() 引用该函数。

    .py 文件:

    #Everything needed for kivy
    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.lang import Builder
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.core.window import Window
    from kivy.uix.button import Button
    from kivy.clock import mainthread
    from functools import partial
    #Import drink list
    from drinks import drink_list, drink_options
    
    class drink:
        def __init__(self,name,ingredients,amount):
            self.name = name
            self.ingredients = ingredients
            self.amount = amount
    
    #Define the different screens
    class MainMenu(Screen):
        pass
    
    class UseLastIngredients(Screen):
        pass
    
    class DrinkMenu(Screen):
    
        #Mainthread will pause shortly to give script time, the rest adds the buttons
        @mainthread
        def on_enter(self):
            self.buttons = []
            self.ids.drinks.clear_widgets()
            for btn in range(len(drink_list)):
                self.buttons.append(Button(text=str(drink_list[btn]['name'])))
                self.buttons[btn].bind(on_press = self.pour_drink)
                self.ids.drinks.add_widget(self.buttons[btn])
    
        def pour_drink(self, button):
            print(button.text)
    
    class LoadNewIngredients(Screen):
        def spinner_clicked(self, ident, value):
            if ident == 1:
                pass
            if ident == 2:
                pass
            if ident == 3:
                pass
            if ident == 4:
                pass
            if ident == 5:
                pass
            if ident == 6:
                pass
            if ident == 7:
                pass
            if ident == 8:
                pass
        #I want to use the ingredients list in the kivy file
        def get_ingredients(self,*args,**kwargs):
            global ingredients
            ingredients = []
            for drink in range(len(drink_list)):
                ings = list(drink_list[drink]['ingredients'].keys())
                for ing in range(len(ings)):
                    elem = ings[ing]
                    if elem not in ingredients:
                        ingredients.append(elem)
            return ingredients
    
    
    #Define the ScreenManager
    class MenuManager(ScreenManager):
        pass
    
    #Designate the .kv design file
    kv = Builder.load_file('bartenderkv.kv')
    
    class BartenderApp(App):
    
        def build(self):
            return kv
    
    if __name__ == '__main__':
        BartenderApp().run()
    
    

    这是 .kv 文件:

    #Need to define everything, the ScreenManager is the entity that keeps tabs
    #on all the different menu windows
    
    #This is for the popup, lets you instansiate a class from anywhere
    #:import Factory kivy.factory.Factory
    #:import ScrollView kivy.uix.scrollview
    
    MenuManager:
        MainMenu:
        LoadNewIngredients:
        DrinkMenu:
    
    <MainMenu>:
        name: "MainMenu"
        GridLayout:
            rows: 3
            size: root.width, root.height
            padding: 10
            spacing: 10
    
            Label:
                text: "Main Menu"
                font_size: 32
    
            GridLayout:
                cols: 2
                size: root.width, root.height
                spacing: 10
                Button:
                    text: "Use Last Ingredients"
                    font_size: 32
                    on_release: app.root.current = "DrinkMenu"
                Button:
                    text: "Load New Ingredients"
                    font_size: 32
                    on_release: app.root.current = "LoadNewIngredients"
            Button:
                text: "See Permissable Ingredients"
                font_size: 32
                on_release: Factory.PermissablePopup().open()
    
    <LoadNewIngredients>:
        name: "LoadNewIngredients"
        GridLayout:
            cols: 2
            size: root.width, root.height
            padding: 10
            spacing: 10
            #size hint sets relative sized, x-dir, y-dir
            GridLayout:
                size: root.width, root.height
                size_hint_x: 0.4
                rows: 2
                Button:
                    text: "Continue"
                    font_size: 24
                    on_release: app.root.current = "DrinkMenu"
                Button:
                    text: "Main Menu"
                    font_size: 24
                    on_release: app.root.current = "MainMenu"
            GridLayout:
                id: choices
                rows: 4
                orientation: 'tb-lr'
                Label:
                    id: pump_1
                    text: "Pump 1"
                    font_size: 24
                Label:
                    id: pump_2
                    text: "Pump 2"
                    font_size: 24
                Label:
                    id: pump_3
                    text: "Pump 3"
                    font_size: 24
                Label:
                    id: pump_4
                    text: "Pump 4"
                    font_size: 24
                Spinner:
                    id: spinner_id_1
                    text: "Pump_1"
                    #This references the get_ingredients function in the main py file
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(1,spinner_id_1.text)
    
                Spinner:
                    id: spinner_id_2
                    text: "Pump_2"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(2,spinner_id_2.text)
    
                Spinner:
                    id: spinner_id_3
                    text: "Pump_3"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(3,spinner_id_3.text)
    
                Spinner:
                    id: spinner_id_4
                    text: "Pump_4"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(4,spinner_id_4.text)
    
                Label:
                    id: pump_5
                    text: "Pump 5"
                    font_size: 24
                Label:
                    id: pump_6
                    text: "Pump 6"
                    font_size: 24
                Label:
                    id: pump_7
                    text: "Pump 7"
                    font_size: 24
                Label:
                    id: pump_8
                    text: "Pump 8"
                    font_size: 24
                Spinner:
                    id: spinner_id_5
                    text: "Pump_5"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(5,spinner_id_5.text)
    
                Spinner:
                    id: spinner_id_6
                    text: "Pump_6"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(6,spinner_id_6.text)
    
                Spinner:
                    id: spinner_id_7
                    text: "Pump_7"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(7,spinner_id_7.text)
    
                Spinner:
                    id: spinner_id_8
                    text: "Pump_8"
                    values: root.get_ingredients()
                    on_text: root.spinner_clicked(8,spinner_id_8.text)
    
    <DrinkMenu>:
        name: "DrinkMenu"
        GridLayout:
            cols: 2
            width: root.width
            height: self.minimum_height
            padding: 10
            spacing: 10
            GridLayout:
                height: root.height
                size_hint_x: 0.4
                rows: 2
                Button:
                    text: "Top Up"
                    font_size: 24
                    on_release:
                Button:
                    text: "Main Menu"
                    font_size: 24
                    on_release: app.root.current = "MainMenu"
            ScrollView:
                size_hint_y: 0.1
                pos_hint: {'x':0, 'y': 0.11}
                do_scroll_x: False
                do_scroll_y: True
    
                GridLayout:
                    id: drinks
                    orientation: 'lr-tb'
                    size_hint_y: None
                    size_hint_x: 1.0
                    cols: 3
                    height: self.minimum_height
                    row_default_height: 100
                    row_force_default: True
    
    <RoundedButton@Button>
        background_color: (0,0,0,0)
        background_normal: ''
        canvas.before:
            Color:
                rgba:
                    (48/255,84/255,150/255,1)\
                    if self.state == 'normal' else (0.6,0.6,1,1)
            RoundedRectangle:
                size: self.size
                pos: self.pos
                radius: [58]
    
    <PermissablePopup@Popup>
        auto_dismiss: False
        #size_hint: 0.6,0.2
        #pos_hint: {"x":0.2, "top":0.9}
        title: "Permissable Ingredients"
        GridLayout:
            rows: 2
            size: root.width, root.height
            spacing: 10
            GridLayout:
                cols: 2
                Label:
                    text: "Sodas"
                    font_size: 32
                    #Add list of sodas
                Label:
                    text: "Alcohol"
                    font_size: 32
                    #Add list of alcohols
    
            Button:
                text: "Done"
                font_size: 24
                on_release: root.dismiss()
    
    

    如果其他人有同样的问题,希望这会有所帮助。 但如果有人有任何其他解决方案(或关于一般代码的建议),请告诉我!

    【讨论】:

      猜你喜欢
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多