我要做的就是绘制12个圆,并将其在窗口中居中。
我有一个FloatLayout
,其中有一个BoxLayout
。 BoxLayout
应该“保持” 12个圆圈。
由于我要连续排列圆圈,因此BoxLayout
的宽度应为高度的12倍。 FloatLayout
会调整BoxLayout
的大小,因此总是这样。 (FloatLayout
为绿色,BoxLayout
为红色)。
当我将窗口调整为足够小的尺寸时,会出现问题。现在,圆圈不在BoxLayout
中居中。当我调整窗口大小(使其看起来完全不光滑)时,圆圈还会从左向右“跳跃”。
此外,如果我最大化窗口(而不是通过拖动窗口的边缘或角落来调整大小),那么它会在任何地方绘制圆。
这里有什么线索吗?我正在使用BoxLayout
的左下(x,y)坐标开始绘制圆。最左边的圆圈应使用相同的精确坐标,但显然已关闭。
我没有尝试将画布指令与on_size
绑定到self.bind(size=self.update_canvas, pos=self.update_canvas)
事件,而是尝试在self.redraw_note_markers
的末尾调用self.on_size
。这样,当我们绘制圆圈时,内部BoxLayout
应该已经被调整大小。但这产生了与上述相同的结果。
更新
我已经将其合并到一个更大的应用程序中,该应用程序是TabbedPanel
的一部分,这些圆圈已完全被替换掉了。
# filename: keysigdisplay.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import InstructionGroup, Ellipse, Color
from kivy.clock import Clock
class KeySigDisplay(FloatLayout):
def __init__(self, **kwargs):
# To get note_markers drawn in center of self.ids.box, need super() at top
# of __init__ and then Clock.schedule_once(self.redraw_note_markers)...?
super().__init__(**kwargs)
self.note_markers = InstructionGroup()
self.bind(size=self.update_canvas, pos=self.update_canvas)
Clock.schedule_once(self.update_canvas)
def update_canvas(self, *args):
self.redraw_note_markers()
def redraw_note_markers(self, *args):
self.canvas.remove(self.note_markers)
self.note_markers.clear()
x, y = self.ids.box.pos
for i in range(12):
self.redraw_note_marker(i, x, y)
self.canvas.add(self.note_markers)
def redraw_note_marker(self, i, x, y):
white = Color(1, 1, 1, 1) # white
blue = Color(68 / 255, 93 / 255, 209 / 255, 1) # blue
black = Color(0, 0, 0, 1)
# Draw 2 concentric circles, c1 and c2.
# Circles are defined by a square's lower left corner.
r1 = self.ids.box.height / 2
r2 = r1 * 0.9
rdiff = r1 - r2
c1x, c1y = (2*r1)*i + x, y
c2x, c2y = c1x + rdiff, c1y + rdiff
self.note_markers.add(white)
self.note_markers.add(Ellipse(pos=[c1x, c1y], size=[2 * r1, 2 * r1]))
self.note_markers.add(blue)
self.note_markers.add(Ellipse(pos=[c2x, c2y], size=[2 * r2, 2 * r2]))
def on_size(self, instance, value):
width, height = self.size
target_ratio = 12
if width / height > target_ratio:
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 KeySigDisplayApp(App):
def build(self):
return KeySigDisplay()
if __name__ == "__main__":
KeySigDisplayApp().run()
# filename: keysigdisplay.kv
<KeySigDisplay>:
canvas:
Color:
rgba: [0, 1, 0, 0.25]
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
id: box
size_hint: [None, None]
pos_hint: {"center_x": 0.5, "center_y": 0.5}
canvas:
Color:
rgba: [1, 0, 0, 0.25]
Rectangle:
size: self.size
pos: self.pos
答案 0 :(得分:0)
尝试放置:
from kivy.config import Config
Config.set('graphics', 'maxfps', 0)
在您的keysigdisplay.py
顶部的。这将意味着kivy
将最大限度地提高其cpu使用率,并产生最平滑的显示效果。 maxfps
的默认值为60
(fps)。如果这可以提高应用程序的图形性能,则可以尝试使用不同的maxfps
值来平衡CPU使用率和图形平滑度。
答案 1 :(得分:0)
正在回答我自己的问题...
我无法找到问题的根源。 FloatLayout
的{{1}}事件应1)调整on_size
的大小,以及2)根据BoxLayout
的大小/位置更改来更新画布。它确实(1)很好,但似乎落后于(2)。更改不同步。结果是,在调整窗口大小时,图形会“跳来跳去”,并且只有一点点偏离。我仍然不确定为什么会这样。
我正在使用的解决方法是绑定到BoxLayout
的位置,并在那里更新画布。
BoxLayout
# filename: keysigdisplay.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import InstructionGroup, Ellipse, Color
from kivy.properties import NumericProperty, ReferenceListProperty
class KeySigDisplay(FloatLayout):
# Added all these properties. box_pos is bound to box.pos in kv file.
box_x = NumericProperty(0)
box_y = NumericProperty(0)
box_pos = ReferenceListProperty(box_x, box_y)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.note_markers = InstructionGroup()
def update_canvas(self, *args):
self.redraw_note_markers()
def redraw_note_markers(self, *args):
self.canvas.remove(self.note_markers)
self.note_markers.clear()
x, y = self.ids.box.pos
for i in range(12):
self.redraw_note_marker(i, x, y)
self.canvas.add(self.note_markers)
def redraw_note_marker(self, i, x, y):
white = Color(1, 1, 1, 1) # white
blue = Color(68 / 255, 93 / 255, 209 / 255, 1) # blue
black = Color(0, 0, 0, 1)
# Draw 2 concentric circles, c1 and c2.
# Circles are defined by a square's lower left corner.
r1 = self.ids.box.height / 2
r2 = r1 * 0.9
rdiff = r1 - r2
c1x, c1y = (2*r1)*i + x, y
c2x, c2y = c1x + rdiff, c1y + rdiff
self.note_markers.add(white)
self.note_markers.add(Ellipse(pos=[c1x, c1y], size=[2 * r1, 2 * r1]))
self.note_markers.add(blue)
self.note_markers.add(Ellipse(pos=[c2x, c2y], size=[2 * r2, 2 * r2]))
def on_size(self, instance, value):
width, height = self.size
target_ratio = 12
if width / height > target_ratio:
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
# Added this method to receive the event.
def on_box_pos(self, instance, value):
self.update_canvas(instance, value)
class KeySigDisplayApp(App):
def build(self):
return KeySigDisplay()
if __name__ == "__main__":
KeySigDisplayApp().run()
不确定这样做是否正确,但是可以。希望有人觉得这有帮助。