2014-01-25 3 views
1

Почему мои кнопки киви действуют нажатыми в момент их создания на питоне?Динамически создаваемые кнопки киви запускаются on_press и on_release немедленно

Итак, позвольте мне сказать, я знаю, что там, кажется, есть ответ на этот вопрос здесь:

on_press in Kivy keeps running at start up instead

... впрочем, нет рабочего примера. Я попытался скопировать пример, чтобы понять ответ, но не хватает опыта, чтобы заполнить то, что отсутствует в этом примере.

Таким образом, это, вероятно, будет легким ответом для тех, кто смотрит на другой ответ, может применить его здесь и объяснить более простым английским языком для noob.

Вот небольшой рабочий пример проблемы:

import kivy 
kivy.require('1.7.2') # replace with your current kivy version ! 

from kivy.app import App 
from kivy.uix.screenmanager import ScreenManager, Screen 
from kivy.properties import ObjectProperty 
from kivy.uix.button import Button 
from kivy.uix.gridlayout import GridLayout 

i = ['some', 'words'] 

class HomeScreen(Screen): 
    grid_l = ObjectProperty(None) 
    top_lbl = ObjectProperty(None) 

    def search_btn_pressed(self): 
     grid = self.grid_l 
     grid.bind(minimum_height=grid.setter('height'), 
        minimum_width=grid.setter('width')) 

     for result in i: 

       btn1 = Button(size_hint=(1, None)) 
       btn1.text = '%r' % result 
       btn1.bind(on_release=self.btn1_pressed(result)) 

       btn2 = Button(size_hint=(1, None)) 
       btn2.text = 'Remove result buttons' 
       btn2.bind(on_release=self.btn2_pressed) 

       grid.add_widget(btn1) 
       grid.add_widget(btn2) 

    def btn1_pressed(self, result, *args): 
     new_text = result 
     self.top_lbl.text = new_text 

    def btn2_pressed(self, *args): 
     self.grid_l.clear_widgets() 
     #pass 

class buttons_pressedApp(App): 

    def build(self): 

     return HomeScreen() 

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

И файл Kv:

#:kivy 1.7.2 

<HomeScreen>: 
    scroll_view: scrollviewID 
    top_lbl: lblID 
    grid_l: gridlayoutID 
    AnchorLayout: 
     size_hint: 1, .1 
     pos_hint: {'x': 0, 'y': .9} 
     anchor_x: 'center' 
     anchor_y: 'center' 
     Label: 
      id: lblID 
      text: 'Button Tester' 
    Button: 
     size_hint: 1, .1 
     pos_hint: {'x': 0, 'y': .8} 
     text: 'Add theoretical search results' 
     on_release: root.search_btn_pressed() 
    ScrollView: 
     id: scrollviewID 
     orientation: 'vertical' 
     pos_hint: {'x': 0, 'y': 0} 
     size_hint: 1, .8 
     bar_width: '8dp' 
     GridLayout: 
      id: gridlayoutID 
      cols: 1 
      size_hint: 1, None 
      row_default_height: 40 
      row_force_default: False 

Как вы можете видеть, когда вы запускаете его, первая кнопка создана в kivy работает супер , Однако вы также заметите, что верхний ярлык сразу изменился, что указывает на то, что первая динамически созданная кнопка уже выполнила функцию on_release.

Вы не можете сказать, что вторая динамически созданная кнопка «Удалить результирующие кнопки» уже выполнена, потому что она удалила все кнопки, когда их еще не было. Тем не менее, очевидно, что кнопка «Удалить кнопки результатов» выполняется сразу, когда вы снова нажимаете кнопку «Добавить теоретические результаты поиска». Он должен добавить еще две кнопки, но кажется, что ничего не происходит. Это происходит потому, что кнопка «Удалить кнопки результатов» удаляет предыдущие две кнопки, а затем они сразу же заменяются.

Тогда, конечно, ни одна из кнопок, похоже, ничего не делает.

Должно быть легко для кого-то исправить пример с учетом аналогичного вопроса!

