2012-12-28 2 views
2

사용자가 정수 값을 특정 단계 및 하한 또는 상한없이 선택할 수있는 Spinner 위젯이 필요합니다. (최소 10 억 개 이상이어야하므로 전체 시퀀스를 암기 할 수 없습니다.).회 전자에 무한한 정수 값을 허용하는 방법은 무엇입니까?

나는 kivy의 Spinner 위젯을 보았지만 Spinner(values=itertool.count())과 같은 일을한다고 생각하지 않습니다. 또한 문자열 값으로 제한됩니다.

QtQSpinBox과 비슷한 것을 얻을 수있는 간단한 방법이 있습니까?

+1

을 갈 때 _long_press_callback (이 드롭 다운 목록처럼 무섭게 보인다) 나는 그것을 사용한 적이 있지만,이 Kivy 위젯은 잘못된 이름 것으로 보인다. – delnan

+0

이 @delnan 그래, 난 생각이 너무. 유사 순전히' QComboBox'. [Slider'] (http://kivy.org/docs/api-kivy.uix.slider.html) 클래스가 사용자로부터 숫자를 가져올 수있는 방법을 제공하지만 범위가 너무 클 수 있기 때문에 사용자가 그 단계에서 충분한 제어권을 갖지 못할 것입니다. 글쎄, 나는 그 사이에 손으로 구현하려고 노력할 것이다. – Bakuriu

+0

android [spinner] (http://developer.android.com/guide/topics/ui/controls/spinner.html)를 보면 Kivy Spinner와 매우 유사합니다. –

답변

2

현재 kivy가 Spinner 또는 SpinBox과 비슷한 것을 제공하지 않거나 전화하고 싶습니다. 대신 사용할 수있는 위젯은 Slider이지만 매우 큰 범위를 허용하고 싶지만 작은 단계 만 허용하려는 경우 너무 유용합니다.

class SpinBox(BoxLayout): 
    """A widget to show and take numeric inputs from the user. 

    :param min_value: Minimum of the range of values. 
    :type min_value: int, float 
    :param max_value: Maximum of the range of values. 
    :type max_value: int, float 
    :param step: Step of the selection 
    :type step: int, float 
    :param value: Initial value selected 
    :type value: int, float 
    :param editable: Determine if the SpinBox is editable or not 
    :type editable: bool 
    """ 

    min_value = NumericProperty(float('-inf')) 
    max_value = NumericProperty(float('+inf')) 
    step = NumericProperty(1) 
    value = NumericProperty(0) 
    range = ReferenceListProperty(min_value, max_value, step) 

    def __init__(self, btn_size_hint_x=0.2, **kwargs): 
     super(SpinBox, self).__init__(orientation='horizontal', **kwargs) 

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

     self.inc_button.bind(on_press=self.on_increment_value) 
     self.inc_button.bind(on_time_slice=self.on_increment_value) 
     self.dec_button.bind(on_press=self.on_decrement_value) 
     self.dec_button.bind(on_time_slice=self.on_decrement_value) 

     self.buttons_vbox = BoxLayout(orientation='vertical', 
             size_hint_x=btn_size_hint_x) 
     self.buttons_vbox.add_widget(self.inc_button) 
     self.buttons_vbox.add_widget(self.dec_button) 

     self.add_widget(self.value_label) 
     self.add_widget(self.buttons_vbox) 

    def on_increment_value(self, btn_instance): 
     if float(self.value) + float(self.step) <= self.max_value: 
      self.value += self.step 

    def on_decrement_value(self, btn_instance): 
     if float(self.value) - float(self.step) >= self.min_value: 
      self.value -= self.step 

    def on_value(self, instance, value): 
     instance.value_label.text = str(value) 

는 사실 내가이 위젯을 구현하기 위해 레이아웃을 서브 클래스에 추악한 생각하기 때문에 약간 다릅니다하고 사용하는 코드 따라서 내가 Widget을 서브 클래스 및 추가

:

그러므로 나는 SpinBox 내 자신의 구현을 썼다 수평 BoxLayoutWidget의 자식으로, 그 다음이 어린이의 크기와 위치를 업데이트하기 위해 모든 크기와 위치가 변경되었습니다 ( this 질문을 참조하십시오).

TimedButton

은과, 긴 프레스 때마다 on_time_slice 이벤트 출사 밀리 일정량 (즉, 사용자가 계속 증가 할 버튼을 길게 할 수있을 것이다)을 장기간 누를 수있게 Button의 서브 . 원하는 경우 보통 Button을 사용하고 bindon_time_slice 이벤트로 제거하면됩니다. 내가 가진

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) 
      # Fixes the bug of multiple presses causing fast increase 
      Clock.unschedule(self._long_press_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 

주 대신에 그들이 어떤 strange behaviour을 제공하기 때문에 on_touch_downon_touch_up을 사용하는 state 속성을 결합하고, "작업"경우에도 몇 가지 이상한 일들이 있었다 :

TimedButton 소스 코드는 이것이다 아무 이유없이 발생합니다 (예 : 감소 버튼을 클릭하면 이 올바른 경우에도 on_increment이 호출됩니다).


편집 : 너무 많은 on_time_slice 이벤트를 얻을 것이다 버튼을 누른 후 빠른 속도로 여러 번을 클릭하면 약간의 버그 (이전의 구현을 고정 TimedButton 클래스를 업데이트 : 나는 잊고하려는에 "스케쥴 취소" 상태가 'normal'

+0

기본적으로 kivy의 on_touch_ * 이벤트는 위젯에 대한 [충돌 확인] (http://kivy.org/docs/guide/inputs.html#touch-events)을 호출하지 않으므로 수동으로 호출해야합니다 [collide_point] (http://kivy.org/docs/api-kivy.uix.widget.html?highlight=collide_point#kivy.uix.widget.Widget.collide_point). 귀하가 직면 한 문제를 설명 할 수 있습니다. [Button] (http://kivy.org/docs/api-kivy.uix.button.html)은 걱정할 필요없이 바로 사용할 수있는 on_press와 on_release 이벤트를 제공합니다. 귀하의 경우에는'state' 속성을 사용하는 것이 더 합리적입니다. –

관련 문제