用于绘制数据的 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 的正确实例的引用。一种方法是使用 ObjectPropertyids。您可以修改 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