我刚拿起Kivy并遇到了这个问题。如果有更好的方法来实现我一般的努力,我很乐意听到它。
我注意到的是,当我将一个小部件添加到另一个小部件时,如果我通过Python代码这样做,它将略微处于与我通过Kivy完成的位置不同的位置。我会在下面粘贴我的代码(现在它很短)你可以自己尝试一下,你会看到我的意思。
client.py:
import kivy
kivy.require('1.9.1') # current kivy version
from kivy.config import Config
Config.set('graphics', 'width', '360')
Config.set('graphics', 'height', '640')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, NumericProperty, ReferenceListProperty
from kivy.graphics import Color, Rectangle
from kivy.clock import Clock
from kivy.vector import Vector
from random import randint
class Bird(Widget):
'''
Bird Widget defines each sprite. / Test version: blue and red cards
Defined attributes:
SIZE
POSITION
(COLOR)
Upade the position of this widget individually every 0.7 seconds with 60 fps
'''
# set attributes
border_color = (1,1,1)
r = NumericProperty(0)
g = NumericProperty(0)
b = NumericProperty(0)
color = ReferenceListProperty(r, g, b) # initial color = red // maybe make it random
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(-3)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def __init__(self, **kwargs):
super(Bird, self).__init__(**kwargs)
self.pick_color()
# Randomly generate 0 or 1, and pick a color based on that
def pick_color(self):
color_num = randint(0,1)
if color_num == 0: # blue
self.color = (0,0,1)
elif color_num == 1: # red
self.color = (1,0,0)
# Move the widget by -3y increment at 60 fps
def increment(self, dt):
self.pos = Vector(*self.velocity) + self.pos
def move(self):
# While the sprite moves at 60 fps, the movement is "cancelled" after 0.3 seconds
# This event sequence is refreshed every 0.7 seoncds in MainApp class
move = Clock.schedule_interval(self.increment, 1.0/60.0)
stop = Clock.schedule_once(lambda dt: move.cancel(), 0.3)
class GameMain(Widget):
'''
Contains two functions: ADD_NEW_BIRD() and UPDATE().
All controls happen in this widget
Not using kivy.screen because there is only one screen used
ADD_NEW_BIRD() adds a new bird to list_of_birds AND add it as a child widget to the GameMain Widget. UPDATE() calls MOVE() (Bird Widget) and receives events
Create global variable limit = 0; if limit == 4, game over; variable accessed in update function, which checks whether the limit has been reached. If the player makes the right decision, then limit -= 1
'''
limit = 0
def add_new_bird(self):
self.new_bird = Bird(center_x=self.center_x, center_y=self.height/1.5)
print (self.center_x, self.height)
self.new_bird.pick_color()
self.add_widget(self.new_bird)
def update(self, dt):
for bird in self.children:
bird.move()
self.add_new_bird()
class MainApp(App):
def build(self):
game = GameMain()
Clock.schedule_interval(game.update, 0.7)
return game
if __name__ == '__main__':
MainApp().run()
main.kv:
#:kivy 1.9
<Bird>:
size: 70, 80
canvas:
Color:
rgb: self.border_color
Rectangle:
size: self.size
pos: self.pos
Color:
rgb: self.color
Rectangle:
size: root.width - 10, root.height - 10
pos: root.x + 5, root.y + 5
<GameMain>
Bird:
center_x: root.center_x
center_y: root.height / 1.5
代码完全符合我的要求(我稍后会触及z值),除了第一张卡稍微偏向左边。我真的很困惑,因为根据我的理解,center_x: root.center_x
中的main.kv
与Bird(center_x=self.center_x
中的client.py
不应该有任何不同。我尝试在init函数中初始化Bird()
的第一个实例,如下所示:
def __init__(self, **kwargs):
super(GameMain, self).__init__(**kwargs)
self.bird = Bird(center_x=self.center_x, center_y=self.height/1.5)
self.bird.pick_color()
self.add_widget(self.bird)
问题仍然存在!如果有人能够解释发生了什么/我做错了什么,甚至可能建议一个更好的方法来解决这个问题,我会很感激。
万一你好奇,我需要直接从Python代码中添加小部件,因为我需要应用程序以恒定的时间间隔不断生成新卡。但是,为简单起见,第一张卡在Kivy文件中初始化。公平地说,除偏移外,它的效果非常好。最后我没有使用布局,因为我不确定使用哪一个......我确实将手放在FloatLayout上了一段时间,但似乎无论如何它都不能解决我的问题。
答案 0 :(得分:1)
构建时,Widget的初始大小为(100,100)。如果你改变这个大小:
<Bird>:
size: 70, 80
到此:
<Bird>:
size: 100, 80
矩形将正确对齐。在kv文件中创建的初始矩形以父窗口为中心,在Python代码中创建的其他矩形偏移到左侧。
如果您在Python代码中更改Bird构造函数:
def __init__(self, **kwargs):
super(Bird, self).__init__(**kwargs)
self.pick_color()
到此(有效地将默认小部件大小从(100,100)覆盖为(50,50)):
def __init__(self, **kwargs):
self.size = (50, 50)
super(Bird, self).__init__(**kwargs)
self.pick_color()
你会注意到用Python代码创建的矩形将向右移动。从以下位置更改kv文件:
<Bird>:
size: 70, 80
为:
<Bird>:
size: 50, 80
匹配(新)初始小部件大小(50,50)的宽度,所有矩形将再次对齐。
解决您的问题的方法是保持原样,除了将Python中的新鸟size
设置为等于kv文件中的新鸟:
def __init__(self, **kwargs):
self.size = (70, 80)
super(Bird, self).__init__(**kwargs)
self.pick_color()
并且一切都会按预期工作。
这意味着来自kv文件的size
属性不会应用于Python端创建的Birds,只会应用于由kv声明创建的属性。这是Kivy的错误还是你错过了Python代码中的另一个步骤,使生成器从kv文件应用size
到Python创建的Birds,我现在还不知道。
根据我的经验,在Kivy开发的这一点上,混合太多的kv和Python代码会导致你在这里遇到这些奇怪的问题。最好是在kv中处理所有与视图相关的东西,或者完全抛弃kv并用Python构建所有东西。
有些东西在kv中根本不起作用,即设置cols
的{{1}}属性(v1.9.1)。
就个人而言,目前,我坚持使用组织良好的Python代码来构建UI,并且几乎不使用kv文件。
希望这有点帮助...