0

我是 python 和 kivy 的新手,正在学习如何在 kivy 对象和 python 之间传递信息。我已经掌握了基本概念,但这个问题让我很难过。

我正在编写一个应用程序来管理分类为组的 GPS 航点。目的是让用户从 Spinner 中选择一个航路点组,该航路点组填充 RecycleView 中的航路点列表。然后用户从 RecycleView 列表中选择一个航路点。选择的航路点被传递以进行进一步处理。失败的是最后一步(通过)。

我在自己的开发程序中开发了这个航点管理功能,它按预期工作。当我将开发代码添加到 ScreenManager 时,问题就来了。这是一个更大项目的一小部分,所以我已经去除了下面代码中的所有干扰,并重新组织以使其更易于调试。

该应用程序有多个使用 ScreenManager 管理的屏幕。航点选择屏幕显示一个用于选择航点组的 Spinner 和一个用于选择航点的 RecycleView(称为 RV())。航点选择在类 RVItem() 中处理。Spinner、RecycleView 和 RVItem() 工作正常。当我尝试将所选航点传递回 kivy 代码中的标签时,会出现问题(在 ScreenManager 版本中)。RVItem.on_release() 事件处理程序成功捕获所选航点,但我不知道如何将选择发送回屏幕上的标签。我的问题出在 RVItem.on_release() 代码中。.kv 文件中 Label 的 id 是 route_id。我在 RVItem.on_release() 代码中留下了一些尝试将航点发送到 route_id.text 的列表,但我找不到任何可行的方法。我错过了什么?

我最后尝试使用route_id = ObjectProperty(None)类 Route() 访问标签。我也无法让它工作,但它不会影响程序的运行或崩溃方式,所以我将属性留在代码中以防它有用。

复制问题:将代码复制到文件 main.py 和 ScreenManager.kv 中。启动程序,当主菜单打开时,单击路线按钮。单击选择组微调器,从下拉列表中选择一个组,然后从 RecycleView 列表中选择一个航点。程序将在 RVItem.on_release() 代码结束时崩溃。错误将是KeyError: 'route_id'

     AttributeError: 'super' object has no attribute '__getattr__'

我花了几个小时试图自己弄清楚这一点。如果您可以提出解决方案,也请让我知道我应该如何自己进行调试。

我正在运行 Python 3.8 和 Kivy 2.0。

# main.py
# BoatInstruments.222
# Stripped down version to demonstrate the problem passing the 
# RecycleView's response back to the kivy Label
  
from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.factory import Factory
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.lang import Builder
from kivy.properties import ObjectProperty

Builder.load_file('ScreenManager.kv')


class ScreenManagement(ScreenManager):
    pass


class MainMenu(Screen):
    pass


class RVItem(Factory.Button):
    # Returns the waypoint selected by RecycleView()
    def get_data_index(self):
        return self.parent.get_view_index_at(self.center)

    @property
    def rv(self):
        return self.parent.recycleview

    def on_release(self):
        app = App.get_running_app()
        data_index = self.get_data_index()
        current_waypoint = app.waypoints[data_index]
        print("\r\ncurrent_waypoint = ", current_waypoint, "\r\n")                              # Successful to this point


        # Write the route (current_waypoint for debugging) to kivy label Route.route_id              # !!! FAIL !!!
        # These are some of the things that I tried.
        print("app.root is ", app.root)
        app.root.ids.route_id.text = current_waypoint                     # This works in dev code (without ScreenManager) because there class WMApp(App) returns the root widget Route()
        # root.ids.route_id.text = current_waypoint
        # root.route_id.text = current_waypoint
        # self.ids.route_id.text = current_waypoint
        # self.parent.ids.route_id.text = current_waypoint
        # scrRoute = app.root.ids.route_id.text
        # root.ids.screen_manager.get_screen('route')
        # scrRoute.ids.route_id.text = current_waypoint
        # self.route_id.text = current_waypoint




class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__()
        self.data = []                                                          # Initialize the list of Groups


