我正在尝试为Kivy应用程序实现测量的实时图,但我不理解kivy园图书馆的内部工作原理。
我想实现的目标:我希望在ScrollView
中有多个绘图,这样我就可以从字典中以编程方式添加多个实时绘图,如果它们占用的空间超过一个屏幕高度,则滚动它们。我遇到的主要问题是Graph不像普通的Widget那样行为,而是表现得像画布一样。我已经尝试使用matplotlib作为backend_kivyagg来实现它,但是我没有为每个subplot that I created设置固定大小。
有很多事情我不明白他们为什么会这样发生。
from math import sin, cos
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.garden.graph import Graph, MeshLinePlot
class Plot(Widget):
def __init__(self):
super(Plot, self).__init__()
self.graph = Graph(xlabel="x", ylabel="y", x_ticks_minor=5, x_ticks_major=25, y_ticks_major=1,
y_grid_label=True, x_grid_label=True, x_grid=True, y_grid=True,
xmin=-0, xmax=100, ymin=-1, ymax=1, draw_border=False)
# graph.size = (1200, 400)
# self.graph.pos = self.center
self.plot = MeshLinePlot(color=[1, 1, 1, 1])
self.plot.points = [(x, sin(x / 10.)) for x in range(0, 101)]
self.plot2 = MeshLinePlot(color=[1, 0, 0, 1])
self.plot2.points = [(x, cos(x / 10.)) for x in range(0, 101)]
self.add_widget(self.graph)
self.graph.add_plot(self.plot)
self.graph.add_plot(self.plot2)
class GraphLayoutApp(App):
def build(self):
scroll_view = ScrollView()
grid_layout = GridLayout(cols=1, row_force_default=True, padding=20, spacing=20)
graph = Plot()
graph2 = Plot()
label = Label(text="Hello World!")
label2 = Label(text="Hello World!")
grid_layout.add_widget(label)
grid_layout.add_widget(graph)
grid_layout.add_widget(label2)
grid_layout.add_widget(graph2)
scroll_view.add_widget(grid_layout)
return scroll_view
if __name__ == '__main__':
GraphLayoutApp().run()
问题:
- 在GraphLayoutApp类中,我创建了两个对象graph和graph2,但如果我将它们添加到GridLayout(),只会出现一个?如何添加多个图表?
- 同样在GraphLayoutApp类的构建方法中,我创建了两个标签。我想首先显示第一个
label
然后是图表,然后是第二个标签label2
。但在我看来,图表始终显示在左下角。我想这与绘制它的画布有关,但我无法解决它。
这是修改后的版本,修改了一些内容:
这里的问题是你让你的Plot继承自Widget,它实际上是框架中最基本的小部件,并且因为它不是布局,不会管理你添加到它的子节点中的任何东西,所以你添加的Graph
小部件它保留在默认大小/位置(分别为[100,100]和[0,0]),因此它们彼此堆叠,我使用RelativeLayout,默认情况下将子项设置为自己的大小和位置,因此图表跟随小部件。另一种解决方案是简单地使Plot继承自Graph,因为它是唯一的子节点,并且使用“self.add_plot”而不是“self.graph.add_plot”,并且要覆盖Graph参数,最好的解决方案可能是创建一个Plot类的KV规则。但第一个解决方案是代码中的最小变化。
你错过的一般原则是,在kivy中,小部件默认不受任何位置/大小的限制,除非他们的父母是专门管理它的布局(就像GridLayout为你的标签做的那样)。
我还让GridLayout自动调整自己的大小为minimum_size(由我放在所有小部件中的硬编码大小决定),所以你实际上有东西要滚动。
这段代码也是非常python驱动的,在kivy中,你通常想要使用KV做更多的事情,而不是使用add_widget
来做静态的东西。
from math import sin, cos
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.uix.relativelayout import RelativeLayout
from kivy.garden.graph import Graph, MeshLinePlot
class Plot(RelativeLayout):
def __init__(self, **kwargs):
super(Plot, self).__init__(**kwargs)
self.graph = Graph(xlabel="x", ylabel="y", x_ticks_minor=5, x_ticks_major=25, y_ticks_major=1,
y_grid_label=True, x_grid_label=True, x_grid=True, y_grid=True,
xmin=-0, xmax=100, ymin=-1, ymax=1, draw_border=False)
# graph.size = (1200, 400)
# self.graph.pos = self.center
self.plot = MeshLinePlot(color=[1, 1, 1, 1])
self.plot.points = [(x, sin(x / 10.)) for x in range(0, 101)]
self.plot2 = MeshLinePlot(color=[1, 0, 0, 1])
self.plot2.points = [(x, cos(x / 10.)) for x in range(0, 101)]
self.add_widget(self.graph)
self.graph.add_plot(self.plot)
self.graph.add_plot(self.plot2)
class GraphLayoutApp(App):
def build(self):
scroll_view = ScrollView()
grid_layout = GridLayout(cols=1, padding=20, spacing=20, size_hint_y=None)
grid_layout.bind(minimum_size=grid_layout.setter('size'))
graph = Plot(size_hint_y=None, height=500)
graph2 = Plot(size_hint_y=None, height=500)
label = Label(text="Hello World!", size_hint_y=None)
label2 = Label(text="Hello World!", size_hint_y=None)
grid_layout.add_widget(label)
grid_layout.add_widget(graph)
grid_layout.add_widget(label2)
grid_layout.add_widget(graph2)
scroll_view.add_widget(grid_layout)
# return grid_layout
return scroll_view
if __name__ == '__main__':
GraphLayoutApp().run()