<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.9Kv語言 #### 一、語言背后的思想 當你的應用程序變得更復雜時,構建部件樹和明確的聲明綁定將變得冗長和難以維護。KV語言試圖克服這些缺點。 KV語言(有時被叫kvlang,或kivy語言),允許你以聲明的方式來創建你的部件樹,并以一種自然的方式綁定部件屬性或回調函數。針對UI,它支持快速原型和敏捷改動。它也使得邏輯和用戶接口能更好的分離。 #### 二、如何加載KV 有兩種方式來加載KV代碼: * **通過名字約定** Kivy查找你的應用程序類的小寫的同名KV文件,如果它以'App'結尾則去掉它,例如: MyApp -> my.kv 如果這個文件定義了一個根部件,它將會附著到應用程序的根特征值,并用它作為應用程序部件樹的根。 * **Builder** 你可以告訴Kivy直接加載一個字符串或一個文件。如果這個字符串或文件定義了根部件,它將被返回。 Builder.load_file('path/to/file.kv') 或者 Builder.load_string('kv_string') #### 三、管理上下文 一個KV源構成的規則,用來描述部件的內容。你可以有一個根規則和任何數量的類或模板規則。 根規則通過聲明你的根部件類來聲明,不需要任何縮進,后面跟著冒號(:),并且被設置為應用程序實例的根特征值。 Widget: 一個類規則,有一對尖括號(<>)包括部件類名組成,后面跟冒號(:),定義類的實例如何被生動地表達: <MyWidget>: 和Python一樣,規則使用縮進進行界定,和良好的Python習慣一樣,縮進的每一級別最好是4個空格。 有三個關鍵字來指定KV語言: * **app**:總是引用你的應用程序的實例。 * **root**:引用當前規則中的根部件/模板。 * **self**:引用當前部件。 #### 四、特殊的語法 有兩個特殊語法來為整個KV上下文定義值: * 為了從KV中訪問Python的模塊和類: ``` #:import name x.y.z #:import isdir os.path.isdir #:import np numpy ``` 上面的代碼等價于: ``` from x.y import z as name from os.path import isdir import numpy as np ``` * 為了設置一個全部變量: ``` #:set name value ``` 等價于: ``` name = value ``` #### 五、實例化子部件 為了聲明部件的子部件,僅在規則里面聲明這些子部件即可: ``` MyRootWidget: BoxLayout: Button: Button: ``` 上面的例子定義了一個MyRootWidget的實例作為我們的根部件,它有一個子部件是BoxLayout的實例。BoxLayout進一步有兩個Button類的子部件。在Python代碼中應該是這樣: ``` root = MyRootWidget() box = BoxLayout() box.add_widget(Button()) box.add_widget(Button()) root.add_widget(box) ``` 你會發現在KV中,僅用很少的代碼,易寫并易讀。 當然,在Python中,你可以傳遞關鍵字參數到你的部件中。例如,設置一個GridLayout的列的數目,我們可以這樣寫: ``` grid = GridLayout(cols = 3) ``` 在KV中,你可以直接在規則中設置子部件的屬性: ``` GridLayout: cols:3 ``` 這個值被評估為一個Python表達式,并且表達式中所有的屬性值都將被監聽。例如在Python中: ``` grid = GridLayout(cols = len(self.data)) self.bind(data = grid.setter('cols')) ``` 當你的數據變化時,顯示跟著更新,在KV中只需這樣: ``` GridLayout: cols:len(root.data) ``` >注意,當屬性名以小寫字母開頭時,部件名首字母應當大寫。遵循*PEP8 Naming Conventions*是被鼓勵的。 #### 六、事件綁定 在KV語言中,你可以使用":"語法來綁定事件: ``` Widget: on_size: my_callback() ``` 你也可以使用args關鍵字傳遞參數: ``` TextInput: on_text:app.search(args[1]) ``` 更復雜的表達式可能類似這樣: ``` pos:self.center_x - self.texture_size[0] / 2, self.center_y - self.texture_size[1] / 2 ``` 這個表達式監聽center_x, center_y, texture_size的變動。如果其中一個發生了改變,表達式將會更新pos字段。 你也可以在KV語言中處理on_事件。例如輸入框有一個聚焦(focus)屬性,它將自動生成on_focus事件: ``` TextInput: on_focus:print(args) ``` #### 七、擴展畫布 KV語言可以這樣來定義你的畫布指令: ``` MyWidget: canvas: Color: rgba: 1, .3, .8, .5 Line: points: zip(self.data.x, self.data.y) ``` 當屬性值改變時它們將更新,當然,你也可以使用canvas.before和canvas.after. #### 八、引用部件 在一個部件樹中,經常需要訪問/引用其他的部件。KV語言提供了一個使用id's的方法來做這些工作。將它們認為是只能用于Kv語言類級別變量。看下面代碼: ``` <MyFirstWidget>: Button: id: f_but TextInput: text: f_but.state <MySecondWidget>: Button: id: s_but TextInput: text: s_but.state ``` 一個**id**被限制到它被聲明的作用域內,所以在<MySecondWidget\>外面s_but不能被訪問。 **id**是一個部件的弱引用(weakref)并且不是部件本身。因此,存儲id不能防止部件被垃圾回收。為了證明: ``` <MyWidget>: label_widget: label_widget Button: text: 'Add Button' on_press: root.add_widget(label_widget) Button: text: 'Remove Button' on_press: root.remove_widget(label_widget) Label: id: label_widget text: 'widget' ``` 上面的代碼中,雖然一個到label_widget的引用被存儲到MyWidget中,但是因為它僅僅是一個弱引用,一旦別的引用被移除,它不足以保持對象存活。因此,當移除按鈕被點擊后(將移除其他的引用)窗口將重新計算尺寸(調用垃圾回收導致重新檢測label_widget),當點擊添加按鈕來添加部件,一個引用錯誤將發生(ReferenceError:weakly-referenced object no longer exists) 為了保持部件存活,一個對label_widget的引用必須被保持。可以使用id._self_或label_widget._self_做到。正確的方式如下: ``` <MyWidget>: label_widget: label_widget.__self__ ``` #### 九、在Python代碼中訪問Kv語言定義的部件 考慮以下在my.kv中的代碼: ``` <MyFirstWidget>: # both these variables can be the same name and this doesn't lead to # an issue with uniqueness as the id is only accessible in kv. txt_inpt: txt_inpt Button: id: f_but TextInput: id: txt_inpt text: f_but.state on_text: root.check_status(f_but) ``` 在myapp.py: ``` ... class MyFirstWidget(BoxLayout): txt_inpt = ObjectProperty(None) def check_status(self, btn): print('button state is: {state}'.format(state=btn.state)) print('text input text is: {txt}'.format(txt=self.txt_inpt)) ... ``` txt_inpt被作為ObjectProperty初始化: txt_inpt = ObjectProperty(None) 這是效果導致self.txt_inpt是None。在KV語言中,這個屬性更新被id:txt_inpt引用的持有TextInput的實例。 txt_inpt:txt_inpt 從這點向上,self.txt_inpt持有一個被id txt_input標識的部件的引用并且能被用在類的任何地方,正如在check_status函數中一樣。對照這個函數,你僅僅需要傳遞id到你想用的地方。 你可以使用**ids**來訪問帶id標識的對象,這是一種更簡單的方法: ``` <Marvel> Label: id: loki text: 'loki: I AM YOUR GOD!' Button: id: hulk text: "press to smash loki" on_release: root.hulk_smash() ``` 在你的Python代碼中: ``` class Marvel(BoxLayout): def hulk_smash(self): self.ids.hulk.text = "hulk: puny god!" self.ids["loki"].text = "loki: >_<!!!" # alternative syntax ``` 當你的kv文件被解析時,kivy收集所有的帶id標簽的部件,并放置它們到self.ids字典中。這意味著你能以字典的風格來迭代這些部件并訪問它們。 ``` for key, val in self.ids.items(): print("key={0}, val={1}".format(key, val)) ``` >注意,雖然self.ids很簡潔,它被認為是使用ObjectProperty的最佳實踐。但是創建一個字典的引用,將會提供更快的訪問速度并更加清晰。 #### 十、動態類 考慮下面代碼: ``` <MyWidget>: Button: text: "Hello world, watch this text wrap inside the button" text_size: self.size font_size: '25sp' markup: True Button: text: "Even absolute is relative to itself" text_size: self.size font_size: '25sp' markup: True Button: text: "Repeating the same thing over and over in a comp = fail" text_size: self.size font_size: '25sp' markup: True Button: ``` 為了替代重復的代碼,我們可以使用模板來代替: ``` <MyBigButt@Button>: text_size: self.size font_size: '25sp' markup: True <MyWidget>: MyBigButt: text: "Hello world, watch this text wrap inside the button" MyBigButt: text: "Even absolute is relative to itself" MyBigButt: text: "repeating the same thing over and over in a comp = fail" MyBigButt: ``` 這個被規則聲明的類繼承自按鈕類。它允許我們改變默認值,并為每一個實例創建綁定而不用在Python那邊添加任何新的代碼。 #### 十一、在多個部件中重用樣式 看下面的在my.kv中的代碼: ``` <MyFirstWidget>: Button: on_press: self.text(txt_inpt.text) TextInput: id: txt_inpt <MySecondWidget>: Button: on_press: self.text(txt_inpt.text) TextInput: id: txt_inpt ``` 在myapp.py中 ``` class MyFirstWidget(BoxLayout): def text(self, val): print('text input text is: {txt}'.format(txt=val)) class MySecondWidget(BoxLayout): writing = StringProperty('') def text(self, val): self.writing = val ``` 因為兩個類共同使用相同的.kv風格。如果我們為兩個部件重用風格,這將使得設計簡化。你可以在my.kv中這樣寫代碼: ``` <MyFirstWidget,MySecondWidget>: Button: on_press: self.text(txt_inpt.text) TextInput: id: txt_inpt ``` 用一個逗號(,)來分離類名,所有的類將都有同樣的kv屬性。 #### 十二、使用KV語言設計 使用Kivy語言的一個目標就是分離邏輯和表現。表現層使用kv文件來表示,邏輯使用py文件來表示。 ##### (一)py文件中寫代碼 讓我們開始一個小例子,首先,在main.py文件中: ``` import kivy kivy.require('1.0.5') from kivy.uix.floatlayout import FloatLayout from kivy.app import App from kivy.properties import ObjectProperty, StringProperty class Controller(FloatLayout): '''Create a controller that receives a custom widget from the kv lang file. Add an action to be called from the kv lang file. ''' label_wid = ObjectProperty() info = StringProperty() def do_action(self): self.label_wid.text = 'My label after button press' self.info = 'New info text' class ControllerApp(App): def build(self): return Controller(info='Hello world') if __name__ == '__main__': ControllerApp().run() ``` 在這個例子中,我們創建了一個帶有兩個屬性的控制類: * **info**:接收一些文本 * **label_wid**接收標簽(label)部件 另外,我們創建了一個do_action()方法來使用這些屬性。它將會改變info文本和label_wid部件的文本。 ##### (二)在controller.kv中布局 執行一個沒有相應的.kv文件的應用程序可以運行,但是沒有任何東西被顯示到屏幕上。這是被期望的,因為控制類沒有部件在里面,它僅僅是一個FloatLayout。我們能圍繞Controller類在一個controller.kv文件中創建UI,當我們運行ControllerApp時它會被加載。這將如何實現及什么文件被加載都在kivy.app.App.load_kv()方法中被描述。 ``` #:kivy 1.0 <Controller>: label_wid: my_custom_label BoxLayout: orientation: 'vertical' padding: 20 Button: text: 'My controller info is: ' + root.info on_press: root.do_action() Label: id: my_custom_label text: 'My label before button press' ``` 在垂直布局的BoxLayout中,有一個標簽和一個按鈕。看起來很簡單,有3個事情將被做: 1. 從Controller使用數據。一旦在controller中info屬性被改變,表達式text:'My Controller info is:' + root.info將會自動更新。 2. 傳遞數據到Controller。表達式id:my_custom_label被賦值給id為my_custom_label的標簽。于是,在表達式label_wid:my_custom_label中使用my_custom_label傳遞部件Label的實例到你的Controller。 3. 使用Controller的on_press方法創建一個定制的回調函數。 * root和self被保留為關鍵字,可用在任何地方。root代表規則內的根部件,self代表當前部件。 * 在規則內你可以使用任何id聲明,同root和self一樣。例如,你可以在on_press()中這樣: Button: on_press:root.do_action();my_custom_label.font_size = 18 現在,我們運行main.py, controller.kv將會被自動加載,按鈕和標簽也將顯示并響應你的觸摸事件。 ### 下節預告:編程向導4.10集成其他框架
                  <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>

                              哎呀哎呀视频在线观看