【问题标题】:how to solve kivy widget error "only one root object is allowed by .kv"如何解决 kivy 小部件错误“.kv 只允许一个根对象”
【发布时间】:2020-07-08 10:13:00
【问题描述】:

首先我想说我大概 2 个月前才开始学习,所以我真的不知道如何表达我的问题。因此,如果问题标题具有误导性,我很抱歉。

基本上我正在做一个项目,我想学习如何添加我已经在我制作的乒乓游戏(pong.py 和 pong.kv)中完成的项目,我想看看我是否可以使用我制作的简单应用程序(main.py、main.kv、playscreen.kv、settingscreen.kv、aboutscreen.kv)来运行乒乓球游戏。基本上我试图让主应用程序能够导航到播放屏幕,然后能够玩乒乓球

我什至不记得我尝试过的所有事情,但是当我想接近时,我最终会看到黑屏,或者我只看到乒乓屏幕,这就是我现在遇到的问题。

Main.py

from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.screen import Screen


class HomeScreen(Screen):
    pass

class SettingScreen(Screen):
    pass

class AboutScreen(Screen):
    pass

class PlayScreen(Screen):
    pass

class PlayPong(Screen):
    pass





#GUI = Builder.load_file("main.kv")

class MainApp(MDApp):
    def build(self):
        self.root = Builder.load_file("main.kv")
        self.theme_cls.primary_palette = "Teal"



    def change_screen(self,screen_name):
        screen_manager = self.root.ids['screen_manager']
        screen_manager.current = screen_name
        ScreenManager.transition
        #screen_manager.play_pong = Builder.load_file("kv/pong.py")




if __name__ == "__main__":
    MainApp().run()

Main.kv

#:include kv/homescreen.kv
#:include kv/settingscreen.kv
#:include kv/aboutscreen.kv
#:include kv/playscreen.kv
#:include kv/playpong.kv


GridLayout:
    cols: 1
    ScreenManager:
        id: screen_manager
        HomeScreen:
            name: "home_screen"
            id: home_screen
        SettingScreen:
            name: "setting_screen"
            id: setting_screen
        AboutScreen:
            name:"about_screen"
            id: about_screen
        PlayScreen:
            name:"play_screen"
            id: play_screen
        PlayPong:
            name: "play_pong"
            id: "play_pong"

playpong.kv

#:import PongApp kv.pong.PongApp
#:import App kivy.app.App

<PlayPong>:

#PongApp().run()

homescreen.kv

#:include kivymd/MDApp.py
#:include kivymd/uix/button.py/MDFloatingActionButton/MDFlatButton
#:include kivymd/uix/screen.py/Screen
#:import MDFillRoundFlatButton kivymd.uix.button.MDFillRoundFlatButton
#:import Builder kivy.lang.Builder

<HomeScreen>:
    FloatLayout:
        BoxLayout:
            orientation: 'horizontal'
            MDToolbar:
                pos_hint: {"center_x": .95, "center_y": .97}
                title: 'Main Menu'
                elevation:10
                left_action_items: [["home", lambda x: x]]
                right_action_items: [["book", lambda x: x]]

        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .3}
            size_hint: .8,.1
            md_bg_color: [.200,.150,.150,.3]
            text: "Settings"
            on_release:
                app.change_screen("setting_screen")
                root.manager.transition.direction = 'right'
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .5}
            size_hint: .8,.1
            md_bg_color: [.200,.150,.150,.3]
            text: "about"
            on_release:
                app.change_screen("about_screen")
                root.manager.transition.direction = 'right'
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .7}
            size_hint: .8,.1
            md_bg_color: [.200,.150,.150,.3]
            text: "play"
            on_release:
                app.change_screen("play_screen")
                root.manager.transition.direction = 'right'

playscreen.kv

<PlayScreen>:
    FloatLayout:
        BoxLayout:
            orientation: 'horizontal'
            MDToolbar:
                pos_hint: {"center_x": .95, "center_y": .95}
                title: 'Game Menu'
                elevation:10
                left_action_items: [["devices", lambda x: x]]
                right_action_items: [["gesture", lambda x: x]]
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .5}
            size_hint: .6,.1
            text: "Main Menu"
            md_bg_color: [.200,.150,.150,.3]
            on_release:
                app.change_screen("home_screen")
                root.manager.transition.direction = 'right'
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .3}
            size_hint: .6,.1
            text: "Play Pong"
            md_bg_color: [.200,.150,.150,.3]
            on_release:
                app.change_screen("play_pong")
                root.manager.transition.direction = 'right'

settingscreen.kv

#:include kivymd/MDApp.py
#:include kivymd/uix/button.py/MDFloatingActionButton/MDFlatButton
#:include kivymd/uix/screen.py/Screen
#:import MDFillRoundFlatButton kivymd.uix.button.MDFillRoundFlatButton
#:import Builder kivy.lang.Builder


<SettingScreen>:
    FloatLayout:
        BoxLayout:
            orientation: 'horizontal'
            MDToolbar:
                pos_hint: {"center_x": .95, "center_y": .95}
                title: 'Settings'
                left_action_items: [["settings", lambda x: x]]
                right_action_items: [["dns", lambda x: x]]
                elevation:10
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .5}
            size_hint: .6,.1
            text: "Main Menu"
            md_bg_color: [.200,.150,.150,.3]
            on_release:
                app.change_screen("home_screen")
                root.manager.transition.direction = 'left'

