用于绘制数据的 Kivy 自定义小部件,无法获取当前小部件尺寸
Kivy custom widget to plot data, can't get current widget dimensions
我想创建一个自定义的 kivy 小部件,它根据用户输入或实时位置数据绘制数据。
我需要小部件的当前尺寸和位置来绘制线条,但我似乎无法正确获取这些信息,而且我无法通过单击按钮等方式触发线条更新。
这是一个示例代码,单击按钮时,GraphWidget 应绘制线条。
import numpy as np
from kivy.app import App
from kivy.properties import ObjectProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
class BoxLayoutMain(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.gw = GraphWidget()
def plot_line(self):
# called when user clicks button
data = np.asarray([[0,0],[100,100],[200,50]]) # test data
self.gw.plot(data, min_x=0, max_x=200, min_y=0, max_y=150)
class GraphWidget(Widget):
trace_points = ObjectProperty((0, 0, 0, 0))
graph_w = NumericProperty(100)
graph_h = NumericProperty(100)
graph_x0 = NumericProperty(0)
graph_y0 = NumericProperty(0)
def on_size(self, *args):
# dimensions are correct here:
self.graph_w = self.width
self.graph_h = self.height
self.graph_x0 = self.pos[0]
self.graph_y0 = self.pos[1]
self.test()
def test(self):
# dimensions are also correct here:
print('W ', self.graph_w)
print('H ', self.graph_h)
print('X ', self.graph_x0)
print('Y ', self.graph_y0)
# a test line is drawn when triggered by on_size method
self.trace_points = [400, 0, 600, 500]
def plot(self,data_xy, min_x, max_x, min_y, max_y):
# called when user clicks button
# dimensions are not correct here:
print('W ', self.graph_w)
print('H ', self.graph_h)
print('X ', self.graph_x0)
print('Y ', self.graph_y0)
# transforming data points to pixels, needs correct widget dimensions/position:
xf = self.graph_w / (max_x - min_x)
yf = self.graph_h / (max_y - min_y)
X = (data_xy[:, 0] - min_x) * xf + self.graph_x0
Y = (data_xy[:, 1] - min_y) * yf + self.graph_y0
nps = np.column_stack((X, Y))
# line is not drawn/updated
self.trace_points = list(nps.flatten().astype(int))
class GraphTestApp(App):
pass
GraphTestApp().run()
kv文件:
BoxLayoutMain:
<BoxLayoutMain>:
orientation: 'horizontal'
Button:
text: 'Click'
on_press: root.plot_line()
GraphWidget:
<GraphWidget>:
canvas:
Color:
rgb: 1,0,0
Line:
width: 2
points: self.trace_points
谢谢!
问题是行:
self.gw = GraphWidget()
在 BoxLayoutMain
的 __init__()
方法中正在创建 GraphWidget
的新实例,而该实例不在您的 GUI 中。因此,任何对 self.gw
的引用都与您的 GUI 中的 GraphWidget
无关。您只需要获取对 GraphWidget
的正确实例的引用。一种方法是使用 ObjectProperty
和 ids
。您可以修改 BoxLayoutMain
以拥有一个名为 gw
:
的 ObjectProperty
class BoxLayoutMain(BoxLayout):
gw = ObjectProperty(None)
# def __init__(self, **kwargs):
# super().__init__(**kwargs)
# self.gw = GraphWidget()
并且不再需要 __init__()
方法。然后将 ids
添加到您的 kv
:
BoxLayoutMain:
<BoxLayoutMain>:
gw: gw # set the gw ObjectProperty to the widget with id of gw
orientation: 'horizontal'
Button:
text: 'Click'
on_press: root.plot_line()
GraphWidget:
id: gw # id used above to get a reference to this GraphWidget
<GraphWidget>:
canvas:
Color:
rgb: 1,0,0
Line:
width: 2
points: self.trace_points
我想创建一个自定义的 kivy 小部件,它根据用户输入或实时位置数据绘制数据。 我需要小部件的当前尺寸和位置来绘制线条,但我似乎无法正确获取这些信息,而且我无法通过单击按钮等方式触发线条更新。
这是一个示例代码,单击按钮时,GraphWidget 应绘制线条。
import numpy as np
from kivy.app import App
from kivy.properties import ObjectProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
class BoxLayoutMain(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.gw = GraphWidget()
def plot_line(self):
# called when user clicks button
data = np.asarray([[0,0],[100,100],[200,50]]) # test data
self.gw.plot(data, min_x=0, max_x=200, min_y=0, max_y=150)
class GraphWidget(Widget):
trace_points = ObjectProperty((0, 0, 0, 0))
graph_w = NumericProperty(100)
graph_h = NumericProperty(100)
graph_x0 = NumericProperty(0)
graph_y0 = NumericProperty(0)
def on_size(self, *args):
# dimensions are correct here:
self.graph_w = self.width
self.graph_h = self.height
self.graph_x0 = self.pos[0]
self.graph_y0 = self.pos[1]
self.test()
def test(self):
# dimensions are also correct here:
print('W ', self.graph_w)
print('H ', self.graph_h)
print('X ', self.graph_x0)
print('Y ', self.graph_y0)
# a test line is drawn when triggered by on_size method
self.trace_points = [400, 0, 600, 500]
def plot(self,data_xy, min_x, max_x, min_y, max_y):
# called when user clicks button
# dimensions are not correct here:
print('W ', self.graph_w)
print('H ', self.graph_h)
print('X ', self.graph_x0)
print('Y ', self.graph_y0)
# transforming data points to pixels, needs correct widget dimensions/position:
xf = self.graph_w / (max_x - min_x)
yf = self.graph_h / (max_y - min_y)
X = (data_xy[:, 0] - min_x) * xf + self.graph_x0
Y = (data_xy[:, 1] - min_y) * yf + self.graph_y0
nps = np.column_stack((X, Y))
# line is not drawn/updated
self.trace_points = list(nps.flatten().astype(int))
class GraphTestApp(App):
pass
GraphTestApp().run()
kv文件:
BoxLayoutMain:
<BoxLayoutMain>:
orientation: 'horizontal'
Button:
text: 'Click'
on_press: root.plot_line()
GraphWidget:
<GraphWidget>:
canvas:
Color:
rgb: 1,0,0
Line:
width: 2
points: self.trace_points
谢谢!
问题是行:
self.gw = GraphWidget()
在 BoxLayoutMain
的 __init__()
方法中正在创建 GraphWidget
的新实例,而该实例不在您的 GUI 中。因此,任何对 self.gw
的引用都与您的 GUI 中的 GraphWidget
无关。您只需要获取对 GraphWidget
的正确实例的引用。一种方法是使用 ObjectProperty
和 ids
。您可以修改 BoxLayoutMain
以拥有一个名为 gw
:
ObjectProperty
class BoxLayoutMain(BoxLayout):
gw = ObjectProperty(None)
# def __init__(self, **kwargs):
# super().__init__(**kwargs)
# self.gw = GraphWidget()
并且不再需要 __init__()
方法。然后将 ids
添加到您的 kv
:
BoxLayoutMain:
<BoxLayoutMain>:
gw: gw # set the gw ObjectProperty to the widget with id of gw
orientation: 'horizontal'
Button:
text: 'Click'
on_press: root.plot_line()
GraphWidget:
id: gw # id used above to get a reference to this GraphWidget
<GraphWidget>:
canvas:
Color:
rgb: 1,0,0
Line:
width: 2
points: self.trace_points