Kivy中的on_press会在启动时继续运行 [英] on_press in Kivy keeps running at start up instead

查看:110
本文介绍了Kivy中的on_press会在启动时继续运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到的问题是应用程序在其他任何事情发生之前立即运行按钮的on_press命令.如果我使用.kv作为布局,则效果很好,但是我希望能够使用简单的列表来管理按钮.

I'm having the problem where the application is running the on_press command of a button immediately before anything else happens. If I us a .kv for the layout it works fine, but I want to be able to manage the buttons using a simple list.

class AppBase(Widget):

    def Launcher(self, launchapp):
        os.system(launchapp)

    def BuildLayout(self):
        layout = GridLayout( rows=4, row_force_default = True, row_default_height = 100, col_force_default = True, col_default_width = 300 )
        with open('config.txt', 'rb') as f:
            reader = csv.reader(f, delimiter="|")
            for row in reader:
                launchbutton = Button( text = row[0], background_normal = 'tile.png', on_press = self.Launcher(row[1]) )
                layout.add_widget(launchbutton)
        return layout


class MyApp(App):

    def build(self):
        Config.set('graphics', 'width', 1920)
        Config.set('graphics', 'height', 400)
        return AppBase().BuildLayout()

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

推荐答案

您没有将回调传递给Button,实际上您正在执行该函数.更改此:

You're not passing a callback into Button, you're actually executing the function at that point. Change this:

launchbutton = Button( text = row[0], background_normal = 'tile.png', 
    on_press = self.Launcher(row[1]) 
)

对此:

launchbutton = Button( text = row[0], background_normal = 'tile.png', 
    on_press = lambda: self.Launcher(row[1])
)

现在,您传递的是一个未命名的函数,该函数将在引发on_press事件时调用self.Launcher,而不是在创建Button时将其设置为self.Launcher的返回结果.

Now you're passing in an unnamed function that will call self.Launcher when an on_press event is raised, rather than setting it to the return result of self.Launcher when the Button is created.

更新:由于某些原因,on_presson_release事件实际上并未分配给Button.__init__中的回调,事件本身只是被注册而没有任何结果. (对我来说,这似乎是个错误,但我对Kivy的了解还不够,无法肯定地说.)您需要显式地bind回调使其起作用:

Update: for some reason, on_press and on_release events aren't actually assigned to callbacks in Button.__init__, the events themselves are just registered with no outcome. (This seems a bug to me, but I'm not familiar enough with Kivy to say for certain.) You need to explicitly bind the callback for it to work:

launchbutton = Button( text = row[0], background_normal = 'tile.png' )
launchbutton.bind( on_press = lambda widget: self.Launcher( row[1] ) )

请注意,回调实际上接收到一个参数,该参数已作为widget包含在lambda中.

Note that the callback actually receives an argument, which I've included as widget in the lambda.

更新2:,对不起,我应该早点抓到这个,但是我已经将本地测试用例缩减为一个按钮.当您循环执行此操作时:

Update 2: I should have caught this earlier, sorry, but I had reduced my local test case down to one button. When you do this in a loop:

funcs = []
for x in xrange(10):
    funcs.append( lambda: x)

每次调用funcs[n](),其中n in [0..9]将返回9,而不是预期的n值. lambda创建了一个闭包,其中包括来自周围范围的x.但是,该x的值会在循环过程中发生变化,最后是9.现在,funcs中的所有lambda都拥有对9的引用.您可以通过在lambda的本地范围内添加所需的 value 来避免这种情况:

Every call to funcs[n]() where n in [0..9] will return 9, and not the value of n as expected. The lambda has created a closure which includes x from the surrounding scope. However, the value of that x changes over the course of the loop, and by the end it is 9. Now all lambdas in funcs are holding a reference to 9. You can avoid this by adding the value you want to the lambda's local scope:

    funcs.append( lambda x=x: x)

这将lambda局部变量x指向与外部范围中的循环变量x所引用的对象相同的对象.如果我们使用不同的变量名,将会更明显地发生什么:

This points the lambda local variable x at the same object as is referred to by the loop variable x in the outer scope. It's more obvious what happens if we use different variable names:

    funcs.append( lambda inner_x=x: inner_x)

但是在这种情况下,x=x形式很常见.因此,要确保每个按钮使用正确的值,您应该能够做到:

But the x=x form is very common in this case. So, to ensure that each button uses the correct value, you should be able to do:

launchbutton.bind( on_press = lambda widget, appname=row[1]: self.Launcher( appname ) )

在这里,您将row[1]的当前值绑定到lambda的本地作用域中的appname,这就是它在被调用时将传递给Launcher的原因.

Here, you bind the current value of row[1] to appname in the lambda's local scope, so that's what it will pass to Launcher when it's called.

这篇关于Kivy中的on_press会在启动时继续运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