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

One Solution collect form web for “on_press в Kivy продолжает работать при запуске”

Вы не передаете обратный вызов в 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 будет поднято, вместо того, чтобы устанавливать его в результат возврата self.Launcher когда Button создана.

Обновление: по какой-то причине события on_press и on_release самом деле не назначены обратным Button.__init__ в Button.__init__ , сами события просто зарегистрированы без каких-либо результатов. (Это кажется ошибкой для меня, но я недостаточно знаком с Киви, чтобы сказать наверняка.) Вам нужно явно bind обратный вызов для его работы:

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

Обратите внимание, что обратный вызов фактически получает аргумент, который я включил в качестве widget в лямбда.

Обновление 2: я должен был поймать это раньше, извините, но я уменьшил свой локальный тестовый файл до одной кнопки. Когда вы сделаете это в цикле:

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

Каждый вызов funcs[n]() где n in [0..9] возвращает 9 , а не значение n как ожидалось. Лямбда создала закрытие, которое включает x из окружающего пространства. Однако значение этого x изменяется в течение цикла, а к концу оно равно 9 . Теперь все funcs в funcs содержат ссылку на 9 . Вы можете избежать этого, добавив значение, которое вы хотите в локальную область лямбда:

  funcs.append( lambda x=x: x) 

Это указывает локальную переменную лямбда x на тот же объект, на который ссылается переменная цикла x во внешней области. Более очевидно, что произойдет, если мы будем использовать разные имена переменных:

  funcs.append( lambda inner_x=x: inner_x) 

Но форма x=x очень распространена в этом случае. Таким образом, чтобы каждая кнопка использовала правильное значение, вы должны иметь возможность:

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

Здесь вы привязываете текущее значение row[1] к appname в локальной области лямбда, так что это будет appname Launcher при его вызове.

  • Kivy: доступ к методу в другом классе
  • Kivy: drag n drop, получить путь к файлу
  • Почему киви меняет все виджеты сразу
  • Возврат из canvas.get_group () вызова в kivy
  • Размеры элементов не обновляются при загрузке приложения в Киви
  • Проблема с выпуском Kivy Popup
  • Не удается установить Kivy: ошибка Cython / GCC
  • Kivy ObjectProperty для обновления текста ярлыка
  • Python - лучший язык программирования в мире.