class Route(Screen):
    # Presents a list of waypoint groups in a spinner. After choosing, populates rv_id.data with that group's waypoints.

    route_id = ObjectProperty(None)


    def spinner_clicked(self, value):                                           # value is the selected waypoint group
        # Get the Group's list of waypoints and send them to RV
        app = App.get_running_app()
        self.ids.rv_id.data = [{'text': item} for item in app.waypoints]

    def new_route(self):
        print("Attempting Route.new_route()")
        app = App.get_running_app()
        app.wptroute = []
        app.root.ids.route_id.text = ""                                         # !!! FAIL !!!


    def done_route(self):
        print("Attempting Route.done_route()")



class BoatInstrumentsApp(App):

    groups = ['CYC', 'MHYC', 'GRYC', 'CLYC', 'Cleveland']        # accessed in kivy via app.list_of_groups
    waypoints = ['GRSC A', 'GRSC B', 'GRSC C', 'GRSC D', 'GRSC E', 'GRSC F']
    wptroute = []

    def __init__(self, **kwargs):
        super().__init__(**kwargs)


    def build(self):
        return ScreenManagement()


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




# ScreenManager.kv

<ScreenManagement>:
    id: screen_manager
    MainMenu:
        id: mainmenu                                 
        name: 'mainmenu'                           
        manager: 'screen_manager'
    Route:
        id: route
        name: 'route'
        manager: 'screen_manager'


# ##################################################################
<MainMenu>:
    BoxLayout:
        orientation: 'vertical'
        padding: 120
        spacing: 30

        Label:
            text: "Main Menu"
            font_size: 60

        Button:
            text: "Route"
            font_size: 40
            on_release: app.root.current = 'route'
    
# ##################################################################
<Route>:
    route_id: route_id                                      # I added this property late. It may or may not be useful
    BoxLayout:
        orientation: 'horizontal'
        padding: 5
        spacing: 5

        BoxLayout:                                                             # Left column: Groups and Waypoints
            orientation: 'vertical'
            Spinner:                                                           # Spinner: Waypoint Group
                id: spinner_id
                size_hint: (1, 0.15)
                text: "Choose a group"
                font_size: '40dp'
                values: app.groups
                on_text: root.spinner_clicked(spinner_id.text)

            Label:
                size_hint: (1, 0.04)

            RV:                                                                         # RecycleView: Waypoints
                id: rv_id
                viewclass: 'RVItem'
                RecycleBoxLayout:
                    default_size: None, 30                                              # Set the RV child box height
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'
                    spacing: 5



        BoxLayout:                                                                      # Right column: Label, list of waypoints, two buttons
            id: box_id
            orientation: 'vertical'

            Label:
                text: "Route"
                size_hint: (1, 0.15)
                font_size: '40dp'


            # ########### HERE ###########################################
            #Display the route (or current_waypoint for debugging)
            Label:                                                  # This label will contain the waypoints of the route, line by line
                id: route_id
                text: "Route goes here"



            RelativeLayout:
                size_hint: 1, 0.24
                Button:                                                                 # Button: New Route
                    id: new_route_id
                    text: "New Route"
                    font_size: '40dp'
                    size_hint: 0.8, 0.48
                    pos_hint: {"x":0.1, "top":1}
                    on_release: root.new_route()

                Button:                                                                 # Button: Done
                    id: done_route_id
                    text: "Done"
                    font_size: '40dp'
                    size_hint: 0.8, 0.48
                    pos_hint: {"x":0.1, "bottom":1}
                    # on_release: root.done_route()
                    on_release: app.root.current = 'mainmenu'
4

1 回答 1

0

由于您使用的是ScreenManager,因此您可以使用 的get_screen()方法ScreenManager来访问Screen包含 的route_id Label。尝试更换:

app.root.ids.route_id.text = current_waypoint

和:

app.root.get_screen('route').ids.route_id.text = current_waypoint
于 2022-01-25T01:42:58.197 回答