【发布时间】:2020-02-23 17:40:35
【问题描述】:
我似乎在尝试连接 Kivy 中的小部件时遇到了不间断的问题。我已经阅读了this useful guide,但我的情况并未直接涵盖。
每个选择器都是它自己的类,由 KeySigChooserContainer 持有。我想根据 KeySigChooserContainer 的大小调整按钮的大小,以便按钮具有一致的大小。这是通过
完成的ChooserButton:
...
width: root.parent.width * (3/32)
但我不喜欢使用parent 引用;随着应用程序复杂性的增加,我更愿意使用直接参考来获得灵活性。但是当我尝试这样做时
<RootNoteChooser>:
...
BoxLayout:
...
ChooserButton:
...
width: root.box.width * (3/32)
<ModeChooser>:
...
BoxLayout:
...
ChooserButton:
...
width: root.box.width * (3/32)
<KeySigChooserContainer>:
BoxLayout:
id: box
RootNoteChooser:
box: box
ModeChooser:
box: box
我收到一个属性错误:AttributeError: 'RootNoteChooser' object has no attribute 'box'
我在项目的其他地方使用了类似的技术,所以我不知道为什么这不起作用。我还尝试在 RootNoteChooser 和 ModeChooser 类中将 box 设为 ObjectProperty,但这不起作用。
# keysigchooser.py
from kivy.app import App
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.relativelayout import RelativeLayout
chrom_scale = ['C', 'C#/Db', 'D', 'D#/Eb', 'E', 'F', 'F#/Gb', 'G', 'G#/Ab', 'A', 'A#/Bb', 'B']
chrom_scale2 = ['C', 'C/D', 'D', 'D/E', 'E', 'F', 'F/G', 'G', 'G/A', 'A', 'A/B', 'B']
class ModeChooser(FloatLayout):
pass
class RootNoteChooser(FloatLayout):
note_idx = NumericProperty(0)
def increment_note_idx(self):
self.note_idx = (self.note_idx + 1) % 12
def decrement_note_idx(self):
self.note_idx = (self.note_idx - 1) % 12
def on_note_idx(self, instance, value):
self.note_text.text = chrom_scale[self.note_idx]
class KeySigChooserContainer(FloatLayout):
def on_size(self, instance, value):
target_ratio = 60/20
width, height = self.size
# check which size is the limiting factor
if width / height > target_ratio:
# window is "wider" than targeted, so the limitation is the height.
self.ids.box.height = height
self.ids.box.width = height * target_ratio
else:
self.ids.box.width = width
self.ids.box.height = width / target_ratio
class KeySigChooserApp(App):
def build(self):
return KeySigChooserContainer()
if __name__ == "__main__":
KeySigChooserApp().run()
# keysigchooser.kv
<ChooserButton@Button>:
font_name: "Arial"
font_size: self.width
border: [2, 2, 2, 2]
<RootNoteChooser>:
note_text: note_text
BoxLayout:
pos_hint: {"center": [0.5, 0.5]}
orientation: "horizontal"
ChooserButton:
text: u'\u25C4'
size_hint: [None, 1]
width: root.box.width * (3/32)
on_press: root.increment_note_idx()
Label:
id: note_text
text: "C"
ChooserButton:
text: u'\u25BA'
size_hint: [None, 1]
width: root.box.width * (3/32)
on_press: root.decrement_note_idx()
<ModeChooser>:
BoxLayout:
pos_hint: {"center": [0.5, 0.5]}
orientation: "horizontal"
ChooserButton:
text: u'\u25C4'
size_hint: [None, 1]
width: root.box.width * (3/32)
Label:
text: "Major"
ChooserButton:
text: u'\u25BA'
size_hint: [None, 1]
width: root.box.width * (3/32)
<KeySigChooserContainer>:
BoxLayout:
id: box
pos_hint: {"center": [0.5, 0.5]}
size_hint: [None, None]
orientation: "horizontal"
RootNoteChooser:
id: rootnotechooser
box: box
size_hint: [0.4, 1]
canvas:
Color:
rgba: [1, 0, 0, 0.5]
Rectangle:
pos: self.pos
size: self.size
ModeChooser:
id: modechooser
box: box
size_hint: [0.6, 1]
canvas:
Color:
rgba: [0, 1, 0, 0.5]
Rectangle:
pos: self.pos
size: self.size
显然我在这里遗漏了一些东西......感谢任何帮助。
更新 这似乎是没有解决问题的好方法的情况之一。感谢@JohnAnderson,这就是我学到的东西:
- An id is limited in scope to the rule it is declared in.
- the outermost widget applies the kv rules to all its inner widgets before any other rules are applied
- 规则总是在在实例之前应用。
这里的问题是我在 <RootNoteChooser> 和 <ModeChooser> rules 中使用了一个属性 (box),但该属性是在 instance 中创建的RootNoteChooser 和 ModeChooser。由于首先应用规则,box 尚不存在。
我为此使用的解决方法是同时在两个规则中创建box 属性,并将其设置为有意义的内容(并且不会导致错误)。然后,在RootNoteChooser 和ModeChooser 实例中(在<KeySigChooser> 规则中),box 将被重置为正确的对象。这是它的要点:
<RootNoteChooser>:
box: self.parent # Initially we'll set it to something reasonable.
BoxLayout:
...
ChooserButton:
...
width: root.box.width * (3/32)
<ModeChooser>:
box: self.parent # Initially we'll set it to something reasonable.
BoxLayout:
...
ChooserButton:
...
width: root.box.width * (3/32)
<KeySigChooserContainer>:
BoxLayout:
id: box
RootNoteChooser:
box: box # Now box attribute is correct, and can be pointed at any
ModeChooser:
box: box # id that is within this rule.
【问题讨论】:
标签: python python-3.x kivy