2012-12-28 34 views
1

我正在爲kivy編寫一個自定義小部件(請參閱this問題),但我發現,由於某些未知原因,有時bind方法實際上並未綁定回調。綁定在隨機時間工作

在我的課我有這樣的代碼:

def __init__(self, **kwargs): 
    super(SpinBox, self).__init__(**kwargs) 

    self._value_label = Label(text=str(self.value)) 
    self.inc_button = TimedButton(text='+') 
    self.dec_button = TimedButton(text='-') 


    def inc(inst): 
     if float(self.value) + float(self.step) <= self.max_value: 
      self.value += self.step 

    def dec(inst): 
     if float(self.value) - float(self.step) >= self.min_value: 
      self.value -= self.step 

    self.inc_button.bind(on_press=inc) 
    self.inc_button.bind(on_time_slice=inc) 
    self.dec_button.bind(on_press=dec) 
    self.dec_button.bind(on_time_slice=dec) 
    # ... 

TimedButton是其他自定義類。這是一個Button子類,它在on_touch_down啓動一個定時器,如果在一段時間後它沒有收到一個on_touch_up它認爲按下了長按並且開始每隔幾毫秒使用Clock.schedule_interval發送on_time_slice事件。

因此,試圖利用我的自定義類這樣的:

class MyApp(App): 
    def build(self): 
     return SpinBox() 

MyApp().run() 

value完全不增加。

如果我做的:

class MyApp(App): 
    def build(self): 
     s = SpinBox() 
     def inc(inst): 
      s.value += 1 
     s.inc_button.bind(on_time_slice=inc) 
     return s 
MyApp().run() 

價值on_time_slice事件增加。我不明白爲什麼MyApp類中的綁定工作,而在SpinBox.__init__方法中的綁定沒有。 我在做什麼錯?

回答

1

我找到了解決辦法。我試圖綁定state屬性,在TimedButton中實現on_state方法,而不是綁定on_touch_downon_touch_up。我仍然不明白爲什麼以前的實現在單獨使用時運行,但不在SpinBox中,除非直接在App類中綁定函數。

無論如何,因爲它看起來像TimedButton類有什麼關係呢,這裏的老執行代碼:

class TimedButton(Button): 
    """A simple ``Button`` subclass that produces an event at regular intervals 
    when pressed. 

    This class, when long-pressed, emits an ``on_time_slice`` event every 
    ``time_slice`` milliseconds. 

    :param long_press_interval: Defines the minimum time required to consider 
           the press a long-press. 
    :type long_press_interval: int 
    :param time_slice: The number of milliseconds of each slice. 
    :type time_slice: int 
    """ 

    def __init__(self, long_press_interval=550, time_slice=225, **kwargs): 
     super(TimedButton, self).__init__(**kwargs) 

     self.long_press_interval = long_press_interval 
     self.time_slice = time_slice 

     self._touch_start = None 
     self._touch_uid = None 
     self._long_press_callback = None 
     self._slice_callback = None 

     self.register_event_type('on_time_slice') 
     self.register_event_type('on_long_press') 


    def on_touch_down(self, touch): 
     start_time = time.time() 
     self._touch_start = start_time 
     self._touch_uid = touch.uid 

     def callback(dt): 
      self._check_long_press(dt) 

     Clock.schedule_once(callback, self.long_press_interval/1000.0) 
     self._long_press_callback = callback 
     super(TimedButton, self).on_touch_down(touch) 

    def _check_long_press(self, dt): 
     delta = dt * 1000 
     if delta > self.long_press_interval and self._touch_uid is not None: 
      self.dispatch('on_long_press') 
      self._long_press_callback = None 
      def slice_callback(dt): 
       self.dispatch('on_time_slice') 

      Clock.schedule_interval(slice_callback, self.time_slice/1000.0) 

      self._slice_callback = slice_callback 

    def on_touch_up(self, touch): 
     end_time = time.time() 
     delta = (end_time - (self._touch_start or 0)) * 1000 
     Clock.unschedule(self._slice_callback) 
     if (self._long_press_callback is not None and 
       delta > self.long_press_interval): 
      self.dispatch('on_long_press') 
     self._touch_start = self._touch_uid = None 
     self._long_press_callback = self._slice_callback = None 
     super(TimedButton, self).on_touch_up(touch) 


    def on_long_press(self): 
     pass 

    def on_time_slice(self): 
     pass 

而這裏的使用state新的代碼工作得很好:

class TimedButton(Button): 
    """A simple ``Button`` subclass that produces an event at regular intervals 
    when pressed. 

    This class, when long-pressed, emits an ``on_time_slice`` event every 
    ``time_slice`` milliseconds. 

    :param long_press_interval: Defines the minimum time required to consider 
           the press a long-press. 
    :type long_press_interval: int 
    :param time_slice: The number of milliseconds of each slice. 
    :type time_slice: int 
    """ 

    def __init__(self, long_press_interval=550, time_slice=225, **kwargs): 
     super(TimedButton, self).__init__(**kwargs) 

     self.long_press_interval = long_press_interval 
     self.time_slice = time_slice 

     self._touch_start = None 
     self._long_press_callback = None 
     self._slice_callback = None 

     self.register_event_type('on_time_slice') 
     self.register_event_type('on_long_press') 


    def on_state(self, instance, value): 
     if value == 'down': 
      start_time = time.time() 
      self._touch_start = start_time 

      def callback(dt): 
       self._check_long_press(dt) 

      Clock.schedule_once(callback, self.long_press_interval/1000.0) 
      self._long_press_callback = callback 
     else: 
      end_time = time.time() 
      delta = (end_time - (self._touch_start or 0)) * 1000 
      Clock.unschedule(self._slice_callback) 
      if (self._long_press_callback is not None and 
       delta > self.long_press_interval): 
       self.dispatch('on_long_press') 
      self._touch_start = None 
      self._long_press_callback = self._slice_callback = None 

    def _check_long_press(self, dt): 
     delta = dt * 1000 
     if delta > self.long_press_interval and self.state == 'down': 
      self.dispatch('on_long_press') 
      self._long_press_callback = None 

      def slice_callback(dt): 
       self.dispatch('on_time_slice') 
       return self.state == 'down' 

      Clock.schedule_interval(slice_callback, self.time_slice/1000.0) 

      self._slice_callback = slice_callback 


    def on_long_press(self): 
     pass 

    def on_time_slice(self): 
     pass 
+0

你的TimedButton正是我要找的。你有沒有嘗試過一個功能來加速某個點後的事情?例如,一旦''on_long_press''被調用了20次,時間就會變得更快。 –