Kivy的on_press继续在启动时运行

时间:2012-09-11 11:11:52

标签: python kivy

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

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()

1 个答案:

答案 0 :(得分:3)

你没有将回调传递给Button,你实际上正在执行该功能。改变这个:

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])
)

现在你传入了一个未命名的函数,它会在引发self.Launcher事件时调用on_press,而不是在{{1}时将其设置为self.Launcher的返回结果已创建。

更新:由于某种原因,Buttonon_press事件实际上并未分配给on_release中的回调,事件本身只是注册为否结果。 (这对我来说似乎是一个错误,但我对Kivy不太熟悉,可以肯定地说。)你需要明确地Button.__init__回调它才能起作用:

bind

请注意,回调实际上会收到一个参数,我将其作为launchbutton = Button( text = row[0], background_normal = 'tile.png' ) launchbutton.bind( on_press = lambda widget: self.Launcher( row[1] ) ) 包含在lambda中。

更新2:我应该早点抓住这个,抱歉,但我已将本地测试用例缩减为一个按钮。当你在循环中执行此操作时:

widget

funcs = [] for x in xrange(10): funcs.append( lambda: x) 的每次通话,其中funcs[n]()将返回n in [0..9],而不是预期的9值。 lambda创建了一个闭包,其中包含来自周围范围的n。但是,x的值会在循环过程中发生变化,最后变为x。现在9中的所有lambdas都持有对funcs的引用。您可以通过将您想要的添加到lambda的本地范围来避免这种情况:

9

这将lambda局部变量 funcs.append( lambda x=x: x) 指向外部作用域中循环变量x所引用的同一对象。如果我们使用不同的变量名,会发生什么更明显:

x

funcs.append( lambda inner_x=x: inner_x) 形式在这种情况下很常见。因此,为了确保每个按钮使用正确的值,您应该能够:

x=x

在这里,您将lambda的本地范围中的launchbutton.bind( on_press = lambda widget, appname=row[1]: self.Launcher( appname ) ) 的当前值绑定到row[1],这样就可以在调用它时传递给appname