aboutscreen.kv

<AboutScreen>:
    FloatLayout:
        BoxLayout:
            orientation: 'horizontal'
            MDToolbar:
                pos_hint: {"center_x": .95, "center_y": .95}
                title: 'About The Game and Creator'
                elevation:10
                left_action_items: [["emoticon", lambda x: x]]
                right_action_items: [["library", lambda x: x]]
        Label:
            pos_hint: {"top":.9 , "left":.5}
            size_hint: 1,.2
            text:
                "About the app and the creator"
        MDFillRoundFlatButton:
            pos_hint: {"center_x": .5, "center_y": .5}
            size_hint: .6,.1
            text: "Main Menu"
            on_release:
                app.change_screen("home_screen")
                root.manager.transition.direction = 'right'

pong.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
from kivy.vector import Vector
from kivy.clock import Clock
from random import randint

class PongPaddle(Widget):
    score = NumericProperty(0)
    def bounce_ball(self,ball):
        if self.collide_widget(ball):
            ball.velocity_x *= -1.1

class PongBall(Widget):
    velocity_x = NumericProperty(0)
    velocity_y = NumericProperty(0)
    velocity = ReferenceListProperty(velocity_x,velocity_y)
# latest postion = Current velocity + Current Position
    def move(self):
        self.pos = Vector(*self.velocity) + self.pos

# moving the ball by calling move function
class PongGame(Widget):
    ball = ObjectProperty(None)
    player1 = ObjectProperty(None)
    player2 = ObjectProperty(None)

    def serve_ball(self):
        self.ball.velocity = Vector(4, 0).rotate(randint(0,360))

    def update(self, dt):
        self.ball.move()

        # bounce off top and bottom
        if (self.ball.y < 0) or (self.ball.y > self.height -30):
            self.ball.velocity_y *= -1

            # bounce off left and increase score
        if self.ball.x < -30:
            self.ball.velocity_x *= -1
            self.player1.score += 1

        # bounce of right
        if self.ball.x > self.width:
            self.ball.velocity_x *= -1
            self.player2.score += 1



        self.player1.bounce_ball(self.ball)
        self.player2.bounce_ball(self.ball)

    def on_touch_move(self, touch):
        if touch.x < self.width / 1/4:
            self.player1.center_y = touch.y
        if touch.x > self.width * 3/4:
            self.player2.center_y = touch.y

class PongApp(App):
    def build(self):
        game = PongGame()
        game.serve_ball()
        Clock.schedule_interval(game.update,0/60.0)
        return game

if __name__ == "__main__":
    PongApp().run()

pong.kv

<PongPaddle>:
    size: 20,200
    canvas:
        Color:
            rgba: 1,0,0,1
        Rectangle:
            pos: self.pos
            size: self.size



<PongBall>:
    size: 30,30
    canvas:
        Ellipse:
            pos: self.pos
            size: self.size


<PongGame>:
    ball : pong_ball
    player1 : player_left
    player2 : player_right
    canvas:
        Color:
            rgba: 0,0,1,1
        Rectangle:
            pos: self.center_x - 5, 0
            size: 10, self.height

    Label:
        font_size: 70
        center_x: root.width / 4
        top: root.top - 30
        text: str(root.player2.score)

    Label:
        font_size: 70
        center_x: root.width * 3/4
        top: root.top - 30
        text: str(root.player1.score)

    PongBall:
        id : pong_ball
        center: self.parent.center

    PongPaddle:
        id:player_left
        x : root.x
        center_y : root.center_y

    PongPaddle:
        id:player_right
        x : root.width - self.width
        center_y : root.center_y

所以在我更新我的应用程序后,我仍然收到小部件错误

 1:from kivy.app import App
 >>    2:from kivy.uix.widget import Widget
       3:from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
       4:from kivy.vector import Vector
 ...
 Only one root object is allowed by .kv

我尝试过使用这些类来尝试只制作一个小部件,但是这会弄乱代码并出现其他错误

我也尝试将所有 Pong.py 代码写入我的 Main.py 文件,但这似乎也不起作用。 无论如何感谢您的帮助!

【问题讨论】:

  • 显示的Screen 将是HomeScreen,但您还没有显示homescreen.kv 的内容。
  • 谢谢!我继续前进,把所有东西都放好了。

标签: python kivy kivy-language


【解决方案1】:

你看到乒乓球比赛的原因是因为这条线:

PongApp().run()

导入该文件后立即开始乒乓球游戏。

将该行替换为:

if __name__ == "__main__":
    PongApp().run()

这可以保护PongApp 的运行,除非pong.py 直接由python 运行,而不仅仅是导入。

【讨论】:

  • 是的,这似乎有效,但现在我得到一个错误... 1:from kivy.app import App >> 2:from kivy.uix.widget import Widget 3:from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty 4:from kivy.vector import Vector ... .kv 只允许一个根对象。
  • 在您的homescreen.kvsettingscreen.kv 中有#:include 语句包含不是kv 文件的文件。首先删除它们。 #:import 语句很好,但只能包含 kv 文件。如果这不能解决问题,请从main.py 中删除self.root = Builder.load_file("main.kv") 行,因为它将自动加载。
猜你喜欢
  • 2019-10-15
  • 1970-01-01
  • 2020-04-23
  • 1970-01-01
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 2012-07-14
相关资源
最近更新 更多