在 Kivy 中,我如何从另一个以 kv 语言显示的另一个屏幕获取变量

Posted

技术标签:

【中文标题】在 Kivy 中,我如何从另一个以 kv 语言显示的另一个屏幕获取变量【英文标题】:In Kivy How do i get a variable from another screen displayed in another in kv language 【发布时间】:2022-01-12 20:44:23 【问题描述】:

我正在尝试从 kivy 文档修改乒乓球游戏。

我已经制作了一个“游戏结束”屏幕,应用程序在宣布获胜者后进入该屏幕,在那里我想要一个显示获胜者得分的标签,使用下面使用的方法我在标签中得到完全不同的输出,

有人可以解释一下我应该如何实现吗?谢谢!!

相关代码位于两者的底部,我只是将整个代码包括在内,以防问题出在其他地方。

import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty
from kivy.vector import Vector
from kivy.uix.floatlayout import FloatLayout
from kivy.uix import label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label





class WindowManager(ScreenManager):

    def On_Win(self):
        p1 =self.Game.player_1.score



class MenuWindow(Screen):
    pass 

class PongBall(Widget):
    velocity_y= NumericProperty(0)
    velocity_x= NumericProperty(0)

    velocity=ReferenceListProperty(velocity_x,velocity_y)

    def move(self):
        self.pos = Vector(self.velocity) +self.pos



class PongPad(Widget):

    score=NumericProperty(0)

    def Check_bounce(self,ball):
        if self.collide_widget(ball)   :
            vx,vy= ball.velocity
            bounced= Vector(-1* vx, vy )
            speedup= abs(((ball.velocity_x *0.1) -(ball.center_y - self.center_y)) *0.002) 
            vel = bounced *  (speedup +1.1)
            offset=(((ball.center_y - self.center_y)/2) - (ball.velocity_x /2)) *0.1
            if (ball.center_y - self.center_y) > 0:
                ball.velocity=vel.x,vel.y
                ball.velocity_y= 2
            else:
                ball.velocity= vel.x,vel.y
                ball.velocity_y= -2


class Game(Screen):



    ball = ObjectProperty(None)
    player_1 = ObjectProperty(None)
    player_2 = ObjectProperty(None)
    win1=NumericProperty(0)
    win2=NumericProperty(0)
    def on_enter(self, *args):
        self.serve_ball()
        Clock.schedule_interval(self.update, 1.0/60.0)

    def Winner(self):
        Winner=""
        if self.player_1.score==2:
            if self.manager.current != "WinGame":
                self.manager.current = "WinGame"
                Winner = "P1 with",str(self.player_1.score) 
        if self.player_2.score == 2:
            if self.manager.current !="WinGame":
                self.manager.current = "WinGame"
                Winner = "P2 with",str(self.player_2.score)

    def TEST(self):#TESTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
        Winner=""
        if self.player_1.score>=2:
            Winner = "P1 with",str(self.player_1.score)
        print("1")
        print(Winner)
        return Winner
    def serve_ball(self,vel=(4,0)):
        print("234Served")
        self.ball.velocity= vel
        self.ball.center = self.center
        self.player_1.center_y=self.center_y
        self.player_2.center_y=self.center_y


    def Check_Top_Bottom(self):
        #Check bottom collion
        if self.ball.y <0:
            self.ball.velocity_y= abs(self.ball.velocity_y)

        #Check top colision
        if self.ball.y+50> self.height:
            self.ball.velocity_y = -abs(self.ball.velocity_y)

    def Check_if_score(self):#Score
        if self.ball.x >self.width:
            self.player_1.score +=1
            self.win1 +=1
            self.serve_ball()
        if self.ball.x+50 <0:
            self.player_2.score += 1
            self.win2 +=1
            self.serve_ball()

    def update(self,dt):
        self.ball.move()
        self.Check_Top_Bottom()
        self.Check_if_score()
        self.player_1.Check_bounce(self.ball)
        self.player_2.Check_bounce(self.ball)
        self.Winner()
        #print("from Update: ",self.Get_Score())


    def on_touch_move(self,touch):
        if touch.x > self.width/2:
            self.player_2.center_y = touch.y
        else:
            self.player_1.center_y= touch.y



class WinGameScreen(Screen):
    def Get_Win(self):
        screen_manager = self.manager
        game = screen_manager.get_screen('Game')
        a= game.TEST()
        return a


