经典常识编程表示将GUI代码与核心处理分开。我在Kivy开始这种方式,但在我的第一轮原型中遇到了问题。
class Card:
def __init__(self, suit, value):
self.name = "%s %s" % (suit, value)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from deck import Card
class CardDisplay(BoxLayout):
card = ObjectProperty(Card("Default", 0))
class BoardDisplay(BoxLayout):
board = [[Card("Player1", 1),
Card("Player1", 2),
Card("Player1", 3),
Card("Player1", 4)],
[Card("Player2", 1),
Card("Player2", 2),
Card("Player2", 3),
Card("Player2", 4)]]
class GameApp(App):
pass
if __name__ in ("__main__", "__android__"):
GameApp().run()
BoardDisplay:
orientation: "vertical"
BoxLayout:
CardDisplay:
card: root.board[0][0]
CardDisplay:
card: root.board[0][1]
CardDisplay:
card: root.board[0][2]
CardDisplay:
card: root.board[0][3]
BoxLayout:
CardDisplay:
card: root.board[1][0]
CardDisplay:
card: root.board[1][1]
CardDisplay:
card: root.board[1][2]
CardDisplay:
card: root.board[1][3]
<CardDisplay>:
Label:
text: root.card.name
运行这个,我按预期得到一张8张牌,但所有牌都是&#34;默认0&#34;。我认为这是因为我使用的是root.card.name,它不是StringProperty,而只是card类的一个属性。但是......有什么更好的方法呢?我是否真的应该在每个包含我想要显示的内容(在本例中为Card)的类中继承Widget(或其类似内容)?或者是否有一种我无法理解的约束方法?我通读了Kivy的文档并且可以发誓它提到了这样的问题,但是我无法再找到这个参考...
答案 0 :(得分:2)
问题是root.card.name
不是Property
,所以当你指定它时(text: root.card.name
),Kivy不知道绑定任何东西。绑定在kv中自动发生,但并不完美。所以这是一个简单的解决方法:
<CardDisplay>:
Label:
text: root.card and root.card.name
表达式root.card and root.card.name
的结果将是root.card.name
的值,假设已分配root.card
。但是,当Kivy读取该任务时,它会发现您正在使用root.card
并且会正确绑定。
使用属性的关键是知道何时需要通知更新。您不需要root.card.name
成为StringProperty
,除非您想知道该属性何时更新。换句话说,如果您更改Card
使用的CardDisplay
实例,则会更新Label
。但是,如果您只是更新name
的{{1}}属性,则Card
会不更新。
但是,这同样适用于Label
上的board
属性。更新此属性不会更新显示,因为BoardDisplay
不是属性。但Kivy可以处理列表列表并提供有关更新的通知:
board
这样您就可以收到通知。
哦,有一件事我忘了提一下:如果你确实需要使用非board1 = ListProperty([Card("Player1", i) for i in range(4)])
board2 = ListProperty([Card("Player2", i) for i in range(4)])
board = ReferenceListProperty(board1, board2)
上的属性(如Widget
),你可以从Card
扩展到获取属性工作。 Kivy不仅仅是一个UI,它还是一个框架。在非UI代码中使用Kivy是可以的。如果您在.NET中使用过数据绑定,则可以将EventDispatcher
视为Widget
或Control
,将UIElement
视为EventDispatcher
。