【问题标题】:Bind a function to multiple dynamically created buttons in kivy?将函数绑定到kivy中的多个动态创建的按钮?
【发布时间】:2017-08-29 08:40:52
【问题描述】:

问题

我想创建多个按钮并将它们绑定到一个函数。问题是,每当我单击一个按钮时,都会多次调用该函数。似乎是事件连接的问题。当我查看按下按钮时调用该函数的实例时,似乎该函数被一次从每个按钮调用?!

KV代码:

...
# This is the button that I'am using
<ProjectSelectButton>:
height: 35
background_color: 0,0,1,1
on_touch_down: self.click_on_button(args[0], args[1])

...

# The buttons are added to this grid
ButtonsPlacedHere@GridLayout:
    id: active_projects
    cols: 1
    size_hint_y: None
    height: self.minimum_height
    spacing: 1
...

Python 代码:

...
class ProjectSelectButton(Button):
    def click_on_button(self, instance, touch, *args):
        print(instance)
        if touch.button == 'right':
            print(self.id, "right mouse clicked")
        else touch.buttom == 'left':
            print(self.id, "left mouse clicked")

...

# The part of my programm that creates the buttons
# projects is a dictionary
for key, project in data_manager.resource_pool.projects.items():
    print(project.project_name)
    button= ProjectSelectButton(text=project.project_name, id=key, size_hint_y=None)
    # Bind without KV-File (same result)
    # label.bind(on_touch_up=self.click_on_button)
    ids.active_projects.add_widget(button)

示例输出:

当我点击一个按钮时,我得到了什么!

<guiMain.ProjectSelectButton object at 0x0BA34260>
ID01 right mouse clicked
<guiMain.ProjectSelectButton object at 0x0BA34260>
ID01 right mouse clicked
<guiMain.ProjectSelectButton object at 0x0BA28F10>
ID02 right mouse clicked
<guiMain.ProjectSelectButton object at 0x0BA28F10>
ID02 right mouse clicked
<guiMain.ProjectSelectButton object at 0x0BA22C00>
ID03 right mouse clicked
<guiMain.ProjectSelectButton object at 0x0BA22C00>
ID03 right mouse clicked

当我按下 ID 为 01 的按钮时我想要什么:

<guiMain.ProjectSelectButton object at 0x0BA34260>
ID01 right mouse clicked

问题

如何创建多个按钮,当它们被按下时会调用一个函数?

【问题讨论】:

  • 你能发布你的整个应用还是太大了?
  • 它很大,但我明天可以添加更多代码。

标签: python events kivy kivy-language


【解决方案1】:

Programming Guide » Input management » Touch events

默认情况下,触摸事件被调度到所有当前显示的小部件。这意味着无论是否发生在其物理区域内,小部件都会接收到触摸事件。

为了提供最大的灵活性,Kivy 调度 所有小部件的事件,并让它们决定如何对它们做出反应。 如果您只想响应小部件内的触摸事件,您 简单检查一下。

解决方案

click_on_button 方法中使用self.collide_point 方法。当它碰撞时,你应该只得到一个按钮。详情请参考我的例子。

片段

class ProjectSelectButton(Button):
    def click_on_button(self, instance, touch, *args):
        print(instance)
        if self.collide_point(*touch.pos):
            if touch.button == 'right':
                print(self.id, "right mouse clicked")
            elif touch.buttom == 'left':
                print(self.id, "left mouse clicked")
            return True
        return super(ProjectSelectButton, self).on_touch_down(touch)

示例

main.py

​​>
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button


class CreateButton(Button):

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            if touch.button == "right":
                print(self.id, "right mouse clicked")
            elif touch.button == "left":
                print(self.id, "left mouse clicked")
            else:
                print(self.id)
            return True
        return super(CreateButton, self).on_touch_down(touch)


class OnTouchDownDemo(GridLayout):

    def __init__(self, **kwargs):
        super(OnTouchDownDemo, self).__init__(**kwargs)
        self.build_board()

    def build_board(self):
        # make 9 buttons in a grid
        for i in range(0, 9):
            button = CreateButton(id=str(i))
            self.add_widget(button)


class OnTouchDownApp(App):

    def build(self):
        return OnTouchDownDemo()


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

ontouchdown.kv

#:kivy 1.10.0

<CreateButton>:
    font_size: 50
    on_touch_down: self.on_touch_down

<OnTouchDownDemo>:
    rows: 3
    cols: 3
    row_force_default: True
    row_default_height: 150
    col_force_default: True
    col_default_width: 150
    padding: [10]
    spacing: [10]

【讨论】:

  • 有趣的答案,所以我需要测试哪个按钮被“击中”?当我单击任何按钮时,所有按钮都会触发该事件,但是当我测试它是否发生碰撞时,我应该只得到一个按钮?
  • 默认情况下,触摸事件被调度到所有当前显示的小部件。这意味着无论是否发生在其物理区域内,小部件都会接收到触摸事件。 Kivy 将触摸事件分派给所有小部件,并让它们决定如何对它们做出反应。如果您只想响应小部件/按钮内的触摸事件,则必须使用 self.collide_point 方法对其进行检查。当它碰撞时,你应该只得到一个按钮。
  • 谢谢,现在这更有意义了。最后,我的代码做了它应该做的!
猜你喜欢
  • 2018-11-11
  • 1970-01-01
  • 2016-02-08
  • 2014-06-01
  • 2021-05-08
  • 1970-01-01
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多