如何将小部件尺寸传递给 __init__

Posted

技术标签:

【中文标题】如何将小部件尺寸传递给 __init__【英文标题】:how to pass widget dimensions to __init__ 【发布时间】:2017-02-16 14:10:25 【问题描述】:

抱歉,如果这个问题有一个明显的答案,但我已经有一段时间找不到解决方案了。我的应用程序中的小部件具有根据小部件尺寸定义的“图表”。我可以从 kv 动态更新“图表”,因为我可以在那里访问小部件的尺寸。但是,我想定义一个默认的“图表”,也就是小部件的大小,它在启动时出现。我不知道如何将小部件的尺寸传递给 __init__ 函数。这是我的简化示例:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.properties import ListProperty

Builder.load_string('''
#:kivy 1.9.2
<MainWidget>:
    BoxLayout:
        size_hint_x: 20
        orientation: 'vertical'
        ToggleButton:
            text: 'WF1'
            state: 'down'
            allow_no_selection: False
            on_press:
                root.line_points = [waveform.x, waveform.top, waveform.right, waveform.y]
                root.event_handler()
            group: 'lhs_buttons'
        ToggleButton:
            text: 'WF2'
            allow_no_selection: False
            on_press:
                root.line_points = [waveform.x, waveform.y, waveform.right, waveform.top]
                root.event_handler()
            group: 'lhs_buttons'
    BoxLayout:
        size_hint_x: 80
        Button:
            id: waveform
            canvas:
                Line:
                    points: root.line_points

''')

class MainWidget(BoxLayout):
    line_points = ListProperty()

    def __init__(self, **kwargs):
        super(MainWidget, self).__init__(**kwargs)
        #self.line_points =  [waveform.x, waveform.top, waveform.right, waveform.y]  

    def event_handler(self):
        print "event"

class MyApp(App):
    def build(self):
        return MainWidget()

if __name__ == '__main__':
    MyApp().run()

我想部分解决方案是在 __init__ 中为其中一个按钮触发 on_press 事件,但我一直无法弄清楚如何做到这一点。我是 Python 和 Kivy 的新手。

【问题讨论】:

【参考方案1】:

一种方法是像这样绑定 line_points:

<MainWidget>:
    line_points: self.calc_line_points(waveform.x, waveform.y, waveform.right, waveform.top)
    ...

calc_line_points会被定义为:

    def calc_line_points(self, x, y, right, top):
        return [ x, top, right, y] #put more logic here ...

【讨论】:

谢谢它完美地工作,并以某种方式实现了在_init_之外进行初始化的预期效果。 Calc_line_points() 实际上是 init_line_points() 因为它在开始时只执行一次?我现在意识到像这样(或以某种方式在_init_中)初始化意味着图形内容不再仅在kv部分中定义。在这方面,为其中一个按钮触发 on_press 事件会更优雅。那可能吗?如有任何指示,我将不胜感激。 @EugeneB - 您可以使用 line_points 将此逻辑放入 kv 文件中:(x,y) if root.some_val else (y,x),那么您应该随时更新 some_val。还要让 some_val 成为一个属性,因此对其进行更改将导致渲染事件 再次感谢您,Yoav,这可以通过嵌套 if.. else 表达式来实现并扩展到更多结果。 Kivy 文档指出,这种语句 - 将表达式分配给 kv 中的属性 - 只能跨越一行并且“不能使用换行符转义扩展到多行”。因此,当有多个结果和复杂的波形时,它会变得混乱。相比之下,在 'on_press:' 语句之后允许转义换行符的多行语句 - 更好的可读性和可维护性。 我也通过 'trigger_action' 路由完成了它,方法是将 MainWidget() 中声明的对象属性链接到 kv 中按钮的 id。然后在 _init_ 中,我可以使用 Clock.schedule_once(self..trigger_action, 2) 安排模拟按钮按下。奇怪的是,将 delta-time 设置为 0 或 1 不起作用,不知道为什么。相同的方法 - 将对象属性链接到 kv 中的小部件 id - 也适用于将小部件的尺寸传递给 python。

以上是关于如何将小部件尺寸传递给 __init__的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5 制作子类小部件

在 kivy (python) 中更新小部件

将我的小部件添加到 Kivy App __init__ 会导致黑屏和警告

将QHboxLayout的每个小部件与Pyqt中的顶部对齐

如何强制 tkinter 文本小部件保持在一行

无法将小部件 ID 传递给配置活动