Заранее спасибо.

EDIT:

Я изменил btn2, чтобы отразить ответ ненастную в. Работает отлично. Однако, как он отметил, когда я делаю то же самое с btn1, в этот метод передаются некоторые аргументы по умолчанию, и он дает ошибку. Итак, я оставил btn1, как и раньше, с круглой скобкой и «результатом» внутри них в качестве аргумента. Конечно, это запускается немедленно и не возвращает ничего связанного (как объяснено в деталях). Я хочу иметь возможность передать «результат», как уже определено в примере, но, естественно, не запускать его немедленно. Мои извинения .. Я должен был написать это так в первый раз.

EDIT 2, ответ:

Чтобы отразить inclements последний комментарий, я просто хотел, чтобы выложили весь рабочий пример снова ответ включен.

import kivy 
kivy.require('1.7.2') # replace with your current kivy version ! 

from kivy.app import App 
from kivy.uix.screenmanager import ScreenManager, Screen 
from kivy.properties import ObjectProperty 
from kivy.uix.button import Button 
from kivy.uix.gridlayout import GridLayout 
from functools import partial 

i = ['some', 'words'] 

class HomeScreen(Screen): 
    grid_l = ObjectProperty(None) 
    top_lbl = ObjectProperty(None) 

    def search_btn_pressed(self): 
     grid = self.grid_l 
     grid.bind(minimum_height=grid.setter('height'), 
        minimum_width=grid.setter('width')) 

     for result in i: 

       btn1 = Button(size_hint=(1, None)) 
       btn1.text = '%r' % result 
       btn1.bind(on_release=partial(self.btn1_pressed, result)) 

       btn2 = Button(size_hint=(1, None)) 
       btn2.text = 'Remove result buttons' 
       btn2.bind(on_release=self.btn2_pressed) 

       grid.add_widget(btn1) 
       grid.add_widget(btn2) 

    def btn1_pressed(self, result, *args): 
     new_text = result 
     self.top_lbl.text = new_text 

    def btn2_pressed(self, *args): 
     self.grid_l.clear_widgets() 
     #pass 

class buttons_pressedApp(App): 

    def build(self): 

     return HomeScreen() 

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

Это работает!

ответ

4

btn2.bind (on_release = self.btn2_pressed())

У вас есть синтаксис, чтобы связать неправильно (и это также проблема в вашем другом вопросе).

Bind выполняет функцию, но вы не передаете функцию, вы - , вызывающая. bind никогда не видит, что вам пришлось написать btn2_pressed в поле аргумента, потому что python вызывает функцию и передает только результат в bind.

Таким образом, решение, вы действительно хотите, чтобы написать что-то вроде

btn2.bind(on_release=self.btn2_pressed) 

Примечания удалённых скобок - это синтаксис для вызова функции, но мы определенно не хотим, чтобы сделать это. Вместо этого мы передаем функцию.

bind также передает некоторые аргументы по умолчанию функции, тогда как ваша функция определена только для принятия одной. Так как вы не заботитесь о дополнительных аргументах здесь, вы можете просто определить свою функцию с

def btn2_pressed(self, *args): 

В *args ловит запасные аргументов. Вы можете посмотреть этот синтаксис, если вы не знакомы с ним.

+0

Ваш ответ был идеален для моего примера (и ясно), и я хочу дать вам ответ. Тем не менее, я только что отредактировал свой вопрос, чтобы отразить, что я хочу иметь возможность передавать аргументы. Теперь btn1 должен передать каждый «результат» в списке до btn1_pressed. – bosky

+1

Затем вам нужно создать функцию, включающую эти аргументы. Обманом является использование 'partial' из модуля' functools', и в этом случае вы можете выполнить 'bind (on_release = partial (self.btn1_pressed, result))'. 'partial' - это функция, которая принимает функцию и некоторые аргументы, а * возвращает * новую функцию, которая сначала будет передана этим аргументам. – inclement

+0

Это билет! Благодаря! – bosky

 Смежные вопросы

  • Нет связанных вопросов^_^