kv= Builder.load_file("myMenu.kv")


class myMenuApp(App):
    def build(self):
        return kv




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

这里是kv文件:

WindowManager:
    MenuWindow:
    Game:
    WinGameScreen:

<MenuWindow>:
    name: "Menu"
    FloatLayout:
        Button:
            size_hint: 0.2,0.05
            pos_hint: "x":0.39,"y":0.75
            text:"Play"
            on_release:
                app.root.current= "Game"
                root.manager.transition.direction= "left"
        Button:
            size_hint: 0.2,0.05
            pos_hint: "x":0.39,"y":0.7
            text:"Settings"
        Button:
            size_hint: 0.2,0.05
            pos_hint: "x":0.39,"y":0.65
            text:"High Score"
        Button:
            size_hint: 0.2,0.05
            pos_hint: "x":0.39,"y":0.6
            text:"Quit"

<PongBall>
    size_hint: None, None
    size: 50,50
    canvas:
        Ellipse:
            pos:self.pos
            size:self.size




<PongPad>
    size_hint: None, None
    size:25,150
    canvas:
        Rectangle:
            pos:self.pos
            size:self.size

<Game>:
    name:"Game"
    ball: Pong_ball
    player_1: Player1
    player_2: Player2


    canvas:
        Rectangle:
            pos:self.center_x -5,0
            size: 15,root.height

    PongPad:
        id: Player2
        pos:root.width-25,root.center_y-75

    PongPad:
        id: Player1
        pos:0,root.center_y-75

    PongBall:
        id: Pong_ball
        center: self.parent.center



        FloatLayout:

        Label:
            text:str(root.player_1.score)
            top:root.top -1
            x:root.width -100

        Label:
            text:"Player 2:"
            top: root.top-1
            x:root.width - 135

        Label:
            text: str(root.player_2.score)
            top: root.top -1
            x: root.x+25


        Label
            text: "Player 1:"
            top:root.top-1
            x:root.x -10

<WinGameScreen>:
    name:"WinGame"

    Label:
        id: Final_score
        text: str(root.Get_Win)
        y:0.2

【问题讨论】:

我在代码中看不到Game End Screen。而且我看不到您要在哪个Label 中显示最终分数。正如我在kv 中记得的那样,您可以使用app 而不是root 来访问主类-稍后您可以尝试使用ids 来访问主类中的对象/子类。最终,您可以尝试使用.parent 或许多.parent.parent 来访问前一个元素 - 即在Screen 中,您可以尝试使用它来访问ScreenManage,然后使用.ids 来访问其他Screen 和此屏幕中的元素。 坦率地说,我不知道你为什么不直接在def Get_Win(self): 中设置标签中的值。 BTW root.Get_Win 应该引用函数 - 如果你想从函数中获取价值,那么你应该使用它和 () 来运行函数 - root.Get_Win() 顺便说一句:如果你想将文本分配给变量,那么你应该格式化字符串 - "P1 with " + str(self.player_1.score) - 或使用 f-string f"P1 with self.player_1.score" - 因为使用 "P1 with ",str(self.player_1.score) 你创建元组和 print() 将用( , )显示它 【参考方案1】:

在您的kv 中,一行:

    text: str(root.Get_Win)

在加载kv 时将Label 的文本设置为Get_Win() 方法的字符串版本。它没有运行Get_Win() 方法。您可以删除该行。

由于您在游戏结束时切换到WinGameScreen,因此您可以为WinGameScreen 定义一个on_enter() 方法,该方法将在输入Screen 时运行:

class WinGameScreen(Screen):
    def on_enter(self, *args):
        screen_manager = self.manager
        game = screen_manager.get_screen('Game')
        a= game.TEST()
        self.ids.Final_score.text = str(a)

【讨论】:

感谢您的智慧老师让代码现在运行

以上是关于在 Kivy 中,我如何从另一个以 kv 语言显示的另一个屏幕获取变量的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 KV 语言在 Kivy 中制作自定义按钮?

在 KV 语言中使用 Kivy Garden Graph

如何打印在.kv(kivy)中输入的TextInput值,以打印在.py文件中?

如何在 OSX 上的 Pycharm 中获得 Kivy、.kv、文件的语法高亮显示? [复制]

Kivy-kv语言VKeyboard

在 Kivy.kv 文件中,我如何引用另一个类中的方法