<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 編程向導4.5事件和屬性 事件是Kivy編程里面一個重要的部分。對于有GUI開發經驗的人來說也許不是那么讓人驚奇,但對于初學者是一個重要的概念。一旦你理解了事件如何工作、如何綁定,你將會在Kivy到處發現它們。它們使你想利用Kivy實現任何的行為變得很容易。 下面的插圖顯示了在Kivy框架中事件如何被處理。 ![events and properties](http://ww2.sinaimg.cn/large/577d3ebejw1f0yoh6riihj20m80fcgpc.jpg) #### 一、介紹事件發送 Kivy框架的最重要的基類之一就是EventDispatcher類。這個類允許你注冊事件類型并發送它們到感興趣的地方(通常是其它事件發送者)。[部件](https://kivy.org/docs/api-kivy.uix.widget.html#kivy.uix.widget.Widget)、[動畫](https://kivy.org/docs/api-kivy.animation.html#kivy.animation.Animation)、[時鐘](https://kivy.org/docs/api-kivy.clock.html#kivy.clock.Clock)類都是事件發送的例子。 EventDispatcher對象依賴主循環生成和處理事件。 #### 二、主循環 在上面插圖中,主循環作為輪廓。這個循環運行在應用程序的全部生命周期中,直到應用程序退出時才終止。 在循環里面,每一次迭代,當發生用戶輸入、傳感器或者一些其他資源、畫面被渲染顯示時,總會有事件生成。 你的應用程序可以指定回調函數,它們在主循環中被調用。如果一個回調函數費時太長或者根本不會退出,則主循環會中斷同時你的應用程序無法正常運行。 在Kivy應用程序中,你必須避免使用長循環、死循環或睡眠(sleeping),如下代碼是需要避免的: ``` python while True: animate_something() time.sleep(.10) ``` 當你運行上面的代碼,則你的程序永遠無法退出該循環,要預防Kivy做類似的事情。結果將會看到一個無法交互的黑色的窗口。正確的方式的,你需要*定制(schedule)*你的animate_somthing()函數重復調用。 ##### (一)重復事件 你可以使用schedule_interval()每隔X時間調用一個函數或方法,下面是一個例子,每隔1/30秒調用一次my_callback函數: ```python def my_callback(dt): print 'my callback is called', dt Clock.schedule_interval(my_callback, 1/30.) ``` 你有兩種方法來取消前面定制的事件,第一種是: Clock.unschedule(my_callback) 或者你在你的回調函數中返回False,那么你的事件將會自動取消: ```python count = 0 def my_callback(dt): global count count += 1 if count == 10: print 'Last call of my callback, bye bye!' return False print 'My callback is called' Clock.schedule_interval(my_callback, 1/30.) ``` ##### (二)單次事件 使用schedule_once(),你可以定制執行一次你的回調函數,比如在下一幀,或X秒后: ```python def my_callback(dt): print 'My callback is called!' Clock.schedule_once(my_callback, 1) ``` 上面的代碼中,my_callback()函數將會在1秒后執行。1秒參數是在執行該程序前等待的時間,以秒為單位。但是你可以使用特殊的值作為時間參數得到一切其它結果: * 如果X > 0,則回調函數會在X秒后執行。 * 如果X = 0, 則回調函數會在下一幀執行。 * 如果x = -1,則回調函數在在下一幀之前執行。 其中 x = -1最為常用。 重復執行一個函數的第二種方法是:一個回調函數使用schedule_once遞歸調用了自己,在外部schedule_once函數中又調用了該回調函數: ```python def my_callback(dt): print 'My callback is called !' Clock.schedule_once(my_callback, 1) Clock.schedule_once(my_callback, 1) ``` 當主循環嘗試保持定制請求時,當恰好一個定制的回調函數被調用時,有一些不確定的情況會發生。有時另外一些回調函數或一些任務花費了超出預期的時間,則定時會被延遲。 在第二種解決方案中,在上一次迭代執行結束后,下一次迭代每秒至少會被調用一次。而使用schedule_interval(),回調函數則每秒都會被調用。 ##### (三)事件跟蹤 如果你想為下一幀定制一個僅執行一次的函數,類似一個出發器,你可能這樣做: Clock.unschedule(my_callback) Clock.schedule_once(my_callback, 0) 這種方式的代價是昂貴的,因為你總是調用unschedule()方法,無論你是否曾經定制過它。另外,unschedule()方法需要迭代時鐘的弱引用列表,目的是找到你的回調函數并移除它。替代的方法是使用出發器: ```python trigger = Clock.create_trigger(my_callback) #隨后 trigger() ``` 每次你調用trigger,它會為你的回調函數定制一個信號調用,如果已經被定制,則不會重新定制。 #### 三、部件事件 每個部件都有兩個默認的事件類型: * **屬性事件(Property event)**:如果你的部件改變了位置或尺寸,則事件被觸發。 * **部件定義事件(Widget-defined event)**:當一個按鈕被按下或釋放時,事件被觸發。 #### 四、自定義事件 為了創建一個自定義事件,你需要在一個類中注冊事件名,并創建一個同名的方法: ```python class MyEventDispatcher(EventDispatcher): def __init__(self, **kwargs): self.register_event_type('on_test') super(MyEventDispatcher, self).__init__(**kwargs) def do_something(self, value): #當do_something被調用時,on_test事件將會連同value被發送 self.dispatch('on_test', value) def on_test(self, *args): print "I am dispatched", args ``` #### 五、附加回調 為了使用事件,你必須綁定回調函數。當事件被發送時,你的回調函數將會連同參數被調用。 一個回調函數可以是任何python函數,但是你必須確保它接受事件發出的參數。因此,使用*args的參數會更安全,這樣將會在args列表中接收到所有的參數。例如: ```python def my_callback(value, *args): print "Hello, I got an event!", args e = MyEventDispatcher() e.bind(on_test = my_callback) e.do_something('test') ``` 有關附加回調函數更多的示例可以參閱[kivy.event.EventDispatcher.bind()文檔](https://kivy.org/docs/api-kivy.event.html#kivy.event.EventDispatcher.bind) #### 六、屬性介紹 屬性是一個很好的方法用來定義事件并綁定它們。本質上來說,當你的對象的特征值發生變化時,它們創造事件,所有的引用特征值的屬性都會自動更新。 有不同類型的屬性來描述你想要處理的數據類型。 * StringProperty * NumericProperty * BoundedNumericProperty * ObjectProperty * DictProperty * ListProperty * OptionProperty * AliasProperty * BooleanProperty * ReferenceListProperty #### 七、聲明屬性 為了聲明屬性,你必須在類的級別進行。當你的對象被創建時,該類將會進行實際特征值的初始化。特寫屬性不是特征值,它們是基于你的特征值創建事件的機制。 ```python class MyWidget(Widget): text = StringProperty('') ``` 當重載__init__時,總是接受**kwargs參數并使用super()調用父類的__init__方法: def __init__(self, **kwargs): super(MyWidget, self).__init__(**kwargs) #### 八、發送屬性事件 Kivy的屬性,默認提供一個on_<property_name>事件。當屬性值改變時該事件被調用。 >注意,如果新的屬性值等于當前值,該事件不會被調用。 例如: ```python class CustomBtn(Widget): pressed = ListProperty([0, 0]) def on_touch_down(self, touch): if self.collide_point(*touch.pos): self.pressed = touch.pos return True return super(CustomBtn, self).on_touch_down(touch) def on_pressed(self, instance, pos): print('pressed at{pos}'.format(pos=pos)) ``` 在第3行: pressed = ListProperty([0,0]) 我們定義了pressed屬性,類型為ListProperty,默認值為[0, 0],當屬性值發生改變時,on_pressed事件被調用。 在第5行: ```python def on_touch_down(self, touch): if self.collide_point(*touch.pos): self.pressed = touch.pos return True return super(CustomBtn, self).on_touch_down(touch) ``` 我們重載了on_touch_down()方法,我們為我們的部件做了碰撞檢測。 如果觸摸發生在我們的部件內部,我們改變touch.pos按下的值并返回True,表明我們處理了這次觸摸并不想它繼續傳遞。 最后,如果觸摸發生在我們的部件外部,我們使用super()調用原始事件并返回結果。它允許觸摸事件繼續傳遞。 最后在11行: ```python def on_pressed(self, instance, pos): print ('pressed at {pos}'.format(pos=pos)) ``` 我們定義了on_pressed函數,當屬性值改變時,該函數被調用。 >注意當屬性值被定義時,on_<prop_name>事件在類內部被調用。為了在類的外部監控或觀察任何屬性值的變動,你可以以下面的方式綁定屬性值。 your_widget_instance.bind(property_name=function_name) 例如,考慮以下代碼: ```python class RootWidget(BoxLayout): def __init__(self, **kwargs): super(RootWidget, self).__init__(**kwargs) self.add_widget(Button(text='btn 1')) cb = CustomBtn() cb.bind(pressed=self.btn_pressed) self.add_widget(cb) self.add_widget(Button(text='btn 2')) def btn_pressed(self, instance, pos): print ('pos: printed from root widget: {pos}'.format(pos=.pos)) ``` 如果你運行上面的代碼,你會注意到在控制臺有兩個打印信息。一個來自on_pressed事件,該事件在CustomBtn類內部被調用,另一個來自我們綁定屬性改變的btn_pressed函數 你也需要注意到傳遞給on_<property_name>事件的參數及綁定屬性的函數。 def btn_pressed(self, instance, pos): 第一個參數是self,是該函數被定義的類的實例。你可以如下面的方式使用一個內聯函數: ``` cb = CustomBtn() def _local_func(instance, pos): print ('pos: printed from root widget: {pos}'.format(pos=.pos)) cb.bind(pressed=_local_func) self.add_widget(cb) ``` 第一個參數是屬性被定義的類的實例。 第二個參數是屬性的新的值。 下面是一個完整的麗日,你能拷貝下來進行實驗。 ``` from kivy.app import App from kivy.uix.widget import Widget from kivy.uix.button import Button from kivy.uix.boxlayout import BoxLayout from kivy.properties import ListProperty class RootWidget(BoxLayout): def __init__(self, **kwargs): super(RootWidget, self).__init__(**kwargs) self.add_widget(Button(text='btn 1')) cb = CustomBtn() cb.bind(pressed=self.btn_pressed) self.add_widget(cb) self.add_widget(Button(text='btn 2')) def btn_pressed(self, instance, pos): print ('pos: printed from root widget: {pos}'.format(pos=pos)) class CustomBtn(Widget): pressed = ListProperty([0, 0]) def on_touch_down(self, touch): if self.collide_point(*touch.pos): self.pressed = touch.pos # we consumed the touch. return False here to propagate # the touch further to the children. return True return super(CustomBtn, self).on_touch_down(touch) def on_pressed(self, instance, pos): print ('pressed at {pos}'.format(pos=pos)) class TestApp(App): def build(self): return RootWidget() if __name__ == '__main__': TestApp().run() ``` 運行結果如下: ![property_events_binding](http://ww1.sinaimg.cn/large/577d3ebejw1f0yohywgvmj20jd095jrh.jpg) 我們的定制按鈕沒有可視的表述,因此顯示一個黑塊。你能觸摸或點擊它以在控制臺查看輸出。 #### 九、混合屬性 當定義一個AliasProperty時,通常的做法是定義getter()和setter函數。當getter()和setter()函數使用*bind*被調用時,它落在了你的肩上。考慮以下代碼: ``` cursor_pos = AliasProperty(_get_cursor_pos, None, bind=( 'cursor', 'padding', 'pos', 'size', 'focus', 'scroll_x', 'scroll_y')) '''Current position of the cursor, in (x, y). :attr:`cursor_pos` is a :class:`~kivy.properties.AliasProperty`, read-only. ''' ``` 這里cursor_pos是一個AliasProperty,它使用_get_cursor_pos作為getter(),并且setter()為None,表明這是一個只讀屬性。 在最后,當任何使用bind=argument的屬性改變時,on_cursor_pos事件被發送。 ### 下節預告:編程向導4.6輸入管理
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看