- Kivy 教程
- Kivy - 首頁
- Kivy 基礎
- Kivy - 入門
- Kivy - 安裝
- Kivy - 架構
- Kivy - 檔案語法
- Kivy - 應用
- Kivy - Hello World
- Kivy - 應用生命週期
- Kivy - 事件
- Kivy - 屬性
- Kivy - 輸入
- Kivy - 行為
- Kivy 按鈕
- Kivy - 按鈕
- Kivy - 按鈕事件
- Kivy - 按鈕顏色
- Kivy - 按鈕大小
- Kivy - 按鈕位置
- Kivy - 圓形按鈕
- Kivy - 停用按鈕
- Kivy - 圖片按鈕
- Kivy 控制元件
- Kivy - 控制元件
- Kivy - 標籤
- Kivy - 文字輸入
- Kivy - 畫布
- Kivy - 線
- Kivy - 複選框
- Kivy - 下拉列表
- Kivy - 視窗
- Kivy - 滾動檢視
- Kivy - 旋轉木馬
- Kivy - 滑塊
- Kivy - 圖片
- Kivy - 彈出視窗
- Kivy - 開關
- Kivy - 旋轉器
- Kivy - 分隔器
- Kivy - 進度條
- Kivy - 氣泡
- Kivy - 標籤頁面板
- Kivy - 散點圖
- Kivy - 手風琴
- Kivy - 檔案選擇器
- Kivy - 顏色選擇器
- Kivy - 程式碼輸入
- Kivy - 模態檢視
- Kivy - 切換按鈕
- Kivy - 相機
- Kivy - 樹形檢視
- Kivy - reStructuredText
- Kivy - 操作欄
- Kivy - 播放器
- Kivy - 模板檢視
- Kivy - 虛擬鍵盤
- Kivy - 觸控漣漪
- Kivy - 音訊
- Kivy - 影片
- Kivy - 拼寫檢查
- Kivy - 效果
- Kivy - 輸入記錄器
- Kivy - OpenGL
- Kivy - 文字
- Kivy - 文字標記
- Kivy - 設定
- Kivy 佈局
- Kivy - 佈局
- Kivy - 浮動佈局
- Kivy - 網格佈局
- Kivy - 箱式佈局
- Kivy - 堆疊佈局
- Kivy - 錨點佈局
- Kivy - 相對佈局
- Kivy - 頁面佈局
- Kivy - 回收佈局
- Kivy - 佈局巢狀
- Kivy 高階概念
- Kivy - 配置物件
- Kivy - 圖集
- Kivy - 資料載入器
- Kivy - 快取管理器
- Kivy - 控制檯
- Kivy - 動畫
- Kivy - 多筆畫
- Kivy - 時鐘
- Kivy - SVG
- Kivy - UrlRequest
- Kivy - 剪貼簿
- Kivy - 工廠
- Kivy - 手勢
- Kivy - 語言
- Kivy - 圖形
- Kivy - 繪製
- Kivy - 打包
- Kivy - Garden
- Kivy - 儲存
- Kivy - 向量
- Kivy - 工具
- Kivy - 檢查器
- Kivy - 工具
- Kivy - 日誌記錄器
- Kivy - 幀緩衝區
- Kivy 應用和專案
- Kivy - 繪圖應用
- Kivy - 計算器應用
- Kivy - 計時器應用
- Kivy - 相機處理
- Kivy - 圖片檢視器
- Kivy - 貝塞爾曲線
- Kivy - 畫布壓力測試
- Kivy - 圓形繪製
- Kivy - 控制元件動畫
- Kivy - 雜項
- Kivy 有用資源
- Kivy - 快速指南
- Kivy - 有用資源
- Kivy - 討論
Kivy - 快速指南
Kivy - 入門
Kivy 是一個開源的 Python 庫。它允許您構建具有自然使用者介面 (NUI) 的多點觸控應用程式。使用 Kivy,您可以開發跨平臺應用程式。相同的程式碼,只需編寫一次,即可部署到不同的各種作業系統平臺,例如 Windows、macOS、Linux、Android 和 iOS。
Python 中流行的 GUI 框架
Kivy 是 Python 生態系統中眾多 GUI 框架之一。一些用於構建桌面 GUI 應用程式的流行 Python 庫有:
Tkinter − Tkinter 包捆綁在 Python 的標準庫中。它是 Tcl/Tk GUI 工具包的標準 Python 介面。
PyQt5 − 此庫是 Qt GUI 工具包的 Python 移植版本。您可以在 此處 訪問我們關於 PyQt5 的完整教程。
WxPython − WxPython 庫允許 Python 程式設計師訪問 WxWidgets,這是一個開源的 GUI 工具包,最初是用 C++ 編寫的。要了解更多關於 WxPython 的資訊,請點選 此處。
Kivy − Kivy 是一個 Python 庫,可幫助您為 Windows、Linux、iOS 和 Android 構建跨平臺 GUI 應用程式。Kivy 支援觸控輸入。Kivy GUI 框架中的所有控制元件都能夠處理多點觸控手勢。
Kivy 擁有強大的圖形和多媒體功能。Kivy 應用程式可以支援音訊、影片、動畫以及 2D 和 3D 圖形。
Python Kivy 的主要特性
以下是 Python Kivy 的一些主要特性:
Kivy 支援觸控輸入。Kivy GUI 框架中的所有控制元件都能夠處理多點觸控手勢。
Kivy 的全面 GUI 控制元件和強大的佈局管理使設計吸引人的介面變得輕而易舉。
Kivy 擁有強大的圖形和多媒體功能。這使得在應用程式中整合 2D 和 3D 圖形、動畫、音訊和影片元件成為可能。
Kivy 支援各種型別的輸入裝置。包括觸控、滑鼠和手勢。
Kivy API 可以訪問移動裝置的硬體元件,例如相機、GPS 等。
Kivy 使用 OpenGL ES 2 圖形庫,並基於頂點緩衝物件和著色器。
Kivy 依靠 Cython 進行核心實現,並依靠 SDL2(簡單直接媒體層)進行底層多媒體和輸入處理。
要在配備 Windows、Linux 或 iOS 作業系統的桌面上部署 Kivy 應用程式,可使用 PyInstaller 構建可分發檔案。要為 Android 構建 APK,您需要使用 Android Studio 和 Buildozer 實用程式。
Kivy 語言
Kivy 使用一種稱為 Kivy 語言(有時也稱為 Kv 語言)的特殊宣告式語言來構建 Kivy 應用程式的使用者介面佈局。它用於將應用程式的設計方面與其程式設計邏輯分離。設計以“.kv”副檔名的文字檔案編寫。Kivy 框架會自動載入“.kv”檔案並根據其中給定的規範構建 UI。
Kivy 庫的初始版本於 2011 年釋出。目前,Kivy 2.2 版本已於 2023 年 5 月釋出。
Kivy - 安裝
要構建 Kivy 應用程式,您需要在計算機上安裝 Python。最新的穩定版本 Kivy 2.2.0 正式支援 Python 3.7 到 3.11 版本。如果尚未安裝 Python,請從 Python 官方網站下載適用於您的作業系統和體系結構的最新 Python 版本的安裝程式:https://python.club.tw/downloads/
Python 虛擬環境
Python 建議使用虛擬環境來避免與其他 Python 版本和包發生衝突。
虛擬環境允許我們為特定專案建立 Python 的隔離工作副本,而不會影響外部設定。我們將使用 Python 標準庫中的“venv”模組來建立虛擬環境。PIP 預設包含在 Python 3.4 或更高版本中。
建立虛擬環境
使用以下命令在 Windows 中建立虛擬環境:
C:\users\user\>python -m venv c:\kivyenv
在 Ubuntu Linux 上,在建立虛擬環境之前,如果需要,請更新 APT 儲存庫並安裝“venv”。
mvl@GNVBGL3:~ $ sudo apt update && sudo apt upgrade -y mvl@GNVBGL3:~ $ sudo apt install python3-venv
然後,使用以下命令建立虛擬環境:
mvl@GNVBGL3:~ $ sudo python3 -m venv kivyenv
啟用虛擬環境
您需要啟用虛擬環境。在 Windows 上,使用以下命令:
C:\>cd kivyenv C:\kivyenv>scripts\activate (kivyenv) C:\kivyenv>
在 Ubuntu Linux 上,使用以下命令啟用虛擬環境:
mvl@GNVBGL3:~$ cd kivyenv mvl@GNVBGL3:~/kivyenv$ source bin/activate (myenv) mvl@GNVBGL3:~/kivyenv$
使用 pip 實用程式安裝 Kivy
安裝任何 Python 包最簡單的方法是使用“pip”實用程式。Python 3 安裝附帶“pip”安裝程式。啟用虛擬環境後,在 Windows 中的 CMD 終端或 Linux 終端中使用以下命令:
pip3 install "kivy[base]" kivy_examples
這將安裝 Kivy 包及其最少依賴項。“kivy_examples”包是可選的。使用“full”選項而不是“base”可以啟用音訊/影片支援。
安裝 Kivy 的依賴庫
SDL2(簡單直接媒體層)是 Kivy 的主要依賴項。在 Windows 作業系統上,當您使用“pip”實用程式時,SDL2 會自動安裝。但是,對於 Linux 和 macOS,您需要單獨安裝 SDL2。
在 macOS 上,您可以使用 Homebrew 透過在終端中執行以下命令來安裝 SDL2:
brew install sdl2
如果在 Linux 作業系統上,請使用相應的包管理器安裝 SDL2。例如,在 Ubuntu Linux 機器上,可以使用以下命令完成此操作:
sudo apt-get install libsdl2-dev
此外,您可能需要安裝其他依賴項,例如“gstreamer”和“Pillow”,以實現 Kivy 的某些特定功能。
驗證 Kivy 安裝
要驗證 Kivy 是否已正確安裝,請啟動 Python 互動式 shell 並匯入包。控制檯顯示 Kivy 的依賴項也已匯入。
>>> import kivy [INFO] [Logger] Record log in C:\Users\mlath\.kivy\logs\kivy_23-05-26_0.txt [INFO] [deps] Successfully imported "kivy_deps.gstreamer" 0.3.3 [INFO] [deps] Successfully imported "kivy_deps.angle" 0.3.3 [INFO] [deps] Successfully imported "kivy_deps.glew" 0.3.1 [INFO] [deps] Successfully imported "kivy_deps.sdl2" 0.6.0 [INFO] [Kivy] v2.2.0 [INFO] [Kivy] Installed at "c:\kivyenv\Lib\site-packages\kivy\__init__.py" [INFO] [Python] v3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] [INFO] [Python] Interpreter at "c:\kivyenv\Scripts\python.exe" [INFO] [Logger] Purge log fired. Processing... [INFO] [Logger] Purge finished!
您還可以使用“pip freeze”命令獲取已安裝的所有包的列表:
(kivyenv) C:\kivyenv>pip3 freeze certifi==2023.5.7 charset-normalizer==3.1.0 docutils==0.20.1 idna==3.4 Kivy==2.2.0 kivy-deps.angle==0.3.3 kivy-deps.glew==0.3.1 kivy-deps.gstreamer==0.3.3 kivy-deps.sdl2==0.6.0 Kivy-examples==2.2.0 Kivy-Garden==0.1.5 Pillow==9.5.0 Pygments==2.15.1 pypiwin32==223 pywin32==306 requests==2.31.0 urllib3==2.0.2
Kivy - 架構
閱讀本章以瞭解 Kivy 框架的設計架構。一方面,Kivy 提供各種控制元件,允許使用者與應用程式互動;另一方面,它與各種硬體裝置互動,例如滑鼠、TUIO、音訊和影片流等。中間層包含用於處理觸控輸入、音訊和影片、圖形指令和文字輸入的驅動程式或提供程式。
這是 Kivy 框架的官方架構圖:
核心提供程式
Kivy 架構的一個重要特性是“模組化”和“抽象”。開啟視窗、讀取音訊和影片流、載入影像等操作是任何圖形應用程式中的核心任務。Kivy 透過為控制硬體的驅動程式提供易於實現的 API 來抽象這些核心任務。
Kivy 使用特定提供程式來處理應用程式執行的作業系統。每個作業系統(Windows、Linux、macOS 等)都有自己的本機 API 用於不同的核心任務。它們充當作業系統與 Kivy 之間的中間通訊層。因此,Kivy 充分利用了作業系統公開的功能來提高效率。
使用特定於平臺的庫可以減小 Kivy 發行版的大小並簡化打包過程。這也使得將 Kivy 移植到其他平臺變得更容易。Android 移植從中受益匪淺。
輸入提供程式
輸入提供程式是一段程式碼,用於新增對特定輸入裝置的支援。Kivy 中內建支援的不同輸入裝置包括:
- Android 操縱桿輸入提供程式
- Apple 的觸控板
- TUIO(有形使用者介面物件)
- 滑鼠模擬器
- HIDInput
要新增對新輸入裝置的支援,請提供一個新類,該類從您的裝置讀取輸入資料並將其轉換為 Kivy 基本事件。
圖形
OpenGL 是 Kivy 框架整個圖形 API 的基礎。Kivy 使用 OpenGL 指令發出硬體加速的繪圖命令。Kivy 透過定義易於使用的功能來消除編寫 OpenGL 命令的困難部分。
Kivy 使用 OpenGL 2.0 ES 版本(GLES 或嵌入式系統的 OpenGL),您可以使用它進行跨平臺開發。
核心庫
Kivy 框架的以下組成部分提供了高階抽象:
時鐘 − 時鐘 API 可幫助您安排定時器事件。支援一次性定時器和週期性定時器。
手勢檢測 − 多點觸控介面的重要需求。手勢識別器可以檢測各種型別的筆劃,例如圓形或矩形。您甚至可以訓練它來檢測您自己的筆劃。
Kivy語言 − kivy語言用於輕鬆高效地描述使用者介面。這使得應用程式設計與開發應用程式邏輯分離。
屬性 − Kivy獨特的屬性類概念(它們與Python類中的屬性不同)是將您的視窗小部件程式碼與使用者介面描述連結的元素。
UIX
Kivy的使用者介面由視窗小部件和佈局構建。
視窗小部件是您新增到應用程式中的 UI 元素,以提供某種功能。視窗小部件的示例包括按鈕、滑塊、列表等等。視窗小部件接收MotionEvents。
多個視窗小部件排列在合適的佈局中。Kivy提供佈局類,以滿足各種用途的視窗小部件放置需求。例如網格佈局或盒子佈局。您還可以巢狀佈局。
事件分發
術語“視窗小部件”在幾乎所有圖形工具包中都用於 UI 元素。任何接收輸入事件的物件都是視窗小部件。一個或多個視窗小部件排列成樹狀結構。
Kivy應用程式視窗只能容納一個根視窗小部件,但根視窗小部件可以在樹狀結構中包含其他視窗小部件。因此,視窗小部件之間存在“父-子-兄弟”關係。
每當發生新的輸入事件時,視窗小部件樹的根視窗小部件首先接收該事件。根據觸控的狀態,事件會向下傳播到視窗小部件樹。
樹中的每個視窗小部件都可以處理事件或將其傳遞給層次結構中的下一個視窗小部件。如果視窗小部件吸收並處理事件,則應返回True,以便停止其向下傳播到樹中,並且不會對該事件進行進一步處理。
def on_touch_down(self, touch):
for child in self.children[:]:
if child.dispatch('on_touch_down', touch):
return True
由於事件透過視窗小部件樹傳播,因此通常需要驗證事件是否發生在預期處理該事件的某個視窗小部件的區域內。collide_point() 方法可以幫助確定這一事實。此方法檢查觸控位置是否落在某個視窗小部件的“監視區域”內,並在否則返回True或False。預設情況下,這檢查螢幕上由視窗小部件的pos(位置;x & y)和size(寬度 & 高度)描述的矩形區域。
Kivy - 檔案語法
Kivy框架提供了一種簡潔的宣告式方法來定義視窗小部件結構和外觀,並使用Kivy語言(也稱為Kv語言)。它是一種宣告式語言,專門用於構建Kivy應用程式中的使用者介面。其主要優點是可以將UI設計與用Python編寫的應用程式邏輯分離。
UI設計定義在文字檔案中,該檔案必須具有“.kv”副檔名。它包含應用程式視窗中視窗小部件的層次序列。該檔案採用樹狀結構,顯示視窗小部件之間的父子兄弟關係。在每個視窗小部件下方,都指定了其屬性、事件和事件處理程式。
kv設計語言在建立“.kv”檔案時規定以下約定,以便Python和Kivy框架能夠識別和載入相應的視窗小部件結構:
檔名必須小寫
它必須與應用程式中的主類匹配。此類繼承自App類。
如果類的名稱以“app”或“App”結尾(例如,HelloApp),則“.kv”檔案必須從其名稱中排除“app”。這意味著,對於HelloApp類,“.kv”檔案的檔名必須為“hello.kv”。
“.kv”檔案必須與Python應用程式檔案(.py)所在的同一資料夾中。
在使用“.kv”檔案時,App類不會覆蓋build()方法。只需使用pass語句宣告一個類就足夠了。當呼叫run()方法時,Kivy會自動從相應的“.kv”檔案中載入UI。
讓我們首先從HelloApp類中刪除build()方法:
示例
from kivy.app import App class HelloApp(App): pass app = HelloApp() app.run()
使用者介面定義在同一資料夾中的“hello.kv”檔案中。我們有一個垂直方向的頂級BoxLayout,在其下方放置了兩個標籤。將以下指令碼儲存為“hello.kv”檔案
BoxLayout:
orientation: 'vertical'
Label:
text: 'Python Kivy Tutorial'
font_size: '30pt'
Label:
text: 'From TutorialsPoint'
font_size: '50'
color: (1,0,0,1)
現在,如果您執行“hello.py”程式,它將產生以下輸出:
輸出
在後面的章節中,我們將學習如何在“.kv”檔案中向視窗小部件新增事件處理程式。
Kivy - 應用
使用Kivy框架編寫的應用程式由繼承“kivy.app.App”類的類的物件表示。呼叫此物件的run()方法啟動應用程式,並進入無限事件迴圈。
應用程式GUI透過覆蓋App類中的build()方法或提供相應的“.kv”檔案來設定。
應用程式配置
如果要提供一個或多個引數的自定義配置,則在呼叫App類的build_config()方法時將建立config.ini檔案。
這是一個build_config()方法的示例。它將兩個引數的值儲存在“ini”檔案的“section1”中。“ini”檔案的檔名將與應用程式類相同(如果它有“App”字尾,則不包含)。因此,如果您的應用程式類是“HelloApp”,則將建立“ini”檔案作為“hello.ini”。當呼叫build()方法時,將載入此檔案中的引數。
def build_config(self, config):
config.setdefaults('section1', {
'Company': 'TutorialsPoint',
'year': '2023'
})
新增部分後,將在包含“hello.py”檔案的同一目錄中建立“hello.ini”檔案。
如下所示在build()方法中載入並使用配置設定:
def build(self):
config = self.config
l1 = Label(text="© {} Year {}".format(
config.get('section1', 'company'),
config.getint('section1', 'year')),
font_size=40)
return l1
執行應用程式時,將透過讀取“config”檔案填充標籤。
示例
以下是完整的程式:
from kivy.app import App
from kivy.uix.label import Label
from kivy.core.window import Window
class HelloApp(App):
Window.size = (720, 300)
def build_config(self, config):
config.setdefaults('section1', {
'Company': 'TutorialsPoint',
'year': '2023'
})
def build(self):
config = self.config
l1 = Label(text="© {} Year {}".format(
config.get('section1', 'company'),
config.getint('section1', 'year')),
font_size=40)
return l1
app = HelloApp()
app.run()
輸出
執行應用程式時,它將生成以下視窗作為輸出:
查詢應用程式資料夾中建立的“hello.ini”檔案。使用文字編輯器開啟後,它顯示以下內容:
[section1] company = TutorialsPoint year = 2023
App類中的例項方法
App類定義了以下例項方法:
build() − 此方法初始化應用程式,並且僅呼叫一次。如果此方法返回一個視窗小部件(樹),則它將用作根視窗小部件並新增到視窗中。
build_config() − 此方法在初始化應用程式之前構造ConfigParser物件。根據您在此處放置的任何預設部分/鍵/值配置,將在本地目錄中建立“ini”檔案。
load_config() − 此函式返回包含應用程式配置的ConfigParser。
load_kv() − 如果在此應用程式之前尚未構建視窗小部件樹,則在第一次執行應用程式時將呼叫此方法。然後,此方法會在與包含應用程式類的檔案相同的目錄中查詢匹配的“kv”檔案。
pause() − 此方法導致應用程式暫停。
run() − 呼叫時,此方法以獨立模式啟動應用程式。
stop() −此方法停止應用程式。
on_pause() − 這是當請求暫停模式時呼叫的事件處理程式方法。如果它返回True,則應用程式可以進入暫停模式,否則應用程式將停止。
on_resume() − 從暫停模式恢復應用程式的事件處理程式方法。
on_start() − 此方法是“on_start”事件的事件處理程式。它在初始化後(在呼叫build()之後)但在應用程式開始執行之前觸發。
on_stop() − 應用程式執行結束時(即視窗即將關閉)觸發的“on_stop”事件。此方法處理on_stop事件。
Kivy - Hello World
讓我們從使用Kivy構建一個簡單的“Hello World”應用程式開始。請按照以下步驟操作:
要開發Kivy應用程式,您需要從“kivy.app”模組匯入App類。
from kivy.app import App
使用App作為其基類的類的物件表示應用程式。要設計介面,請覆蓋build()方法,該方法返回一個根視窗小部件。現在,讓我們在build()方法中放置一個pass語句。
class HelloApp(App):
def build(self):
pass
接下來,例項化上述“HelloApp”類:
app = HelloApp()
App類的run()方法啟動無限事件迴圈。它顯示一個當前沒有任何視窗小部件的空白應用程式視窗。
app.run()
現在讓我們向根視窗小部件新增一個不可編輯的標籤,其中包含“Hello World”標題。為此,我們必須從“kivy.uix.label”模組匯入Label類。更改build()方法,如下面的程式所示。
Python Kivy中的Hello World
以下是使用Kivy列印“Hello World”的完整程式碼:
示例
from kivy.app import App from kivy.uix.label import Label class HelloApp(App): def build(self): l1 = Label(text="Hello World", font_size=50) return l1 app = HelloApp() app.run()
Label物件可以使用許多屬性進行配置。在這裡,我們只設置text和font_size屬性。
從命令列執行上述程式碼(hello.py):
python hello.py
Kivy在終端中生成更多日誌文字
[INFO ] [Factory] 190 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil (img_ffpyplayer ignored) [INFO ] [Text ] Provider: sdl2 [INFO ] [Window ] Provider: sdl2 [INFO ] [GL ] Using the "OpenGL" graphics system [INFO ] [GL ] GLEW initialization succeeded [INFO ] [GL ] Backend used <glew> [INFO ] [GL ] OpenGL version <b'4.6.0 - Build 31.0.101.3959'> [INFO ] [GL ] OpenGL vendor <b'Intel'> [INFO ] [GL ] OpenGL renderer <b'Intel(R) Iris(R) Xe Graphics'> [INFO ] [GL ] OpenGL parsed version: 4, 6 [INFO ] [GL ] Shading version <b'4.60 - Build 31.0.101.3959'> [INFO ] [GL ] Texture max size <16384> [INFO ] [GL ] Texture max units <32> [INFO ] [Window ] auto add sdl2 input provider [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked [INFO ] [Base ] Start application main loop [INFO ] [GL ] NPOT texture support is available
執行此應用程式時,您將獲得預設的Kivy應用程式視窗,其中包含一個帶有“Hello World”文字的標籤。
您可以按“X”按鈕關閉視窗並停止正在執行的應用程式。
Kivy中的佈局
在上面的程式中,我們在應用程式的根樹中只使用了一個視窗小部件,即Label。如果要放置多個視窗小部件,則需要將它們新增到佈局中,然後從build()方法返回佈局物件。Kivy支援各種型別的佈局,例如BoxLayout、FlowLayout、AnchorLayout等等。
讓我們設計介面,以便在垂直BoxLayout物件中新增兩個標籤。標籤一個接一個地新增。HelloApp類的build()方法將相應地更改。
示例
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class HelloApp(App):
def build(self):
lo = BoxLayout(orientation='vertical')
l1 = Label(text="Hello World", font_size=50)
l2 = Label(text = "From TutorialsPoint",
font_size=30,
color = (1,0,0,1))
lo.add_widget(l1)
lo.add_widget(l2)
return lo
app = HelloApp()
app.run()
輸出
執行上述程式以獲得以下輸出:
Kivy - 應用生命週期
Kivy應用程式從執行到停止會經歷不同的階段。下圖顯示了不同的階段:
現在讓我們詳細討論每個階段:
初始化UI
Kivy框架中的App類是表示Kivy應用程式的類。建立App物件是應用程式生命週期中的第一步。
from kivy.app import App
宣告App類的子類,並覆蓋build()方法。
from kivy.app import App
class MyApp(App):
def build(self):
#UI Design
它透過呼叫build()方法或藉助“.kv”檔案來構建應用程式的UI。如果需要,應用程式的配置將從相應的“.ini”檔案中載入。
事件迴圈
載入使用者介面後,App物件進入無限事件迴圈。
if __name__ == '__main__': MyApp().run()
介面中組裝的各種視窗小部件現在吸收使用者互動(例如按鈕點選或文字輸入),並根據相應的事件處理程式做出響應。響應使用者互動,任何視窗小部件或應用程式的狀態都可能被修改。
要執行應用程式,請從OS終端執行以下命令:
Python MyApp.py
雖然你可以在 Windows 或 Linux 上以這種方式執行你的 Kivy 應用,但在 Android 上執行它可能需要一些額外的步驟。對於 Android,你應該構建一個 APK(Android 軟體包工具包)。
你應該使用 **Buildozer**,這是一個自動化整個構建過程的工具。它安裝了 python-for-android 的所有先決條件,包括 android SDK 和 NDK,然後構建一個可以自動推送到裝置的 APK。Buildozer 目前僅在 Linux 和 macOS 上執行(對於 Windows,請在機器上啟用 WSL,然後從 WSL 中使用 Buildozer)。
暫停/恢復
當應用正在執行時,可以使其暫停。例如,如果應用程式視窗被最小化,或者裝置本身進入睡眠模式,暫停模式有助於節省資源。
Kivy 有一個 on_pause() 事件處理程式。當請求暫停模式時,它會被呼叫。如果你的應用可以進入暫停模式,則應返回 True,否則返回 False,你的應用程式將停止。你無法控制應用程式何時進入此模式。它由作業系統決定,主要用於移動裝置(Android/iOS)和調整大小。
應用可以從暫停的地方恢復執行。
當你的應用程式從暫停模式恢復時,Kivy 的 on_resume() 事件處理程式會被呼叫。
恢復時,OpenGL 上下文可能已損壞/釋放。在這裡你可以重建一些 OpenGL 狀態。
停止
當用戶透過呼叫應用程式碼中的適當方法關閉應用時。在應用程式執行終止之前,會進行所有清理操作。
Kivy - 事件
Kivy 是一個 Python 庫,可幫助你構建跨平臺的 GUI 應用程式。任何 GUI 應用程式都是事件驅動的,其中程式的流程不是順序的(從上到下),而是由使用者與介面上的小部件互動來決定的。使用者操作,例如點選按鈕、“從列表中選擇一個專案”或“從可用的單選按鈕中選擇一個選項”等,稱為 **事件**。
基於 GUI 的程式會預料到其環境內外可能發生的所有事件,並在某個事件發生時(以及如果發生)將其分派給相應的處理程式函式。
當呼叫 Kivy 的 App 物件的 run() 方法時,應用程式啟動一個“事件監聽”迴圈並觸發相應的回撥函式,每個事件型別一個。
全域性事件分發器
Kivy 框架包含 EventDispatcher 類。它將事件物件分派到視窗小部件樹,並且事件透過視窗小部件層次結構傳播。當處於處理事件位置的視窗小部件時,其關聯的回撥處理程式將被觸發。**Widget、Animation** 和 **Clock** 類是事件分發器的示例。
Clock 是一個全域性事件分發器,允許你在特定時間間隔安排和觸發事件。它定義了諸如 'schedule_once()' 和 'schedule_interval()' 之類的方法,以註冊在特定延遲後或以定期間隔呼叫的函式或方法。此機制對於處理定時事件、動畫更新以及應用中的其他重複任務很有用。
示例
在下面的示例中,我們在視窗小部件樹中放置了一個標籤和兩個按鈕。標題為“開始”的按鈕安排每隔一秒定期發生一個事件。schedule_interval() 函式使用以下語法編寫:
Clock.schedule_interval(callback, timeout)
另一方面,標題為“停止”的第二個按鈕呼叫 unscheduled() 方法,該方法刪除已安排的事件。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class DemoApp(App):
def build(self):
lo = BoxLayout(orientation='vertical')
self.l1 = Label(text="0", font_size=100)
self.b1 = Button(text="start", font_size=100, color=(0, 0, 1, 1))
self.b1.bind(on_press=self.onstart)
self.b2 = Button(text="Stop", font_size=100, color=(1, 0, 0, 1))
self.b2.bind(on_press=self.onstop)
lo.add_widget(self.l1)
lo.add_widget(self.b1)
lo.add_widget(self.b2)
return lo
def onstart(self, event):
print("started")
Clock.schedule_interval(self.update_label, 1)
def onstop(self, event):
Clock.unschedule(self.update_label)
def update_label(self, event):
self.l1.text = str(int(self.l1.text) + 1)
if __name__ == '__main__':
DemoApp().run()
輸出
執行以上程式。標籤最初顯示“0”。點選“開始”按鈕。標籤開始每秒在其上遞增數字。按“停止”按鈕取消安排事件。
視窗小部件事件
大多數 Kivy 視窗小部件都具有內建的事件處理功能。實際上,每個視窗小部件都設計為處理特定型別的事件。例如,Button 視窗小部件處理由點選它引起的事件。你可以為視窗小部件上發生的特定事件(例如按鈕點選、觸控事件或鍵盤事件)註冊事件處理程式。
通常,事件處理程式在視窗小部件的類或 App 類中定義為方法。它們通常以“on_”為字首,後跟事件的名稱。例如,按鈕按下事件的“on_press”。
當事件發生時,Kivy 會自動呼叫相應的事件處理程式方法,並將有關事件的相關資訊作為引數傳遞。在事件處理程式中,你可以定義所需的行為或要執行的操作。
與視窗小部件關聯的事件
下面列出了與一些最常用視窗小部件關聯的事件:
按鈕
**on_press** - 當按鈕被按下時觸發。
**on_release** - 當按鈕被釋放時觸發。
**on_touch_down** - 當按鈕上開始觸控事件時觸發。
**on_touch_up** - 當按鈕上結束觸控事件時觸發。
TextInput
**on_text_validate** - 當用戶完成文字輸入編輯(透過按下 Enter 或 Return)時觸發。
**on_focus** - 當文字輸入獲得或失去焦點時觸發。
**on_text** - 每當輸入欄位中的文字更改時觸發。
CheckBox
**on_active** - 當複選框被選中或取消選中時觸發。
Slider
**on_value** - 當滑塊的值更改時觸發。
**on_touch_down** - 當滑塊上開始觸控事件時觸發。
**on_touch_up** - 當滑塊上結束觸控事件時觸發。
ToggleButton
**on_state** - 當切換按鈕的狀態更改(切換開啟或關閉)時觸發。
**on_press** - 當切換按鈕被按下時觸發。
ListView
**on_select** - 當列表檢視中的專案被選中時觸發。
FileChooser
**on_selection** - 當在檔案選擇器中選擇檔案或目錄時觸發。
Switch
**on_active** - 當開關切換開啟或關閉時觸發。
Video
**on_load** - 當影片載入完成時觸發。
**on_play** - 當影片開始播放時觸發。
**on_pause** - 當影片暫停時觸發。
**on_stop** - 當影片停止播放時觸發。
Spinner
**on_text** - 當從微調器中選擇一個專案時觸發。
ActionButton
**on_press** - 當操作按鈕被按下時觸發。
示例 - Kivy 中的事件處理
當我們解釋 Kivy 框架中的每個視窗小部件時,將討論這些事件。但是,在本節中,這裡給出了兩個事件處理示例。
示例 1
第一個示例顯示了 Button 視窗小部件的“on_press”事件。在下面的程式碼中,我們有一個 Label 和一個 Button 視窗小部件,排列在一個 BoxLayout 中。為了處理 on_press 事件,我們將按鈕與 DemoApp 類中定義的 onstart() 方法繫結
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class DemoApp(App):
def build(self):
lo = BoxLayout(orientation='vertical')
self.l1 = Label(text="0", font_size=100)
self.b1 = Button(text = "start", font_size = 100, color=(1,0,0,1))
self.b1.bind(on_press=self.onstart)
lo.add_widget(self.l1)
lo.add_widget(self.b1)
return lo
def onstart(self, event):
print ("started")
self.l1.text = str(int(self.l1.text)+1)
if __name__ == '__main__':
DemoApp().run()
輸出
將以上程式碼儲存為“demo.py”並從命令列或 Python IDE 執行它。程式以標籤顯示 0 作為其標題開始。每次單擊按鈕時,標題都會增加 1。
示例 2
在此示例中,我們有一個 TextInput 視窗小部件和一個 Label。TextInput 繫結到 onkey() 方法。使用者輸入的每個按鍵都反映在 Label 上。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.core.window import Window
Window.size = (720,400)
class DemoApp(App):
def build(self):
lo = BoxLayout(orientation='vertical')
self.t1 = TextInput(multiline=False)
self.l1 = Label(font_size=50)
self.t1.bind(text=self.onkey)
lo.add_widget(self.t1)
lo.add_widget(self.l1)
return lo
def onkey(self, event, value):
print ("press")
self.l1.text = value
if __name__ == '__main__':
DemoApp().run()
輸出
執行程式並在文字框中輸入一些文字。當你輸入時,Label 標題會更新。
還可以定義自定義事件和事件處理程式來處理特定於應用程式的事件。為此,你需要對 'EventDispatcher' 類進行子類化並定義所需屬性和方法。
自定義事件可以使用類似於視窗小部件事件的 'trigger()' 和 'on_event_name' 模式進行分派和處理。
Kivy - 屬性
屬性是 Kivy 中的一個特殊類,允許你定義和管理視窗小部件或物件的屬性。Property 類在“kivy.properties”模組中定義。你可以跟蹤對這些屬性的更改,並且它們允許你繫結回撥函式以便在屬性更改時執行。
Kivy 的屬性類支援以下功能:
值檢查/驗證
每當將新值分配給屬性時,都會根據驗證約束對其進行檢查,以防止錯誤。例如,OptionProperty 的驗證將確保該值位於預定義的可能性列表中。NumericProperty 的驗證將檢查你的值是否為數字型別。
觀察者模式
你可以指定屬性值更改時應該發生什麼。你可以將自己的函式繫結為屬性更改的回撥。例如,如果你希望在視窗小部件的 pos 屬性更改時呼叫一段程式碼,則可以將一個函式繫結到它。
更好的記憶體管理
同一屬性的例項在多個視窗小部件例項之間共享。
需要注意的是,Property 物件與 Python 中的 property() 內建函式不同。
必須在類級別宣告屬性物件,而不是在類的任何方法中。
每個屬性預設提供一個“on_<propertyname>”事件,每當屬性的狀態/值更改時都會呼叫該事件。
示例
讓我們透過以下示例研究 Kivy 中 Property 的行為。App 類具有一個 NumericProperty 屬性。NumericProperty 物件(值)繫結到 on_value_change() 方法。
class NumPropApp(App):
value = NumericProperty(0)
def on_value_change(self, instance, value):
print(f"Value changed: {value}")
self.l1.text = str(value)
在 build() 方法中,應用有一個 Label 和一個 Button 組裝在一個垂直 BoxLayout 中。Button 響應 on_press 事件呼叫 onstart() 方法並將值加 1。
def onstart(self, event):
print ("started")
self.value = self.value+1
def build(self):
lo = BoxLayout(orientation='vertical')
self.l1 = Label(text=str(self.value), font_size = 50)
self.b1 = Button(text = "start", font_size = 50)
self.b1.bind(on_press=self.onstart)
self.bind(value=self.on_value_change)
lo.add_widget(self.l1)
lo.add_widget(self.b1)
return lo
由於“on_value_change()”方法在每次值更改時都會被呼叫,因此效果是每次按下按鈕時,標籤標題都會顯示從“0”開始遞增的數字。
以下是示例的**完整程式碼**:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class NumPropApp(App):
value = NumericProperty(0)
def on_value_change(self, instance, value):
print(f"Value changed: {value}")
self.l1.text = str(value)
def onstart(self, event):
print ("started")
self.value = self.value+1
def build(self):
lo = BoxLayout(orientation='vertical')
self.l1 = Label(text=str(self.value), font_size = 50)
self.b1 = Button(text = "start", font_size = 50)
self.b1.bind(on_press=self.onstart)
self.bind(value=self.on_value_change)
lo.add_widget(self.l1)
lo.add_widget(self.b1)
return lo
if __name__ == '__main__':
NumPropApp().run()
輸出
從命令列執行程式。按按鈕檢視標籤上顯示的數字每次都會增加。
屬性型別
Kivy 提供以下屬性型別:
**NumericProperty** - 處理數字值,例如整數和浮點數。它只接受 int 或 float 數字資料型別或可以轉換為數字的字串。
count = NumericProperty(0)
**StringProperty** - 用於處理字串值。你可以使用“defaultvalue”引數對其進行初始化。
text = StringProperty("start")
**BoundedNumericProperty** - 此屬性類似於 NumericProperty,但允許你為值定義最小和最大邊界。它還支援 get_min() 和 get_max() 方法,分別返回最小和最大可接受值。
a = BoundedNumericProperty(1, min=0, max=100)
**BooleanProperty** - 處理布林值(True 或 False)。defaultvalue 引數可以設定為 True 或 False。
active = BooleanProperty(False)
**ListProperty** - 此屬性的值是 List 物件。將列表分配給 ListProperty 時,儲存在屬性中的列表是列表的淺複製,而不是原始列表。
colors = ListProperty([1, 0, 0, 1])
**ObjectProperty** - 處理單個物件例項。如果 rebind 引數設定為 True,則關聯的 **kv** 規則將被重新評估,並且當任何中間屬性更改時,所有屬性都將被重新繫結。
person = ObjectProperty(None)
OptionProperty − 指定屬性的預設值。它應該來自“Options”引數中給出的列表。例如:
state = OptionProperty("None", options=["On", "Off", "None"])
ReferenceListProperty − 此屬性用於引用一個或多個其他型別的屬性物件。
x = NumericProperty(0) y = NumericProperty(0) z = ReferenceListProperty(x, y)
更改“z”的值將自動相應地更改“x”和“y”的值。如果讀取“z”的值,它將返回一個包含“x”和“y”值的元組。
AliasProperty − 為現有屬性提供別名或替代名稱。
def _get_width(self):
return self.size
def _set_width(self, value):
self.size = value
width = AliasProperty(_get_width, _set_width)
DictProperty − 用於定義具有多個引數作為字典鍵的物件的初始值。
params = DictProperty({
'xlog': False,
'xmin': 0,
'xmax': 100,
'ylog': False,
'ymin': 0,
'ymax': 100,
'size': (0, 0, 0, 0)
})
VariableListProperty − 列表項並將其擴充套件到所需的列表大小。
obj = VariableListProperty(defaultvalue, length)
defaultvalue 引數指定列表的預設值。length 引數是一個整數,可以是 2 或 4。
ConfigParserProperty − ConfigParserProperty 允許您根據其他 Kivy 屬性自動偵聽和更改指定鍵的值。
ConfigParserProperty(defaultvalue, section, key, config)
ConfigParser 由多個部分組成,每個部分都有一些與這些鍵關聯的鍵和值。
username = ConfigParserProperty('', 'info', 'name', None)
ColorProperty − 處理各種格式的色彩值,例如 RGB 或十六進位制。此屬性可以分配以下任何值:
0-1 之間的一組 3 或 4 個浮點值(Kivy 預設值)
格式為 #rrggbb 或 #rrggbbaa 的字串
表示顏色名稱的字串(例如,“red”、“yellow”、“green”)
Kivy - 輸入
Kivy 框架能夠接收和處理來自滑鼠、觸控式螢幕、陀螺儀、加速計等的不同型別的輸入。大多數情況下,Kivy 會自動檢測可用的硬體。但是,如果要支援自定義硬體,則需要相應地配置 Kivy。
不同輸入源生成的所有事件都由相應的事件類表示。MotionEvent 是用於指向裝置(觸控和非觸控事件)提供的事件的基本類。
觸控事件 − 包含至少 X 和 Y 位置的運動事件。所有觸控事件都跨 Widget 樹分派。
非觸控事件 − 加速計就是一個非觸控事件的例子,因為它是一個連續的事件,沒有位置。它從不啟動或停止。這些事件不會跨 Widget 樹分派。
Kivy 對輸入應用後處理並對其進行分析以做出有意義的解釋,例如:
它是雙擊/三擊檢測嗎?(根據距離和時間閾值)
當硬體不準確時使事件更準確
如果本機觸控硬體傳送的事件位置幾乎相同,則減少生成的事件數量
處理後,運動事件將分派到 Window。如果它只是一個運動事件,它將分派到 on_motion()。另一方面,如果它是觸控事件,觸控的 (x,y) 位置(0-1 範圍)將按比例縮放至 Window 大小(寬度/高度),並分派到:
- on_touch_down()
- on_touch_move()
- on_touch_up()
示例
在下面的示例中,我們定義了一個名為 widget 的新類,它繼承自 Widget。我們需要使用以下語句匯入 Widget 類:
from kivy.uix.widget import Widget
widget 類中有三個方法:
on_touch_down − 初始按下。
on_touch_move − 按下後以及按下期間的移動。
on_touch_up − 按下的“釋放”。
class widget(Widget):
def on_touch_down(self, touch):
print("Down:",touch)
def on_touch_move(self, touch):
print("Move:",touch)
def on_touch_up(self, touch):
print("UP!",touch)
接下來,App 類的 build() 方法返回 widget() 物件。
class MotionApp(App):
def build(self):
return widget()
您可以透過點選並拖動螢幕來測試程式碼。您應該看到您執行的所有移動和按壓的滑鼠位置。
以下是完整程式碼。您可以儲存並執行它:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class widget(Widget):
def on_touch_down(self, touch):
print("Down:",touch)
def on_touch_move(self, touch):
print("Move:",touch)
def on_touch_up(self, touch):
print("UP!",touch)
class MotionApp(App):
def build(self):
return widget()
if __name__ == '__main__':
MotionApp().run()
輸出
輸出是一個空應用程式視窗,其中沒有任何 UI 小部件。
在視窗中的任何位置單擊滑鼠。將捕獲“on_touch_down”和“on_touch_up”事件,顯示滑鼠觸控的位置,如下所示:
Down: <MouseMotionEvent spos=(0.4228094575799722, 0.38596491228070173) pos=(304.0, 154.0)> UP! <MouseMotionEvent spos=(0.4228094575799722, 0.38596491228070173) pos=(304.0, 154.0)> Down: <MouseMotionEvent spos=(0.5730180806675939, 0.5137844611528822) pos=(412.0, 205.0)> UP! <MouseMotionEvent spos=(0.5730180806675939, 0.5137844611528822) pos=(412.0, 205.0)> Down: <MouseMotionEvent spos=(0.2517385257301808, 0.5588972431077694) pos=(181.0, 223.0)> UP! <MouseMotionEvent spos=(0.2517385257301808, 0.5588972431077694) pos=(181.0, 223.0)>
MouseMotionEvent 的spos屬性在 0-1 座標系中提供相對位置。應用程式視窗的左下角對應於 (0,0),右上角對應於 (1,1)
pos屬性顯示滑鼠單擊的實際座標。在上面的示例中,它相對於 (0,0) 位置向右 378.85 畫素,向上 281.39 畫素。
按住滑鼠並將其移動到視窗中,您將獲得 spos 和 pos 屬性的瞬時變化值。例如:
Move: <MouseMotionEvent spos=(0.41863699582753827, 0.5338345864661654) pos=(376.3546592489569, 266.38345864661653)> Move: <MouseMotionEvent spos=(0.4172461752433936, 0.531328320802005) pos=(375.1043115438108, 265.1328320802005)> Move: <MouseMotionEvent spos=(0.41585535465924894, 0.5288220551378446) pos=(373.8539638386648, 263.88220551378447)>
事件配置檔案
基於輸入提供程式和使用的硬體型別,事件配置檔案包含有關輸入事件的更多資訊。該配置檔案是 MotionEvent 物件的裝置特定屬性。例如,觸控輸入具有 (x,y) 位置,但可能還具有壓力資訊、斑點大小、加速度向量等。
透過在 touch_down 事件處理程式中新增以下語句,我們可以找出當前裝置支援的功能。
def on_touch_down(self, touch): print(touch.profile)
輸出將取決於裝置型別。它可能是:
['pos', 'button']
或者,
['pos', 'angle']
配置檔案值
以下是預設支援的一些配置檔案值。
| 序號 | 配置檔案值和描述 |
|---|---|
| 1 | 角度 二維角度。透過“a”屬性訪問。 |
| 2 | 按鈕 滑鼠按鈕('left'、'right'、'middle'、'scrollup' 或 'scrolldown')。透過 button 屬性訪問。 |
| 3 | 標記 ID 標記或基準 ID。透過 fid 屬性訪問。 |
| 4 | 位置 二維位置。透過 x、y 或 pos 屬性訪問。 |
| 5 | pos3d 三維位置。透過 x、y 或 z 屬性訪問。 |
| 6 | 壓力 接觸壓力。透過 pressure 屬性訪問。 |
| 7 | 形狀 接觸形狀。透過 shape 屬性訪問。 |
觸控形狀
在 Kivy 中,觸控事件期間的互動區域由術語“觸控形狀”表示。它指的是用於表示螢幕上觸控或觸控事件的幾何形狀。如果觸控具有形狀,它將反映在“shape”屬性中。
Kivy 支援不同的觸控形狀,包括橢圓形、矩形、圓形和正方形。
雙擊/三擊
在多點觸控裝置的上下文中,雙擊是在規定時間和距離內連續點選兩次的操作。類似地,裝置可以識別“三擊”操作。
事件物件具有“is_double_tap”屬性和“is_triple_tap”屬性,兩者都評估為 True 或 False。您可以測試當前觸控是否為雙擊之一:
def on_touch_down(self, touch):
if touch.is_double_tap:
print('Touch is a double tap!')
print(' - interval is', touch.double_tap_time)
print(' - distance between previous is', touch.double_tap_distance)
快速連續按下滑鼠按鈕兩次。您可能會獲得類似於以下所示的結果:
Touch is a double tap! - interval is 0.17462420463562012 - distance between previous is 0.0
Kivy - 行為
在 Kivy 中,“kivy.uix.behaviors”模組定義了行為混合,也稱為“可重用類”,它們為小部件提供額外的功能。它們封裝了常見的功能,可以與多個小部件混合以擴充套件其行為。
行為有助於保持程式碼模組化、可重用和可維護。它們允許您為標準 Kivy 小部件定義自己的實現,這些實現可以作為直接替換。
行為混合的一個應用是將影像用作按鈕。我們可以定義一個擴充套件 ButtonBehavior 的自定義類,使其響應“on_press”或“on_touch”等事件,以便影像本身可以充當按鈕。在本章的後面,我們將看看將影像轉換為按鈕的示例。
“kivy.uix.behaviors”模組定義了幾個混合。下面解釋了一些最常用的類:
ButtonBehavior
此行為為小部件提供類似按鈕的功能。它添加了諸如按下/釋放視覺反饋、自動觸發“on_press”和“on_release”事件以及處理觸控事件等功能。
它通常與 Button、ToggleButton 或需要類似按鈕行為的自定義小部件一起使用。
DragBehavior
此行為類允許透過觸控輸入拖動和移動小部件。它處理諸如 on_touch_down、on_touch_move 和 on_touch_up 等觸控事件以實現拖動功能。
它可用於在應用程式中建立可拖動的小部件。
FocusBehavior
此行為提供對管理小部件之間焦點的支援。它允許小部件接收鍵盤輸入並處理與焦點相關的事件。
它可用於實現鍵盤導航和管理應用程式內的焦點遍歷。
SelectableBehavior
此行為為小部件新增選擇功能。它允許使用者從一組可選小部件中選擇一個或多個專案。它處理選擇狀態、視覺反饋和觸發與選擇相關的事件。
它通常與 ListView、RecycleView 或需要選擇功能的自定義小部件一起使用。
ButtonBehavior 示例
我們現在將開發一個 Kivy 程式來實現 ButtonBehavior。我們使用 Kivy 的 Image 物件在 Kivy 視窗上顯示影像。但是,要向其新增類似按鈕的行為,我們首先定義一個名為 imgbtn 的自定義類,該類擴充套件了 Image 和 ButtonBehavior 類。
Image 類的 source 屬性被分配一個字串,該字串是影像檔案路徑。然後我們覆蓋 on_press() 方法,如下所示:
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
self.source = 'Logo.jpg'
def on_press(self):
print("Button pressed")
之後,定義了imgbtn類。讓 App 類的 build() 方法返回其物件。
以下是可執行程式碼。您可以儲存並執行它:
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
self.source = 'Logo.jpg'
def on_press(self):
print("Button pressed")
class ImageApp(App):
def build(self):
return imgbtn()
if __name__ == '__main__':
ImageApp().run()
輸出
執行上述程式。它將在其中心顯示一個帶有影像的 Kivy 視窗:
請注意,影像本身充當按鈕。要測試,請單擊影像,它將在控制檯上列印以下訊息:
Button pressed
Kivy - 按鈕
按鈕是任何 GUI 庫(包括 Kivy)中最重要的元素之一。按鈕物件包含一個標籤,通常用於指示其用途(例如,一個帶有“開始”標題的標籤,或一個帶有“資料夾”圖示的標籤,用於指示“開啟檔案操作”),並能夠響應某些事件,例如觸控或滑鼠單擊。
Button 類在“kivy.uix.button”模組中定義。Button 物件的外觀可以透過在 Label 類中定義的同一組屬性進行配置。Button 類也繼承自 ButtonBehavior 混合。
Button 物件使用以下語法例項化:
b1 = Button(**kwargs)
要配置按鈕,您可以將它的屬性指定為建構函式的關鍵字引數:
background_color − 按鈕的背景顏色是一個 ColorProperty,格式為 (r, g, b, a),預設值為 [1,1,1,1]。
background_disabled_down − 按鈕的背景影像是 StringProperty,一個包含影像檔案路徑的字串,用於按鈕停用並按下時的預設圖形表示。
background_disabled_normal − 按鈕的背景影像也是一個影像路徑,用於按鈕停用且未按下時的預設圖形表示。
background_down − 按鈕的背景影像,用作按鈕按下時的預設圖形表示。
background_normal − 按鈕的背景影像,用作按鈕未按下時的預設圖形表示。
除了以上內容外,Button 按鈕還繼承了 Label 標籤類的屬性,其中一些如下所示:
bold − 指示是否使用粗體字型的版本。它是一個 BooleanProperty 屬性,預設為 False。
underline − 為文字新增下劃線。此功能需要 SDL2 文字提供程式,它是一個 BooleanProperty 屬性,預設為 False。
strikethrough − 為文字新增刪除線。此功能需要 SDL2 文字提供程式。它是一個 BooleanProperty 屬性,預設為 False。
text − 標籤的文字。例如:
widget = Button(text='Hello world')
text 是一個 StringProperty 屬性,預設為 ''。
color − 文字顏色,格式為 (r, g, b, a)。它是一個 ColorProperty 屬性,預設為 [1, 1, 1, 1]。
font_size − 文字的字型大小,以畫素為單位。“font_size” 是一個 NumericProperty 屬性,預設為 15sp。
Button 類還繼承了 ButtonBehavior 類的 state 屬性。
state − 按鈕的狀態,必須是 'normal' 或 'down' 之一。當按鈕當前被觸控/點選時,狀態為 'down',否則為 'normal'。它是一個 OptionProperty 屬性,預設為 'normal'。
Button 類還繼承了 Widget 類的屬性,例如 disabled、height、width 和 pos 等。
如果要在 Kivy 應用程式視窗中顯示一個 Button 按鈕,則可以透過在 build() 方法中宣告一個 Button 物件來實現,或者使用 "kv" 語言指令碼。
使用 build() 方法顯示 Button 按鈕
讓我們使用上面解釋的一些屬性來配置 Button 按鈕:
示例
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class HelloApp(App):
def build(self):
b1 = Button(text = "A Kivy Button",
font_size=50,
color = [0.8, 0.2, 0.3, 1])
return b1
app = HelloApp()
app.run()
輸出
執行此程式碼,您將獲得以下輸出:
使用 "kv" 語言方法顯示 Button 按鈕
示例
將以下指令碼儲存為 "hello.kv"。
Button:
text: 'A Kivy Button'
font_size: '20pt'
underline: True
background_color: [1,0,0,1]
size_hint: (.25, .25)
pos_hint: {'center_x':.5, 'center_y':.5}
輸出
註釋掉 App 類中的 build() 方法,然後再次執行應用程式。您將獲得以下視窗作為輸出:
Kivy - 按鈕事件
Button 按鈕(與 Kivy 中的大多數 GUI 小部件一樣)被程式設計為響應特定型別的事件。Button 按鈕處理以下事件型別:
**on_press** - 當按鈕被按下時觸發。
**on_release** - 當按鈕被釋放時觸發。
**on_touch_down** - 當按鈕上開始觸控事件時觸發。
**on_touch_up** - 當按鈕上結束觸控事件時觸發。
Kivy 的 EventDispatcher 類提供了一個 bind() 方法,該方法負責將事件委派給某個回撥函式進行處理。
EventDispatcher.bind(self, **kwargs)
Button 按鈕(每個 Kivy 小部件也一樣)繼承了此方法。因此,我們可以將 Button 物件繫結到任何回撥事件處理函式。您還可以將屬性繫結到回撥函式。
繫結事件
下面是繫結按鈕的 on_press 事件到函式的典型方法:
def callback(instance):
print('The button is being pressed')
btn1 = Button(text='Hello world')
btn1.bind(on_press=callback)
示例
在下面的示例中,我們在 FloatLayout 中放置了兩個按鈕。每個按鈕的 "on_press" 事件都繫結到 callback() 方法。
發生 "on_press" 事件的按鈕的引用被傳遞給 callback() 方法,以便我們可以識別按下按鈕的標題。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class ButtonApp(App):
def on_button_press(self, instance):
print("{} Button pressed!".format(instance.text))
def build(self):
flo = FloatLayout()
btn1 = Button(text= 'Hello World',
background_color= [1,0,0,1],
font_size= 20, underline= True,
size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.8})
btn1.bind(on_press = self.on_button_press)
btn2 = Button(text= 'Hello Python',
color= [0,0,1,1], font_size= 20,
size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.2})
flo.add_widget(btn1)
btn2.bind(on_press = self.on_button_press)
flo.add_widget(btn2)
return flo
if __name__ == '__main__':
ButtonApp().run()
輸出
執行以上程式碼並按下按鈕:
每次按下時,都會呼叫 callback() 方法:
Hello World Button pressed! Hello Python Button pressed!
繫結屬性
如前所述,我們可以將回調函式繫結到小部件的屬性。每次屬性的值發生變化時,都會呼叫回撥函式以通知更改。
btn1.bind(property=callback)
讓我們在 App 類中定義另一個方法 "on_textchanged()",並將其與 btn2 的 text 屬性繫結。btn1 上的 on_press 事件會更改 btn2 的標題,並且更改會立即呼叫 on_textchanged() 方法。
示例
將ButtonApp 類的程式碼更改如下:
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class ButtonApp(App):
def on_button_press(self, instance):
print("{} Button pressed!".format(instance.text))
self.btn2.text="Hello Tutorialspoint"
def on_textchanged(self, instance, value):
print ("Text property changed to", instance.text)
def build(self):
flo = FloatLayout()
self.btn1 = Button(text= 'Hello World',
background_color= [1,0,0,1],
font_size= 20, underline= True,
size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.8})
self.btn1.bind(on_press = self.on_button_press)
self.btn2 = Button(text= 'Hello Python', color= [0,0,1,1],
font_size= 20, size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.2})
flo.add_widget(self.btn1)
self.btn2.bind(text = self.on_textchanged)
flo.add_widget(self.btn2)
return flo
if __name__ == '__main__':
ButtonApp().run()
輸出
執行程式碼並首先按下btn1。它會更改btn2的標題,進而呼叫 "on_textchanged()" 方法。
Hello World Button pressed! Text property changed to Hello Tutorialspoint
以下是輸出視窗:
通常,屬性回撥函式使用兩個引數(物件和屬性的新值)呼叫,而“事件回撥函式”使用一個引數(物件)呼叫。
使用 Lambda 函式繫結
另一種繫結方法是使用 lambda(或匿名)函式。它們的優點是可以避免宣告新函式,即它們提供了一種簡潔的“重定向”回撥函式的方法。
將繫結 btn1 的 "on_press" 事件的語句更改為:
self.btn1.bind(on_press = lambda btn1: self.on_button_press(btn1))
使用 Partial 函式
在 Python 中,Partial 函式允許我們將具有 x 個引數的函式派生為具有較少引數的函式,併為更有限的函式設定常量值。它使函式可重用。partial() 函式在 Python 標準庫的 functools 模組中定義。
示例
我們可以將事件繫結到部分方法。在下面的示例中,傳遞了 Button 物件 bt1 和 btn2。該函式交換這兩個物件的 text 屬性。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
from functools import partial
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class ButtonApp(App):
def on_textchanged(self, instance, value):
print ("Text property changed to", instance.text)
def a_function(self, *args):
args[0].text, args[1].text = args[1].text, args[0].text
def build(self):
flo = FloatLayout()
self.btn1 = Button(text= 'Hello World',
background_color= [1,0,0,1],
font_size= 20, underline= True,
size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.8})
self.btn2 = Button(text= 'Hello Python',
color= [0,0,1,1],
font_size= 20,
size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.2})
flo.add_widget(self.btn1)
self.btn1.bind(on_press = partial(self.a_function, self.btn1, self.btn2))
self.btn2.bind(text = self.on_textchanged)
flo.add_widget(self.btn2)
return flo
if __name__ == '__main__':
ButtonApp().run()
輸出
請檢視以下輸出視窗,並觀察按下第一個按鈕如何交換兩個按鈕的文字:
Kivy - 按鈕顏色
在任何 GUI 應用程式中,按鈕都是一個重要的元件。其主要功能是響應點選事件並呼叫回撥函式。為了設計吸引人的 GUI,應適當地選擇按鈕顏色。您可以透過指定其標題的顏色、正常狀態和停用狀態下的背景顏色來配置按鈕。
在 Kivy 中,Button 類定義了以下與顏色相關的屬性:
- color
- background_color
- disabled_color
- outline_color
- disabled_outline_color
color 屬性
Button 類從 Label 類繼承了此屬性,因為 Button 是一個響應點選相關事件的 Label。color 屬性定義按鈕文字或按鈕標題的顏色。
由於 color 是 ColorProperty 型別,因此必須以 (r,g,b,a) 格式指定。顏色取值為“0”到“1”之間。“a”元件用於透明度。對於按鈕,color 預設為 [1, 1, 1, 1]。
background_color 屬性
它充當紋理顏色的乘數。預設紋理為灰色,因此僅設定背景顏色將產生較暗的結果。按鈕的背景顏色是一個 ColorProperty,格式為 (r, g, b, a),預設值為 [1,1,1,1]。
disabled_color 屬性
此屬性繼承自 Label 類。它定義按鈕停用時按鈕文字或標題的顏色。它是一個 ColorProperty,預設為 [1,1,1,3]。
outline_color 屬性
繼承自 Label 類,此屬性配置文字輪廓的顏色。請注意,這需要 SDL2 文字提供程式。此屬性為 ColorProperty 型別,其預設值為 [0,0,0,1]。
disabled_outline_color 屬性
此屬性定義小部件停用時文字輪廓的顏色,格式為 (r, g, b)。它繼承自 Label 類。此功能需要 SDL2 文字提供程式。disabled_outline_color 是一個 ColorProperty,預設為 [0, 0, 0]。
示例 1
讓我們演示 color 和 disabled_color 屬性的使用。在下面的示例中,我們在 floatlayout 中放置了兩個按鈕。它們使用不同的 color 和 disabled_color 屬性例項化。單擊時,文字顏色會發生變化。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class HelloApp(App):
def on_button_press(self, instance):
instance.disabled = True
def build(self):
flo = FloatLayout()
btn1 = Button(text= 'Hello Python', color= [1,0,0,1],
disabled_color = [0,0,1,1],
font_size= 40, size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.8})
btn1.bind(on_press = self.on_button_press)
btn2 = Button(text= 'Hello Kivy', color= [0,0,1,1],
disabled_color = [1,0,0,1],
font_size= 40, size_hint= (.4, .25),
pos_hint= {'center_x':.5, 'center_y':.2})
flo.add_widget(btn1)
btn2.bind(on_press = self.on_button_press)
flo.add_widget(btn2)
return flo
if __name__ == '__main__':
HelloApp().run()
輸出
最初,這兩個按鈕都處於啟用狀態。當您按下按鈕時,它們會變為停用狀態(它們無法接收“on_press”事件),並且文字顏色會根據配置更改。
示例 2
在下面的程式中,當單擊任何按鈕時,其文字顏色和背景顏色會互換。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class HelloApp(App):
def on_button_press(self, instance):
print("change color")
instance.background_color, instance.color = instance.color, instance.background_color
def build(self):
flo = FloatLayout()
self.btn1 = Button(text='Hello Python',
color=[1, 0, 0, 1],
background_color=[0, 0, 1, 1],
font_size=40, size_hint=(.4, .25),
pos_hint={'center_x': .5, 'center_y': .8})
self.btn2 = Button(text='Hello Kivy',
color=[0, 0, 1, 1],
background_color=[1, 0, 0, 1],
font_size=40, size_hint=(.4, .25),
pos_hint={'center_x': .5, 'center_y': .2})
flo.add_widget(self.btn1)
self.btn1.bind(on_press=self.on_button_press)
self.btn2.bind(on_press=self.on_button_press)
flo.add_widget(self.btn2)
return flo
if __name__ == '__main__':
HelloApp().run()
輸出
當您單擊任意兩個按鈕時,它們的色彩會像此處顯示的那樣互換:
Kivy - 按鈕大小
Kivy 應用程式使用者介面上的小部件應具有適當的大小非常重要。與 position 屬性一樣,按鈕的大小屬性(任何小部件都一樣)受其所在佈局的控制。
可以透過“size”和“size_hint”這兩個屬性來配置按鈕的大小。“kivy.uix.button.Button”類從 Widget 類繼承了這些屬性。
按鈕的“size_hint”屬性是一個值元組,其父佈局使用該元組來決定大小。它定義相對於佈局大小的大小,而不是絕對大小。例如:
btn.size_hint = (w, h)
兩個引數“w”和“h”都指定為 0 到 1 範圍內的浮點數。例如,0.5 表示 50%,1 表示 100%。
# This button has width and height of the parent layout btn.size_hint=(1,1) # Width of this button will be half of the container's width btn.size_hint=(0.5, 1) # This button will be of width and height 20% of the layout btn.size_hint=(.2,.2)
另一方面,“size”屬性以絕對術語分配按鈕的寬度和高度,並以畫素為單位表示。
btn.size=(200,100)
但是,要使按鈕具有絕對大小,您必須要求 Kivy 佈局忽略大小提示。如果您不想對寬度或高度使用 size_hint,請將該值設定為 None。換句話說,您必須在以絕對測量單位分配大小之前設定“size_hint=(None, None)”。
您還可以使用“size_hint_x”和“size_hint_y”屬性分別設定寬度或高度的大小提示。
假設您想製作一個寬度為 250px 且高度為父元素高度 30% 的按鈕。
btn.size_hint_x = None btn.size_hint_y= 0.3 widget.width = 250
這些屬性也可以在 Button 建構函式引數中設定:
btn = Button(text="Hi there!", size_hint=(None, 0.3), width=250)
示例
以下程式將各種按鈕放置在應用程式視窗的 FloatLayout 中,並使用 size_hint、size、pos_hint 和 pos 屬性的不同組合:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.core.window import Window
Window.size = (720,400)
class DemoApp(App):
def build(self):
f = FloatLayout()
b1 = Button(text="B1", size_hint=(None, None))
f.add_widget(b1)
b2 = Button(text="B2", size_hint=(1, None), height=20)
f.add_widget(b2)
b3 = Button(text="B3", size_hint=(None, None), pos=(0, 100), size=(400, 100))
f.add_widget(b3)
b4 = Button(text='B4', size_hint=(None,.3), width=50, pos_hint={'x':.6, 'y':.2} )
f.add_widget(b4)
b5 = Button(text='B5', size_hint=(None,.9), width=50, pos_hint={'x':.5, 'y':.5} )
f.add_widget(b5)
return f
if __name__ == '__main__':
DemoApp().run()
輸出
執行此程式碼後,您將獲得以下輸出視窗:
Kivy - 按鈕位置
將小部件放置在適當的位置是設計符合人體工程學使用者介面的關鍵。在 Kivy 中,按鈕(以及其他小部件)的位置主要由使用的佈局控制。在本章中,我們將學習如何在 Kivy 應用程式視窗的某個位置放置按鈕。
決定位置的第一個因素是佈局。在 Kivy 中,佈局是用於以特定方式排列小部件的容器。例如:
BoxLyout 按順序放置小部件,可以是垂直順序或水平順序。
如果使用 GridLayout,則小部件的位置由 rows 和 cols 屬性決定。
FloatLayout 對放置沒有限制。您可以透過分配按鈕或任何其他小部件的絕對座標將其放置在任何位置。
視窗大小
要在某個位置放置按鈕,我們首先定義應用程式視窗的大小。Window 物件的“size”屬性可幫助您設定所需的大小。
from kivy.core.window import Window Window.size = (720,400)
Kivy 的視窗座標系定義小部件的位置以及分派給它們觸控事件。它將 (0, 0) 放置在視窗的左下角。顯然,視窗的右上角對應於 (1,1)。
Button 類從 Widget 類繼承了“pos”和“pos_hint”屬性。它們有助於確定按鈕在視窗表面上的位置。
位置屬性
pos − 此屬性是水平和垂直軸上座標值“x”和“y”的元組,從視窗的左下角測量。例如:
button = Button(text ='Hello world', pos =(20, 20))
pos_hint − 此屬性提供小部件位置的提示。它允許您在父佈局內設定小部件的位置。該屬性是一個最多包含 8 個鍵的字典,用於確定位置:
- x
- y
- left
- right
- top
- bottom
- center_x
- center_y
鍵“x”、“right”和“center_x”將使用父級寬度。鍵“y”、“top”和“center_y”將使用父級高度。例如,如果要將按鈕的頂部設定為其父佈局高度的 10%,則可以編寫:
button = Button(text ='Hello world', pos_hint={'top': 0.1})
"pos_hint" 是一個 ObjectProperty。並非所有佈局都使用它。
支援定位的佈局
FloatLayout − 支援 "pos_hint" 屬性。這些值是 0 到 1 之間的數字,表示視窗大小的比例。
RelativeLayout − 定位屬性(pos、x、center_x、right、y、center_y 和 top)相對於佈局大小,而不是視窗大小。
BoxLayout − 僅在垂直方向上 "x" 鍵(x、center_x 和 right)有效,在水平方向上 "y" 鍵(y、center_y、top)有效。固定定位屬性(pos、x、center_x、right、y、center_y 和 top)也遵循相同的規則。
在下面的程式碼中,我們在上方的垂直 BoxLayout 中放置了一個水平 BoxLayout 和一個 FloatLayout。上方的水平框包含四個按鈕:LEFT、RIGHT、TOP 和 BOTTOM。在 FloatLayout 內部,我們使用 "pos" 屬性放置了一個按鈕。
App 類有一個名為 movebtn() 的方法,它識別按下按鈕的標題並更改按鈕的 "x" 或 "y" 位置。
def movebtn(self,instance):
if instance.text =='RIGHT':
self.btn.pos[0]=self.btn.pos[0]+10
if instance.text == 'LEFT':
self.btn.pos[0] = self.btn.pos[0]-10
if instance.text == 'UP':
self.btn.pos[1] = self.btn.pos[1]+10
if instance.text == 'DOWN':
self.btn.pos[1] = self.btn.pos[1]-10
RIGHT 和 LEFT 按鈕按下會導致 "x" 位置增加或減少 10 畫素。類似地,TOP 和 BOTTOM 按鈕將 "y" 值更改 ±10。
示例 1
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class MovableButtonApp(App):
def movebtn(self,instance):
if instance.text =='RIGHT':
self.btn.pos[0]=self.btn.pos[0]+10
if instance.text == 'LEFT':
self.btn.pos[0] = self.btn.pos[0]-10
if instance.text == 'UP':
self.btn.pos[1] = self.btn.pos[1]+10
if instance.text == 'DOWN':
self.btn.pos[1] = self.btn.pos[1]-10
def build(self):
mblo = BoxLayout(orientation='vertical')
blo = BoxLayout(orientation ='horizontal')
b1 = Button(text='LEFT')
b1.bind(on_press=self.movebtn)
b2 = Button(text = 'RIGHT')
b2.bind(on_press=self.movebtn)
b3 = Button(text = 'UP')
b3.bind(on_press=self.movebtn)
b4 = Button(text = 'DOWN')
b4.bind(on_press=self.movebtn)
blo.add_widget(b1)
blo.add_widget(b2)
blo.add_widget(b3)
blo.add_widget(b4)
mblo.add_widget(blo)
flo = FloatLayout()
self.btn = Button(text='Movable Button', size_hint= (.350, .150))
flo.add_widget(self.btn)
mblo.add_widget(flo)
return mblo
MovableButtonApp().run()
輸出
執行程式時,您應該會看到頂部有四個按鈕,左下角有一個可移動的按鈕。按下按鈕,檢視可移動按鈕的位置變化。
這是另一個演示按鈕定位用法的示例。讓我們定義一個擴充套件 Button 類的 MovableButton 類。我們定義 on_touch_down()、on_touch_up() 和 on_touch_move() 方法來處理觸控事件。
on_touch_down() 方法檢查觸控事件是否發生在按鈕的邊界內,透過將小部件設定為當前觸控目標來處理觸控事件。
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
touch.grab(self)
return True
return super().on_touch_down(touch)
如果我們的按鈕正在處理觸控事件,則使用 on_button_move() 方法更新其位置:
def on_touch_move(self, touch):
if touch.grab_current == self:
self.pos = (self.pos[0] + touch.dx, self.pos[1] + touch.dy)
最後,釋放按鈕作為當前觸控目標並處理觸控事件。
def on_touch_up(self, touch):
if touch.grab_current == self:
touch.ungrab(self)
return True
return super().on_touch_up(touch)
build() 方法構建視窗,視窗中只有一個位於左下角的按鈕。
def build(self): return MovableButton(text='Drag me', size_hint= (.250, .100))
示例 2
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class MovableButton(Button):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
touch.grab(self)
return True
return super().on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current == self:
self.pos = (self.pos[0] + touch.dx, self.pos[1] + touch.dy)
# Override the on_touch_up method to update
# the widget's position when the touch event ends
def on_touch_up(self, touch):
if touch.grab_current == self:
touch.ungrab(self)
return True
return super().on_touch_up(touch)
class TestApp(App):
def build(self):
return MovableButton(text='Drag me', size_hint=(.250, .100))
if __name__ == "__main__":
TestApp().run()
輸出
執行以上程式碼。按住滑鼠按鈕並拖動按鈕到視窗的任意位置。
Kivy - 圓形按鈕
Kivy 框架中的所有小部件都是矩形形狀。按鈕物件始終具有直角。因此,建立圓角按鈕沒有簡單的解決方案,但是我們可以透過一些技巧來實現它。
使用影像作為按鈕
我們可以定義一個擴充套件 ButtonBehavior 混合和 Image 類的類。使用任何照片編輯器,建立一個看起來像圓形按鈕的橢圓形,並將其用作 Image 物件的 source 屬性。
您可以覆蓋 ButtonBehavior 類的 on_press() 方法,使影像可以用作按鈕。
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
self.source = 'hello.png'
self.pos_hint= {'center_x':.5, 'center_y':.6}
def on_press(self):
print("Button pressed")
我們現在可以在 Kivy App 中使用 imgbtn 物件。
KivyMD 按鈕
使用 KivyMD 擴充套件,我們可以設計更具吸引力的介面。KivyMD 是一個材料設計小部件的集合,用於 Kivy 應用程式。KivyMD 庫提供了帶有圓角的不同按鈕物件。
- MDRoundFlatButton
- MDRoundFlatIconButton
- MDFillRoundFlatButton
- MDFillRoundFlatIconButton
首先,安裝 KivyMD 擴充套件(確保 Kivy 框架已提前安裝)。
pip3 install KivyMD
App 類必須是 MDApp 類的子類,而不是 App 類。在這個例子中,我們將使用 MDRoundFlatButton 類。它的大多數屬性與 Kivy Button 相同。
from kivymd.app import MDApp
from kivymd.uix.button import MDRoundFlatButton
btn = MDRoundFlatButton(
text= 'Hello Python',
font_size= 20,
size_hint= (.3, .1),
pos_hint= {'center_x':.5, 'center_y':.3},
line_width=3
)
示例
在下面的示例中,我們有一個 MDApp 類。build() 方法將一個影像按鈕和一個 MDRoundButton 物件放在應用程式視窗中。
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivymd.uix.button import MDRoundFlatButton
Window.size = (720, 300)
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
self.source = 'btnnormal.png'
self.pos_hint= {'center_x':.5, 'center_y':.6}
def on_press(self):
print("Button pressed")
class ButtonApp(MDApp):
def build(self):
flo = FloatLayout()
self.btn1 = imgbtn()
self.btn2 = MDRoundFlatButton(
text= 'Hello Python',
font_size= 20, size_hint= (.3, .1),
pos_hint= {'center_x':.5, 'center_y':.3},
line_width=3
)
flo.add_widget(self.btn1)
flo.add_widget(self.btn2)
return flo
if __name__ == '__main__':
ButtonApp().run()
輸出
執行應用程式。您應該會得到以下輸出,其中包含圓角按鈕。
使用 Canvas
在 Kivy 中,canvas 是小部件繪製的根物件。為了模擬 Label 作為圓形按鈕工作,我們定義了一個擴充套件 ButtonBehavior 和 Label 的類。 "kv" 檔案定義了此物件的結構,如下所示:
<RoundCorneredButton>:
canvas:
Color:
rgb: (1, 0, 0, 1) if self.state == 'normal' else (0, 0, 0, 1)
RoundedRectangle:
size: (self.size)
pos: (self.pos)
radius: [200, ]
on_release:
print("This is the button made up by the canvas")
類的定義如下所示:
class RoundCorneredButton(ButtonBehavior, Label): pass
示例
我們將在以下 App 程式碼中使用上述類和 kv 設計:
from kivy.app import App
from kivy.uix.label import Label
from kivy.config import Config
from kivy.uix.button import ButtonBehavior
from kivy.graphics import Rectangle, Color
# Configuration
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
from kivy.app import App
class RoundCorneredButton(ButtonBehavior, Label):
pass
class HelloApp(App):
def build(self):
return RoundCorneredButton()
HelloApp().run()
輸出
現在執行程式碼。您將獲得一個圓形形狀的按鈕,如下所示:
Kivy - 停用按鈕
Kivy API 具有不同型別的按鈕小部件。Button、ToggleButton、CheckBox 的物件都是具有不同特徵的按鈕。它們都有一個共同的屬性。它們可以接受和傳播點選事件上的“觸控”事件。所有按鈕物件都可以引發按鈕事件,因為這些類繼承了 ButtonBehavior 介面。
您可以透過將 "disabled" 屬性設定為 True 來使按鈕對按鈕事件無響應。(disabled 屬性的預設值為 False。disabled 屬性繼承自 Widget 類。)
from kivy.uix.button import Button b1 = Button(text="OK", disabled=True)
為了從正常或啟用按鈕配置停用按鈕的外觀,可以使用以下屬性:
background_disabled_down − 按鈕的背景影像是 StringProperty,一個包含影像檔案路徑的字串,用於按鈕停用並按下時的預設圖形表示。
background_disabled_normal − 按鈕的背景影像也是一個影像路徑,用於按鈕停用且未按下時的預設圖形表示。
disabled_color − 此屬性繼承自 Label 類。它定義了按鈕文字或標題在停用時的顏色。它是一個 ColorProperty,預設為 [1,1,1,3]。
disabled_outline_color − 此屬性定義了小部件停用時文字輪廓的顏色,格式為 (r, g, b)。它繼承自 Label 類。此功能需要 SDL2 文字提供程式。disabled_outline_color 是一個 ColorProperty,預設為 [0, 0, 0]。
示例
下面給出的程式碼在垂直 BoxLayout 中排列了一個 ToggleButton 和一個普通 Button。如果 ToggleButton 的狀態為按下或正常,則它會將另一個按鈕的 disabled 屬性更改為 True 或 False。
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
Window.size = (720, 350)
class HelloApp(App):
def on_button_press(self, instance, value):
if value == 'down':
self.btn2.disabled = True
self.btn2.text = 'Disabled'
instance.text = 'Enable Btn 2'
if value == 'normal':
self.btn2.disabled = False
self.btn2.text = 'Enabled'
instance.text = 'Disable Btn 2'
def build(self):
flo = BoxLayout(orientation='vertical')
btn1 = ToggleButton(
text='Disable Btn 2', font_size=40,
size_hint=(1, .25),
pos_hint={'center_x': .5, 'center_y': .8}
)
btn1.bind(state=self.on_button_press)
self.btn2 = Button(
text='Enabled', color=[0, 0, 1, 1],
disabled_color=[1, 0, 0, 1], font_size=40,
size_hint=(1, .25),
pos_hint={'center_x': .5, 'center_y': .2}
)
flo.add_widget(btn1)
flo.add_widget(self.btn2)
return flo
if __name__ == '__main__':
HelloApp().run()
輸出
程式執行時,它會顯示底部的按鈕(即 btn2)為啟用狀態,其標題為 Color 屬性。
當頂部的按鈕 (btn1) 被按下時,下面的按鈕將被停用,顏色更改為 "disabled_color" 屬性指定的顏色。
Kivy - 圖片按鈕
Kivy 庫沒有現成的影像按鈕小部件。它確實有一個普通的 Button 和一個 ToggleButton 小部件。您當然可以在正常狀態或停用狀態下使用影像檔案作為其背景:
background_disabled_down − 按鈕的背景影像是 StringProperty,一個包含影像檔案路徑的字串,用於按鈕停用並按下時的預設圖形表示。
background_disabled_normal − 按鈕的背景影像也是一個影像路徑,用於按鈕停用且未按下時的預設圖形表示。
background_down − 按鈕的背景影像,用作按鈕按下時的預設圖形表示。
background_normal − 按鈕的背景影像,用作按鈕未按下時的預設圖形表示。
例如,您可以使用:
B1 = Button(background_normal='images/play.png')
但是,要使影像小部件充當可點選按鈕,您需要根據 ButtonBehavior 混合和 Image 類定義一個自定義類,並覆蓋 on_press() 方法。
ButtonBehavior
在 Kivy 中,"kivy.uix.behaviors" 模組定義了行為混合,也稱為“可重用類”,它們為小部件提供了額外的功能。
要將影像用作按鈕,我們定義一個擴充套件 ButtonBehavior 的自定義類,使其能夠響應 on_press 或 on_touch 等事件,以便影像本身可以充當按鈕。
我們使用 Kivy 的 Image 物件在 Kivy 視窗上顯示影像。但是,要向其新增類似按鈕的行為,我們首先定義一個名為 "imgbtn" 的自定義類,該類擴充套件了 Image 和 ButtonBehavior 類。
Image 類的 source 屬性被分配一個字串,該字串是影像檔案的路徑。然後我們覆蓋 on_press() 方法。
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
def on_press(self):
print("Button pressed", self.source)
ImgBtnApp.l1.text=self.source
示例
讓我們實現這個概念,並在應用程式佈局中放置四個影像並將它們繫結到回撥。提供類似按鈕的功能到影像的類首先定義如下:
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
def on_press(self):
ImgBtnApp.l1.text=self.source
我們現在將在應用程式佈局上使用此類的物件來顯示影像,並且它們將引發 on_press 事件。被點選影像的 source 屬性將顯示在 Label 上作為其文字。
from kivy.app import App
from kivy.graphics import *
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.window import Window
Window.size = (720, 400)
class imgbtn(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(imgbtn, self).__init__(**kwargs)
def on_press(self):
print("Button pressed", self.source)
ImgBtnApp.l1.text = self.source
class ImgBtnApp(App):
def build(self):
main = GridLayout(cols=1)
ImgBtnApp.l1 = Label(text='Hello', font_size=32)
main.add_widget(ImgBtnApp.l1)
root = FloatLayout(size=(Window.width, 100))
with root.canvas:
Color(.2, .7, .1, 1)
Rectangle(pos=root.pos, size=root.size)
self.btn1 = imgbtn(
source='previous.png', size_hint=(None, None),
pos_hint={'center_x': .2, 'center_y': .25}
)
self.btn2 = imgbtn(
source='play.png', size_hint=(None, None),
pos_hint={'center_x': .4, 'center_y': .25}
)
self.btn3 = imgbtn(
source='pause.png', size_hint=(None, None),
pos_hint={'center_x': .6, 'center_y': .25}
)
self.btn4 = imgbtn(
source='stop.png', size_hint=(None, None),
pos_hint={'center_x': .8, 'center_y': .25}
)
root.add_widget(self.btn1)
root.add_widget(self.btn2)
root.add_widget(self.btn3)
root.add_widget(self.btn4)
main.add_widget(root)
return main
ImgBtnApp().run()
輸出
執行程式碼並依次點選四個按鈕中的每一個。
Kivy - 控制元件
Kivy 應用程式的使用者介面使用 Kivy 庫中的各種小部件進行設計。"kivy.uix" 模組包含對應於小部件名稱的類的定義。這些類提供了對應小部件物件的屬性和功能。
Kivy 庫中的各種小部件可以歸類為以下類別:
通用小部件
從本質上講,這些小部件是經典的,因為它們用於大多數應用程式的介面設計。UX 小部件(如 Label、各種 Button 型別、輸入框、Image 容器、滑塊和進度指示器等)屬於此類別。
下面顯示了一些 UX 小部件:
佈局
Kivy 應用程式視窗只能包含一個小部件作為其根物件。但是,如果您需要使用多個控制元件來組合應用程式介面,則必須使用佈局小部件,並將多個 UX 小部件放置在其中,然後將佈局作為根小部件放在應用程式視窗上。
需要注意的是,佈局小部件本身沒有視覺表示。Kivy 提供了各種佈局,例如網格佈局、框佈局、浮動佈局等。
複雜 UX 小部件
此型別的小部件是組合多個經典小部件的結果。它們很複雜,因為它們的組裝和使用不像經典小部件那樣通用。
複雜小部件類別的示例包括下拉列表、檔案選擇器、微調器、影片播放器、虛擬鍵盤等。
行為小部件
這些小部件沒有自己的渲染,但會響應其子級的圖形指令或互動(觸控)行為。Scatter、Stencil View 小部件屬於此型別。
螢幕管理器
管理螢幕並在從一個螢幕切換到另一個螢幕時進行過渡。
Widget 類
Widget 類(定義在 kivy.uix.widget 模組中)是所有小部件類的基礎。此 Widget 類中定義的常見屬性(如 size、width、height、pos、pos_hint 等)被其他小部件繼承。
任何 Widget 物件的互動性取決於兩個方面:“事件處理程式”和“屬性回撥”。如果一個小部件繫結到某個處理程式以在發生特定型別的事件時發生,則會呼叫相應的處理程式函式。
def callback(instance):
print('Callback handler')
wid = Widget()
wid.bind(on_event=callback)
回撥函式也基於某個屬性被呼叫。如果屬性發生更改,則小部件可以透過 'on_<propname>' 回撥響應更改。
def on_pos_change(instance, value):
print('The widget position changed to ', value)
wid = Widget()
wid.bind(pos=on_pos_change)
基礎 Widget 類或任何小部件都沒有 draw() 方法。每個小部件都有自己的 Canvas,您可以使用它進行繪製。
widget = Widget() with widget.canvas: Rectangle(pos=widget.pos, size=widget.size)
Color、Rectangle 和 Line、Scale 和 Rotate 等圖形指令可以新增到任何小部件的 Canvas 中。
在 Kivy 中,事件從第一個子級向上傳播到其他子級。如果一個小部件有子級,則事件會在傳遞到其後面的小部件之前先透過其子級傳遞。
每個小部件都透過 add_widget() 方法新增到其父級。每次新增都由一個遞增的索引標識。
box = BoxLayout() l1=Label(text="a") l1=Label(text="b") l1=Label(text="c") box.add_widget(l1) box.add_widget(l2) box.add_widget(l3)
分別為 l1、l2、l3 新增標籤的索引為 0、1 和 2。您可以顯式地將 index 引數傳遞給 add_widget() 方法。
box.add_widget(l1, index=1) box.add_widget(l2, index=0) box.add_widget(l3, index=2)
如果小部件排列是巢狀的,則最內部小部件上的事件會向上傳播。假設 Button 是一個子級小部件,新增到 Widget 物件本身。因此,touch_down 回撥將同時為這兩個物件呼叫。要確認觸控事件僅發生在按鈕上,請使用 collide_points() 方法。
def callback(self, touch):
if instance.collide_point(touch.x, touch.y):
#consume event
return True
else:
#the upper level widget processes the event
示例
一個基本的 Kivy 應用程式在使用以下程式碼新增到 Widget 物件的 Label 上顯示一條簡單的單行訊息:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.core.window import Window
Window.size = (720,300)
class HelloApp(App):
def build(self):
w = Widget()
l1=Label(
text='Fortune Favours the Brave!',
font_size=50, size=(200,100),
pos_hint={'center_x':.5, 'center_y':.5},
pos=(250,200)
)
w.add_widget(l1)
return w
app = HelloApp()
app.run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
Kivy - 標籤
標籤是任何 GUI 工具包中最常使用的小部件之一。標籤顯示任何無法直接編輯的文字內容。標籤用於顯示頁面標題,作為欄位名稱的佔位符以及文字框等輸入控制元件,或僅用於呈現輸出訊息。
在 Kivy 中,標籤小部件是 Label 類的一個物件,定義在 "kivy.uix.label" 模組中。
from kivy.uix.Label import Label lbl = Label(**kwargs)
要自定義標籤物件,您可以將以下屬性用作建構函式的關鍵字引數:
bold − bold 是一個 BooleanProperty,預設為 False。將其設定為 True 以使用字型粗體版本。請注意,根據您的字型,粗體屬性可能對您的文字渲染沒有影響。
color − 文字顏色,格式為 (r, g, b, a)。它是一個 ColorProperty,預設為 [1, 1, 1, 1]。
disabled_color − 標籤停用時的文字顏色,格式為 (r, g, b, a)。它是一個 ColorProperty,預設為 [1, 1, 1, .3]。
font_name − 要使用的字型檔名。font_name 是一個 StringProperty,預設為 'Roboto'。此值取自 Config。
font_size − 文字的字型大小,單位為畫素。它是一個 NumericProperty,預設為 15sp。
halign − 文字的水平對齊方式。halign 是一個 OptionProperty,預設為 'auto'。可用選項包括:auto、left、center、right 和 justify。
italic − 指示是否使用字型的斜體版本。italic 是一個 BooleanProperty,預設為 False。
markup − 如果為 True,則文字將使用 MarkupLabel 渲染:您可以使用標籤更改文字的樣式。
outline_color − 文字輪廓的顏色,格式為 (r, g, b)。它是一個 ColorProperty,預設為 [0, 0, 0, 1]
padding − 文字的內邊距,格式為 [padding_left, padding_top, padding_right, padding_bottom]。padding 也接受兩個引數的形式 [padding_horizontal, padding_vertical] 和一個引數的形式 [padding]。
strikethrough − 為文字新增刪除線。strikethrough 是一個 BooleanProperty,預設為 False。
text − 標籤標題的文字。text 是一個 StringProperty,預設為 ''。例如 -
lbl = Label(text='Hello world')
text_size − 預設情況下,標籤不受任何邊界框的約束。您可以使用此屬性設定標籤的大小約束。文字將自動流入約束。因此,雖然字型大小不會減小,但文字將盡可能地排列以適合框中,框外的任何文字都將被裁剪。
Label(text='long text . . . ', text_size=(200, None))
text_size 是一個 ListProperty,預設為 (None, None),表示預設情況下沒有大小限制。
texture − 文字的紋理物件。當屬性更改時,文字會自動重新渲染。texture 是一個 ObjectProperty,預設為 None。
texture_size − 文字的紋理大小。大小由字型大小和文字決定。如果 text_size 為 [None, None],則紋理將是適合文字所需的大小,否則它會被裁剪以適合 text_size。
underline − 為文字新增下劃線。underline 是一個 BooleanProperty,預設為 False。
valign − 文字的垂直對齊方式。它是一個 OptionProperty,預設為 'bottom'。可用選項包括:'bottom'、'middle'(或 'center')和 'top'。
對齊方式
雖然 Label 類具有 halign 和 valign 屬性,但文字影像(紋理)的大小僅足以使字元位於 Label 的中心。
valign 屬性將不起作用,並且 halign 僅在文字包含換行符時才會起作用;即使 halign 設定為 left(預設值),單行文字也會顯示為居中。
要使對齊屬性生效,請設定 text_size,它是文字對齊所在的邊界框的大小。例如,以下程式碼將此大小繫結到 Label 的大小,因此文字將在視窗部件邊界內對齊。
Label: text_size: self.size halign: 'left' valign: 'middle'
標記
如果 Label 的 markup 屬性為 True,則文字將使用 Text 標記進行渲染,用於內聯文字樣式。就像 html 標籤一樣,Text 標記標籤具有 [tag],並且應該有一個對應的 [/tag] 關閉標籤。例如 -
[b]Hello [color=ff0000]world[/color][/b]
可以使用以下標籤構建標籤文字:
| 序號 | 標籤 & 標籤文字描述 |
|---|---|
| 1 | [b][/b] 啟用粗體文字 |
| 2 | [i][/i] 啟用斜體文字 |
| 3 | [u][/u] 下劃線文字 |
| 4 | [s][/s] 刪除線文字 |
| 5 | [font=<str>][/font] 更改字型(注意 - 這指的是 TTF 檔案或已註冊的別名) |
| 6 | [size=<size>][/size] 更改字型大小。 |
| 7 | [color=#<color>][/color] 更改文字顏色 |
| 8 | [sub][/sub] 相對於其之前的文字,將文字顯示在腳註位置。 |
| 9 | [sup][/sup] 相對於其之前的文字,將文字顯示在尾註位置。 |
例如,這將建立一個標籤 hello world,其中 world 為粗體
l = Label(text='Hello [b]World[/b]', markup=True)
大小調整
Label 的大小不受文字內容的影響,文字也不受大小的影響。為了控制大小調整,必須指定 text_size 來約束文字和/或將 size 繫結到 texture_size 以隨文字一起增長。
例如在 kv 語言指令碼中,此標籤的大小將設定為文字內容(加上內邊距):-
Label: size: self.texture_size
示例
我們現在將在以下示例中演示一些 Label 屬性的使用。這裡在垂直盒佈局中放置了三個標籤。每個標籤都使用 Label 類的某些屬性構建。
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window
Window.size = (720, 350)
class LblApp(App):
def build(self):
layout = BoxLayout(orientation='vertical')
self.l1 = Label(
text='Hello World', color=[1, 0, 0, 1],
font_size=40, bold=True
)
self.l2 = Label(
text='Hello Python', color=[0, 1, 0, 1],
font_size=40, italic=True
)
self.l3 = Label(
text='Hello Kivy', color=[0, 0, 1, 1],
font_size=40, font_name='Arial',
underline=True
)
layout.add_widget(self.l1)
layout.add_widget(self.l2)
layout.add_widget(self.l3)
return layout
if __name__ == '__main__':
LblApp().run()
輸出
執行上述程式時,將顯示三個標籤,其標題採用程式碼中定義的相應格式屬性:-
帶 kv 檔案的示例
現在將使用“kv”檔案建立上述設計。除了上述 Python 程式碼中使用的屬性外,我們還將背景顏色應用於每個標籤。
Label 類不支援背景顏色屬性。為了克服這個問題,我們在按鈕的畫布上繪製一個具有所需顏色的矩形作為其填充顏色。例如 -
Label:
canvas:
Color :
rgba: 0, 1, 0, 0.25
Rectangle:
pos:self.pos
size : self.size
我們利用此功能為三個標籤應用不同的顏色作為背景。
BoxLayout:
orientation:'vertical'
Label:
text:'Hello World'
color : [1,0,0,1]
font_size : 40
bold : True
canvas:
Color :
rgba: 0, 1, 0, 0.25
Rectangle:
pos:self.pos
size : self.size
Label:
text:'Hello Python'
color:[0,1,0,1]
font_size:40
italic:True
canvas:
Color :
rgba: 1, 1, 0, 0.1
Rectangle:
pos:self.pos
size : self.size
Label:
text:'Hello Kivy'
color:[0,0,1,1]
font_size:40
font_name:'Arial'
underline:True
輸出
將此“lbl.kv”檔案合併到 Python Kivy 應用程式中,然後執行程式。您應該會看到以下顯示,顯示三個具有相應背景顏色的標籤。
Kivy - 文字輸入
在桌面和 Web 應用程式中,您經常會看到一個矩形框,供使用者輸入一些文字。文字框是任何 GUI 工具包中必不可少的視窗部件。在 Kivy 中,TextInput 提供了一個控制元件,使用者可以在其中輸入和編輯文字。
可以自定義 TextInput 控制元件以接收單行或多行文字。可以使用滑鼠選擇文字的某一部分。還可以使用游標移動在其中執行全屏編輯。
TextInput 類定義在 kivy.uix.textinput 模組中。
from kivy.uix.textinput import TextInput textbox = TextInput(**kwargs)
TextInput 類中定義了以下屬性:
allow_copy − 決定是否允許複製文字。allow_copy 是一個 BooleanProperty,預設為 True。
background_color − 背景的當前顏色,格式為 (r, g, b, a)。它是一個 ColorProperty,預設為 [1, 1, 1, 1](白色)。
border − 用於 BorderImage 圖形指令的邊框。與 background_normal 和 background_active 一起使用。可用於自定義背景。它必須是一個包含四個值的列表:(bottom, right, top, left)。border 是一個 ListProperty,預設為 (4, 4, 4, 4)。
cursor − 表示當前游標位置的 (col, row) 值的元組。如果要移動游標,可以設定新的 (col, row)。滾動區域將自動更新以確保游標在視口中可見。cursor 是一個 AliasProperty。
cursor_color − 游標的當前顏色,格式為 (r, g, b, a)。cursor_color 是一個 ColorProperty,預設為 [1, 0, 0, 1]。
cut() − 將當前選擇複製到剪貼簿,然後將其從 TextInput 中刪除。
delete_selection(from_undo=False) − 刪除當前文字選擇(如果有)。
disabled_foreground_color − 停用時前景色當前顏色,格式為 (r, g, b, a)。disabled_foreground_color 是一個 ColorProperty,預設為 [0, 0, 0, 5](50% 透明黑色)。
font_name − 要使用的字型的檔名。路徑可以是絕對路徑或相對路徑。相對路徑由 resource_find() 函式解析。
font_name − 是一個 StringProperty,預設為 'Roboto'。此值取自 Config。
font_size − 文字的字型大小,單位為畫素。font_size 是一個 NumericProperty,預設為 15 sp。
foreground_color − 前景的當前顏色,格式為 (r, g, b, a)。oreground_color 是一個 ColorProperty,預設為 [0, 0, 0, 1](黑色)。
halign − 文字的水平對齊方式。halign 是一個 OptionProperty,預設為 'auto'。可用選項包括:auto、left、center 和 right。
hint_text − 視窗部件的提示文字,如果文字為 '',則顯示。hint_text 是一個 AliasProperty,預設為 ''。
hint_text_color − hint_text 文字的當前顏色,格式為 (r, g, b, a),ColorProperty,預設為 [0.5, 0.5, 0.5, 1.0](灰色)。
input_filter − 根據指定的模式過濾輸入,如果未指定,則不應用任何過濾。它是一個 ObjectProperty,預設為 None。可以是 None、'int'(字串)或 'float'(字串)或可呼叫物件。
insert_text(substring, from_undo=False) − 在當前游標位置插入新文字。覆蓋此函式以對輸入驗證的文字進行預處理。
line_height − 一行的高度。此屬性會根據 font_name 和 font_size 自動計算。更改 line_height 不會產生任何影響。line_height 是一個 NumericProperty,只讀。
line_spacing − 行之間佔用的空間。line_spacing 是一個 NumericProperty,預設為 0。
minimum_height − TextInput 內部內容的最小高度。minimum_height 是一個只讀 AliasProperty。
multiline − 如果為 True,則視窗部件將能夠顯示多行文字。如果為 False,則“Enter”鍵按下將使文字輸入失去焦點,而不是新增新行
on_touch_down(touch) − 接收觸控按下事件。touch 引數是 MotionEvent 類的物件。它返回布林值如果為 True,則觸控事件的分派將停止。如果為 False,則事件將繼續分派到視窗部件樹的其餘部分。
on_touch_move(touch) − 接收觸控移動事件。touch 位於父級座標中。
on_touch_up(touch) − 接收觸控抬起事件。touch 位於父級座標中。
padding − 文字的內邊距:[padding_left, padding_top, padding_right, padding_bottom]。Padding 也接受兩個引數的形式 [padding_horizontal, padding_vertical] 和一個引數的形式 [padding]。Padding 是一個 VariableListProperty,預設為 [6, 6, 6, 6]。
password − 如果為 True,則視窗部件將顯示其字元作為 password_mask 中設定的字元集。
password_mask − 設定在 password 為 True 時用於遮蔽文字的字元。password_mask 是一個 StringProperty,預設為 '*'。
paste() − 將系統剪貼簿中的文字插入到 TextInput 中當前游標位置。
readonly − 如果為 True,則使用者將無法更改文字輸入的內容。
select_all() − 選擇此 TextInput 中顯示的所有文字。
select_text(start, end) − 選擇此 TextInput 中顯示的一部分文字。引數為 start - textinput.text 的索引,從中開始選擇,以及 end - textinput.text 的索引,選擇應顯示到該索引為止
selection_color − 選擇的當前顏色,格式為 (r, g, b, a)。
selection_from − 如果正在進行或已完成選擇,則此屬性將表示選擇開始處的遊標索引。
selection_text − 當前內容選擇。selection_text 是一個 StringProperty,預設為 '',只讀。
tab_width − 預設情況下,每個製表符將在文字輸入視窗部件上替換為四個空格。您可以設定較低或較高的值。tab_width 是一個 NumericProperty,預設為 4。
text − 視窗部件的文字。它是一個 AliasProperty。
用法
建立簡單的 hello world:-
widget = TextInput(text='Hello world')
如果要使用 Unicode 字串建立視窗部件,請使用:-
widget = TextInput(text=u'My unicode string')
當用戶在 TextInput 視窗部件內輸入資料時,它將成為 text 屬性的值。
當 TextInput 物件的 text 屬性更改時,您可以呼叫回撥。
def callback(instance, value):
print('The widget', instance, 'have:', value)
textinput = TextInput()
textinput.bind(text=callback)
當 multiline 屬性為 False 時,TextInput 接受單行輸入。當用戶按下 Enter 時,將生成 on_text_validate 事件:-
def callback(instance, value):
print('The widget', instance, 'have:', value)
textinput = TextInput(multiline=False)
textinput.bind(on_text_validate=callback)
示例
讓我們使用上面解釋的一些 TextInput 類的屬性和方法。在以下示例中,我們有兩個多行文字框和兩個按鈕,它們排列在一個 BoxLayout 中。
COPY 按鈕呼叫 gettext() 方法,該方法儲存來自上文字框的選擇的文字。
def gettext(self, instance): mydemoapp.text = self.text1.selection_text
PASTE 按鈕呼叫回撥 insert(),該回調將在游標位置貼上選定的文字。
def insert(self, instance): self.text2.insert_text(mydemoapp.text)
這兩個函式繫結到兩個按鈕:-
self.b1=Button(text='COPY') self.b1.bind(on_press=self.gettext) self.b2=Button(text='PASTE') self.b2.bind(on_press=self.insert)
build() 方法用於組裝文字框和按鈕。
以下是完整程式碼 -
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.config import Config
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '300')
Config.set('graphics', 'resizable', '1')
class mydemoapp(App):
text=''
def gettext(self, instance):
mydemoapp.text = self.text1.selection_text
def insert(self, instance):
self.text2.insert_text(mydemoapp.text)
def build(self):
main= BoxLayout(orientation= 'vertical')
self.text1 = TextInput(multiline=True, font_size=20)
btns = BoxLayout(orientation='horizontal')
self.b1=Button(text='COPY')
self.b1.bind(on_press=self.gettext)
self.b2=Button(text='PASTE')
self.b2.bind(on_press=self.insert)
self.text2 = TextInput(
multiline=True, font_size=20,
foreground_color=[0,0,1,1]
)
btns.add_widget(self.b1)
btns.add_widget(self.b2)
main.add_widget(self.text1)
main.add_widget(btns)
main.add_widget(self.text2)
return main
mydemoapp().run()
輸出
Kivy - 畫布
與其他一些 GUI 工具包(例如 TKinter)不同,Kivy 沒有獨立的 Canvas 小部件。相反,您需要使用 Kivy 中每個小部件預設具有的畫布。建立小部件時,可以建立在畫布上繪製所需的所有指令。
需要注意的是,所有小部件都有不同的畫布,但所有畫布都在完全相同的繪圖空間(即座標空間)中繪製。此外,繪圖空間不限於小部件的位置和大小。繪圖空間的 (0,0) 始終是左下角。
"canvas.before" 屬性在需要操作例項的顏色時特別有用。另一方面,canvas.after 用於在新增子項後執行任何指令。它在遍歷所有子項後呼叫。
Kivy 中的 Canvas 是一組繪圖指令。要進行繪製,您將需要一個 Canvas 物件和 Instruction 物件。例如,要在標籤的畫布上繪製矩形 -
from kivy.graphics import * with label.canvas: Color(1., 0, 0) # Add a red color # Add a rectangle Rectangle(pos=(10, 10), size=(500, 500))
如果您必須在不使用 Python 的上下文管理器的情況下執行相同的操作 -
label.canvas.add(Color(1., 0, 0)) label.canvas.add(Rectangle(size=(500, 500)))
您可以在任何小部件的畫布上繪製矩形、橢圓、線和貝塞爾曲線等形狀,包括 Widget 物件本身。(Widget 類是 Kivy 中所有其他可視小部件的基礎)
要在畫布上繪製矩形,我們需要指定 pos 和 size 屬性 -
from kivy.graphics import Rectangle Rectangle(**kwargs)
引數
pos - 指定矩形位置的 X 和 Y 座標值列表,格式為 (x, y)。
size - 指定矩形寬度和高度的列表,格式為 (width, height)。
以下程式碼在 Widget 物件的畫布上繪製一個矩形 -
widget=Widget() with widget.canvas: Color(0,0,1,1) Rectangle(pos=(50,300), size_hint=(None, None), size=(300,200))
指令Color 和Rectangle 自動新增到 canvas 物件,並在繪製視窗時使用。
語法
您可能希望使用 "kv" 語言語法 -
Widget:
canvas:
color:
rgb: 0,0,1
Rectangle:
pos: self.pos
size: self.size
Kivy 中的 Label 物件沒有背景顏色屬性。要解決此問題,您可以在其畫布上繪製一個填充所需顏色的矩形以提供背景。
lbl = Label(text='Hello World', font_size=24)
with lbl.canvas.before:
Color(1,1,0)
Rectangle(pos=lbl.pos, size=lbl.size)
或者,使用 "kv" 指令碼 -
Label:
text:'Hello World'
font_size:24
canvas.before:
Color:
rgb: (1,1,0)
Rectangle:
pos:self.pos
size=:self.size
語法
您可以使用以下語法在畫布上繪製橢圓 -
from kivy.graphics import Ellipse Ellipse(*args, **kwargs)
引數
segments - 定義繪製橢圓所需的段數。段數越多,如果段數很多,繪製會更平滑。
angle_start - 浮點數,預設為 0.0,並指定圓盤部分的起始角度(以度為單位)。
angle_end - 浮點數,預設為 360.0,指定圓盤部分的結束角度(以度為單位)。
angle_end - 橢圓的結束角度(以度為單位),預設為 360。
angle_start - 橢圓的起始角度(以度為單位),預設為 0。
pos - 畫布座標系中的位置
size - 橢圓的 X 和 Y 半徑。如果兩者相等,則成為圓形。
您還可以透過將影像檔案作為矩形或橢圓的 source 屬性直接在畫布上繪製圖像。
示例 1
以下程式碼實現了上面解釋的所有繪圖指令,以在小部件畫布上顯示矩形、橢圓和影像。它還在其畫布上繪製了具有背景顏色的矩形的標籤。
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.graphics import *
from kivy.core.window import Window
Window.size = (720,400)
class canvasdemoapp(App):
def build(self):
widget=Widget()
# rectangle on canvas
with widget.canvas:
Color(0,0,1,1)
Rectangle(
pos=(50,300), size_hint=(None, None),
size=(300,200)
)
Color(0.5, .2, 0.4, 1)
d = 100
# ellipse
Ellipse(pos=(600,100), size=(d+75, d))
Color(.5,.5,.5)
# image
Rectangle(source='kivy-logo.png', pos=(50,100))
Color(1,1,1)
Rectangle(source='TPlogo.png', pos=(300, 100))
# label with background
lbl = Label(
text='Hello World', font_size=24,
pos=(Window.width/2, 300), size =(200,200),
color=(0,0,1,1)
)
with lbl.canvas.before:
Color(1,1,0)
Rectangle(pos=lbl.pos, size=lbl.size)
widget.add_widget(lbl)
btn=Button(
text='Button', font_size=24,
background_color= (.8, .4, .3, 1),
pos=(500,10)
)
widget.add_widget(btn)
return widget
canvasdemoapp().run()
輸出
執行此程式碼時,將生成以下輸出 -
示例 2
Widget 物件響應所有觸控事件(例如 on_touch_down 和 on_touch_move 等)。
在下面的示例中,Widget 物件上 on_touch_down 事件的回撥獲取觸控事件發生的位置的座標,並繪製一個圓圈(X 和 Y 半徑相等的橢圓),並使用隨機的 RGB 顏色值。
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
import random
from kivy.core.window import Window
Window.size = (720,300)
class widget(Widget):
def on_touch_down(self, touch):
colorR = random.randint(0, 255)
colorG = random.randint(0, 255)
colorB = random.randint(0, 255)
self.canvas.add(Color(
rgb=(colorR / 255.0, colorG / 255.0, colorB / 255.0)
))
d = 30
self.canvas.add(Ellipse(
pos=(touch.x - d / 2, touch.y - d / 2),
size=(d, d)
))
class circlesapp(App):
def build(self):
return widget()
circlesapp().run()
輸出
執行程式並在不同位置生成 touch_down 事件。圓圈將繪製在位置上。
Kivy - 線
在 Kivy 庫中,“Line” 是“kivy.graphics”模組中重要的頂點指令。在 Kivy 中,所有繪製都在與任何可用小部件關聯的 Canvas 上完成。Line 指令繪製一條線或一系列線以及其他形狀,如矩形、橢圓、貝塞爾曲線等。
必須注意,Kivy 繪圖指令不是自動相對於小部件的位置或大小的。相反,所有小部件的畫布共享一個公共座標空間。
Line 函式需要一個數字值列表。數字的解釋取決於將此列表分配到的引數。List 函式的引數是點、矩形、橢圓、貝塞爾曲線等。
繪製矩形
語法
您可以使用以下語法使用 Line 函式繪製矩形 -
with self.canvas: Line(rectangle=[x, y, w, h], width)
這裡,“x” 和“y”表示矩形的左下角位置,“w” 和“h”表示寬度和高度。線條自動閉合。
您還可以使用 rounded_rectangle 屬性構建具有圓角的矩形。引數必須是以下形式之一的元組 -
(x, y, width, height, corner_radius)
(x, y, width, height, corner_radius, resolution)
(x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4)
(x, y, width, height, corner_radius1, corner_radius2, corner_radius3, corner_radius4, resolution)
示例
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.core.window import Window
Window.size = (720,300)
class drawRectangle(App):
def build(self):
widget = Widget()
with widget.canvas:
Color(1, 0, 1, 1)
Line(
rectangle=(50, 50, 300, 200),
width=3
)
Line(rounded_rectangle=(500, 200, 300, 200, 20, 20, 20, 20))
return widget
drawRectangle().run()
輸出
它將生成以下輸出視窗 -
繪製橢圓
您需要將數字值列表分配給 Line 指令的 ellipse 屬性。ellipse 引數的值必須是以下元組
(x, y, width, height, angle_start, angle_end, segments)
其中,
"x" 和 "y" 表示橢圓的左下角
"width" 和 "height" 表示橢圓的大小。如果這兩個值相同,則結果將是一個圓圈
"angle_start" 和 "angle_end" 以度為單位。預設值為 0 和 360。
"segments" 是橢圓的精度。您可以使用此屬性建立具有 3 個或更多邊的多邊形。小於 3 的值將不會表示。
示例
在下面的程式碼中,Line 指令用於使用不同的引數繪製橢圓 -
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.core.window import Window
Window.size = (720,400)
class drawEllipse(App):
def build(self):
widget = Widget()
with widget.canvas:
Color(0.5, .2, 0.4, 1)
Line(ellipse=(500, 70, 200, 200), width=4)
Line(ellipse=(100, 200, 100, 200), width=4)
Color(.2, .8, 0, 1)
Line(ellipse=(200, 100, 200, 100), width=4)
Line(ellipse=(500, 300, 250, 90, 45, 270), width=3)
Color(.1, .8, .3, 1)
Line(ellipse=(200, 400, 200, 80, 180, 420, 30), width=5)
return widget
drawEllipse().run()
輸出
繪製貝塞爾曲線
貝塞爾曲線由一些控制點加權,我們將其包含在指令中。Line() 函式接受 Bezier 引數,並將 (x,y) 座標對列表傳遞給該引數。引數必須是 2n 個元素的列表,“n”是點的數量。
with self.canvas: Line(bezier=[x1, y1, x2, y2, x5, y3], width)
需要注意的是,Line 指令函式的 points 引數也接收類似的 2n 個元素集。points 屬性在連續點之間繪製一條線。
with self.canvas: Line(points=[x1, y1, x2, y2, x5, y3], width)
Line 指令的 point 引數僅繪製與每個 x-y 座標對相對應的點,而沒有任何連線它們的線。
with self.canvas: Line(point=[x1, y1, x2, y2, x5, y3], width)
示例
以下程式碼使用相同的“x”和座標對集僅繪製點、線和貝塞爾曲線 -
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
from kivy.core.window import Window
Window.size = (720, 400)
class drawBezier(App):
def build(self):
widget = Widget()
with widget.canvas:
Color(0, 1, 1, 1)
Bezier(
points=[700, 400, 450, 300, 300, 350, 350, 200, 200, 100, 150, 10],
segments=20
)
Color(1, 1, 0, 1)
Point(
points=[700, 400, 450, 300, 300, 350, 350, 200, 200, 100, 150, 10],
pointsize=5
)
Color(.1, .1, .8)
Line(
points=[700, 400, 450, 300, 300, 350, 350, 200, 200, 100, 150, 10],
pointsize=3
)
return widget
drawBezier().run()
輸出
執行此程式碼時,將生成一個類似於此處所示的輸出視窗 -
需要注意的是,Kivy 提供了另一組頂點指令來使用 Rectangle、Ellipse、Bezier 指令繪製這些形狀。這些與 Line 指令的 rectangle、ellipse 和 bezier 引數不同。
注意指令本身和引數的大寫第一個字母(Ellipse 指令與 Line 指令的 ellipse 引數)。Line 函式在不重新計算點的情況下繪製形狀。
Kivy - 複選框
在任何 GUI 工具包中,複選框用於使使用者能夠從可用選項中選擇一個或多個選項。在 Kivy 中,可以配置 CheckBox 以使選擇互斥(僅可以選擇一個可用選項),或允許使用者標記任意數量的選擇。
如果兩個或多個複選框的 group 屬性具有相同的值,則它們將顯示為圓形單選按鈕;使用者只能選擇一個選項,因為只有一個複選框的 active 屬性可以為 True,對於其他複選框,active 屬性將自動變為 False。
對於沒有 group 屬性的複選框,它將顯示為一個矩形框,按下時,將顯示一個複選標記,active 屬性變為 True。再次點選它,複選標記將被移除,active 屬性變為 False。
CheckBox 類定義在 kivy.uix.checkbox 模組中
from kivy.uix.checkbox import CheckBox cb = CheckBox(**kwargs)
如果複選框物件繫結到其 active 屬性,則每次 active 屬性更改時都會呼叫回撥。
checkbox = CheckBox() checkbox.bind(active=callback)
示例
以下 Python 程式碼演示瞭如何使用互斥的複選框以及多選複選框。
程式碼使用一個垂直 BoxLayout,其中包含兩個水平佈局和兩個標籤。上部水平佈局包含兩個複選框,這兩個複選框的 group 屬性均為“sex”
self.m = CheckBox(group='sex', color=[1,0,1,1]) self.m.bind(active=self.on_male) gendergrp.add_widget(self.m) gendergrp.add_widget(Label(text='Female')) self.f = CheckBox(active=False, group='sex') self.f.bind(active=self.on_female) gendergrp.add_widget(self.f)
這兩個複選框都呼叫一個回撥方法,該方法識別 active 屬性。
下部水平框包含三個獨立的複選框 -
interests.add_widget(Label(text='Sports')) self.cb1 = CheckBox() self.cb1.bind(active=self.on_interest) interests.add_widget(self.cb1) self.cb2 = CheckBox() self.cb2.bind(active=self.on_interest) interests.add_widget(Label(text='Music')) interests.add_widget(self.cb2) self.cb3 = CheckBox() self.cb3.bind(active=self.on_interest) interests.add_widget(Label(text='Travel')) interests.add_widget(self.cb3)
單擊每個複選框時,都會構建一個選定興趣列表,並在水平框下方的標籤上顯示。
以下是完整程式碼 -
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720,400)
class CheckBoxApp(App):
gender=''
intrst=[]
def on_male(self, instance, value):
if value:
CheckBoxApp.gender='Male'
self.lbl.text = "Gender selected: "+CheckBoxApp.gender
else:
self.lbl.text = "Gender selected: "
def on_female(self, instance, value):
if value:
CheckBoxApp.gender='Female'
self.lbl.text = "Gender selected: "+CheckBoxApp.gender
else:
self.lbl.text = "Gender selected: "
def on_interest(self, instance, value):
CheckBoxApp.intrst=[]
if self.cb1.active:
CheckBoxApp.intrst.append("Sports")
if self.cb2.active:
CheckBoxApp.intrst.append("Music")
if self.cb3.active:
CheckBoxApp.intrst.append("Travel")
self.lbl1.text="Interests Selected: "+" ".join(CheckBoxApp.intrst)
def build(self):
main=BoxLayout(orientation='vertical')
gendergrp=BoxLayout(orientation='horizontal')
interests = BoxLayout(orientation='horizontal')
gendergrp.add_widget(Label(text='Gender:'))
gendergrp.add_widget(Label(text='Male'))
self.m = CheckBox(group='sex', color=[1,0,1,1])
self.m.bind(active=self.on_male)
gendergrp.add_widget(self.m)
gendergrp.add_widget(Label(text='Female'))
self.f = CheckBox(active=False, group='sex')
self.f.bind(active=self.on_female)
gendergrp.add_widget(self.f)
main.add_widget(gendergrp)
self.lbl = Label(text="Gender selected: ", font_size=32)
main.add_widget(self.lbl)
interests.add_widget(Label(text='Interests:'))
interests.add_widget(Label(text='Sports'))
self.cb1 = CheckBox()
self.cb1.bind(active=self.on_interest)
interests.add_widget(self.cb1)
self.cb2 = CheckBox()
self.cb2.bind(active=self.on_interest)
interests.add_widget(Label(text='Music'))
interests.add_widget(self.cb2)
self.cb3 = CheckBox()
self.cb3.bind(active=self.on_interest)
interests.add_widget(Label(text='Travel'))
interests.add_widget(self.cb3)
self.lbl1 = Label(text="Interests selected: ", font_size=32)
main.add_widget(interests)
main.add_widget(self.lbl1)
return main
if __name__ == '__main__':
CheckBoxApp().run()
輸出
執行此程式碼時,將生成一個類似於此處所示的 GUI -
Kivy - 下拉列表
Kivy 中的下拉小部件與其他 GUI 工具包中的類似小部件完全不同。Kivy 的下拉選單不僅顯示標籤,還顯示其他任何小部件,例如按鈕、影像等。
DropDown 類定義在“kivy.uix.dropdown”模組中。
from kivy.uix.dropdown import DropDown dropdown=DropDown()
構建下拉選單物件需要執行以下步驟 -
在此物件中新增其他小部件時,我們需要透過停用 size_hint 手動指定高度,從而下拉選單計算所需區域。
對於在 DropDown 中新增的每個子小部件,您都需要附加一個回撥,該回調將在下拉選單上呼叫 select() 方法。繫結每個子項並新增到下拉選單物件。
將下拉選單新增到主按鈕並將其與下拉選單類的 open() 方法繫結
最後,執行應用程式並單擊主按鈕。您將看到一系列子小部件下拉。單擊其中任何一個以呼叫其關聯的回撥。
示例
在此示例中,我們將演示 Kivy 中的下拉小部件是如何工作的。我們將使用 for 迴圈將十個按鈕新增到下拉選單中,如下所示 -
dropdown = DropDown()
for index in range(1, 11):
btn = Button(text ='Button '+str(index),
size_hint_y = None, height = 40)
btn.bind(on_release = lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
box.add_widget(dropdown)
我們將主按鈕放置在 BoxLayout 中,將下拉選單物件新增到其中,並將主按鈕與下拉選單物件的 open() 方法繫結。
box = BoxLayout(orientation='vertical')
mainbutton = Button(text ='Drop Down Button', size_hint=(None, None), size =(250, 75), pos_hint ={'center_x':.5, 'top':1})
box.add_widget(mainbutton)
mainbutton.add_widget(dropdown)
mainbutton.bind(on_release = dropdown.open)
最後,我們需要偵聽下拉列表中的選擇並將資料分配給按鈕文字。
dropdown.bind(on_select = lambda instance, x: setattr(mainbutton, 'text', x))
所有這些步驟都包含在以下程式碼中 App 類的 build() 方法中 -
from kivy.app import App
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720, 400)
class Drop_down_app(App):
def build(self):
box = BoxLayout(orientation='vertical')
mainbutton = Button(
text='Drop Down Button', size_hint=(None, None),
size=(250, 75), pos_hint={'center_x': .5, 'top': 1}
)
box.add_widget(mainbutton)
dropdown = DropDown()
for index in range(1, 11):
btn = Button(text='Button ' + str(index),
size_hint_y=None, height=40)
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
box.add_widget(dropdown)
mainbutton.add_widget(dropdown)
mainbutton.bind(on_release=dropdown.open)
dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
return box
Drop_down_app().run()
輸出
當我們執行上述程式碼時,主按鈕可見。
單擊按鈕。結果,按鈕列表下拉。當單擊列表中的按鈕時,主按鈕的標題將更改為該按鈕的標題。
Kivy - 視窗
Window 類是 Kivy 框架的核心類之一。應用程式視窗是透過在特定佈局中放置一個或多個小部件來構建的。build() 方法通常返回一個單一的根小部件,它可能是以樹狀結構排列的多個其他小部件的組合。相反,小部件樹的根可以直接新增到應用程式視窗。
Window 類定義在“kivy.core.window”模組中。它繼承了 WindowBase 類,WindowBase 類是任何視窗實現的抽象視窗小部件。預設應用程式視窗是在 App 物件啟動其事件迴圈時建立的。請注意,Kivy 每個應用程式僅支援一個視窗。
許多 Window 屬性是從 Kivy 配置檔案(KIVY_HOME 目錄中的“config.ini”檔案)中讀取的。
小部件尺寸取決於預設視窗的大小。App 類 build() 方法中的以下程式碼將小部件樹放入應用程式視窗中。請注意,build() 方法不會返回根小部件。相反,它被新增到 Window 物件的 add_widget() 方法中。
box=BoxLayout(orientation='vertical') l=Label(text='Window Properties', font_size=32) box.add_widget(l) b1=ToggleButton(text='Fullscreen') b2=ToggleButton(text='Border') b3=ToggleButton(text='Position') bh=BoxLayout(orientation='horizontal', size_hint=(1, .2)) bh.add_widget(b1) bh.add_widget(b2) bh.add_widget(b3) box.add_widget(bh) Window.add_widget(box)
事件
Window 物件可以識別不同型別的事件 -
當分發新的 MotionEvent 時,會觸發 on_motion 事件。
Window 吸收觸控事件 on_touch_down, on_touch_move, on_touch_up 等。
當 Window 關閉時,會觸發 on_close 事件。
當用戶想要透過按下標題欄上的關閉按鈕來結束事件迴圈時,會發生 on_request_close 事件。
當游標進入視窗時,會觸發 on_cursor_enter 事件。
類似地,當游標離開視窗時,會發生 on_cursor_leave 事件。
當視窗分別最小化和最大化時,會觸發 on_minimize 和 on_maximize 事件。
當視窗恢復時,會觸發 on_restore 事件。
類似於觸控事件,當按鍵按下或釋放時,按鍵事件 on_key_down 和 on_key_up 事件分別發出按鍵、掃描碼、程式碼點、修飾符。
對於本章中的演示示例,讓我們將一些 Window 事件與回撥方法繫結。
Window.bind(on_request_close = self.on_close) Window.bind(on_cursor_leave=self.on_leave) Window.bind(on_cursor_enter=self.on_enter)
每當滑鼠指標離開視窗區域時,都會呼叫 on_leave() 方法。
def on_leave(self, *args):
print ("leaving the window")
類似地,當滑鼠進入視窗區域時,將呼叫 on_enter 回撥。
def on_enter(self, *args):
print ("Entering the window")
當用戶選擇關閉事件迴圈時,會引發 on_request_close 事件。如果使用者按下 X 按鈕,以下回調會詢問使用者是否要退出。您還可以使彈出窗口出現。
def on_close(self, instance):
resp=input("Do you want the window to close?")
if resp=='y': Window.close()
屬性
應用程式視窗的外觀由 Window 類中定義的許多屬性決定。它們的預設值由 config.ini 檔案提供。但是,它們可以在應用程式程式碼中修改。一些 Wiindow 屬性如下所示 -
borderless - 當設定為 True 時,此屬性將刪除視窗邊框/裝飾。
children - 返回此視窗子級的列表。
clearcolor - 用於清除視窗的顏色。clear() 方法使用此屬性與此顏色值一起使用
from kivy.core.window import Window Window.clearcolor = (1, 0, 0, 1) Window.clear()
custom_titlebar - 當設定為 True 時,允許使用者設定一個 widget 作為標題欄。
fullscreen - 此屬性設定視窗的全屏模式。可用選項包括:True、False、'auto' 和 'fake'。
left , top - 視窗的左和上位置。它是 SDL2 屬性,左上角為 [0, 0]。
size - 獲取/設定視窗的大小。
from kivy.core.window import Window Window.size = (720,400)
您還可以透過修改配置值來設定大小 -
from kivy.config import Config
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
讓我們處理一些 Window 屬性。在這個程式的應用程式視窗上,我們有三個切換按鈕。我們將它們繫結到某些回撥。
b1.bind(on_press=self.pressed) b2.bind(on_press=self.bordered) b3.bind(on_press=self.positioned)
pressed() 方法在全屏和普通之間切換全屏狀態。
def pressed(self, instance):
if instance.state=='down':
Window.set_title("Kivy Full screen window")
Window.maximize()
elif instance.state=='normal':
Window.set_title('Kivy Restored Window')
Window.restore()
當按下 b2 按鈕時,bordered() 方法使視窗無邊框,釋放時恢復為原始邊框視窗。
def bordered(self, instance):
print (Window.top, Window.left)
if instance.state=='down':
Window.borderless=True
elif instance.state=='normal':
Window.borderless=False
當按下/釋放 b3 時,positioned() 回撥將視窗移動到 (0,0) 位置並返回到其早期位置。
def positioned(self, instance):
print (Window.top, Window.left)
if instance.state=='down':
self.x, self.y=Window.left, Window.top
Window.left, Window.top=(0,0)
elif instance.state=='normal':
Window.left, Window.top=self.x,self.y
應用程式視窗首先顯示如下。生成事件(滑鼠離開、進入 on_request_close)並查看回調的執行情況。同樣檢查切換按鈕的動作。
Kivy - 滾動檢視
Kivy 框架中的 ScrollView widget 包含任何其他尺寸大於分配給它的尺寸的 widget,併為其提供一個可滾動的面板。這使得包含的 widget 可以垂直或水平平移/滾動。
ScrollView 類在 kivy.uix.scrollview 模組中定義。通常,您在一個佈局中組合一個或多個 widget,並將佈局新增到 ScrollView。
from kivy.uix.scrollview import ScrollView view = ScrollView() view.add_widget(layout)
ScrollView 物件的“scroll_x”和“scroll_y”屬性控制滾動面板的滾動行為。ScrollView 允許雙向滾動。您可以透過將“do_scroll_x”或“do_scroll_y”設定為 False 來停用某個軸上的滾動。
此外,“scroll_distance”屬性設定要移動的最小距離,預設為 20 畫素。此外,scroll_timeout 屬性指定最大時間段,預設為 55 毫秒。
“scroll_distance”和“scroll_timeout”的重要性在於:如果觸控手勢滾動的畫素數大於或等於 scroll_distance,並且在 scroll_timeout 時間段內,則將其識別為滾動手勢,並且將開始平移(滾動/平移)。如果超時發生,則觸控按下事件將傳播到子級。
ScrollView 類的其他屬性如下所示 -
do_scroll - 允許在 X 或 Y 軸上滾動。
do_scroll_x - 允許在 X 軸上滾動。這是一個 BooleanProperty,預設為 True。
do_scroll_y - 允許在 Y 軸上滾動。這是一個 BooleanProperty,預設為 True。
scroll_distance - 開始滾動 ScrollView 之前要移動的距離(以畫素為單位)。這是一個 NumericProperty,預設為 20 畫素。
scroll_timeout - 觸發 scroll_distance 允許的超時時間(以毫秒為單位),預設為 55 毫秒
scroll_to() - 滾動視口以確保給定的 widget 可見,可以選擇新增填充和動畫。
scroll_type - 設定用於 scrollview 內容的滾動型別。可用選項包括:['content']、['bars']、['bars', 'content']。
ScrollView 物件發出以下事件 -
on_scroll_start - 從觸控開始滾動時觸發的通用事件。
on_scroll_move - 從觸控移動滾動時觸發的通用事件。
on_scroll_stop - 從觸控停止滾動時觸發的通用事件。
示例
為了能夠理解 ScrollView 的工作原理,我們需要一個足夠大的佈局,以便它溢位主應用程式視窗的尺寸。為此,我們將 100 個按鈕新增到一個單列網格佈局中,並對其應用 scrollview。
以下示例中的操作程式碼如下所示 -
layout = GridLayout(cols=1) for i in range(100): btn = Button(text='Button ' + str(i), size_hint_y=None, height=40) layout.add_widget(btn) root = ScrollView() root.add_widget(layout)
為了確保高度足以滾動,將佈局物件的 minimum_height 屬性繫結到其 setter。
layout.bind(minimum_height=layout.setter('height'))
以下是 ScrollView 演示程式碼的完整程式碼 -
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.app import App
from kivy.core.window import Window
Window.size = (720, 350)
class scrollableapp(App):
def build(self):
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(100):
btn = Button(text='Button ' + str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
root = ScrollView(
size_hint=(1, None),
size=(Window.width, Window.height)
)
root.add_widget(layout)
return root
scrollableapp().run()
輸出
執行上述程式碼。要超出檢視中可見的按鈕,請使用滑鼠或手指垂直滾動(如果您正在使用觸控式螢幕裝置)。
Kivy - 旋轉木馬
Carousel 是一種用於迴圈瀏覽一系列內容的幻燈片。Kivy 框架包含一個 Carousel widget,它允許您輕鬆建立可瀏覽的幻燈片,尤其適用於智慧手機等觸控式螢幕裝置。Carousel 中的頁面可以水平或垂直移動。
Carousel 類在“kivy.uix.carousel”模組中定義。
from kivy.uix.carousel import Carousel carousel = Carousel(**kwargs)
下面給出了一個使用 Carousel 建立簡單幻燈片的 Python/Kivy 程式 -
from kivy.app import App
from kivy.uix.carousel import Carousel
from kivy.uix.image import Image
class CarouselApp(App):
def build(self):
carousel = Carousel(direction='right')
img1=Image(source='1.png')
carousel.add_widget(img1)
img2=Image(source='2.png')
carousel.add_widget(img2)
img3=Image(source='3.png')
carousel.add_widget(img3)
return carousel
CarouselApp().run()
您還可以使用“kv”語言指令碼構建 Carousel。
Carousel:
direction: 'right'
Image:
source: '1.png'
Image:
source: '2.png'
Image:
source: '3.png'
Image:
source: '4.png'
Carousel 類定義了以下屬性 -
current_slide - 當前顯示的幻燈片。current_slide 是一個 AliasProperty。
direction - 指定幻燈片排序的方向。這對應於使用者從哪個方向滑動以從一個幻燈片轉到下一個幻燈片的方向。它可以是 right、left、top 或 bottom。
index - 根據索引獲取/設定當前幻燈片。index 預設為 0(第一個專案)。
load_next(mode='next') - 動畫到下一張幻燈片。
load_previous() - 動畫到上一張幻燈片。
load_slide(slide) - 動畫到作為引數傳遞的幻燈片。
loop - 允許 Carousel 無限迴圈。如果為 True,當用戶嘗試滑動到最後一頁之外時,它將返回到第一頁。如果為 False,它將保留在最後一頁。
next_slide - Carousel 中的下一張幻燈片。如果當前幻燈片是 Carousel 中的最後一張幻燈片,則為 None。
previous_slide - Carousel 中的上一張幻燈片。如果當前幻燈片是 Carousel 中的第一張幻燈片,則為 None。
scroll_distance - 開始滾動 Carousel 之前要移動的距離(以畫素為單位)。預設距離為 20dp。
scroll_timeout - 觸發 scroll_distance 允許的超時時間(以毫秒為單位)。預設為 200(毫秒)
slides - Carousel 內部的幻燈片列表。
示例
例如,在 Kivy 中使用 Carousel,請檢視以下程式碼。Carousel 物件用作應用程式的根 widget,我們將標籤、按鈕和影像作為其幻燈片新增。
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.carousel import Carousel
from kivy.uix.image import Image
from kivy.core.window import Window
Window.size = (720,350)
class CarouselApp(App):
def build(self):
carousel = Carousel(direction='right')
carousel.add_widget(Button(text='Button 1', font_size=32))
src = "ganapati.png"
image = Image(source=src, fit_mode="contain")
carousel.add_widget(image)
carousel.add_widget(Button(text="Button 2", font_size=32))
return carousel
CarouselApp().run()
輸出
這是一個簡單的應用程式,可以透過在裝置的顯示屏上滑動來瀏覽一系列幻燈片。direction 引數設定為 right,這意味著後續幻燈片位於右側。
使用“kv”語言組裝 Carousel
讓我們使用“kv”語言指令碼組裝 Carousel。這次,direction 設定為 top,這意味著您必須向上滑動螢幕才能看到下一個顯示。
示例
Carousel:
direction:'top'
Button:
text:'Button 1'
font_size:32
Image:
source:"kivy-logo.png"
fit_mode:"contain"
Button:
text:"Button 2"
font_size:32
輸出
幻燈片一個接一個地堆疊。
Kivy - 滑塊
在 Kivy 框架中,當您想要設定連續變化的數字屬性的值時,Slider widget 是一個非常有用的控制元件。例如,電視螢幕或移動裝置或揚聲器聲音的亮度。
滑塊 widget 的外觀是一個水平或垂直的條形,上面有一個滑塊,用於設定值。當滑塊位於水平滑塊的左側時,它對應於最小值;當它位於最右側時,它對應於最大值。
Slider 類在“kivy.uix.slider”類中定義。
from kivy.uix.slider import Slider slider = Slider(**kwargs)
要在 Kivy 中建立基本的滑塊控制元件,我們可以使用以下程式碼 -
from kivy.uix.slider import Slider s = Slider(min=0, max=100, value=25)
滑塊控制元件的預設方向是水平方向。如果需要,請設定 orientation='vertical'。您應該在 Kivy 應用程式視窗上看到如下所示的滑塊。
可以使用滑鼠或觸控(在觸控式螢幕的情況下)沿滑塊移動滑塊。
要根據滑塊值的更改呼叫某個操作,請將 value 屬性繫結到某個回撥。
def on_value_changed(self, instance, val): print (val) s.bind(value = on_value_changed)
以下是 Slider 類的一些重要屬性 -
max - 允許的最大值。max 是一個 NumericProperty,預設為 100。
min - 允許的最小值。min 是一個 NumericProperty,預設為 0。
orientation - 滑塊的方向。orientation 是一個 OptionProperty,預設為 'horizontal'。可以取值為 'vertical' 或 'horizontal'。
padding − 滑塊的填充。填充用於圖形表示和互動。它防止游標超出滑塊邊界框的範圍。padding 是一個 NumericProperty,預設為 16sp。
range − 滑塊的範圍,格式為 (最小值,最大值),是 (min, max) 屬性的 ReferenceListProperty。
sensitivity − 觸控是否與小部件的整個主體碰撞,還是僅與滑塊手柄部分碰撞。sensitivity 是一個 OptionProperty,預設為 'all'。可以取值為 'all' 或 'handle'。
step − 滑塊的步長。確定滑塊在 min 和 max 之間每次移動的間隔或步長的大小。step 是一個 NumericProperty,預設為 0。
value − 滑塊當前使用的值。value 是一個 NumericProperty,預設為 0。
value_track − 決定滑塊是否應該繪製表示 min 和 value 屬性值之間空間的線。它是一個 BooleanProperty,預設為 False。
value_track_color − value_line 的顏色,採用 rgba 格式。value_track_color 是一個 ColorProperty,預設為 [1, 1, 1, 1]。
value_track_width − 軌跡線的寬度,預設為 3dp。
示例
在下面的程式碼中,我們使用三個滑塊小部件來讓使用者設定所需顏色的 RGB 值。滑塊的值用於更改 RGB 值。例如,紅色滑塊的更改會設定 'r' 分量的值 -
def on_red(self, instance, val): self.r = int(val)/255 self.colour=[self.r, self.g, self.b, self.t] self.redValue.text = str(int(val))
綠色和藍色的類似回撥也進行了編碼。這些被分配給 colur 變數的值,colur 變數是 ColorProperty 型別。它繫結到 Label 小部件的顏色屬性。
colour = ColorProperty([1,0,0,1]) def on_colour_change(self, instance, value): self.ttl.color=self.colour
因此,透過滑塊設定 RGB 值會更改 Label 的文字顏色。
三個滑塊控制元件以及所需的標籤放置在一個具有四列的內部網格佈局中。一個具有一個列的上層網格包含一個標籤,該標籤的顏色希望隨著滑塊移動而更改。
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.properties import ColorProperty, NumericProperty
from kivy.core.window import Window
Window.size = (720, 400)
class SliderExample(App):
r = NumericProperty(0)
g = NumericProperty(0)
b = NumericProperty(0)
t = NumericProperty(1)
colour = ColorProperty([1, 0, 0, 1])
def on_colour_change(self, instance, value):
self.ttl.color = self.colour
def on_red(self, instance, val):
self.r = int(val) / 255
self.colour = [self.r, self.g, self.b, self.t]
self.redValue.text = str(int(val))
def on_green(self, instance, val):
self.g = int(val) / 255
self.colour = [self.r, self.g, self.b, self.t]
self.greenValue.text = str(int(val))
def on_blue(self, instance, val):
self.b = int(val) / 255
self.colour = [self.r, self.g, self.b, self.t]
self.blueValue.text = str(int(val))
def build(self):
maingrid = GridLayout(cols=1)
self.ttl = Label(
text='Slider Example',
color=self.colour, font_size=32
)
maingrid.add_widget(self.ttl)
grid = GridLayout(cols=4)
self.red = Slider(min=0, max=255)
self.green = Slider(min=0, max=255)
self.blue = Slider(min=0, max=255)
grid.add_widget(Label(text='RED'))
grid.add_widget(self.red)
grid.add_widget(Label(text='Slider Value'))
self.redValue = Label(text='0')
grid.add_widget(self.redValue)
self.red.bind(value=self.on_red)
grid.add_widget(Label(text='GREEN'))
grid.add_widget(self.green)
grid.add_widget(Label(text='Slider Value'))
self.greenValue = Label(text='0')
grid.add_widget(self.greenValue)
self.green.bind(value=self.on_green)
grid.add_widget(Label(text='BLUE'))
grid.add_widget(self.blue)
grid.add_widget(Label(text='Slider Value'))
self.blueValue = Label(text='0')
grid.add_widget(self.blueValue)
self.blue.bind(value=self.on_blue)
self.bind(colour=self.on_colour_change)
maingrid.add_widget(grid)
return maingrid
root = SliderExample()
root.run()
輸出
執行此程式碼時,將生成一個類似於此處所示的輸出視窗 -
Kivy - 圖片
能夠顯示影像是在任何 GUI 應用程式中必不可少的。Kivy 框架包含 Image 小部件作為影像容器。它能夠從 png、jpg 和 GIF 檔案載入影像資料。對於 SVG 檔案,您可能需要使用另一個名為 Svg 本身的小部件。
Kivy 包含兩個影像小部件 - Image 和 AsyncImage。它們在“kivy.uix.image”模組中定義。
Image 小部件用於載入本地計算機中可用的影像檔案。
from kivy.uix.image import Image img = Image(source = 'logo.png')
要從任何外部源載入任何影像,您需要使用 AsyncImage 小部件。AsyncImage 類是 Image 類的子類。
from kivy.uix.image import AsyncImage img = AsyncImage(source = 'http://xyz.com/logo.png')
如果您需要透過從 URL 檢索影像來顯示影像,AsyncImage 會在後臺執行緒中執行此操作,而不會阻塞您的應用程式。
Image 類定義了以下屬性 -
source − 影像的檔名/源。source 是一個 StringProperty,預設為 None。
fit_mode − 如果影像的大小與小部件的大小不同,則此屬性決定如何調整影像大小以適合小部件框內。
可用選項
scale-down − 對於大於 Image 小部件尺寸的影像,影像將縮小以適合小部件框內,保持其縱橫比且不拉伸。如果影像的大小小於小部件,則將以其原始大小顯示。
fill − 影像將拉伸以填充小部件,無論其縱橫比或尺寸如何。如果影像的縱橫比與小部件不同,則此選項可能導致影像失真。
contain − 影像調整大小以適合小部件框內,保持其縱橫比。如果影像大小大於小部件大小,則行為將類似於“scale-down”。但是,如果影像大小小於小部件大小,與“scale-down”不同,影像將調整大小以適合小部件內。
cover − 影像將水平或垂直拉伸以填充小部件框,保持其縱橫比。如果影像的縱橫比與小部件不同,則影像將被裁剪以適合。
texture − 影像的紋理物件。紋理表示原始的載入影像紋理。它根據 fit_mode 屬性在渲染期間進行拉伸和定位。
texture_size − 影像的紋理大小。這表示原始的載入影像紋理大小。
color − 影像顏色,格式為 (r, g, b, a)。此屬性可用於“著色”影像。但是,如果源影像不是灰色/白色,則顏色將無法按預期工作。
image_ratio − 一個只讀屬性,返回影像的比例(寬度 / float(高度))。
reload() − 從磁碟重新載入影像。這有助於在影像內容更改的情況下從磁碟重新載入影像。
img = Image(source = '1.jpg') img.reload()
示例
在以下示例程式碼中,我們主要嘗試演示 fit_mode 屬性的效果。下面給出了一個“kv”語言指令碼,該指令碼在輪播小部件中顯示不同的影像。每個影像都有一個不同的 fit_mode 屬性值。
“kv”語言指令碼為 -
Carousel:
direction:'top'
Image:
source:'1.png'
fit_mode:"scale-down"
Image:
source:"TPlogo.png"
fit_mode:"contain"
Image:
source:"TPlogo.png"
fit_mode:"fill"
Image:
source:"TPlogo.png"
fit_mode:"cover"
輸出
在 Kivy App 類中載入此指令碼並執行它後,將根據相應的 fit_mode 顯示不同的影像 -
fit_mode = scaled-down
源大於 Image 小部件。
fit_mode=contain
源影像小於 Image 小部件。
fit_mode: fill
影像調整大小以適合而不丟失縱橫比。
fill_mode=cover
影像拉伸以覆蓋整個小部件區域。
Kivy - 彈出視窗
Kivy 中的 Popup 小部件呈現一個對話方塊,該對話框出現在主父視窗之上,通常是響應按鈕點選事件而出現的。對話方塊用於多種目的,例如向用戶顯示特定訊息、讓使用者輸入某些內容或詢問使用者是否確認特定操作。
通常,任何 GUI 應用程式中的對話方塊有兩種型別:模態和非模態。不允許使用者在不與之互動的情況下與父視窗互動的對話方塊稱為模態對話方塊。另一方面,如果使用者可以在不與之互動的情況下關閉對話方塊,則它是非模態對話方塊。
在 Kivy 中,彈出對話方塊預設覆蓋整個父視窗。您可以根據需要配置其大小。
Popup 類在“kivy.uix.popup”模組中定義。
from kivy.uix.popup import Popup popup = Popup(**kwargs)
Popup 物件預配置了一個佈局,該佈局具有標題和分隔線。我們可以透過向其佈局引數新增其他小部件來自定義佈局。
以下程式碼段在父視窗上生成一個簡單的彈出視窗 -
from kivy.uix.popup import Popup popup = Popup(title='Popup Demo', content=Label(text='This is a Popup'), size_hint=(None, None), size=(400, 400))
您需要呼叫 Popup 物件的 open() 方法來顯示它。
popup.open()
當彈出視窗顯示時,它將被其外部的任何點選關閉。要防止彈出視窗自動關閉,請將 auto_dismiss 屬性設定為 False。您需要顯式呼叫 popup.dismiss() 方法。通常,這是透過將其繫結到按鈕的 on_press 事件來完成的。
class popdemo(App):
def build(self):
btn = Button(text="Click here")
btn.bind(on_press=self.onButtonPress)
return btn
def onButtonPress(self, button):
layout = GridLayout(cols=1)
lbl = Label(text='Hello world')
closeButton = Button(text="OK")
layout.add_widget(lbl)
layout.add_widget(closeButton)
popup = Popup(
title='Popup Demo', content=layout,
auto_dismiss=False, size_hint=(None, None),
size=(400, 400)
)
popup.open()
closeButton.bind(on_press=self.on_close)
def on_close(self, event):
self.popup.dismiss()
當單擊標題為“點選此處”的按鈕時,您將看到如下所示的彈出對話方塊 -
按彈出視窗上的“確定”按鈕將其關閉。
Popup 類定義了以下屬性 -
content − 彈出視窗的內容,顯示在標題下方。content 是一個 ObjectProperty,預設為 None。
title − 表示彈出視窗標題的字串。title 是一個 StringProperty,預設為“無標題”。
Popup 物件響應以下事件 -
on_open − 彈出視窗開啟時觸發。
on_dismiss − 彈出視窗關閉時觸發。如果回撥返回 True,則關閉操作將被取消。
示例
以下程式碼很好地舉例說明了 Kivy 中的 Popup 對話方塊。首先,我們在父視窗的垂直框佈局中新增一個標籤和一個按鈕。按鈕點選會彈出一個單列網格佈局,其中包含一個文字輸入,要求使用者輸入姓名。當彈出視窗關閉時,該文字用於更改父視窗的標籤。
以下是完整程式碼 -
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.core.window import Window
Window.size = (720, 400)
class PopupExample(App):
def build(self):
self.layout = GridLayout(cols=1, padding=10)
self.l1 = Label(
text='enter your name', font_size=32,
color=[.8, .6, .4, 1]
)
self.layout.add_widget(self.l1)
self.button = Button(text="Click Here")
self.layout.add_widget(self.button)
self.button.bind(on_press=self.onButtonPress)
return self.layout
def onButtonPress(self, button):
layout = GridLayout(cols=1, padding=10)
popupLabel = Label(text="Enter name")
self.t1 = TextInput()
closeButton = Button(text="OK")
layout.add_widget(popupLabel)
layout.add_widget(self.t1)
layout.add_widget(closeButton)
self.popup = Popup(
title='Hello', content=layout,
auto_dismiss=False, size_hint=(None, None),
size=(200, 200)
)
self.popup.open()
closeButton.bind(on_press=self.on_close)
def on_close(self, event):
self.l1.text = 'Thanks ' + self.t1.text
self.popup.dismiss()
PopupExample().run()
輸出
App 視窗如下所示 -
Kivy - 開關
Kivy 框架中的 Switch 小部件類似於我們在家中用來開啟或關閉燈泡或風扇的電開關。應用程式視窗上的開關可以透過將其 active 屬性滑動到 True 或 False 來翻轉。
Switch 類在“kivy.uix.switch: 模組中定義。
from kivy.uix.switch import Switch switch = Switch(**kwargs)
放置在應用程式視窗上時,Switch 物件如下所示 -
Switch 類定義了一個名為 active 的布林屬性,該屬性指示開關是開啟/關閉。通常,此屬性附加到回撥函式,以便在值從 True 更改為 False 或反之亦然時呼叫所需的操作。
def callback(instance, value):
if value:
print('the switch is ON')
else:
print ('The switch is OFF')
switch = Switch()
switch.bind(active=callback)
示例
我們將在以下程式碼中使用 Switch 小部件來啟動或停止音訊播放。應用程式設計包含一個標籤和一個放置在水平框佈局中的開關。
Switch 的 active 屬性繫結到 switched() 方法。開啟時,載入 Sound 物件並呼叫其 play() 方法。另一方面,當翻轉到關閉時,將呼叫 stop() 方法。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.core.audio import SoundLoader
from kivy.uix.switch import Switch
from kivy.core.window import Window
Window.size = (720, 250)
class switchdemoapp(App):
def switched(self, instance, value):
if value == True:
self.sound = SoundLoader.load('sample.mp3')
self.l1.text = 'Playing. . .'
self.sound.play()
else:
self.sound.stop()
self.l1.text = 'Switch ON to Play'
def build(self):
box = BoxLayout(orientation='horizontal')
self.l1 = Label(
text = 'Switch ON to Play',
font_size = 32, color = [.8, .6, .4, 1]
)
box.add_widget(self.l1)
switch = Switch()
switch.bind(active = self.switched)
box.add_widget(switch)
return box
switchdemoapp().run()
輸出
程式以標籤開始,要求使用者將開關滑動到開啟。標籤標題更改為“正在播放”訊息。將開關滑動到關閉以停止播放音樂。
Kivy - 旋轉器
Kivy 框架中的 Spinner 控制元件是一種更傳統的下拉控制元件型別,不同於 Kivy 的 DropDown 小部件。與 DropDown 相比,構建和使用 Spinner 小部件更加簡單方便。
Kivy 的下拉選單和小部件之間的主要區別在於,下拉選單可能包含任何其他 Kivy 小部件,例如 Label、Button、Image 等;而 Spinner 只是一個字串列表。
Spinner 類在“kivy.uix.spinner”模組中定義
from kivy.uix.spinner import Spinner spin = Spinner(**kwargs)
Spinner 小部件顯示一個與當前選定值對應的文字標題。Spinner 物件可以使用不同的屬性作為關鍵字引數構建。但是,這兩個屬性很重要 -
text 屬性是一個字串,顯示預設值。
values 屬性是一個 ListProperty,包含所有可供選擇的選項。
要構建一個簡單的 Spinner,請使用以下程式碼片段 -
from kivy.base import runTouchApp
from kivy.uix.spinner import Spinner
spinner = Spinner(
text='English',
values=('English', 'French', 'German', 'Chinese')
)
Spinner 物件的 text 屬性可以繫結到回撥,以便在每次進行選擇時呼叫適當的操作。
def value_changed(spinner, text): print(You selected', text, 'language') spinner.bind(text=show_selected_value)
Spinner 類中的其他屬性列在下面 -
dropdown_cls − 用於在按下 Spinner 時顯示下拉列表的類。它是一個 ObjectProperty,預設為 DropDown。
is_open − 預設情況下,Spinner 未開啟。設定為 True 以開啟它。
option_cls − 用於在 Spinner 下顯示的下拉列表中顯示選項的類。該類的 text 屬性將用於表示值。其 on_release 事件用於在按下/觸控時觸發選項。
text_autoupdate − 這是一個 BooleanProperty。它指示 Spinner 的文字是否應使用 values 屬性的第一個值自動更新。將其設定為 True 將導致 Spinner 在每次 values 更改時更新其 text 屬性。
values − 使用者可以選擇的值。它必須是字串列表。它是一個 ListProperty,預設為 []。
下面的程式碼組裝了一個 Spinner,並與一個標籤關聯,以在水平框中顯示選定的值。下方的水平框包含一個 TextInput 和一個 Button。目的是為該按鈕提供一個回撥,該回調將文字框中的字串新增到 Spinner 值中
程式在 App 類中包含兩個回撥方法。一個用於顯示 Spinner 中選定的值,另一個用於向 Spinner 新增新的語言。
新增新語言的回撥函式 -
def addvalue(self, instance): self.spin1.values.append(self.t1.text)
我們將此方法繫結到“新增”按鈕。
在標籤上顯示所選語言 -
def on_spinner_select(self, spinner, text): self.spinnerSelection.text = "Selected Language is: %s" %self.spin1.text
我們將此方法繫結到 Spinner 小部件的“text”屬性。
示例
將以下程式碼儲存並執行為“spiinerdemo.py”
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.spinner import Spinner
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.core.window import Window
Window.size = (720, 400)
class SpinnerExample(App):
def addvalue(self, instance):
self.spin1.values.append(self.t1.text)
def build(self):
layout = BoxLayout(orientation='vertical')
lo1 = BoxLayout(orientation='horizontal')
self.spin1 = Spinner(
text="Python",
values=("Python", "Java", "C++", "C", "C#", "PHP"),
background_color=(0.784, 0.443, 0.216, 1),
size_hint=(.5, .4), pos_hint={'top': 1}
)
lo1.add_widget(self.spin1)
self.spinnerSelection = Label(
text="Selected value in spinner is: %s" % self.spin1.text,
pos_hint={'top': 1, 'x': .4}
)
lo1.add_widget(self.spinnerSelection)
layout.add_widget(lo1)
lo2 = BoxLayout(orientation='horizontal')
lo2.add_widget(Label(text="Add Language"))
self.t1 = TextInput()
self.b1 = Button(text='add')
lo2.add_widget(self.t1)
lo2.add_widget(self.b1)
layout.add_widget(lo2)
self.spin1.bind(text=self.on_spinner_select)
self.b1.bind(on_press=self.addvalue)
return layout
def on_spinner_select(self, spinner, text):
self.spinnerSelection.text = "Selected value in spinner is: %s" % self.spin1.text
print('The spinner', spinner, 'have text', text)
if __name__ == '__main__':
SpinnerExample().run()
輸出
左上角的按鈕是 Spinner。單擊時,語言列表會下拉。您可以進行選擇。所選名稱將顯示在其右側的標籤上。
要向列表中新增新語言,請在文字框中鍵入,然後單擊“新增”按鈕。Spinner 小部件將在底部附加新語言名稱。如果列表足夠長,您可以使用滑鼠向下滾動。
Kivy - 分隔器
Kivy 中的 Splitter 小部件在其包含的任何其他小部件或佈局周圍放置一個可拖動的邊界。您可以拖動邊界以調整其包含的物件的大小。邊界可以放置在包含小部件的頂部或底部,或左側或右側。
Splitter 類在“kivy.uix.splitter”模組中定義。
from kivy.uix.splitter import Splitter split = Splitter(**kwargs)
配置邊界放置所需的重要屬性之一是“sizable_from”。它定義了指定從哪個方向調整小部件的大小。選項包括:left、right、top 或 bottom;預設為“left”。
邊界中間有一個手柄。您可以使用此手柄或雙擊它來拖動邊界。
Splitter 類的其他屬性如下 -
border - 用於 BorderImage 圖形指令的邊框。這必須是一個包含四個值的列表:(bottom, right, top, left),預設為 [4,4,4,4]
keep_within_parent - 如果為 True,它將限制 Splitter 停留在其父小部件內。
max_size - 指定小部件不可調整大小的最大尺寸。max_size 預設為 500pt。
min_size - 指定小部件不可調整大小的最小尺寸。預設為 100 pt。
rescale_with_parent - 如果為 True,則在調整其大小時會自動更改大小以佔據父小部件的相同比例,同時保持在 min_size 和 max_size 範圍內。
sizable_from - 指定小部件是否可調整大小。選項包括 - left、right、top 或 bottom;預設為 left。
示例
讓我們建立一個簡單的水平框佈局,並在兩個按鈕之間放置一個 Image 小部件。但是,Image 物件放置在從左側可調整大小的 Splitter 內部。
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.splitter import Splitter
from kivy.core.window import Window
Window.size = (720,350)
class splitterApp(App):
def build(self):
layout=BoxLayout(orientation='horizontal')
b1=Button(
text='Button1',
font_size=24, color=(1,0,0,1)
)
layout.add_widget(b1)
spl=Splitter(sizable_from = 'left')
img=Image(source='Logo.jpg')
spl.add_widget(img)
layout.add_widget(spl)
b2=Button(
text='Button 2', font_size=24,
background_color =(.8, .4, .3, 1)
)
layout.add_widget(b2)
return layout
splitterApp().run()
輸出
程式執行時,您將看到一個可拖動的邊界,其手柄位於影像的左側。拖動它以調整影像大小。
這是程式的“kv”指令碼版本,用於演示從底部可調整大小的垂直 Splitter 的用法。
BoxLayout:
orientation:'vertical'
Button:
text: 'Button 1'
font_size:24
color:(1,0,0,1)
Splitter:
sizable_from : 'bottom'
Image:
source:'Logo.jpg'
Button:
text:'Button 2'
font_size:24
background_color: (.8, .4, .3, 1)
垂直可調整大小的 Image 小部件顯示如下 -
Kivy - 進度條
當 GUI 應用程式正在執行一些耗時的過程時,應該有一些機制讓使用者知道其進度。Kivy 框架中的 Progressbar 小部件顯示正在進行的任務的進度視覺化表示。
Kivy 的進度條小部件僅支援水平模式,並在應用程式視窗上以增量進度顯示。
Progressbar 類在“kivy.uix.progressbar”模組中定義。
from kivy.uix.progressbar import ProgressBar pb = Progressbar(**kwargs)
Progressbar 小部件是僅顯示的小部件,沒有任何互動元素,因為它不會引發或傳播任何事件。
要建立 Progressbar 的例項,您需要設定其 max 屬性。
from kivy.uix.progressbar import ProgressBar pb = ProgressBar(max=1000)
該小部件具有 value 屬性。您可以將其分配給小於其“max”屬性的任何數字。
pb.value=100
但是,由於 progressbar 類沒有任何事件和事件處理程式,因此我們需要手動將 value 屬性連結到某個程序。
這可以透過定期讀取漸進任務屬性的瞬時值並更新進度條的 value 屬性來完成。
假設我們有一個長的 for 迴圈,它在每隔一秒鐘後進行下一次迭代。
for i in range(1000): time.delay(1) print (i)
我們希望在進度條上顯示 I 的增量。因此,我們安排了一個時鐘事件,該事件在每隔一秒鐘後呼叫一個函式。
progev = Clock.schedule_interval(update_progress, 1.0)
每秒鐘後,update_progesss() 函式將進度條的 value 屬性更新為迭代計數器 i
def update_progress(): pb.value = i
示例
讓我們在以下程式碼中實現此方法。GUI 設計包含兩個按鈕和一個標籤。按下開始按鈕時,它會將 mp3 檔案載入到 Sound 物件中。聲音檔案的長度用作進度條的 max 屬性
self.sound = SoundLoader.load('sample.mp3')
self.length = self.sound.length
當呼叫 play() 方法時,我們按上述方式安排進度事件。
self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
update_progress() 方法讀取 Sound 物件的 pos 屬性並使用它來更新進度條的 value 屬性
def update_progress(self, dt):
if self.sound.state=='play':
if self.prg.value < self.length:
self.progress += 1 # Update value.
self.prg.value=self.progress
以下是完整程式碼 -
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.core.audio import SoundLoader
from kivy.uix.progressbar import ProgressBar
from kivy.properties import NumericProperty
from kivy.core.window import Window
Window.size = (720, 400)
class audiodemoapp(App):
length = NumericProperty(0.0)
progress = NumericProperty(0.0)
def build(self):
layout = GridLayout(cols=1, padding=10)
self.prg = ProgressBar()
layout.add_widget(self.prg)
self.l1 = Label(
text='Press Start to Play', font_size=40,
color=[.8, .6, .4, 1]
)
layout.add_widget(self.l1)
box = BoxLayout(orientation='horizontal')
self.button1 = Button(text="Start", font_size=32)
self.button2 = Button(
text='Pause', font_size=32,
disabled=True
)
box.add_widget(self.button1)
box.add_widget(self.button2)
layout.add_widget(box)
self.button1.bind(on_press=self.start_stop)
self.button2.bind(on_press=self.pause_resume)
return layout
def start_stop(self, event):
if self.button1.text == 'Start':
self.l1.text = 'Playing'
self.button1.text = 'Stop'
self.sound = SoundLoader.load('sample.mp3')
self.length = self.sound.length
self.pos = 0
self.button2.disabled = False
self.sound.play()
self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
else:
if self.button1.text == 'Stop':
self.l1.text = 'Press Start to Play'
self.sound.state = 'stop'
self.button1.text = 'Start'
self.sound.unload()
self.button2.disabled = True
self.pos = 0
def pause_resume(self, event):
if self.button2.text == 'Pause':
self.button2.text = 'Resume'
self.l1.text == 'Paused'
self.pos = self.sound.get_pos()
self.sound.stop()
else:
if self.button2.text == 'Resume':
self.l1.text = 'Playing'
self.button2.text = 'Pause'
print(self.pos)
self.sound.seek(self.pos)
self.sound.play()
self.prog_ev = Clock.schedule_interval(self.update_progress, 1.0)
def update_progress(self, dt):
if self.sound.state == 'play':
if self.prg.value < self.length:
self.progress += 1 # Update value
self.prg.value = self.progress
else: # End case.
self.progress = 0 # Reset value
self.prog_ev.cancel() # Stop updating
audiodemoapp().run()
輸出
執行以上程式碼。按下開始按鈕。頂部的進度條顯示音樂檔案的瞬時播放位置。
Kivy - 氣泡
Kivy 框架包含一個 Bubble 小部件,它充當一個小彈出選單,在其內容的任何一側都有一個箭頭。箭頭的方向可以根據需要配置。您可以透過設定其“arrow_pos”屬性的相對位置來放置它。
氣泡的內容放置在“BubbleContent”物件中,它是 BoxLayout 的子類。可以水平或垂直放置一個或多個 BubbleButtons。雖然建議使用 BubbleButtons,但您可以在氣泡的內容中新增任何小部件。
Bubble、BubbleContent 和 BubbleButton 類在 kivy.uix.bubble 模組中定義。
from from kivy.uix.bubble import Bubble
Bubble 類的以下屬性有助於自定義 Bubble 選單的外觀和行為 -
arrow_color - 箭頭顏色,格式為 (r, g, b, a)。要使用它,您必須首先設定 arrow_image,預設為 [1, 1, 1, 1]。
arrow_image - 指向氣泡的箭頭的影像。
arrow_margin - 自動計算的邊距,箭頭小部件以畫素為單位佔據 x 和 y 方向。
arrow_pos - 指定箭頭的相對位置,其中之一為預定義值:left_top、left_mid、left_bottom top_left、top_mid、top_right right_top、right_mid、right_bottom bottom_left、bottom_mid、bottom_right。預設值為“bottom_mid”。
content - 這是儲存氣泡主要內容的物件。
show_arrow - 指示是否顯示箭頭。預設為 True。
BubbleButton - 旨在用於 BubbleContent 小部件的按鈕。您可以使用“普通”按鈕代替它,但除非更改背景,否則它可能看起來不錯。
BubbleContent - 可用作 Bubble 內容小部件的樣式化的 BoxLayout。
以下示意圖“kv”語言指令碼用於構建一個簡單的 Bubble 物件 -
Bubble:
BubbleContent:
BubbleButton:
text: 'Button 1'
BubbleButton:
text: 'Button 2'
就像普通按鈕一樣,我們可以將 BubbleButton 繫結到其“on_press”事件的回撥函式。
示例
執行以下程式碼時,它會顯示一個普通按鈕。單擊時,會彈出一個包含三個 BubbleButtons 的 Bubble 選單。這些 BubbleButtons 中的每一個都會呼叫一個 pressed() 回撥方法,該方法讀取按鈕的標題並在控制檯上列印它。
我們使用以下“kv”語言指令碼來組裝 Bubble 選單。已定義一個名為“Choices”的類,它繼承自“kivy.uix.bubble.Bubble”類。
class Choices(Bubble):
def pressed(self, obj):
print ("I like ", obj.text)
self.clear_widgets()
該類具有 pressed() 例項方法,由每個 BubbleButton 呼叫。
以下是“kv”指令碼 -
<Choices>
size_hint: (None, None)
size: (300, 150)
pos_hint: {'center_x': .5, 'y': .6}
canvas:
Color:
rgb: (1,0,0)
Rectangle:
pos:self.pos
size:self.size
BubbleContent:
BubbleButton:
text: 'Cricket'
size_hint_y: 1
on_press:root.pressed(self)
BubbleButton:
text: 'Tennis'
size_hint_y: 1
on_press:root.pressed(self)
BubbleButton:
text: 'Hockey'
size_hint_y: 1
on_press:root.pressed(self)
BoxLayout 小部件充當主應用程式視窗的根小部件,幷包含一個按鈕和一個標籤。“on_press”事件呼叫“show_bubble()”方法,該方法會彈出氣泡。
class BubbleTest(FloatLayout):
def __init__(self, **temp):
super(BubbleTestApp, self).__init__(**temp)
self.bubble_button = Button(
text ='Your favourite Sport',
pos_hint={'center_x':.5, 'center_y':.5},
size_hint=(.3, .1),size=(300, 100)
)
self.bubble_button.bind(on_release = self.show_bubble)
self.add_widget(self.bubble_button)
def show_bubble(self, *arg):
self.obj_bub = Choices()
self.add_widget(self.obj_bub)
驅動程式 App 類程式碼如下 -
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.bubble import Bubble
from kivy.properties import ObjectProperty
from kivy.core.window import Window
Window.size = (720,400)
class MybubbleApp(App):
def build(self):
return BubbleTest()
MybubbleApp().run()
輸出
該應用程式在主視窗的中心顯示一個按鈕。單擊時,您應該在它上面看到 Bubble 選單。
每次單擊氣泡中的任何選項時,控制檯都會顯示結果並隱藏氣泡。
I like Tennis I like Hockey
Kivy - 標籤頁面板
許多 GUI 工具包都包含選項卡面板,因為它非常方便地將介面控制元件分組顯示,而不是一個大型表單,遠遠超出了顯示裝置的尺寸。Kivy 中的 TabbedPanel 小部件使能夠在不同的面板中顯示小部件或佈局,而不會使 GUI 設計看起來笨拙。不同面板中的控制元件可以在它們之間共享資料。
不同的選項卡顯示為頂部的選單,其中包含實際選項卡按鈕的標題區域和顯示當前選項卡內容的內容區域。
TabbedPanel 物件是用於一個或多個面板的頂級容器。對應於每個面板,都會新增一個 TabbedPanelItem 物件。每個 TabbedPAnelItem 又可以容納任何一個小部件或包含多個小部件(例如 GridLayout 或 BoxLayout 等)的佈局
這兩個類都在 kivy.uix.tabbedpanel 模組中定義。
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelItem
構建選項卡面板的示意圖語句流可能如下 -
main=TabbedPanel() tab1=TabbedPanelItem(text='Tab 1') Label=Label(text='Label') tab1.add_widget(label) tab2=TabbedPanelItem(text='Tab 2') btn=Button(text="Button") tab2.add_widget(btn) main.add_widget(tab1) main.add_widget(tab2)
可以透過調整一些屬性來進一步自定義選項卡面板 -
您可以選擇顯示選項卡的位置,方法是將tab_pos屬性設定為以下值之一:left_top、left_mid、left_bottom、top_left、top_mid、top_right、right_top、right_mid、right_bottom、bottom_left、bottom_mid、bottom_right。
每個選項卡都有一個特殊的按鈕TabbedPAnelHeader,其中包含一個 content 屬性。
選項卡面板帶有一個預設選項卡,您可以透過將do_default_tab設定為 False 來將其刪除。
如果顯示預設選項卡,則會提供on_default_tab事件以關聯回撥函式 -
tp.bind(default_tab = my_default_tab_callback)
可以透過多種方式刪除選項卡和內容 -
tp.remove_widget()刪除選項卡及其內容。
tp.clear_widgets()清除內容區域中的所有小部件。
tp.clear_tabs()刪除 TabbedPanelHeaders
示例
在下面的示例中,我們使用兩個選項卡面板,第一個用於顯示簡單的登錄檔單,第二個用於顯示登入表單。
我們將使用“kv”語言指令碼構建設計。
預設選項卡已刪除。
第一個選項卡包含一個 2 列網格佈局,幷包含標籤和文字輸入框,供使用者輸入其詳細資訊,然後是“提交”按鈕。
第二個選項卡也包含一個兩列網格,允許已註冊使用者輸入電子郵件和密碼。
TabbedPanel:
size_hint: .8, .8
pos_hint: {'center_x': .5, 'center_y': .5}
do_default_tab: False
TabbedPanelItem:
text:"Register Tab"
GridLayout:
cols:2
Label:
text:"Name"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.75}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.65}
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
TabbedPanelItem:
text:'Login Tab'
GridLayout:
cols:2
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
利用以上“kv”指令碼設計的 App 程式碼如下 -
from kivy.app import App
from kivy.core.window import Window
Window.size = (720,300)
class TabDemoApp(App):
def build(self):
pass
TabDemoApp().run()
輸出
執行以上程式碼時,應用程式視窗會顯示選項卡面板,並顯示第一個選項卡的內容。單擊“登入”選項卡以檢視第二個選項卡的內容。
Kivy - 散點圖
Kivy 中的 Scatter 小部件對於多點觸控裝置特別有用,在其中它用於旋轉和縮放應用程式視窗的內容。
Scatter 小部件透過在繪製子級之前更改模型檢視矩陣來執行矩陣變換,並在繪製完成後恢復先前的矩陣,以便可以在整個子級樹上執行旋轉、縮放和平移,而無需更改任何小部件屬性。
預設情況下,Scatter 控制元件沒有圖形表示:它只是一個容器。其他控制元件會新增到 Scatter 物件中。但是,需要注意的是,Scatter 控制元件不是佈局。您必須自己管理子控制元件的大小。它們相對於 Scatter 定位,類似於 RelativeLayout。這就是為什麼拖動 Scatter 不會改變子控制元件的位置,只有 Scatter 的位置會改變。Scatter 的大小不會影響其子控制元件的大小。
Scatter 類定義在 "kivy.uix.scatter" 模組中。Scatter 控制元件的基本用法如下:
from kivy.uix.scatter import Scatter scatter=Scatter.add_widget(Image(source='logo.jpg'))
Scatter 物件建立時,預設情況下所有互動都啟用。但是,您可能希望自定義互動,為此需要相應地定義 Scatter 物件的屬性。
auto_bring_to_front − 如果為 True,則該控制元件將在繪製時自動推到父控制元件列表的頂部。
do_rotation − 允許旋轉。預設情況下,此屬性為 True。
do_scale − 允許縮放。預設為 True。
do_translation − 允許在 X 或 Y 軸上平移。
scale − Scatter 的縮放值。scale 是一個 AliasProperty,預設為 1.0。
scale_max − 允許的最大縮放因子。允許的最大縮放因子的預設值為 1e20。
scale_min − 允許的最小縮放因子,預設值為 0.01。
示例 1
這是一個關於 Scatter 控制元件如何工作的簡單示例。我們只是在 Kivy 應用中的 Scatter 控制元件中添加了一個標籤。應用程式啟動時,標籤文字顯示在應用程式視窗的左下角。使用滑鼠將其拖動到視窗表面上的任意位置。
為了在普通桌面電腦上模擬多點觸控操作,請透過滑鼠右鍵在標籤區域建立兩個標記,然後您可以透過拖動這兩個標記來放大或旋轉標籤。
如果您使用的是多點觸控裝置,則可以透過雙指觸控執行縮放和旋轉。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.core.window import Window
Window.size = (720,350)
class scatterdemoapp(App):
def build(self):
box=BoxLayout(orientation='vertical')
scatr=Scatter()
lbl=Label(text="Hello", font_size=60)
scatr.add_widget(lbl)
box.add_widget(scatr)
return box
scatterdemoapp().run()
輸出
讓我們檢查一下輸出是什麼樣子的:
示例 2
或者,也可以使用 "kv" 語言指令碼構建相同的介面。
BoxLayout:
orientation:'vertical'
Scatter:
Label:
text:"Hello"
font_size:60
讓我們為上面的示例新增更多互動性。在這裡,我們在 Scatter 控制元件上方,垂直佈局中添加了一個文字輸入框。
"text" 屬性繫結到標籤的 text 屬性。因此,當您在文字框中新增/刪除字母時,標籤文字會更新。仍然可以執行所有 Scatter 操作,如旋轉和縮放。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.core.window import Window
Window.size = (720,300)
class scatterdemoapp(App):
def build(self):
box = BoxLayout(orientation='vertical')
text1 = TextInput(
text='Hello World', height=100,
size_hint=(Window.width, None)
)
box.add_widget(text1)
scatr = Scatter()
self.lbl = Label(text="Hello", font_size=60)
text1.bind(text=self.lbl.setter('text'))
scatr.add_widget(self.lbl)
box.add_widget(scatr)
return box
scatterdemoapp().run()
輸出
現在讓我們檢查一下輸出視窗是什麼樣子的:
Kivy - 手風琴
這個 GUI 控制元件,因為它與同名的樂器相似,所以被稱為 "手風琴"。在 Kivy 中,手風琴是一個圖形控制元件元素,包含一個垂直或水平堆疊的專案列表,例如標籤、按鈕或影像。
就像在手風琴中,可以透過向外拉伸來擴充套件風箱的部分一樣,每個專案都可以“展開”或“摺疊”以顯示與該專案關聯的內容。可以有零個展開的專案、恰好一個專案或多個專案同時展開,具體取決於配置。
手風琴在用途上類似於選項卡面板,一個專案列表,其中恰好有一個專案展開成一個面板。
"kivy.uix.accordion" 模組中有兩個重要的類 - "Accordion" 和 "AccordionItem"。每個 AccordianItem 物件都包含任何一個 Kivy 控制元件,例如標籤、按鈕、影像,甚至其他佈局物件。然後將多個 AccordioItems 新增到主 Accordion 物件中。
Accordion 類支援以下屬性/方法:
title − AccordionItem 的標題字串。
min_space − 為每個專案的標題使用的最小空間。每次發生佈局事件時,此值都會自動為每個子項設定。它是一個 NumericProperty,預設為 44(畫素)。
orientation − 手風琴佈局的方向。可以是垂直或水平。
collapse − 布林屬性,指示當前專案是否已摺疊。
示例 1
在以下程式碼中,Accordion 物件用作應用程式視窗的根控制元件。標籤、按鈕和影像控制元件分別新增到其每個 AccordionItem 控制元件中。
完整的程式碼如下:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.core.window import Window
Window.size = (720,400)
class accordiandemoapp(App):
def build(self):
acc=Accordion(orientation='horizontal')
item1=AccordionItem(title='Text Panel')
item1.add_widget(Label(text='Hello World'))
item2=AccordionItem(title='Button Panel')
self.btn=Button(text='ok')
item2.add_widget(self.btn)
item3=AccordionItem(title='Image Panel')
img = Image()
img.source='kivy-logo.png'
item3.add_widget(img)
acc.add_widget(item1)
acc.add_widget(item2)
acc.add_widget(item3)
return acc
accordiandemoapp().run()
輸出
執行以上程式並點選“圖片面板”,以顯示其內容,即 Kivy 的 logo。
您可以透過點選其他面板來進一步展開它們。
示例 2(使用“kv”指令碼)
我們刪除 build() 方法中的所有語句,將其替換為 pass 語句,然後將以下指令碼儲存為 accordiondemo.kv 檔案。這次,Accordion 的預設方向更改為垂直方向。
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Accordion:
orientation: 'vertical'
AccordionItem:
title: "Button Panel"
Button:
text: 'OK'
AccordionItem:
title: "Text Panel"
Label:
text: "Hello World"
font_size: 32
AccordionItem:
title: "Image Panel"
Image:
source: 'kivy-logo.png'
輸出
程式執行後,按鈕面板展開:
Kivy - 檔案選擇器
在 GUI 應用程式中,您通常需要從本地檔案系統中選擇所需的檔案。Kivy 框架提供了 "kivy.uix.filechooser" 模組,該模組提供了用於描述、顯示和瀏覽檔案系統的各種類。
filechooser 模組中的類採用 MVC 設計。它們可以分類如下:
模型 由 FileSystemAbstract 類的具體實現表示,例如 FileSystemLocal。
檢視 由 FileChooserListLayout 和 FileChooserIconLayout 類表示。這些分別由 FileChooserListView 和 FileChooserIconView 控制元件使用。
控制器 由 FileChooserController 的具體實現表示,即 FileChooser、FileChooserIconView 和 FileChooserListView 類。
FileChooserIconView 和 FileChooserListView 類提供了非常易於使用的控制元件,它們提供了兩種不同的視覺表示形式來訪問檔案系統,顧名思義。
FileChooserListView 控制元件以垂直列表中文字項的形式顯示檔案和資料夾。資料夾在其名稱左側用“>”符號標識,單擊可展開或摺疊其檔案和子資料夾。
FileChooserIconView 控制元件顯示一個資料夾圖示,其名稱位於下方,以及一個檔案圖示及其名稱。
如果檔案/資料夾數量超過控制元件的高度和寬度,則垂直和水平捲軸將附加到它。
FileChooser 檢視具有以下屬性:
files − 應用過濾器後,路徑指定的目錄中的檔案列表。files 是一個只讀 ListProperty。
filter_dirs − 指示過濾器是否也應應用於目錄。filter_dirs 是一個 BooleanProperty,預設為 False。
filters − filters 指定要應用於目錄中檔案的過濾器。filters 是一個 ListProperty,預設為 []。如果為空,則等效於 "*",表示沒有檔案從列表中過濾掉。當路徑更改時,過濾器不會重置。如果需要,您需要自己執行此操作。
您可以在列表中指定以下一種或多種模式:
| 序號 | 模式列表和描述 |
|---|---|
| 1 | * 匹配所有內容 |
| 2 | ? 匹配任何單個字元 |
| 3 | [seq] 匹配 seq 中的任何字元 |
| 4 | [!seq] 匹配 seq 中不存在的任何字元 |
這兩個檢視都會引發 on_selection 事件,可以將回調繫結到該事件。當生成此事件時,如果選擇了資料夾,它將展開或摺疊它。如果選擇了檔案,則其名稱將傳遞給回撥。
ListView 示例
在第一個示例中,我們使用 FileChhoserListView 控制元件和標籤在垂直框佈局中構建應用程式視窗。
為此,請使用以下“kv”檔案指令碼。select() 方法繫結到檢視的“on_selection”事件。
<Filechooser>:
label: label
orientation: 'vertical'
BoxLayout:
FileChooserListView:
canvas.before:
Color:
rgb: .4, .5, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(*args)
Label:
id: label
size_hint_y: .1
canvas.before:
Color:
rgb: .5, .5, .4
Rectangle:
pos: self.pos
size: self.size
請注意 FileChooseListView 和 Label 控制元件的 canvas 物件的使用,以提供背景顏色。
Kivy 應用程式類程式碼如下:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720,400)
class Filechooser(BoxLayout):
def select(self, *args):
try: self.label.text = args[1][0]
except: pass
class FileDemoApp(App):
def build(self):
return Filechooser()
if __name__ == '__main__':
FileDemoApp().run()
輸出
執行以上程式碼後,您將獲得檔案/資料夾列表。標籤上將顯示檔案的名稱及其完整路徑。
IconView 示例
我們現在演示 FileChooserIconView 的用法。它放置在一個水平框中,旁邊有一個影像控制元件。雖然 FileChooserIconView 的大多數配置與上一個示例相同,但我們添加了 filters 屬性以將檔案的顯示限制為僅 png 檔案。
<Filechooser>:
img: img
orientation: 'horizontal'
BoxLayout:
FileChooserIconView:
filters: ['*.png']
canvas.before:
Color:
rgb: .5, .4, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(*args)
Image:
id: img
source:""
由於我們打算顯示選定的影像,因此更改 select() 方法,以便將 Image 物件的 source 屬性分配給選定的檔案。
class Filechooser(BoxLayout):
def select(self, *args):
try:
self.img.source = args[1][0]
except:
print ('error')
class FileIconApp(App):
def build(self):
return Filechooser()
# run the App
if __name__ == '__main__':
FileIconApp().run()
輸出
執行程式並瀏覽到所需的影像檔案。選定的影像將顯示在右側。
Kivy - 顏色選擇器
Kivy 的 ColorPicker 控制元件是一個內建的對話方塊,它允許您以多種方式選擇顏色。它提供了一個色輪,從中可以選擇所需的顏色。它還具有滑塊控制元件,可以調整以獲得所需的顏色值。滑塊也可用於 HSV 方案中的透明度和顏色值。
每個顏色屬性都有一個文字框,您可以在其中直接輸入 0 到 255 之間的數字顏色值。
ColorPicker 控制元件如下所示:
ColorPicker 類定義在 "kivy.uix.colorpicker" 模組中。
from kivy.uix.colorpicker import ColorPicker colour = ColorPicker(**kwargs)
要呈現上述顏色對話方塊,只需將 ColorPicker 物件新增到父視窗即可。如果其 color 屬性繫結到事件處理程式,則顏色值可用於進一步處理,例如使用所選顏色更改某個物件的顏色。
除了顏色之外,ColorPicker 物件還具有 hsv 和 hex_color 屬性。在以下程式碼片段中,當選擇顏色時,顏色、hsv 和 hex_color 值將列印到控制檯。
對於從色輪中選擇的顏色,RGB、HSV、A 和十六進位制值將顯示在文字框中,並由滑塊位置指示。
回撥方法將值列印到控制檯:
RGBA = [1, 0.5, 0.5, 1] HSV = (0.0, 0.5, 1) HEX = #ff7f7fff
ColorPicker 屬性
r − 當前選擇的顏色的紅色值。它是一個 BoundedNumericProperty,可以是 0 到 1 之間的值。預設為 0。
g − 當前選擇的顏色的綠色值。"g" 是一個 BoundedNumericProperty,可以是 0 到 1 之間的值。
b − 當前選擇的顏色的藍色值。"b" 是一個 BoundedNumericProperty,可以是 0 到 1 之間的值。
a − 當前選擇的顏色的 Alpha 值。"a" 是一個 BoundedNumericProperty,可以是 0 到 1 之間的值。
hsv − hsv 以 hsv 格式儲存當前選擇的顏色。hsv 是一個 ListProperty,預設為 (1, 1, 1)。
hex_color − hex_color 以十六進位制格式儲存當前選擇的顏色。hex_color 是一個 AliasProperty,預設為 #ffffffff。
color − color 以 rgba 格式儲存當前選擇的顏色。color 是一個 ListProperty,預設為 (1, 1, 1, 1)。
font_name − 指定 ColorPicker 上使用的字型。font_name 是一個 StringProperty。
wheel − wheel 儲存色輪。wheel 是一個 ObjectProperty,預設為 None。
示例
讓我們使用 ColorPicker 控制元件選擇任何所需的顏色,無論是從色輪還是從滑塊,或者透過直接輸入顏色值;並將其應用於父視窗上的標籤。
Kivy 應用程式視窗包含一個標籤和一個按鈕,放置在網格佈局中。在按鈕的 on_press 事件上,將顯示一個彈出視窗。
彈出視窗使用 ColorPicker 和一個按鈕,並以另一個網格佈局進行設計。彈出視窗按鈕在關閉彈出視窗之前,將所選顏色應用於應用程式視窗上的標籤。
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.colorpicker import ColorPicker
from kivy.core.window import Window
Window.size = (720, 350)
class ColorPickApp(App):
def build(self):
self.layout = GridLayout(cols=1, padding=10)
self.l1 = Label(
text='www.tutorialspoint.com',
font_size=32, color=[.8, .6, .4, 1]
)
self.layout.add_widget(self.l1)
self.button = Button(text="Click Here")
self.layout.add_widget(self.button)
self.button.bind(on_press=self.onButtonPress)
return self.layout
def onButtonPress(self, button):
layout = GridLayout(cols=1, padding=10)
self.clr = ColorPicker()
closeButton = Button(text="OK", size_hint=(.1, .05))
layout.add_widget(self.clr)
layout.add_widget(closeButton)
self.popup = Popup(
title='Hello', content=layout, auto_dismiss=False
)
self.popup.open()
closeButton.bind(on_press=self.on_close)
def on_close(self, event):
self.l1.color = self.clr.hex_color
self.popup.dismiss()
ColorPickApp().run()
輸出
此 Kivy 應用程式的初始顯示將顯示一個標籤和一個按鈕。當您點選按鈕時,ColorPicker 小部件將彈出。
選擇所需的顏色並按確定。您將看到標籤文字相應地更改其顏色。
Kivy - 程式碼輸入
Kivy 框架中的 CodeInput 小部件是一個專門的 TextInput 框,能夠顯示可編輯的文字,並根據所選語言詞法分析器的語法進行突出顯示。
CodeInput 小部件需要安裝 **pygments** 包。
pygments 包是一個 Python 語法高亮器。
它用於需要美化原始碼的應用程式。
Pygments 支援幾乎所有語言,包括程式語言、指令碼語言,甚至能夠根據框架和庫語法提供語法高亮。
支援以 Lexer 類的形式提供。例如,要選擇 Python 語法以突出顯示語言元素,我們需要匯入 Python3Lexer,對於 C++ 程式碼,需要匯入 CppLexer 類。具體來說,Kivy 程式碼使用 KivyLexer 進行高亮顯示。
如果您的當前工作環境未安裝 pygments,請執行以下命令:
pip3 install pygments
CodeInput 類定義在 "kivy.uix.codeinput" 模組中。
from kivy.uix.codeinput import CodeInput codewidget = CodeInput(**kwargs)
CodeInput 類繼承 TextInput 類,以及 CodeNavigationBehaviou 混合類。就像 TextInput 物件一樣,CodeInput 小部件是一個多行文字框,可以新增到其他佈局類中。可以透過指定以下屬性來例項化它:
**lexer** - 儲存 pygments 用於突出顯示程式碼的所選 Lexer。它是一個 ObjectProperty,預設為 PythonLexer。
**style** - 用於格式化的 pygments 樣式物件。當設定 style_name 時,它將更改為相應的樣式物件。
**style_name** - 用於格式化的 pygments 樣式的名稱。style_name 是一個 OptionProperty,預設為 'default'。pygments 中提供了許多樣式。一些示例包括 emacs、xcode、vs、bw、colorful 等等。
除了這些之外,屬性也繼承自 TextInput 類。CodeNavigationBehavior 混合類修改了 TextInput 中的導航行為,使其像 IDE 而不是文字處理器一樣工作。
示例
在以下程式碼中,CodeInput 小部件使用 PythonLexer 對 Python 原始碼執行語法高亮。使用 Python 的檔案物件讀取 "code.py" 檔案,並將資料分配給 CodeInput 物件的 text 屬性。
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.codeinput import CodeInput
from pygments.lexers.python import Python3Lexer
from kivy.uix.scrollview import ScrollView
from kivy.uix.codeinput import CodeInput
from kivy.core.window import Window
Window.size = (720,400)
class codeinputdemoapp(App):
def build(self):
scr = ScrollView(size=Window.size)
codinp = CodeInput(style='emacs')
codinp.height = max(codinp.minimum_height, scr.height)
file=open('code.py')
text=file.read()
codinp.text=text
scr.add_widget(codinp)
return scrx
codeinputdemoapp().run()
要突出顯示使用 Kivy 相關關鍵字和函式的程式碼,請載入 KivyLexer。您還可以嘗試使用 "pigment" 樣式,將其更改為 "colorful" 或任何其他可用的樣式。
from kivy.extras.highlight import KivyLexer
讀取 "kivycode.py" 檔案並將其載入到 CodeInput 框中。
file=open('kivycode.py')
text=file.read()
codinp.text=text
您也可以嘗試使用 CppLexer 顯示 C++ 程式碼:
from pygments.lexers.c_cpp import CppLexer
這次,將樣式更改為 "friendly"。
file=open('test.cpp')
text=file.read()
codinp.text=text
Kivy - 模態檢視
Kivy 框架中的 ModalView 小部件用於在父視窗頂部彈出對話方塊。ModalView 小部件的行為類似於 Kivy 的 Popup 小部件。實際上,Popup 類本身是 ModalView 類的子類,具有一些額外的功能,例如具有標題和分隔符。
預設情況下,Modalview 的大小等於“主”視窗的大小。小部件的 size_hint 預設值為 (1, 1)。如果您不希望檢視全屏顯示,請使用小於 1 的 size_hint 值(例如 size_hint=(.8, .8)),或者將 size_hint 設定為 None 並使用固定大小屬性。
ModalView 類定義在 kivy.uix.modalview import ModalView 模組中。以下語句將生成一個 ModalView 對話方塊:
from kivy.uix.modalview import ModalView view = ModalView(size_hint=(None, None), size=(300, 200)) view.add_widget(Label(text='ModalView Dialog'))
與 Popup 一樣,當您單擊 ModalView 對話方塊外部時,它將被關閉。要阻止此行為,請將 auto-dismiss 設定為 False。
要使 ModalView 對話框出現,您需要呼叫其 open() 方法。
view.open()
如果 auto_dismiss 為 False,則需要呼叫其 dismiss() 方法將其關閉。
view.dismiss()
通常,open() 和 dismiss() 方法都將在某個事件(例如按鈕的 on_press 事件)上呼叫。通常在單擊父視窗上的按鈕時開啟 ModalView,並在單擊 ModalView 佈局中的按鈕時關閉它。
ModalView 事件
ModalView 在檢視開啟和關閉之前以及檢視開啟和關閉時發出事件。
**on_pre_open** - 在 ModalView 開啟之前觸發。當此事件觸發時,ModalView 尚未新增到視窗中。
**on_open** - ModalView 開啟時觸發。
**on_pre_dismiss** - 在 ModalView 關閉之前觸發。
**on_dismiss** - ModalView 關閉時觸發。如果回撥返回 True,則關閉操作將被取消。
示例
以下程式碼提供了一個易於實現的 ModalView 對話方塊示例。主應用程式視窗顯示一個標題為“單擊此處”的按鈕。單擊時,將彈出一個模態對話方塊。
ModalView 透過將標籤和按鈕放在網格佈局中來構建。在彈出視窗中,我們有一個標題為“確定”的按鈕。它的 on_press 事件繫結到 ModalView 物件的 dismiss() 方法,導致它消失。
下面給出了該示例的完整程式碼:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.modalview import ModalView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720, 300)
class ModalViewDemoApp(App):
def showmodal(self, obj):
view = ModalView(
auto_dismiss=False, size_hint=(None, None),
size=(400, 100)
)
grid = GridLayout(cols=1, padding=10)
grid.add_widget(Label(
text='ModalView Popup', font_size=32,
color=[1, 0, 0, 1]
))
btn = Button(
text='ok', font_size=32,
on_press=view.dismiss
)
grid.add_widget(btn)
view.add_widget(grid)
view.open()
def build(self):
btn = Button(
text='click here', font_size=32,
on_press=self.showmodal,
pos_hint={'center_x': .5, 'center_y': .1},
size_hint=(.3, None), size=(200, 100)
)
return btn
ModalViewDemoApp().run()
輸出
當單擊主應用程式視窗上的按鈕時,ModalView 對話方塊將彈出。
Kivy - 切換按鈕
Kivy 框架中的 ToggleButton 小部件的行為有點像 Checkbox 小部件。它還具有一個名為 state 的二進位制屬性,該屬性有兩個可能的值:**normal** 或 **down**。
ToggleButton 是一個按鈕,不同之處在於,當按下按鈕時,按下和釋放事件幾乎同時發生;而當按下切換按鈕時,down 狀態將持續存在,直到再次按下將其恢復到 normal 狀態。
ToggleButton 的兩種狀態分別具有不同的背景顏色,可以透過為 "background_normal" 和 "background_down" 屬性賦值來自定義。
ToggleButton 類繼承 Button 類和 ToggleButtonBehavior 混合類。它定義在 kivy.uix.togglebutton 模組中。
from kivy.uix.togglebutton import ToggleButton toggle = ToggleButton(**kwargs)
就像 Checkbox 一樣,可以將多個 ToggleButton 物件組合在一起。預設情況下,每個切換按鈕可用於表示兩種狀態(例如 Switch 小部件中的 ON/OFF)。但是,如果多個切換按鈕的 group 屬性具有相同的值,則該組中只有一個具有 down 狀態。當其中一個分組按鈕處於 down 狀態時,其餘按鈕將自動設定為 normal。
btn1 = ToggleButton(text='Male', group='sex',) btn2 = ToggleButton(text='Female', group='sex', state='down')
在這種情況下,這兩個按鈕屬於同一個組,因此一次只能有一個處於 down 狀態。
由於它繼承了 Button 類,因此我們可以處理切換按鈕上的 on_press 事件。此外,"on_state" 事件可以繫結到其 state 屬性。
示例 1
以下程式碼放置了三個未分組的 ToggleButton。因此,每個按鈕都可以設定為 normal 或 down 狀態。在下面的示例中,這些切換按鈕表示使用者要選擇的興趣主題。
self.button1 = ToggleButton(text ="Sports", font_size=32) self.button2 = ToggleButton(text='Music', font_size=32) self.button3 = ToggleButton(text='Travel', font_size=32)
它們繫結到回撥函式以識別每個按鈕的狀態。
self.button1.bind(on_press=self.btn1pressed) self.button2.bind(on_press=self.btn2pressed) self.button3.bind(on_press=self.btn3pressed)
每個回撥方法都檢查狀態是否為 down,並相應地更新標籤文字。
def btn1pressed(self, instance):
if instance.state=='down':
self.sports='Sports'
else:
self.sports=''
self.l1.text="{} {} {}".format(self.sports, self.music, self.travel)
此練習的完整程式碼如下所示:
from kivy.app import App
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720, 350)
class toggledemoapp(App):
def build(self):
self.sports = self.music = self.travel = ''
layout = GridLayout(cols=1, padding=10)
box = BoxLayout(orientation='horizontal')
lbl = Label(text="My Interests", font_size=40)
layout.add_widget(lbl)
self.l1 = Label(
text='Choose One or More', font_size=32,
color=[.8, .6, .4, 1]
)
layout.add_widget(self.l1)
self.button1 = ToggleButton(text="Sports", font_size=32)
self.button2 = ToggleButton(text='Music', font_size=32)
self.button3 = ToggleButton(text='Travel', font_size=32)
self.button1.bind(on_press=self.btn1pressed)
self.button2.bind(on_press=self.btn2pressed)
self.button3.bind(on_press=self.btn3pressed)
box.add_widget(self.button1)
box.add_widget(self.button2)
box.add_widget(self.button3)
layout.add_widget(box)
return layout
def btn1pressed(self, instance):
if instance.state == 'down':
self.sports = 'Sports'
else:
self.sports = ''
self.l1.text = "{} {} {}".format(self.sports, self.music, self.travel)
def btn2pressed(self, instance):
if instance.state == 'down':
self.music = 'Music'
else:
self.music = ''
self.l1.text = "{} {} {}".format(self.sports, self.music, self.travel)
def btn3pressed(self, instance):
if instance.state == 'down':
self.travel = 'Travel'
else:
self.travel = ''
self.l1.text = "{} {} {}".format(self.sports, self.music, self.travel)
toggledemoapp().run()
輸出
應用程式以所有按鈕都處於 normal 狀態開啟。嘗試將其中任何一個置於“down”狀態。
示例 2
以下示例以與上圖所示類似的佈局組合標籤和切換按鈕,只是切換按鈕現在已分組。
我們將使用“kv”指令碼設計應用程式佈局。Mylayout 類用作應用程式的根,並使用 GridLayout 作為其基礎。
class Mylayout(GridLayout):
def callback(self, *args):
print (args[0].text)
self.ids.l1.text=args[0].text
class togglegroupapp(App):
def build(self):
return Mylayout()
togglegroupapp().run()
這是“kv”語言指令碼。它將三個切換按鈕放在一個水平框中,該水平框又是一個單列網格佈局的一部分。所有按鈕的 group 屬性都具有相同的值“branch”,並且繫結到上面 MyLayout 類的 callback() 方法。callback() 方法將導致 on_press 事件的按鈕的標題放在標籤上,以顯示使用者選擇了哪個分支。
<Mylayout>:
size: root.width, root.height
cols:1
Label:
text:"Which is your Engineering branch?"
font_size:40
Label:
id:l1
text: 'Choose Any One'
font_size:32
color:[.8,.6,.4,1]
BoxLayout:
orientation:'horizontal'
ToggleButton:
text : "Electronics"
font_size : 32
group:'branch'
on_press:root.callback(*args)
ToggleButton:
text:'Mechanical'
font_size:32
group:'branch'
on_press:root.callback(*args)
ToggleButton:
text:'Comp.Sci'
font_size:32
group:'branch'
on_press:root.callback(*args)
輸出
執行程式並使用按鈕狀態進行實驗,如下所示:
Kivy - 相機
使用 Kivy 中的 Camera 小部件,可以顯示來自攝像機裝置的影片流。Kivy 可能需要一些時間來初始化攝像機裝置,並在之後更新小部件紋理。
Camera 類定義在 "kivy.uix.camera: 模組中。
from kivy.uix.camera import Camera cam = Camera(**kwargs)
如果系統找到多個攝像機裝置,則需要透過其索引指定要使用的攝像機。
cam = Camera(index=1)
您還可以使用 resolution 引數指定攝像機解析度:
cam = Camera(index=1, resolution=(640, 480))
kivy.uix.camera.Camera 類是來自 "kivy.core.camera" 模組的核心 Camera 類的具體實現,並執行初始化和幀捕獲功能。
Kivy 需要找到合適的攝像機提供程式才能檢測硬體。為此,請安裝最新版本的 opencv-python 包,該包還安裝其依賴包,包括 NumPy。
pip install opencv-python
要在應用程式視窗上開始從攝像機流式傳輸饋送,請將 Camera 物件的 play 屬性設定為 True,並將其設定為 False 以停止饋送。
cam.play = True
要將攝像機流的快照捕獲到影像中,請使用 export_to_png() 方法。指定要儲存到的檔名。
Camera 類定義了以下屬性:
**index** - 使用的攝像機的索引,從 0 開始。將其設定為 -1 以允許自動選擇。
**play** - 布林值,指示攝像機是否正在播放。您可以透過設定此屬性來啟動/停止攝像機:
# create the camera, and start later (default) cam = Camera() # and later cam.play = True # to sop cam.play = False
**resolution** - 呼叫攝像機時要使用的首選解析度。如果您使用 [-1, -1],則解析度將是預設解析度。要設定所需的解析度,前提是裝置支援:
cam = Camera(resolution=(640, 480))
示例
以下示例程式碼在垂直 BoxLayout 中添加了一個 Camera 小部件和一個 ToggleButton。繫結到切換按鈕的回撥函式在按鈕處於 down 狀態時將攝像機物件的 play 屬性設定為 True,否則將停止影片。
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.camera import Camera
from kivy.core.window import Window
Window.size = (720,350)
class TestCameraApp(App):
def build(self):
box=BoxLayout(orientation='vertical')
self.mycam=Camera(play=False, resolution= (640, 480))
box.add_widget(self.mycam)
tb=ToggleButton(text='Play', size_hint_y= None, height= '48dp')
tb.bind(on_press=self.play)
box.add_widget(tb)
return box
def play(self, instance):
if instance.state=='down':
self.mycam.play=True
instance.text='Stop'
else:
self.mycam.play=False
instance.text='Play'
TestCameraApp().run()
輸出
執行程式碼並檢查輸出:
您還可以使用“kv”語言指令碼設計應用程式窗口布局。將以下指令碼另存為“TestCamera.kv”,註釋掉 build() 方法中的程式碼,並在其中放置一個“pass”語句。
BoxLayout:
orientation: 'vertical'
Camera:
id: camera
resolution: (640, 480)
play: False
ToggleButton:
text: 'Play'
on_press: camera.play = not camera.play
size_hint_y: None
height: '48dp'
Kivy - 樹形檢視
大多數 GUI 工具包(包括 Kivy)都提供了一個 TreeView 小部件,使用者可以使用它以樹狀格式導航和互動以節點形式呈現的分層資料。作業系統檔案瀏覽器中顯示的檔案和目錄結構是 TreeView 的典型示例。
"kivy.uix.treeview" 模組包含三個重要類的定義:TreeView、TreeViewNode 和 TreeViewLabel。這些類的物件構成樹形檢視小部件。
TreeView 由 TreeViewNode 例項填充。庫中的任何小部件,例如標籤或按鈕,或使用者定義的小部件物件,都與 TreeViewNode 結合使用。
樹形檢視的根是 TreeView 物件本身。
from kivy.uix.treeview import TreeView tv = TreeView()
可以在此根節點下方直接新增一個或多個節點。TreeViewLabel 用作 add_node 方法的引數。
from kivy.uix.treeview import TreeViewLabel n1 = tv.add_node(TreeViewLabel(text='node 1'))
除了將節點新增到樹的根節點之外,還可以將其新增到節點本身。將父節點的例項作為第二個引數提供給 add_node() 方法 -
n2 = tv.add_node(TreeViewLabel(text='Political Sci'), n1)
樹形檢視的根小部件預設情況下處於開啟狀態,其預設標題為“Root”。要更改它,可以使用 TreeView.root_options 屬性。這會將選項傳遞給根小部件 -
tv = TreeView(root_options=dict(text='My root'))
TreeViewLabel 本身是一個標籤,因此無法生成任何事件,例如 on_press。為此,您應該定義一個繼承 TreeView 和 Button 的類。
class TreeViewButton(Button, TreeViewNode): pass
然後,您可以處理不同的事件,例如 -
on_node_expand - 節點展開時觸發
on_node_collapse - 節點摺疊時觸發
示例
以下程式碼構建了一個簡單的樹形檢視,顯示了大學每個系提供的科目。垂直盒佈局包含一個樹形檢視小部件和一個按鈕。樹形檢視的根節點處於開啟狀態。
要展開節點,請單擊其左側的“>”按鈕。它會變成向下箭頭。如果再次單擊,則節點將摺疊。
from kivy.app import App
from kivy.uix.treeview import TreeView, TreeViewLabel
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720, 350)
class DemoApp(App):
def build(self):
lo = BoxLayout(orientation='vertical')
self.tv = TreeView(root_options={
'text': 'Faculty-wise Subjects',
'font_size': 20}
)
self.n1 = self.tv.add_node(TreeViewLabel(text='Arts'))
self.n2 = self.tv.add_node(TreeViewLabel(text='Commerce'))
self.n3 = self.tv.add_node(TreeViewLabel(text='Science'))
self.n4 = self.tv.add_node(
TreeViewLabel(text='Sociology'), self.n1
)
self.n5 = self.tv.add_node(
TreeViewLabel(text='History'), self.n1
)
self.n6 = self.tv.add_node(
TreeViewLabel(text='Political Sci'), self.n1
)
self.n7 = self.tv.add_node(
TreeViewLabel(text='Accountancy'), self.n2
)
self.n8 = self.tv.add_node(
TreeViewLabel(text='Secretarial Practice'), self.n2
)
self.n9 = self.tv.add_node(
TreeViewLabel(text='Economics'), self.n2
)
self.n10 = self.tv.add_node(
TreeViewLabel(text='Physics'), self.n3
)
self.n11 = self.tv.add_node(
TreeViewLabel(text='Mathematics'), self.n3
)
self.n12 = self.tv.add_node(
TreeViewLabel(text='Chemistry'), self.n3
)
lo.add_widget(self.tv)
return lo
DemoApp().run()
輸出
Kivy - reStructuredText
reStructuredText 是一種文字檔案格式,其中包含主要用於 Python 技術文件的資料。該檔案通常具有“.rst”副檔名。
reStructuredText 是 DocUtils 專案的一部分,其主要目的是為 Python 提供一組類似於 Java 的 Javadoc 的工具。由 David Goodger 編寫,其最早版本於 2001 年釋出,最新版本於 2019 年釋出。
reStructuredText 可以被認為是一種輕量級標記語言,與 MarkDown 語法有很多相似之處。它被用作 Python 的 Sphinx 文件生成系統的核心元件。
Kivy 以 RstDocument 類的形式提供了 reStructuredText 文件渲染器,該類定義在“kivy.uix.rst”模組中。
from kivy.uix.rst import RstDocument doc = RstDocument(**kwargs)
格式化 reStructuredText
段落 - 由空行(一個就足夠了)分隔的文字塊。段落必須具有相同的縮排。
粗體 - 兩個星號之間的字元(例如:**Hello**)
斜體 - 單個星號之間的字元(例如:*world*)
列舉列表 - 以數字或字母開頭,後跟句點“.”、右括號“)”或括在括號“( )”中。例如 -
1. Python 2. Java 3. C++
專案符號列表 - 以專案符號字元開頭 - “-”、 “+” 或 “*”
節 - 這些是帶有裝飾的單行文字(一個或多個單詞):單獨的下劃線,或下劃線和上劃線一起,用破折號“-----”、等號“======"
影像 - 要在文件中包含影像,可以使用 image 指令。例如 -
.. image:: kivi-logo.png
示例
以下文字根據 reStructuredText 語法進行格式化。將以下文字儲存為 index.rst -
================ Welcome to Kivy ================ Welcome to Kivy's documentation. **Kivy** is an open source software library for the rapid development of applications equipped with novel user interfaces, such as multi-touch apps. With Kivy, you can create apps that run on: * Desktop computers: macOS, Linux, *BSD Unix, Windows. * iOS devices: iPad, iPhone. * Android devices: tablets, phones. ------------------- Virtual environment ------------------- Create the virtual environment named kivy_venv in your current directory_:: python -m virtualenv kivy_venv Activate the *virtual environment*. For Windows default CMD, in the command line do_:: kivy_venv\Scripts\activate Your terminal should now preface the path with something like (kivy_venv), indicating that the kivy_venv environment is active. If it doesn't say that, the virtual environment is not active and the following won't work. Install Kivy ------------ The simplest is to install the current stable version of kivy is to use pip_:: python -m pip install "kivy[base]" kivy_examples
讓我們編寫一個程式,在 Kivy 應用程式中渲染此 reStructuredText 文件。我們將一個 RstDocument 小部件放在具有單列的網格佈局中。將此物件的 source 屬性設定為我們建立的 RST 檔案。
from kivy.app import App
from kivy.uix.rst import RstDocument
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720,400)
class rstdemoapp(App):
def build(self):
grid=GridLayout(cols=1)
doc = RstDocument(source="index.rst")
grid.add_widget(doc)
return grid
rstdemoapp().run()
輸出
執行以上程式碼。RST 文件將根據上面解釋的格式化語法顯示。
Kivy - 操作欄
Kivy 框架提供 ActionBar 小部件,它充當易於訪問的選單,通常位於應用程式視窗的頂部或底部,有點類似於 Android 中的 ActionBar。
ActionBar 類定義在 kivy.uix.actionbar 模組中。操作欄的外觀取決於其內部 ActionView 的組成。ActionView 包含一個或多個 ActionButtons,由相應的文字標題和/或圖標表示。
ActionView 包含 ActionButtons、分隔符或 ActionGroup。ActionGroup 是 ActionButtons 的集合。當您單擊 ActionGroup 標題時,按鈕將顯示在下拉選單中。
當 ActionBar 區域變得太小而無法容納所有內容時,小部件將移動到 ActionOverflow 區域。
您可能希望始終在 ActionBar 上顯示某些 ActionItems,而不管存在多少項。如果將 ActionButton 的 Important 屬性設定為 True,它將在欄上獲得優先順序放置。
示例
以下程式碼將標籤和 ActionBar 放置在應用程式視窗的底部。ActionBar 顯示幾個 ActionButtons,每個按鈕的“on_press”事件都將標籤標題更新為其自己的 text 屬性。
App 程式碼由 myActionApp 類組成,其 build 方法透過載入關聯的 kv 檔案指令碼構建視窗的外觀。
Python 程式碼如下所示 -
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
Window.size = (720,400)
class mywidget(Widget):
def pressed(self, obj):
self.ids.l1.text=obj.text
class myActionApp(App):
def build(self):
return mywidget()
myActionApp().run()
這裡,mywidget 類是 Widget 類的子類。以下 kv 語言指令碼(儲存為 myAaction.kv)組合了 ActionBar 和兩個按鈕。它還放置了一個標籤以顯示按下 ActionButton 的標題。
<mywidget>
Label:
id:l1
text:'Hello'
pos_hint:{'center_x':.5, 'center_y':1}
pos:(root.width/2-150, root.height/2-50)
font_size:48
size:(300,100)
ActionBar:
size:root.width, 50
pos_hint: {'top':1}
background_color: .6, 4, .2, .6
ActionView:
use_separator: True
ActionPrevious:
title: 'Action Bar'
with_previous: False
ActionOverflow:
ActionButton:
icon: 'atlas://data/images/defaulttheme/audio-volume-high'
ActionButton:
important: True
text: 'Important'
on_press:root.pressed(self)
ActionButton:
text: 'Btn1'
on_press:root.pressed(self)
輸出
Kivy - 播放器
Kivy 庫中的 VideoPlayer 小部件是一個現成的控制元件,用於播放影片檔案並控制其播放和聲音。它是一個預定義的佈局,包含播放區域和播放/停止以及暫停/恢復播放的按鈕。它還有一個可以將播放位置移動到所需位置的 seekbar。
VideoPlayer 類定義在“kivy.uix.videoplayer”模組中。
from kivy.uix.videoplayer import VideoPlayer player = VideoPlayer(**kwargs)
您需要將 VideoPlayer 物件的 source 屬性分配給表示要播放的影片檔案的字串。Kivy 支援不同的影片格式,包括“mp4”、“avi”和“mpg”。
要啟動影片,您應該將 state 屬性設定為“play”。
from kivy.uix.videoplayer import VideoPlayer player = VideoPlayer(source = "test.mp4") player.state = 'play'
Kivy 的 VideoPlayer 的重要功能之一是能夠在影片中的特定位置顯示文字註釋,並持續一段時間。註釋儲存在副檔名為“.jsa”的檔案中,並且與影片檔案同名。
.jsa 檔案是一種基於 JSON 的檔案格式。它包含註釋的開始位置、在螢幕上顯示的持續時間(以秒為單位)以及註釋文字的值。
[
{"start": 0, "duration": 2,
"text": "Introduction"},
{"start": 10, "duration": 5,
"text": "Hello World"},
]
要使影片迴圈播放,請將 eos 選項設定為 loop -
options={'eos': 'loop'}
VideoPlayer 類定義了以下屬性 -
source - 要讀取的影片源。source 是一個 StringProperty,表示要播放的影片檔案的路徑。
state - 字串,指示是播放、暫停還是停止影片。state 是一個 OptionProperty,預設為“stop”。
allow_fullscreen - 預設情況下,您可以雙擊影片使其全屏顯示。將此屬性設定為 False 以防止此行為。
position - 影片在 0 到 duration 之間的位置。position 預設為 -1,並在影片載入時設定為實際位置。
seek(percent, precise=True) - 將位置更改為 duration 的百分比(嚴格來說,是比例)。percent 值應為浮點數或整數,介於 0-1 之間。precise 引數是一個布林值,預設為 True,其中精確查詢速度較慢,但查詢至確切的請求百分比。
thumbnail - 要顯示的影片縮圖。如果為 None,VideoPlayer 將嘗試從 source + '.png' 中查詢縮圖。
volume - 影片的音量範圍為 0-1。1 表示最大音量,0 表示靜音。
annotation - VideoPlayer 使用 VideoPlayerAnnotation 物件根據儲存在 JSA 檔案中的 JSON 資料構建註釋。
允許在 JSA 檔案中使用以下鍵 -
start - 顯示註釋的位置
duration - 註釋標籤在播放器視窗上顯示的時間。
text - 要顯示為註釋的文字。
bgcolor - [r, g, b, a] - 文字框的背景顏色
bgsource - 'filename' - 用於文字框背景的背景影像
border - (n, e, s, w) - 用於背景影像的邊框
示例
以下程式碼在應用程式視窗上呈現一個影片播放器小部件 -
from kivy.app import App
from kivy.uix.videoplayer import VideoPlayer
from kivy.core.window import Window
Window.size = (720, 350)
class MainApp(App):
title = "Simple Video"
def build(self):
player = VideoPlayer(
source="video.mp4",
size_hint=(0.8, 0.8),
options={'fit_mode': 'contain'}
)
player.state = 'play'
player.options = {'eos': 'loop'}
player.allow_stretch = True
return player
MainApp().run()
輸出
執行程式碼並檢查輸出:
Kivy - 模板檢視
Kivy 庫中的 StencilView 小部件限制了新增到其中的其他子小部件的畫布區域。任何嘗試在 StencilView 區域外部繪製的指令都將被剪裁。
StencilView 小部件在後臺使用 Stencil 圖形指令。它提供了一種有效的方法來剪裁子元素的繪圖區域。
StencilView 類定義在“kivy.uix.stencilview”模組中。
from kivy.uix.stencilview import StencilView
需要注意的是,StencilView 不是佈局。因此,要將小部件新增到 StencilView,必須將 StencilView 和 Layout 組合起來才能實現佈局的行為。此外,不能向 StencilView 新增超過 128 個支援 stencil 的小部件。
StencilView 的一般用法如下 -
st = StencilView(size=(x,y)) w = Widget() st.add_widget(w)
要了解 StencilView 如何準確地限制小部件的可繪製區域,讓我們首先執行某些圖形繪製指令,然後應用 StencilView 以檢視差異。
示例
在以下程式碼中,mywidget 類擴充套件了 Widget 類,並在隨機位置和隨機 RGB 值下繪製 200 個圓形。(這還沒有使用 StencilView)
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import *
import random
from kivy.core.window import Window
Window.size = (720, 350)
class mywidget(Widget):
def __init__(self, *args):
super().__init__(*args)
for i in range(200):
colorR = random.randint(0, 255)
colorG = random.randint(0, 255)
colorB = random.randint(0, 255)
posx = random.randint(0, Window.width)
posy = random.randint(0, Window.height)
self.canvas.add(Color(rgb=(colorR / 255.0, colorG / 255.0, colorB / 255.0)))
d = 30
self.canvas.add(Ellipse(pos=(posx, posy), size=(d, d)))
class circlesapp(App):
def build(self):
w = mywidget()
return w
circlesapp().run()
輸出
如您所見,圓形在應用程式視窗區域的各個位置隨機繪製。
現在我們將應用 StencilView,並將繪圖區域限制在主視窗中心的 400×300 畫素。
建立 StencilView 物件,並將 Widget 物件新增到其中。繪圖迴圈保持不變。
class circlesapp(App):
def build(self):
st = StencilView(
size_hint=(None, None), size=(400, 300),
pos_hint={'center_x':.5, 'center_y':.5}
)
w=widget()
st.add_widget(w)
return st
如果我們現在執行應用程式,我們應該看到隨機圓形出現在 stencil 區域內,因為對於 stencil 區域之外的所有位置,繪圖指令都受到限制。
Kivy - 虛擬鍵盤
Kivy 庫中的 VKeyboard 小部件對於在智慧手機和平板電腦等多點觸控裝置上執行的應用程式特別有用。VKeyboard 是一個螢幕鍵盤。其操作旨在對使用者透明。
VKeyboard 以兩種模式使用 - 停靠和自由模式。自由模式適用於多點觸控裝置,而停靠模式在使用類似平板電腦的計算機時啟用。
VKeyboard 類定義在 kivy.uix.vkeyboard 模組中。
from kivy.uix.vkeyboard import VKeyboard kb = VKeyboard(**kwargs)
虛擬鍵盤永遠不會直接使用。相反,它受配置控制。如果應用程式有任何需要鍵盤的小部件(例如 TextInput),請不要直接使用虛擬鍵盤,而是首選在平臺上可用的最佳方法。
VKeyboard 類繼承自 ScatterLayout。虛擬鍵盤小部件右下角的一個按鈕允許您在可用的佈局之間切換。
VKeyboard 物件具有以下屬性:
available_layouts - 所有可用佈局的字典。鍵是佈局 ID,值是 JSON,預設為 {}。
callback - 回撥可以設定為一個函式,如果使用者關閉 VKeyboard,則會呼叫該函式。
docked - 指示 VKeyboard 是否停靠在螢幕上。如果更改它,則必須手動呼叫 setup_mode(),否則它將不起作用。
key_margin - 鍵邊距,用於在鍵之間建立空間。邊距由四個值組成,單位為畫素:
key_margin = [top, right, bottom, left]
key_margin 預設為 [2, 2, 2, 2]
target - 與 VKeyboard 關聯的目標小部件。如果設定,它將用於傳送鍵盤事件。
示例
在以下示例中,一個單列網格佈局的初始構成顯示了一個標籤和一個 TextInput 小部件。當用戶透過點選文字框內部生成 touch_down 事件時,一個 VKeyboard 小部件將新增到佈局中。
def ontouch(self, instance, value):
self.kb = VKeyboard(
on_key_up = self.vkbinput,
pos_hint={'center_x':.5},
size_hint=(.8, None)
)
self.layout.add_widget(self.kb)
當按下鍵盤上的任何鍵時,它會生成 on_key_up 事件。它繫結到 vkbinput() 方法。此方法讀取被按下的鍵的鍵碼並更新文字框的內容。
def vkbinput(self, keyboard, keycode, *args):
text = self.text1.text
if keycode == '~':
self.layout.remove_widget(self.kb)
return
self.text1.text = f'{text}{keycode}'
每當使用者按下“~”鍵時,鍵盤小部件將從佈局中移除。
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.vkeyboard import VKeyboard
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720, 400)
class MainApp(App):
def build(self):
self.layout = GridLayout(cols=1)
self.text1 = TextInput(
font_size=32,
on_touch_down=self.ontouch
)
self.label = Label(
text="Enter Text....",
font_size=32,
color=[.8, .6, .1]
)
self.layout.add_widget(self.label)
self.layout.add_widget(self.text1)
return self.layout
def ontouch(self, instance, value):
self.kb = VKeyboard(
on_key_up=self.vkbinput,
pos_hint={'center_x': .5},
size_hint=(.8, None)
)
self.layout.add_widget(self.kb)
def vkbinput(self, keyboard, keycode, *args):
text = self.text1.text
if keycode == '~':
self.layout.remove_widget(self.kb)
return
self.text1.text = f'{text}{keycode}'
MainApp().run()
輸出
當以上程式碼執行時,應用程式視窗的初始顯示如下:
點選文字框內部,虛擬鍵盤將出現在其下方:
您現在可以輸入文字。按“~”移除鍵盤。
Kivy - 觸控漣漪
在 Kivy 框架中,“Touch Ripple”(觸控波紋)並不是真正的小部件或任何具體的類。相反,TouchRippleBehavior 混合類為佈局或單個小部件添加了觸控波紋視覺效果。通常,Kivy 有一個預設的按下/釋放視覺化效果。此類添加了來自 Google Material Design 的波紋效果。
此混合類在“kivy.uix.behaviors.touchripple”模組中定義。
from kivy.uix.behaviors.touchripple import TouchRippleBehavior
Ripple 行為不會自動觸發。具體的類需要實現此行為混合類並顯式地手動呼叫 ripple_show() 或 ripple_fade() 方法。
要自定義波紋效果,請使用以下屬性:
ripple_duration_in - 顯示疊加層所需的動畫持續時間。它是一個 NumericProperty,預設為 0.5。
ripple_duration_out - 一個 NumericProperty,預設為 0.2,設定淡出疊加層所需的動畫持續時間。
ripple_fade_from_alpha - 波紋顏色動畫開始時的 Alpha 通道。預設值為 0.5。
ripple_fade_to_alpha - 波紋顏色動畫目標的 Alpha 通道,預設為 0.8。
ripple_rad_default - 動畫開始時的預設半徑。它是一個 NumericProperty,預設為 10。
ripple_scale - 從裝飾小部件的 max(width/height) 計算出的動畫疊加層的最大縮放比例。
ripple_show() 方法開始當前小部件上的波紋動畫。您需要將觸控事件作為引數傳遞。
ripple_fade() 方法用於在當前小部件上完成波紋動畫。
ripple_func_in 和 ripple_funcion_out 是顯示和隱藏疊加層的動畫回撥。
示例
在以下示例中,我們使用了 kv 指令碼,該指令碼將標籤放在網格佈局中,並處理 touch_down 和 touch_up 事件。
on_touch_down() 方法呼叫 ripple_show() 方法以生成持續時間為 3 秒的波紋效果。
on_touch_up() 方法透過呼叫 ripple_fade() 方法來結束波紋效果。
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.behaviors.touchripple import TouchRippleBehavior
from kivy.core.window import Window
Window.size = (720,300)
class RippleLabel(TouchRippleBehavior, GridLayout):
def __init__(self, **kwargs):
super(RippleLabel, self).__init__(**kwargs)
def on_touch_down(self, touch):
collide_point = self.collide_point(touch.x, touch.y)
if collide_point:
touch.grab(self)
self.ripple_duration_in=3
self.ripple_show(touch)
return True
return False
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
self.ripple_duration_out=3
self.ripple_fade()
return True
return False
class MyRippleApp(App):
def build(self):
return RippleLabel(cols=1)
MyRippleApp().run()
“kv”指令碼:
<RippleLabel>:
GridLayout:
cols:1
Label:
size:(root.width, root.height)
pos_hint:{'center_x':.5, 'center_y':.5}
text:'OK'
font_size:100
color:(1,0,0,1)
輸出
執行程式並點選“OK”標籤。它將在視窗表面上產生波紋。增加持續時間以檢視效果。
Kivy – 音訊
Kivy 框架提供 Sound 類來處理載入音訊檔案、播放和停止播放等功能。Sound 類是核心類之一,在“kivy.core.audio”模組中定義。
不建議直接例項化 Sound 物件。相反,請使用如下所示的 SoundLoader 函式:
from kivy.core.audio import SoundLoader
sound = SoundLoader.load('test.mp3')
音訊播放由 Gstreamer 實現處理:使用 Gi/Gst 和 PyGST。Gi/GST 適用於 Python 2+3 和 Gstreamer 1.0,而 PyGST 僅適用於 Python 2 + Gstreamer 0.10。
請注意,核心音訊庫不支援錄製音訊。如果您需要此功能,請參考 audiostream 擴充套件。
Sound 物件具有以下重要屬性/方法:
| 序號 | 屬性/方法 & 說明 |
|---|---|
| 1 | load() 將檔案載入到記憶體中。 |
| 2 | play() 播放檔案。 |
| 3 | stop() 停止播放。 |
| 4 | unload() 從記憶體中解除安裝檔案。 |
| 5 | seek(position) 跳轉到 <position>(以秒為單位)。 |
| 6 | get_pos() 返回音訊檔案的當前位置。如果未播放,則返回 0。 |
| 7 | length 獲取聲音的長度(以秒為單位)。 |
| 8 | loop 如果聲音在完成後應自動迴圈,則設定為 True。 |
| 9 | source 音訊檔案的名稱/來源。 |
| 10 | state 聲音的狀態,'stop' 或 'play' 之一。 |
讓我們使用 Sound 物件並在 Kivy 中構建一個簡單的音訊播放器。應用程式視窗包含一個標籤,顯示播放器的當前狀態,即它是在播放還是已停止,以及兩個用於控制播放的按鈕。左邊的按鈕最初標題為“播放”。
單擊時,它從 mp3 檔案載入聲音物件,呼叫 play() 方法,將標籤標題更改為“正在播放”並啟用暫停按鈕,其標題更改為“停止”。
當左按鈕的標題為“停止”時被單擊時,播放將停止,恢復標籤標題並停用暫停按鈕。
當您點選暫停按鈕時,音訊檔案的當前位置將儲存在 pos 變數中,按鈕標題更改為恢復。當它被點選時,播放位置將透過呼叫 seek() 方法檢索。
示例
以下是完整程式碼:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.core.audio import SoundLoader
from kivy.core.window import Window
Window.size = (720, 350)
class audiodemoapp(App):
def build(self):
layout = GridLayout(cols=1, padding=10)
self.l1 = Label(
text='Press Start to Play',
font_size=40, color=[.8, .6, .4, 1]
)
layout.add_widget(self.l1)
box = BoxLayout(orientation='horizontal')
self.button1 = Button(text="Play", font_size=32)
self.button2 = Button(
text='Pause', font_size=32, disabled=True
)
box.add_widget(self.button1)
box.add_widget(self.button2)
layout.add_widget(box)
self.button1.bind(on_press=self.start_stop)
self.button2.bind(on_press=self.pause_resume)
return layout
def start_stop(self, event):
if self.button1.text == 'Play':
self.l1.text = 'Playing'
self.button1.text = 'Stop'
self.sound = SoundLoader.load('sample.mp3')
self.pos = 0
self.button2.disabled = False
self.sound.play()
else:
if self.button1.text == 'Stop':
self.l1.text = 'Press to Play'
self.button1.text = 'Play'
self.sound.unload()
self.button2.disabled = True
self.pos = 0
def pause_resume(self, event):
if self.button2.text == 'Pause':
self.button2.text = 'Resume'
self.l1.text == 'Paused'
self.pos = self.sound.get_pos()
print(self.pos)
self.sound.stop()
else:
if self.button2.text == 'Resume':
self.l1.text = 'Playing'
self.button2.text = 'Pause'
print(self.pos)
self.sound.seek(self.pos)
self.sound.play()
audiodemoapp().run()
輸出
下圖顯示狀態標題設定為“正在播放”並且暫停按鈕已啟用。暫停按鈕在暫停和恢復狀態之間切換。
Kivy - 影片
Kivy 框架中的 Video 小部件能夠顯示影片檔案和流。您可以使用 Video 小部件播放的影片格式取決於作業系統、安裝的影片提供程式以及任何所需的外掛。GStreamer 提供程式能夠處理幾乎所有影片編解碼器,例如 mpg、avi、mp4、mov 等。
Video 類在“kivy.uix.video”模組中定義。
from kivy.uix.video import Video vid = Video(**args)
建構函式唯一必需的引數是 source 屬性 - 一個表示影片檔案路徑的字串。
vid = Video(source = "test.mp4")
為了開始影片播放,您需要將其 play 屬性設定為 True。您可以在建構函式中傳遞此引數以在影片載入後立即啟動它,或者根據需要將其設定為 True/False。
# start playing the video at creation video = Video(source='test.mp4', play=True) # create the video, and start later video = Video(source='test.mp4') # and later video.play = True
Video 類的其他屬性如下所示:
duration - 影片的持續時間。持續時間預設為“-1”,並在影片載入時設定為實際持續時間。
eos - 代表“流結束”。一個布林屬性指示影片是否已完成播放(到達流的末尾)。
play - 指示影片是否正在播放。您可以透過將此屬性設定為 True 或 False 來啟動/停止影片。
position - 影片在 0 到 duration 之間的位置。位置預設為 -1,並在影片載入時設定為實際位置。
seek() - 將位置更改為作為總持續時間的一部分進行查詢,必須在 0-1 之間。
state - 一個字串,指示是播放、暫停還是停止影片:
# start playing the video at creation video = Video(source='test.mp4', state='play') # create the video, and start later video = Video(source='test.mp4') # and later video.state = 'play'
volume - 影片的音量,範圍為 0-1。1 表示全音量,0 表示靜音。
示例
from kivy.app import App
from kivy.uix.videoplayer import VideoPlayer
from kivy.uix.video import Video
from kivy.core.window import Window
Window.size = (720,400)
class MainApp(App):
title = "Simple Video"
def build(self):
player = Video(source = "earth.mp4",
size_hint = (1,1),
options={'fit_mode': 'contain'})
player.state = 'play'
player.options = {'eos': 'loop'}
player.allow_stretch=True
return player
MainApp().run()
輸出
當您執行以上程式碼時,影片播放將開始:
Kivy - 拼寫檢查
Kivy 庫在其“kivy.core”包中帶有一個拼寫模組。它提供了對一系列拼寫檢查後端以及單詞建議的抽象訪問。API 借鑑了“python-enchant”庫。
您需要安裝 enchant 才能使用此功能。
pip3 install pyenchant
示例
建立 Spelling 類(在“kivy.core.spelling”模組中定義)的物件以呼叫其各種方法。例如,list_languages() 方法返回支援的語言列表。
from kivy.core.spelling import Spelling s = Spelling() s.list_languages()
輸出
它將列出所有支援的語言:
['en_BW', 'en_AU', 'en_BZ', 'en_GB', 'en_JM', 'en_DK', 'en_HK', 'en_GH', 'en_US', 'en_ZA', 'en_ZW', 'en_SG', 'en_NZ', 'en_BS', 'en_AG', 'en_PH', 'en_IE', 'en_NA', 'en_TT', 'en_IN', 'en_NG', 'en_CA']
您可以從列表中選擇特定語言以供後續使用。
s.select_language('en_US')
Spelling 類中的 check() 方法檢查給定單詞在當前活動語言中是否有效。如果是,則返回 True。如果單詞不應該被檢查,則返回 None(例如對於 '')。如果它不是 self._language 中的有效單詞,則返回 False。
>>> s.check('this')
True
>>> s.check('thes')
False
您可以從 Spelling 類中獲取給定單詞的建議。
s.suggest('wold')
['wild', 'wolf', 'old', 'wolds', 'woald', 'world', 'would',
'weld', 'sold', 'woad', 'word', 'told', 'wood', 'cold', 'gold']
如果您嘗試選擇列表中不存在的支援語言,Kivy 將引發以下 NoSuchLangError 異常:
s.select_language('Hindi')
kivy.core.spelling.NoSuchLangError: Enchant Backend: No
language for "Hindi"
當呼叫使用語言的方法但之前未選擇任何語言時,Kivy 將引發“NoLanguageSelectedError”。
Kivy - 效果
Kivy 庫提供“kivy.effects”子包來控制在 Kivy 應用程式中使用 ScrollView 小部件時的過度滾動效果。Effect 類可以執行彈回、更改不透明度或防止滾動超出正常邊界的操作。
有三個 Effect 類:
ScrollEffect - 用於實現效果的基類。它僅計算滾動和過度滾動。此類在 kivy.effects.scroll 模組中定義
DampedScrollEffect - 使用過度滾動資訊允許使用者比預期拖動更多。一旦使用者停止拖動,位置將返回到其中一個邊界。此類的定義位於 kivy.effects.dampedscroll 模組中。
OpacityScrollEffect − 利用滾動檢視部件的滾動超出資訊來降低其不透明度。當用戶停止拖動時,不透明度會恢復為 1。類的定義可以在 kivy.effects.opacityscroll 模組中找到。
這些類使用 KineticEffect 作為基類,用於根據運動計算速度。
要在 ScrollView 的滾動行為上應用這些類的任何一個效果,請將這些類中的一個設定為 ScrollView 部件的 effect_cls 屬性的值。
scr = ScrollView(size=Window.size) scr.eefect_cls=ScrollEffect
示例
下面的 "kv" 語言指令碼構建了一個 ScrollView,並在一個 GridLayout 中添加了 100 個按鈕。 "effect_cls" 屬性被設定為 ScrollEffect 類。
#:import ScrollEffect kivy.effects.scroll.ScrollEffect
#:import Button kivy.uix.button.Button
<RootWidget>
effect_cls: ScrollEffect
GridLayout:
size_hint_y: None
height: self.minimum_height
cols: 1
on_parent:
for i in range(100):
self.add_widget(Button(text=str(i), size_hint_y=None))
上面的 "kv" 程式碼使用了名為 RootWidget 的類規則。以下 Python 程式碼中 App 類的 build() 方法返回一個 RootWidget 類物件。
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.effects.dampedscroll import DampedScrollEffect
from kivy.core.window import Window
from kivy.app import App
from kivy.core.window import Window
Window.size = (720,350)
class RootWidget(ScrollView):
pass
class scrollableapp(App):
def build(self):
return RootWidget()
scrollableapp().run()
輸出
從命令列執行上述 Python 程式。您將得到一個包含滾動檢視的應用程式視窗,顯示按鈕的快照。您可以上下滾動,並激活 ScrollEffect。
您可以透過在 RootWidget 類中指定屬性來自定義 Effect 類,並將其用作 "effect_cls" 屬性。
例如,您可以設定用於滾動的 max 和 min 邊界。當用戶滾動超出邊界時,overscroll 屬性是計算出的值。
Kivy - 輸入記錄器
Kivy 框架中 Recorder 類的功能仍在開發中,目前仍處於實驗階段。Recorder 物件記錄輸入事件,例如觸控事件、鍵盤事件和點選事件。它們被記錄在一個副檔名為 ".kvi" 的檔案中。Kivy 使用此檔案,透過生成等效的偽事件並將其分派到事件迴圈來重放事件。
Recorder 類定義在 "kivy.input.recorder" 模組中 -
from kivy.input.recorder import Recorder rec = Recorder(**kwargs)
要開始錄製,在例項化 Recorder 物件後按 F8。事件資料將記錄在當前資料夾中的 "recorder.kvi" 檔案中。您可以為 file 屬性指定任何其他檔名。
rec = Recorder(filename='myrecorder.kvi')
按 F7 重放事件。
要手動控制錄製和重放,請使用 Recorder 物件的 record 和 play 屬性。
要開始錄製 -
rec = Recorder(filename='myrecorder.kvi') rec.record = True rec.start()
要停止錄製 -
rec.record = False rec.stop()
類似地,要開始重放 -
rec.play = True rec.start()
以及,要停止回放 -
rec.play = False rec.stop()
您可以使回放迴圈播放 -
def playloop(instance, value):
if value is False:
instance.play = True
rec = Recorder(filename='myrecorder.kvi')
rec.bind(play=playloop)
rec.play = True
示例
在下面給出的程式碼中,一個 Label 新增到一個 Scatter 部件上,以便您可以執行旋轉、縮放和變換操作。此外,當用戶更改 TextInput 框的內容時,標籤的 text 屬性也會更新。
事件的錄製和重放定義在兩個按鈕的 on_press 事件上。
以下是完整的程式碼 -
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scatter import Scatter
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.togglebutton import ToggleButton
from kivy.input.recorder import Recorder
from kivy.core.window import Window
Window.size = (720,400)
class scatterdemoapp(App):
def build(self):
self.rec = Recorder(filename='myrecorder.kvi')
box=BoxLayout(orientation='vertical')
box1=BoxLayout(orientation='horizontal')
text1=TextInput(text='Hi', pos_hint={'top':1},height=100, size_hint=(.5, None))
b1=ToggleButton(text='record',pos_hint={'top':1}, height=100, size_hint=(.25, None))
b1.bind(on_press=self.on_recording)
b2=ToggleButton(text='play', pos_hint={'top':1},height=100, size_hint=(.25, None))
b2.bind(on_press=self.on_playing)
box1.add_widget(text1)
box1.add_widget(b1)
box1.add_widget(b2)
box.add_widget(box1)
scatr=Scatter()
self.lbl=Label(text="Hi", font_size=60, pos=(Window.width/2-100,200 ))
text1.bind(text=self.lbl.setter('text'))
scatr.add_widget(self.lbl)
box.add_widget(scatr)
return box
def on_recording(self, obj):
if obj.state=='down':
self.rec.record=True
self.rec.start()
else:
self.rec.record=False
self.rec.stop()
def on_playing(self, obj):
if obj.state=='down':
self.rec.play=True
self.rec.start()
else:
self.rec.play=False
self.rec.stop()
scatterdemoapp().run()
輸出
應用程式視窗如下所示 -
點選錄製按鈕,所有螢幕活動(包括 key_down 事件)都將記錄在 ".kvi" 檔案中。控制檯視窗顯示輸入已記錄。
[INFO ] [Recorder ] Recording inputs to 'myrecorder.kvi' [INFO ] [Recorder ] Recorded 901 events in 'myrecorder.kvi'
按下播放按鈕重放已記錄的事件。相應地,控制檯會回顯相應的日誌。
[INFO ] [Recorder ] Start playing 901 events from 'myrecorder.kvi'
Kivy - OpenGL
Kivy 框架擁有強大的圖形功能,構建在 OpenGL 和 SDL 指令之上。Kivy 使用 OpenGL ES 2 圖形庫,並基於頂點緩衝物件和著色器。 "kivy.graphics.opengl" 模組是圍繞 OpenGL 命令的 Python 包裝器。
著色器是一個使用者定義的程式,旨在在圖形處理器的某個階段執行。著色器是用 OpenGL 著色語言 (GLSL) 編寫的,這是一種高階著色語言,其語法基於 C 程式語言。
在 Web 上建立圖形的兩種常用著色器是頂點著色器和片段(畫素)著色器。
頂點著色器 − 它們接收來自前一管道階段的輸入(例如頂點位置、顏色和光柵化畫素),並自定義輸出到下一階段。
片段著色器 − 它們接收所有畫素的 2D 位置作為輸入,並自定義每個畫素的輸出顏色。
關於 GLSL 的功能和語法的詳細討論超出了本教程的範圍。我們將在本章中使用一個開源著色器檔案 (kaleidoscope.glsl)。
#ifdef GL_ES
precision highp float;
#endif
uniform vec2 resolution;
uniform float time;
uniform sampler2D tex0;
uniform sampler2D tex1;
void main(void){
vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
vec2 uv;
float a = atan(p.y,p.x);
float r = sqrt(dot(p,p));
uv.x = 7.0*a/3.1416;
uv.y = -time+ sin(7.0*r+time) + .7*cos(time+7.0*a);
float w = .5+.5*(sin(time+7.0*r)+ .7*cos(time+7.0*a));
vec3 col = texture2D(tex0,uv*.5).xyz;
gl_FragColor = vec4(col*w,1.0);
}
在我們的 Kivy 應用程式程式碼中,我們使用了一個 .kv 檔案,該檔案只是在 FloatLayout 部件的畫布上繪製一個矩形。
<ShaderWidget>:
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
此 "kv" 檔案的 ShaderWidget 規則對應於 ShaderWidget 類。它安排一個時鐘間隔,每秒觸發一次,以更新著色器定義中的 glsl 變數。
class ShaderWidget(FloatLayout):
fs = StringProperty(None)
def __init__(self, **kwargs):
self.canvas = RenderContext()
super(ShaderWidget, self).__init__(**kwargs)
Clock.schedule_interval(self.update_glsl, 1 / 60.)
"fs" 類變數儲存來自 glsl 檔案的程式碼。來自 kivy.graphics 模組的 RenderContext() 方法儲存所有必要的繪圖資訊,即頂點著色器和片段著色器等。
"fs" StringProperty 繫結到 "on_fs()" 方法,該方法將設定著色器。
def on_fs(self, instance, value):
shader = self.canvas.shader
old_value = shader.fs
shader.fs = value
if not shader.success:
shader.fs = old_value
raise Exception('failed')
每次計劃的時鐘事件發生時,都會呼叫 update_glsl() 方法。它基本上更新應用程式視窗上每個畫素的片段顏色。
def update_glsl(self, *largs): self.canvas['time'] = Clock.get_boottime() self.canvas['resolution'] = list(map(float, self.size)) win_rc = Window.render_context self.canvas['projection_mat'] = win_rc['projection_mat'] self.canvas['modelview_mat'] = win_rc['modelview_mat'] self.canvas['frag_modelview_mat'] = win_rc['frag_modelview_mat']
App 類簡單地從 kv 檔案和類定義中載入 ShaderWidget。
示例
完整程式碼如下所示:
from kivy.clock import Clock
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Window
from kivy.graphics import RenderContext
from kivy.properties import StringProperty
from kivy.core.window import Window
Window.size=(720,400)
file=open('kaleidoscope.glsl')
shader=file.read()
class ShaderWidget(FloatLayout):
fs = StringProperty(None)
def __init__(self, **kwargs):
self.canvas = RenderContext()
super(ShaderWidget, self).__init__(**kwargs)
Clock.schedule_interval(self.update_glsl, 1 / 60.)
def on_fs(self, instance, value):
shader = self.canvas.shader
old_value = shader.fs
shader.fs = value
if not shader.success:
shader.fs = old_value
raise Exception('failed')
def update_glsl(self, *largs):
self.canvas['time'] = Clock.get_boottime()
self.canvas['resolution'] = list(map(float, self.size)).
win_rc = Window.render_context
self.canvas['projection_mat'] = win_rc['projection_mat']
self.canvas['modelview_mat'] = win_rc['modelview_mat']
self.canvas['frag_modelview_mat'] = win_rc['frag_modelview_mat']
class 'kaleidoscopeApp(App):
title='kaleidoscope'
def build(self):
return ShaderWidget(fs=shader)
'kaleidoscopeApp().run()
輸出
執行此程式碼並檢查輸出 -
Kivy - 文字
Kivy 庫中的 "kivy.core.text" 模組充當渲染文字的後端層。但是,只有在 "kivy.uix.label.Label" 部件無法提供令人滿意的結果時才應使用它。
此模組有兩個重要的用途:一個是派生來自核心 Label 物件的紋理並將其應用於應用程式中的任何部件,另一個是將自定義字型應用於部件的 text 屬性,例如標籤、按鈕或文字輸入(或任何具有 text 屬性的部件)。
使用紋理
Label 部件(在 "kivy.uix.label" 模組中)在記憶體中的載入效率通常不高。為了克服這個問題,可以使用核心 label 類的物件,並將其紋理與常規部件一起使用。
首先從 "kivy.core.label" 中匯入 Label 類(為避免混淆,將其命名為 CoreLabel)。
from kivy.core.text import Label as CoreLabel cl=CoreLabel(text="Hi there!", font_size=50, color=(1, 0, 0, 1))
在此物件上呼叫 refresh() 方法以計算內容並生成紋理。
cl.refresh()
獲取紋理和紋理大小。
texture = cl.texture texture_size = list(texture.size)
現在可以將其與任何部件一起使用。
示例
在以下程式碼中,我們將一個 label 部件新增到一個垂直框佈局中,並使用核心 label 物件的紋理。
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
from kivy.core.text import Label as CoreLabel
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.core.window import Window
Window.size = (720,400)
class CoreLabelApp(App):
def build(self):
cl=CoreLabel(text="Hi there!", font_size=50, color=(1, 0, 0, 1))
cl.refresh()
texture = cl.texture
main=BoxLayout(orientation='vertical')
l=Label()
texture_size = list(texture.size)
l.canvas.add(Rectangle(texture=texture, size=texture_size))
main.add_widget(l)
return main
CoreLabelApp().run()
輸出
它將產生以下輸出 -
自定義字型
所有具有 text 屬性的部件都使用預設的一組字型進行渲染,這些字型根據 Kivy 安裝的 config.ini 檔案中的設定確定。
default_font = ['Roboto', 'data/fonts/Roboto-Regular.ttf', 'data/fonts/Roboto-Italic.ttf', 'data/fonts/Roboto-Bold.ttf', 'data/fonts/Roboto-BoldItalic.ttf']
但是,您可能希望使用特定字型在任何部件上顯示文字,它可以是標籤、TextInput 框或按鈕。為此,您需要下載相關的字型檔案(True Type 字型由 .ttf 檔案表示)並將其放置在應用程式資料夾中。
為了使這些字型可用於我們的應用程式,必須在應用程式中註冊它們。LabelBase 類的 register() 方法用於此目的。LabelBase 是一個抽象類,由您的作業系統使用的特定字型渲染器使用。
register() 是一個靜態方法,具有以下引數 -
register(name, fn_regular, fn_italic=None, fn_bold=None, fn_bolditalic=None)
其中 "name" 是您將在程式中引用字型的字型名稱,"fn_regular" 引數是字型的 TTF 檔案。
下載 Consolas 字型和 Monotype Corsiva 字型的 TTF 檔案,並將它們儲存在應用程式資料夾中。
示例
在以下程式中,我們在三個文字輸入框中顯示相同的字串。第一個框使用預設字型渲染文字。第二個框使用 Monotype Corsiva,第三個框應用 Consolas 字型。
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.core.text import LabelBase
from kivy.core.window import Window
Window.size = (720,400)
class CustomFontApp(App):
def build(self):
main=GridLayout(cols=1)
LabelBase.register(name='font1', fn_regular='consolas.ttf')
LabelBase.register(name='font2', fn_regular='MonotypeCorsivaFont.ttf')
txt='Simple Is Better Than Complicated'
t1=TextInput(text=txt, halign='center', font_size=48)
t2=TextInput(
text=txt, halign='center',
font_name='font2', font_size=48
)
t3=TextInput(
text=txt, halign='center',
font_name='font1', font_size=48
)
main.add_widget(t1)
main.add_widget(t2)
main.add_widget(t3)
return main
CustomFontApp().run()
輸出
它將生成以下輸出視窗 -
Kivy - 文字標記
儘管 Kivy 的 Label 物件具有粗體、斜體和顏色等屬性,但它還提供標記功能,可以使用類似於 HTML 標籤的語法來裝飾標籤文字。要使標記生效,需要將標籤的 markup 屬性設定為 True。
l = Label(text='Hello [b]World[/b]', markup=True)
請注意,kivy 標記只能用於內聯樣式。與 HTML 中使用尖括號的標籤(如 <b>Hello</b>)不同,這裡使用方括號(例如:[b]Hello</b])。
使用此標記語法的文字與 HTML 語法非常相似,如下表所示 -
| HTML | Kivy 標記 |
|---|---|
| <b>bolded text</b> | [b]bolded text[/b] |
| <i>italicized text</i> | [i]italicized text[/i] |
| <u>underlined text</u> | [u]underlined text[/u] |
以下標籤可用於 label 部件的 text 屬性的內聯樣式 -
| 序號 | 文字屬性和說明 |
|---|---|
| 1 | [b][/b] 啟用粗體文字 |
| 2 | [i][/i] 啟用斜體文字 |
| 3 | [u][/u] 下劃線文字 |
| 4 | [s][/s] 刪除線文字 |
| 5 | [font=<str>][/font] 更改字型(str 應為 TTF 檔案的名稱) |
| 6 | [font_family=<str>][/font_family] 請求繪製的字體系列。 |
| 7 | [size=<size>][/size] 更改字型大小。<size> 應為整數。 |
| 8 | [color=#<color>][/color] 更改文字顏色 |
| 9 | [anchor=<str>] 在文字中放置一個錨點。 |
| 10 | [sub][/sub] 相對於其之前的文字,將文字顯示在腳註位置。 |
| 11 | [sup][/sup] 相對於其之前的文字,將文字顯示在尾註位置。 |
如果需要從當前文字中轉義標記,請使用 kivy.utils.escape_markup()。
Kivy - 設定
"kivy.uix.settings" 模組包含一個非常有用的功能,允許您處理 Kivy 安裝環境的設定引數。您可以在應用程式視窗上開啟設定面板,並修改任何配置令牌。
安裝 Kivy 軟體時,它會建立一個配置檔案,其中包含各種引數令牌及其預設值。該檔名為 "config.ini",儲存在由 KIVY_HOME 環境變數標識的目錄中。
在 Windows 機器上 - 檔案儲存在 C:\Users\user\.kivy\config.ini 中。
在 Linux 上 - /home/user/.kivy/config.ini。
在 macOS 上 - /Users/user/.kivy/config.ini。
在 Android 上 - /data/data/org.kivy.launcher/files/.kivy/config.ini。
在 iOS 上 - <HOME_DIRECTORY>/Documents/.kivy/config.ini。
要開啟設定面板,請呼叫 App 類的 open_settings() 方法,通常是在 GUI 上的 on_press 事件(或任何其他事件)響應中。
def onpress(self, instance): app.open_settings()
我們從一個簡單的 Kivy 應用程式開始,該應用程式在視窗上安裝了一個 Button。當按鈕被按下時,它會呼叫 onpress() 方法以顯示 Kivy 設定面板。
class HelloApp(App):
def onpress(self, instance):
app.open_settings()
def build(self):
b1=Button(
text='Click Here', font_size=50,
on_press=self.onpress
)
return b1
app = HelloApp()
app.run()
應用程式執行後,點選按鈕進入設定面板。
此處顯示的設定與您在 config.ini 檔案中看到的相同。嘗試更改任何配置令牌的值,您將看到對配置檔案所做的更改。
有幾種可用的設定面板佈局。
設定 − 顯示設定,左側帶有一個側邊欄,用於在 json 面板之間切換。
SettingsWithSidebar − Settings 的一個簡單子類。
SettingsWithSpinner − 顯示設定,頂部帶有一個微調器,可用於在 json 面板之間切換。這是預設設定。
SettingsWithTabbedPanel − 在 TabbedPanel 中將 json 面板顯示為單獨的選項卡。
SettingsWithNoMenu − 顯示單個 json 面板,沒有切換到其他面板的方法,也沒有關閉按鈕。
要使用 SeetingsWithSidebar 佈局,請從 kivy.uix.settings 模組匯入它,並將其分配為 App 類的 settings_cls 引數的值。
from kivy.uix.settings import SettingsWithSidebar
class HelloApp(App):
def onpress(self, instance):
app.open_settings()
def build(self):
self.settings_cls = SettingsWithSidebar
b1=Button(text='Click Here', font_size=50, on_press=self.onpress)
return b1
現在視窗提供了一個側邊欄,用於在設定面板之間切換。
建立新面板
目前,您只有一個名為 Kivy 的面板,它顯示 Kivy 配置的預設設定。您可以新增一個新面板來定義應用程式的設定。您需要兩樣東西 -
一個帶有預設值的 ConfigParser 例項。
一個 JSON 物件。
您必須建立和處理 ConfigParser 物件,以告知 kivy 的 configparser 在配置檔案中儲存哪些設定。SettingsPanel 將從中讀取值。這些設定的預設值在您的 JSON 物件中為所有部分/鍵指定了 setdefaults。
讓我們新增 build_config 方法,該方法為按鈕文字和字型大小屬性提供預設值。
def build_config(self, config):
config.setdefaults('My Button', {'text': 'Hello Kivy, 'font_size': 20})
build_settings() 方法根據程式碼中的 JSON 物件在配置中構建一個新面板。
此示例中使用的 JSON 物件為 -
json = '''
[
{
"type": "string",
"title": "Button text",
"desc": "text on the button",
"section": "My Button",
"key": "text"
},
{
"type": "numeric",
"title": "Button font size",
"desc": "font size",
"section": "My Button",
"key": "font_size"
}
]
要根據此 JSON 物件的定義新增一個新面板,請定義 build_settings() 方法 -
def build_settings(self, settings):
settings.add_json_panel('My Button', self.config, data=json)
就是這樣。開啟設定時,您應該會看到添加了一個新的“我的按鈕”面板。
示例
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.settings import SettingsWithSidebar
Window.size = (720,350)
json = '''
[
{
"type": "string",
"title": "Button text",
"desc": "text on the button",
"section": "My Button",
"key": "text"
},
{
"type": "numeric",
"title": "Button font size",
"desc": "font size",
"section": "My Button",
"key": "font_size"
}
]
'''
class MyApp(App):
def onpress(self, instance):
app.open_settings()
def build(self):
self.settings_cls = SettingsWithSidebar
self.btn = Button(on_press=self.onpress)
self.btn.text = self.config.get('My Button', 'text')
self.btn.font_size = float(self.config.get('My Button', 'font_size'))
return self.btn
def build_config(self, config):
config.setdefaults(
'My Button', {'text': 'Hello Python', 'font_size': 20}
)
def build_settings(self, settings):
settings.add_json_panel('My Button', self.config, data=json)
def on_config_change(self, config, section, key, value):
if section == "My Button":
if key == "text":
self.btn.text = value
elif key == 'font_size':
self.btn.font_size = float(value)
app=MyApp()
app.run()
輸出
開啟設定面板時,您現在會看到“我的按鈕”面板,其中有兩個設定。根據需要修改值。最後,關閉設定對話方塊並返回檢視更改。
Kivy - 佈局
Kivy 應用程式視窗一次只能容納一個部件。因此,如果您嘗試新增兩個按鈕,則只會顯示第二個按鈕。另一方面,一個好的 GUI 需要不同的部件,例如標籤、文字輸入框、按鈕等,以便符合人體工程學地放置。為此,Kivy 框架提供了佈局。佈局本身是一個能夠容納其他部件的部件。因此,佈局被稱為容器部件。
在 Kivy 中,提供了不同型別的佈局容器。它們都實現了“kivy.uix.layout”模組中定義的 Layout 介面。Layout 介面本身繼承了 Widget 類。
此介面的兩個最重要的方法是 -
add_widget()
remove_widget()
add_widget()
此方法用於將新部件作為此佈局的子部件新增。其語法如下 -
add_widget(self, widget, *args, **kwargs)
引數
部件 − 要新增到我們的子部件列表中的部件。
索引 − 在列表中插入部件的索引。請注意,0 的預設值表示部件插入列表的開頭,因此將在其他同級部件的頂部繪製。
畫布 − 要將部件的畫布新增到其中的畫布。可以是“before”、“after”或 None(用於預設畫布)。
remove_widget
此方法用於從此部件的子部件中刪除部件。以下是其語法 -
remove_widget(self, widget, *args, **kwargs)
其中,引數“部件”表示要從子部件列表中刪除的部件。
請注意,Layout 是一個介面,因此不能直接使用。實現這些方法的 Layout 類是具體的類,如下面的列表所示 -
| 序號 | 方法和描述 |
|---|---|
| 1 | AnchorLayout 部件可以錨定到“頂部”、“底部”、“左側”、“右側”或“中心”。 |
| 2 | BoxLayout 部件按順序排列,以“垂直”或“水平”方向排列。 |
| 3 | FloatLayout 部件基本上不受限制。 |
| 4 | RelativeLayout 子部件相對於佈局定位。 |
| 5 | GridLayout 部件排列在由 rows 和 cols 屬性定義的網格中。 |
| 6 | PageLayout 用於建立簡單的多頁面佈局,以便可以使用邊框輕鬆地在頁面之間翻轉。 |
| 7 | ScatterLayout 部件的定位類似於 RelativeLayout,但可以平移、旋轉和縮放。 |
| 8 | StackLayout 部件以 lr-tb(從左到右,然後從上到下)或 tb-lr 順序堆疊。 |
在後續章節中,我們將詳細討論這些佈局中的每一個,並提供相關的示例。
Kivy - 浮動佈局
在 Kivy 中,FloatLayout 使您可以完全控制部件的放置。它不對部件的定位和大小方式施加任何限制。FloatLayout 會遵守其子部件的“pos_hint”和“size_hint”屬性。
FloatLayout 類在“kivy.uix.floatlayout”模組中定義。
from kivy.uix.floatlayout import FloatLayout layout = FloatLayout(**kwargs)
您可以使用 size 引數指定佈局大小。它是以畫素為單位的寬度和高度的元組。
layout = FloatLayout(size=(300, 300))
當使用 add_widget() 方法將部件放置在 FloatLayout 物件中時,將採用與佈局相同的大小。
您可以指定“size_hint”、“pos_hint”、“pos”和“size”屬性來定義部件在 FloatLayout 中的大小和位置。
button = Button( text='TutorialsPoint', size_hint=(.4, .3), pos=(100, 100))
這將在 100,100 座標(從左下角測量)處放置一個按鈕,其大小為佈局寬度的 40%、佈局高度的 30%。
FloatLayout 支援從 Widget 類繼承的兩個主要方法:add_widget() 和 remove_widget()。
FloatLayout 的基本用法如下所示 -
class FloatApp(App):
def build(self):
flo = FloatLayout()
l1 = Label(text="TutorialsPoint")
flo.add_widget(l1)
return flo
您還可以使用“kv”檔案填充應用程式視窗,如下所示 -
FloatLayout:
Label:
text : 'TutorialsPoint'
示例
讓我們設計一個表單,其中包含三個標籤、三個文字輸入框(其中一個是多行文字框)和一個提交按鈕。
為此使用 FloatLayout 物件。標籤放置在 x 座標值為 200 px 的位置,文字框放置在 x 座標值為 400 px 的位置。標籤和文字框的寬度為佈局的 10%。單個按鈕水平放置在中心。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Color, Rectangle
from kivy.core.window import Window
Window.size = (720,350)
class FloatApp(App):
def build(self):
flo = FloatLayout()
l1 = Label(
text="Name", size_hint=(.2, .1),
pos=(200, 350), color = [1,1,1,1]
)
with l1.canvas:
Color(0, 1, 0, 0.25)
Rectangle(pos=l1.pos, size=(350, 50))
flo.add_widget(l1)
t1 = TextInput(size_hint=(.4, .1), pos=(400, 350))
flo.add_widget(t1)
l2 = Label(
text="Address", size_hint=(.2, .1),
pos=(200, 250),color = [1,1,1,1]
)
with l2.canvas:
Color(0, 1, 0, 0.25)
Rectangle(pos=l2.pos, size=(350, 50))
flo.add_widget(l2)
t2 = TextInput(
multiline=True, size_hint=(.4, .1), pos=(400, 250)
)
flo.add_widget(t2)
l3 = Label(
text="College", size_hint=(.2, .1),
pos=(200, 150), color = [1,1,1,1]
)
with l3.canvas:
Color(0, 1, 0, 0.25)
Rectangle(pos=l3.pos, size=(350, 50))
flo.add_widget(l3)
t3 = TextInput(size_hint=(.4, .1), pos=(400, 150))
flo.add_widget(t3)
b1 = Button(
text='Submit', size_hint = (.2, .1),
pos_hint = {'center_x':.5, 'center_y':.09}
)
flo.add_widget(b1)
return flo
FloatApp().run()
輸出
執行此程式碼時,將生成如下所示的輸出視窗 -
請注意,標籤透過在標籤畫布上繪製具有 RGBA 顏色值 (0, 1, 0, 0.25) 的矩形來賦予背景顏色。
如果您希望使用“kv”檔案而不是在 build() 方法中設計 UI,則以下是“kv”語言指令碼 -
FloatLayout:
Label:
id:l1
text:"Name"
size_hint:(.2, .1)
pos:(200, 350)
color : [1,1,1,1]
canvas:
Color :
rgba: 0, 1, 0, 0.25
Rectangle:
pos:self.pos
size : (350, 50)
Label:
id:l2
text:"Address"
size_hint:(.2, .1)
pos:(200, 250)
color : [1,1,1,1]
canvas:
Color :
rgba: 0, 1, 0, 0.25
Rectangle:
pos:self.pos
size : (350, 50)
Label:
id:l3
text:"College"
size_hint:(.2, .1)
pos:(200, 150)
color : [1,1,1,1]
canvas:
Color :
rgba: 0, 1, 0, 0.25
Rectangle:
pos:self.pos
size : (350, 50)
TextInput:
id:t1
size_hint:(.4, .1)
pos:(400, 350)
TextInput:
id:t2
multiline:True
size_hint:(.4, .1)
pos:(400, 250)
TextInput:
id:t3
size_hint:(.4, .1)
pos:(400, 150)
Button:
id:b1
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
Kivy - 網格佈局
GridLayout 是 Kivy 中常用的佈局型別之一。GridLayout 物件充當容器網格。它將視窗區域劃分為指定數量的行和列,並將其他部件放置在單元格中。
GridLayout 類在 kivy.uix.gridlayout 模組中定義。物件必須至少定義了一個屬性 - rows 和 cols。如果您沒有指定這兩個屬性中的任何一個,Kivy 將丟擲 GridLayoutException。
from kivy.uix.gridlayout import GridLayout grid = GridLayout(**kwargs)
GridLayout 物件的屬性如下 -
cols − 網格中的列數。您不能再將其設定為負值。cols 是 NumericProperty,預設為 None。
rows − 網格中的行數。您不能再將其設定為負值。rows 是 NumericProperty,預設為 None。
cols_minimum − 每列最小寬度的字典。字典鍵是列號(例如 0、1、2…)。它是一個 DictProperty,預設為 {}。
rows_minimum − 每行最小高度的字典。字典鍵是行號(例如 0、1、2…)。它是一個 DictProperty,預設為 {}。
minimum_width − 自動計算包含所有子部件所需的最小寬度。它是一個 NumericProperty,預設為 0。它是隻讀的。
minimum_height − 自動計算包含所有子部件所需的最小高度。它是一個 NumericProperty,預設為 0。它是隻讀的。
orientation − 佈局的方向。此屬性決定了部件如何在網格中的連續單元格中放置。“orientation”是 OptionProperty。其有效值為 -
'lr-tb' − 從左到右,從上到下填充單元格。
'tb-lr' − 從上到下,從左到右填充單元格。
'rl-tb' − 從右到左,從上到下填充單元格。
'tb-rl' − 從上到下,從右到左填充單元格。
'lr-bt' − 從左到右,從下到上填充單元格。
'bt-lr' − 從下到上,從左到右填充單元格。
'rl-bt' − 從右到左,從下到上填充單元格。
'bt-rl' − 從下到上,從右到左填充單元格。
orientation 屬性的預設值為“lr-tb”。
row_default_height − 用於行的預設最小大小。row_default_height 是 NumericProperty,預設為 0。
row_force_default − 如果為 True,則忽略子部件的高度和 size_hint_y,並使用預設行高。row_force_default 是 BooleanProperty,預設為 False。
spacing −:子部件之間的間距:[spacing_horizontal, spacing_vertical]。spacing 是 VariableListProperty,預設為 [0, 0]。
padding − 佈局框與其子部件之間的填充:[padding_left, padding_top, padding_right, padding_bottom]。padding 也接受兩個引數形式 [padding_horizontal, padding_vertical] 和一個引數形式 [padding]。
預設情況下,所有部件的大小相同。這是因為預設的 size_hint 為 (1,1)。
def build(self): self.lo = GridLayout(cols=2) self.b1 = Button(text='Button 1', font_size=20) self.b2 = Button(text='Button 2', font_size=20) self.b3 = Button(text='Button 3', font_size=20) self.b4 = Button(text='Button 4', font_size=20) self.lo.add_widget(self.b1) self.lo.add_widget(self.b2) self.lo.add_widget(self.b3) self.lo.add_widget(self.b4) return self.lo
使用此程式碼,您將獲得以下佈局 -
現在,讓我們將“Hello”按鈕的大小固定為 250px,而不是使用“size_hint_x=None”。
self.lo = GridLayout(cols = 2) self.b1 = Button( text='Button 1', font_size=20, size_hint_x=None, width=250 ) self.b2 = Button(text='Button 2', font_size=20) self.b3 = Button( text='Button 3', font_size=20, size_hint_x=None, width=250 ) self.b4 = Button(text='Button 4', font_size=20
App 視窗如下所示 -
如果我們將 row_default_height 定義為 100 並設定“row_force_default=True” -
self.lo = GridLayout( cols=2, row_force_default=True, row_default_height=100 ) self.b1 = Button( text='Button 1', font_size=20, size_hint_x=None, width=250 ) self.b2 = Button(text='Button 2', font_size=20) self.b3 = Button( text='Button 3', font_size=20, size_hint_x=None, width=250 ) self.b4 = Button(text='Button 4', font_size=20)
現在視窗如下所示 -
示例 1
在此程式中,我們在具有四列的網格佈局中添加了 15 個按鈕。每個按鈕的標題都是一個唯一的隨機生成的數字,介於 1 到 15 之間。random 模組中的 randint() 函式用於此目的。
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
import random
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class MyApp(App):
def build(self):
self.grid = GridLayout(cols = 4)
nums=[]
for i in range(1,16):
while True:
num = random.randint(1,15)
if num not in nums:
nums.append(num)
self.grid.add_widget(Button(text = str(num)))
break
return self.grid
if __name__ == '__main__':
MyApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
示例 2
Kivy 中的 GridLayout 沒有跨行和/或列擴充套件部件的規定。也不可能按行號和列號放置部件。
需要在兩列網格中排列一些標籤和文字輸入框,但下面的提交按鈕應跨兩列。為此,我們在單列網格內放置一個兩列網格,並在其下方放置一個按鈕。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720, 400)
class DemoApp(App):
def build(self):
self.grid = GridLayout(rows=2)
self.top_grid = GridLayout(
cols=2, row_force_default=True,
row_default_height=100
)
self.top_grid.cols = 2
self.top_grid.add_widget(
Label(text="Name: ", size_hint_x=None, width=250)
)
self.fname = TextInput(
multiline=False, size_hint_x=None, width=650
)
self.top_grid.add_widget(self.fname)
self.top_grid.add_widget(Label(text="Address: "))
self.address = TextInput(multiline=True)
self.top_grid.add_widget(self.address)
self.top_grid.add_widget(Label(text="College: "))
self.college = TextInput(multiline=False)
self.top_grid.add_widget(self.college)
self.grid.add_widget(self.top_grid)
self.b1 = Button(text='Submit', size_hint_y=None, height=200)
self.grid.add_widget(self.b1)
return self.grid
if __name__ == '__main__':
DemoApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
Kivy - 箱式佈局
Kivy 框架提供了 BoxLayout 類,我們可以使用它按順序排列部件。順序由 BoxLayout 物件的 orientation 屬性確定,可以是字串:“vertical”或“horizontal”。
BoxLayout 類在“kivy.uix.boxlayout”模組中定義。要宣告 BoxLayout 物件,請使用。
from kivy.uix.boxlayout import BoxLayout blo = BoxLayout(**kwargs)
屬性
orientation − 佈局的方向。orientation 是 OptionProperty,預設為“horizontal”。可以是“vertical”或“horizontal”。
padding − 佈局框與其子部件之間的填充:[padding_left, padding_top, padding_right, padding_bottom]。padding 也接受兩個引數形式 [padding_horizontal, padding_vertical] 和一個引數形式 [padding]。
minimum_height − 自動計算包含所有子部件所需的最小高度。minimum_height 是 NumericProperty,預設為 0。它是隻讀的。
minimum_size − 自動計算包含所有子部件所需的最小大小。minimum_size 是 (minimum_width, minimum_height) 屬性的 ReferenceListProperty。它是隻讀的。
minimum_width − 自動計算包含所有子部件所需的最小寬度。minimum_width 是 NumericProperty,預設為 0。它是隻讀的。
BoxLayout 類還繼承了add_widget()和remove_widget()方法,我們之前已經討論過這些方法。
垂直 BoxLayout
BoxLayout 的典型用法如下所示。我們在垂直框佈局中添加了一個標籤、一個文字輸入和一個按鈕。
示例
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720,200)
class DemoApp(App):
def build(self):
lo = BoxLayout(orientation = 'vertical')
self.l1 = Label(text='Enter your name', font_size=20)
self.t1 = TextInput(font_size = 30)
self.b1 = Button(text = 'Submit', size_hint = (None, None),pos_hint={'x':.4, 'y':.2}, size = (200,75))
lo.add_widget(self.l1)
lo.add_widget(self.t1)
lo.add_widget(self.b1)
return lo
if __name__ == '__main__':
DemoApp().run()
輸出
它將產生以下輸出 -
您可以使用以下“Demo.kv”檔案構建上述 GUI -
BoxLayout:
orientation : 'vertical'
Label:
id : l1
text : 'Enter your name'
font_size : '20pt'
TextInput:
id : t1
font_size : 30
Button:
id : b1
text : 'Submit'
size_hint : (None, None)
pos_hint : {'x':.4, 'y':.2}
size : (200,75)
水平 BoxLayout
在以下程式中,我們在具有水平方向的框佈局中放置了一個標籤、一個文字輸入框和一個按鈕。
示例
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.core.window import Window
Window.size = (720,200)
class DemoApp(App):
def build(self):
self.lo = BoxLayout(orientation = 'horizontal')
self.l1 = Label(text='Enter your name', font_size=20)
self.t1 = TextInput(font_size = 30, pos_hint={'y':0.25}, pos = (0,100), size_hint = (None, None), size = (650,100))
self.b1 = Button(text = 'Submit', size_hint = (None, None),pos_hint={'x':.4, 'y':.35}, size = (75, 40))
self.lo.add_widget(self.l1)
self.lo.add_widget(self.t1)
self.lo.add_widget(self.b1)
return self.lo
if __name__ == '__main__':
DemoApp().run()
輸出
它將產生以下輸出 -
您可以使用以下“Demo.kv”檔案獲得相同的 GUI 設計 -
BoxLayout:
orientation : 'horizontal'
Label:
text : 'Enter your name'
font_size : '20pt'
TextInput :
font_size : '30pt'
pos_hint : {'y':0.25}
pos : (0,100)
size_hint : (None, None)
size : (650,100)
Button :
text : 'Submit'
size_hint : (None, None)
pos_hint : {'x':.4, 'y':.35}
size : (75, 40)
Kivy - 堆疊佈局
StackLayout 類的物件充當小部件容器,其中子小部件並排放置,可以水平或垂直放置,具體取決於 orientation 屬性。佈局尺寸可以容納儘可能多的部件。每個部件的尺寸可以是不同的。
假設 StackLayout 物件被配置為從左到右、從上到下放置部件。在水平放置“x”個部件後,如果無法在同一行放置部件“x+1”,則將其推到下一行,依此類推,直到佈局的高度用盡。
StackLayout 類定義在“kivy.uix.stacklayout”模組中。
from kivy.uix.stacklayout import StackLayout stack = StackLayout(**kwargs)
透過定義以下屬性來自定義 StackLayout 物件:
minimum_width − 自動計算包含所有子部件所需的最小寬度。它是一個 NumericProperty,預設為 0。它是隻讀的。
minimum_height − 自動計算包含所有子部件所需的最小高度。它是一個 NumericProperty,預設為 0。它是隻讀的。
minimum_height − 自動計算包含所有子部件所需的最小高度。minimum_height 是 NumericProperty,預設為 0。它是隻讀的。
minimum_size − 自動計算包含所有子部件所需的最小大小。minimum_size 是 (minimum_width, minimum_height) 屬性的 ReferenceListProperty。它是隻讀的。
minimum_width − 自動計算包含所有子部件所需的最小寬度。minimum_width 是 NumericProperty,預設為 0。它是隻讀的。
orientation − 佈局的方向。此屬性決定了部件如何在網格的連續單元格中放置。orientation 是一個 OptionProperty。其有效值為:
'lr-tb' − 從左到右,從上到下填充單元格。
'tb-lr' − 從上到下,從左到右填充單元格。
'rl-tb' − 從右到左,從上到下填充單元格。
'tb-rl' − 從上到下,從右到左填充單元格。
'lr-bt' − 從左到右,從下到上填充單元格。
'bt-lr' − 從下到上,從左到右填充單元格。
'rl-bt' − 從右到左,從下到上填充單元格。
'bt-rl' − 從下到上,從右到左填充單元格。
orientation 屬性的預設值為“lr-tb”。
示例
以下程式演示了 StackLayout 的用法。如前所述,預設方向為“lr-tb”。從左到右,然後從上到下按順序放置寬度逐漸增加但高度相同的按鈕。
當下一個按鈕無法容納在當前行時,它會被向下推。每個按鈕都帶有 1 到 50 之間的隨機生成的唯一數字作為標題。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.stacklayout import StackLayout
import random
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class StackApp(App):
def build(self):
stack = StackLayout()
width=100
nums=[]
for i in range(1, 25):
while True:
num = random.randint(1,25)
if num not in nums:
nums.append(num)
btn = Button(
text = str(num), width=width,
size_hint=(None, 0.15)
)
width = width+num*2
stack.add_widget(btn)
break
return stack
StackApp().run()
輸出
它將生成如下所示的堆疊佈局:
如果嘗試調整視窗大小,按鈕的位置將相應更改,並且它們要麼被容納在上一行,要麼被向下推。
讓我們將佈局的方向更改為“tb-lr”。
stack = StackLayout(orientation='tb-lr')
再次執行程式並檢視更改:
再次將 orientation 屬性更改為“rl-bt”並執行程式:
stack = StackLayout(orientation='rl-bt')
佈局開始從右到左、從下到上填充按鈕。因此,生成的視窗如下所示:
Kivy - 錨點佈局
使用此佈局時,我們可以以某種方式在其內部排列部件,使其錨定到佈局尺寸的某個位置。AnchorLayout 類定義在“kivy.uix.anchorlayout”模組中。
from kivy.uix.anchorlayout import AnchorLayout lo = AnchorLayout(**kwargs)
關鍵字引數
anchor_x − 定義要放置的小部件的水平錨點。它是一個 OptionProperty,其值必須來自“left”、“center”或“right”。預設為“center”。
anchor_y − 定義要放置的小部件的垂直錨點。它是一個 OptionProperty,其值必須來自“top”、“center”或“bottom”。預設為“center”。
padding − 小部件框與其子部件之間的填充,以畫素為單位:[padding_left, padding_top, padding_right, padding_bottom]。它也接受兩個引數的形式 [padding_horizontal, padding_vertical] 和一個引數的形式 [padding]。padding 是一個 VariableListProperty,預設為 [0, 0, 0, 0]。
AnchorLayout 類繼承了我們已在前幾章中介紹過的兩種方法“add_widget()”和“remove_widget()”。
示例 1
以下示例顯示了 AnchorLayout 的典型用法:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.anchorlayout import AnchorLayout
from kivy.core.window import Window
Window.size = (720, 400)
class DemoApp(App):
def build(self):
lo = AnchorLayout(
anchor_x='left', anchor_y='bottom'
)
self.l1 = Label(
text='Hello World', font_size=20,
size_hint=(None, None), size=(200, 75)
)
lo.add_widget(self.l1)
return lo
if __name__ == '__main__':
DemoApp().run()
輸出
可以看出,標籤已錨定到佈局的左下角。
使用“kv”語言指令碼也可以構建帶有 AnchorLayout 的 Kivy 應用程式:
AnchorLayout:
anchor_x : 'left'
anchor_y : 'bottom'
Label:
id:l1
text: 'Hello World'
font_size: '20pt'
size_hint : (None, None)
size : (200, 75)
示例 2
在下面的示例中,應用程式視窗具有一個頂級 GridLayout,其中包含要排列成 3 行的小部件。在每一行中,我們放置三個 AnchorLayout,這樣視窗包含九個 AnchorLayout,它們具有 lefttop、left-center、left-bottom、center-top、center-center、center-bottom、right-top、right-center 和 right-bottom anchor-x 和 anchor-y 屬性。
在每個佈局中,根據錨點配置放置一個按鈕部件。
from kivy.app import App
from kivy.uix.button import Button
from kivy.config import Config
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class AnchorApp(App):
def build(self):
lo = GridLayout(rows=3)
ax = ['left', 'center', 'right']
ay = ['top', 'center', 'bottom']
c = 0
# 3X3 grid with anchor layout in each
for i in range(3):
for j in range(3):
print(ax[i], ay[j])
anchrlo = AnchorLayout(
anchor_x=ax[i], anchor_y=ay[j]
)
b = Button(
text=ax[i] + "-" + ay[j],
size_hint=(None, None),
size=(200, 75), halign=ax[i]
)
# red text color for top row,
# green for middle row,
# blue for bottom row
if i == 0: b.color = [1, 0, 0, 1]
if i == 1: b.color = [0, 1, 0, 1]
if i == 2: b.color = [0, 0, 1, 1]
anchrlo.add_widget(b)
lo.add_widget(anchrlo)
return lo
AnchorApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
Kivy - 相對佈局
RelativeLayout 的行為與 FloatLayout 非常相似。兩者之間的主要區別在於,RelativeLayout 中子部件的位置座標相對於佈局大小,而不是像 FloatLayout 那樣相對於視窗大小。
要了解這意味著什麼,請考慮使用 FloatLayout 設計的以下 UI。
當調整視窗大小時,由於 FloatLayout 中的絕對定位,部件的放置與調整大小的視窗不成比例。結果,介面設計不一致。
RelativeLayout 沒有這種影響,因為部件的大小和位置相對於佈局。
當帶有位置 (0,0) 的部件新增到 RelativeLayout 時,當 RelativeLayout 的位置發生變化時,子部件也會移動。子部件的座標始終相對於父佈局。
RelativeLayout 類定義在“kivy.uix.relativelayout”模組中。
from kivy.uix.relativelayout import RelativeLayout rlo = RelativeLayout(**kwargs)
示例
以下程式碼在 RelativeLayout 中組裝標籤、文字框和提交按鈕。
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.relativelayout import RelativeLayout
from kivy.core.window import Window
Window.size = (720, 400)
class RelDemoApp(App):
def build(self):
rlo = RelativeLayout()
l1 = Label(
text="Name", size_hint=(.2, .1),
pos_hint={'x': .2, 'y': .75}
)
rlo.add_widget(l1)
t1 = TextInput(
size_hint=(.4, .1), pos_hint={'x': .3, 'y': .65}
)
rlo.add_widget(t1)
l2 = Label(
text="Address", size_hint=(.2, .1),
pos_hint={'x': .2, 'y': .55}
)
rlo.add_widget(l2)
t2 = TextInput(
multiline=True, size_hint=(.4, .1),
pos_hint={'x': .3, 'y': .45}
)
rlo.add_widget(t2)
l3 = Label(
text="College", size_hint=(.2, .1),
pos_hint={'x': .2, 'y': .35}
)
rlo.add_widget(l3)
t3 = TextInput(
size_hint=(.4, .1), pos=(400, 150),
pos_hint={'x': .3, 'y': .25}
)
rlo.add_widget(t3)
b1 = Button(
text='Submit', size_hint=(.2, .1),
pos_hint={'center_x': .5, 'center_y': .09}
)
rlo.add_widget(b1)
return rlo
RelDemoApp().run()
輸出
執行上述程式碼後,應用程式視窗將顯示如下所示的 UI:
請注意,與 FloatLayout 不同,調整視窗大小不會改變部件的比例大小和位置。
“kv”設計語言指令碼
用於生成上述 UI 而不是 App 類中的 build() 方法的“kv”檔案如下:
RelativeLayout:
Label:
text:"Name"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.75}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.65}
Label:
text:"Address"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
multiline:True
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"College"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
Kivy - 頁面佈局
Kivy 中的 PageLayout 類與 Kivy 中的其他容器部件略有不同。使用 PageLayout,您可以建立一個簡單的多頁佈局,以便可以透過邊框輕鬆地在頁面之間翻頁。
從一個頁面到下一個頁面的轉換是透過從右側或左側的邊框區域滑動完成的。由於 PageLayout 不支援 size_hint、size_hint_min、size_hint_max 或 pos_hint 屬性,因此每個頁面只能顯示一個小部件。但是,您可以透過將複合佈局物件(如 BoxLayout、GridLayout 或 FloatLayout)放在單個頁面中,在一個頁面中放置多個部件。
PageLayout 類定義在“kivy.uix.pagelayout”模組中。
from kivy.uix.pagelayout import PageLayout pg = PageLayout(**kwargs)
您可以將以下屬性定義為 PageLayout 建構函式的關鍵字引數:
anim_kwargs − 用於構造動畫的動畫 kwargs。它是一個 DictProperty,預設為 {'d': .5, 't': 'in_quad'}。
border − 當前頁面周圍邊框的寬度,用於在需要時顯示前一個/下一個頁面的滑動區域。它是一個 NumericProperty,預設為 50dp。
page − 當前顯示的頁面,它是一個 NumericProperty,預設為 0。
swipe_threshold − 用於觸發滑動的閾值,以部件大小的比率表示。swipe_threshold 是一個 NumericProperty,預設為 0.5。
PageLayout 識別觸控事件,您可以覆蓋以下事件處理程式:
on_touch_down(touch) − 接收一個觸控按下事件,其中 touch 引數為 MotionEvent 類。它返回一個布林值。如果為 True,則觸控事件的排程將停止。如果為 False,則事件將繼續排程到部件樹的其餘部分。
on_touch_move(touch) − 接收觸控移動事件。touch 位於父級座標中。
n_touch_up(touch) − 接收一個觸控抬起事件。觸控位於父座標中。
這是一個簡單的 PageLayout 示例。我們將三個按鈕分別作為單獨的頁面放置。
class PageApp(App):
def build(self):
pg = PageLayout()
btn1 = Button(text ='Page 1')
btn2 = Button(text ='Page 2')
btn3 = Button(text ='Page 3')
pg.add_widget(btn1)
pg.add_widget(btn2)
pg.add_widget(btn3)
return pg
執行時,帶有頁面 1 標題的按鈕顯示。按住滑鼠並從右向左滑動,以顯示第二頁和第三頁。從左向右滑動使前幾頁聚焦。
示例
在以下示例中,我們在 PageLayout 中添加了兩個 FloatLayout。“kv”檔案用於設計 UI。
首先,執行 PageLayout 應用程式的 Python 程式碼:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.pagelayout import PageLayout
from kivy.config import Config
Config.set('graphics', 'width', '720')
Config.set('graphics', 'height', '400')
Config.set('graphics', 'resizable', '1')
class PageDemoApp(App):
def build(self):
pass
if __name__ == '__main__':
PageDemoApp().run()
以下是“PageDemo.kv”檔案指令碼。PageLayout 嵌入到 FloatLayout 物件中。上方的 FloatLayout 是註冊頁面的設計,底部的 FloatLayout 是由登入螢幕組成的第二頁。
PageLayout:
FloatLayout:
orientation:'vertical'
Label:
text:'Register'
font_size:'20pt'
pos_hint:{'center_x': .5, 'center_y': .9}
Label:
text:"Name"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.75}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.65}
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
FloatLayout:
orientation:'vertical'
size:(720,400)
canvas.before:
Color:
rgba: 0,0,0, 1
Rectangle:
pos: self.pos
size: self.size
Label:
text:"Login"
font_size: '30pt'
pos_hint:{'center_x': .5, 'center_y': .75}
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
輸出
儲存“PageDemoApp.py”和“PageDemo.kv”這兩個檔案,然後執行 Python 指令碼。您應該首先獲得註冊頁面。
現在,從右向左滑動螢幕以使登入頁面出現在應用程式視窗中:
Kivy - 回收佈局
很多時候,如果應用程式介面需要大量的小部件來顯示資料項,其效能就會下降。Kivy 中的 RecycleView 小部件提供了一種靈活的替代方案。使用 RecycleView,可以僅檢視大型資料集的選定部分。它能夠重用部件以顯示可滾動的列表資料項。此功能對於讓使用者滾動瀏覽產品列表、影像等非常有用。
回收佈局的機制基於 MVC(模型-檢視-控制器)架構。
RecycleView.data 屬性構成模型層。
RecycleDataModel 類實現檢視層。檢視在佈局和檢視之間分割,並使用介面卡實現。它定義在 RecycleLayout 中,RecycleLayout 是一個抽象類。
對於第三個元件——控制器——RecycleViewBehavior 類定義了邏輯互動。RecycleView 類實現邏輯。它定義在“kivy.uix.recycleview”模組中。
需要例項化 RecycleView 物件,它會自動建立檢視和資料類。RecycleView 的兩個必須設定的重要屬性是 viewclass 和 data。
viewclass − 將此屬性設定為部件類的名稱。可回收檢視將由此類的物件組成。例如,如果 viewclass 是 Button,則回收檢視將是按鈕的可滾動列表。任何部件都可以用作此屬性的值。
data − data 本質上是一個字典列表,並使用這些字典根據需要生成 viewclass 的例項。這是一個字典列表,其鍵對映到 viewclass 的對應屬性名稱。例如,如果 viewclass 設定為 Button,則 data 可以是字典項列表,在每個字典中,鍵應為 Button 類的屬性之一。
RecycleView 部件樹還必須包含某個佈局管理器,以便可以找到視口。有兩個佈局可用於 RecycleView。一個是RecycleBoxLayout(在“kivy.uix.recycleboxlayout”模組中可用),另一個是RecycleGridLayout(在“kivy.uix.recyclegridlayout”模組中)。這兩個佈局類都繼承了 BoxLayout 和 GridLayout 類。
示例
讓我們在 RecycleView 部件中載入一百個按鈕。它們被新增到 RecycleBoxLayout 中。
要將按鈕用作回收檢視中的元素,請將其 viewclass 設定為 Button。
它的資料屬性是一個字典列表。每個字典都有一個“text”鍵,每個鍵的值是按鈕標題,例如BTN 1、BTN 2等。下面的列表推導式語句構建了字典:
data=[{'text': 'BTN {}'.format(str(x))} for x in range(20)]
[{'text': 'BTN 0'}, {'text': 'BTN 1'}, {'text': 'BTN 2'},
{'text': 'BTN 3'}, {'text': 'BTN 4'}, {'text': 'BTN 5'},
{'text': 'BTN 6'}, {'text': 'BTN 7'}, {'text': 'BTN 8'},
{'text': 'BTN 9'}, {'text': 'BTN 10'}, {'text': 'BTN 11'},
{'text': 'BTN 12'}, {'text': 'BTN 13'}, {'text': 'BTN 14'},
{'text': 'BTN 15'}, {'text': 'BTN 16'}, {'text': 'BTN 17'},
{'text': 'BTN 18'}, {'text': 'BTN 19'}]
以下是RecycleView應用程式的“kv”語言指令碼:
RecycleView:
viewclass: 'Button'
data: [{'text': 'BTN {}'.format(str(x))} for x in range(20)]
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
App類只需要載入這個“kv”檔案,只需保留build()方法並使用pass語句即可。
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
Window.size = (720,400)
class recycled(App):
def build(self):
pass
recycled().run()
輸出
透過執行上面的Python指令碼測試程式碼的輸出。您應該會看到一個如下所示的按鈕滾動檢視:
Kivy - 佈局巢狀
Kivy中的佈局是一個容器小部件。它提供了一種有效的機制來構建具有不同小部件的GUI。Kivy庫包含不同的佈局小部件,例如GridLayout、BoxLayout、AnchorLayout等。
佈局本身是Widget類的子類。因此,我們可以策略性地將一個或多個佈局放置在佈局內。這樣,就可以構建一個小部件結構的層次結構,為應用程式設計有效的GUI。任何佈局都可以包含在任何其他佈局中。這完全取決於開發人員如何設想應用程式的設計。
讓我們根據以下示意圖規劃應用程式介面佈局:
這裡,我們需要一個最上面的單列網格佈局。在它裡面,我們想放一個TextInput和另外兩個水平的盒子佈局。
第一個盒子包含三個按鈕。它下面的盒子包含一個影像控制元件和一個AnchorLayout小部件,其中包含一個滑塊控制元件。
示例
以下“kv”語言指令碼使用了這種計劃好的結構:
GridLayout:
cols: 1
size: root.width, root.height
TextInput:
text: "Hello World!"
font_size: 32
size_hint: (1, .2)
BoxLayout:
orientation:'horizontal'
size_hint: (1, .2)
Button:
text:"Btn 1"
font_size:32
Button:
text:"Btn 2"
font_size:32
Button:
text:"Btn 3"
font_size:32
FloatLayout:
Image:
source: "kivy-logo.png.png"
size_hint: .5, .75
pos_hint: {"center_x": 0.25}
AnchorLayout:
anchor_x : 'center'
anchor_y : 'top'
size_hint: .5, .75
pos_hint: {"center_x": 0.75}
Slider:
min:0
max:100
value:25
您可以在以下App類中載入此“kv”指令碼:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.animation import Animation
from kivy.core.window import Window
Window.size = (720,400)
class MyLayoutApp(App):
def build(self):
pass
if __name__ == '__main__':
MyLayoutApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
應用程式視窗的最終外觀類似於初始計劃,它使用了“佈局中的佈局”。
Kivy - 配置物件
安裝Kivy軟體時,它會建立一個配置檔案,其中包含各種引數及其預設值。該檔名為“config.ini”,儲存在由KIVY_HOME環境變數標識的目錄中。
在Windows上:該檔案儲存在C:\Users\user\.kivy\config.ini。
在Linux上:/home/user/.kivy/config.ini。
在macOS上:/Users/user/.kivy/config.ini。
在Android上:/data/data/org.kivy.launcher/files/.kivy/config.ini。
在iOS上:<HOME_DIRECTORY>/Documents/.kivy/config.ini。
為了更改預設設定,您可以手動更改此檔案或使用Config物件。Config物件的read()、set()和write()方法分別用於讀取設定的值、分配新值以及將更改寫入配置檔案。
from kivy.config import Config Config.read(<file>) Config.write() # set config
您還可以透過設定環境變數(以程式設計方式或從作業系統終端)來為任何配置引數(稱為令牌)分配僅在當前會話中有效的值。
從Python設定環境變數:
import os os.environ['KIVY_LOG_MODE'] = MIXED'
您也可以從OS終端設定環境變數。在Windows命令提示符終端中:
set KIVY_LOG_MODE = MIXED'
在Linux/MacOS上:
export KIVY_LOG_MODE = MIXED'
配置檔案config.ini包含一個或多個部分,每個部分包含稱為令牌的引數。KIvy安裝的典型“config.ini”檔案包含Kivy、Graphics、widgets等部分。
要使用環境變數更改某個配置設定,請使用以下指令格式:
KCFG_<section>_<key> = <value>
例如,要設定日誌級別:
KCFG_KIVY_LOG_LEVEL= "warning"
可以使用以下語法以程式設計方式執行相同的操作:
os.environ["KCFG_KIVY_LOG_LEVEL"] = " warning"
配置令牌
配置檔案分為幾個部分,每個部分包含令牌或引數。以下是一些按部分順序排列的重要令牌:
部分 - [Kivy]
default_font - 用於顯示任何文字的小部件的預設字型。
desktop - 整數,0或1。此選項控制功能,例如啟用或停用滾動檢視中的可拖動捲軸、停用TextInput中的氣泡等。
log_dir - 日誌目錄的路徑。
log_level - 字串,'trace'、'debug'、'info'、'warning'、'error'或'critical'之一。設定要使用的最小日誌級別。
部分 - [postproc]
double_tap_distance - 雙擊允許的最大距離,在0-1000範圍內歸一化。
double_tap_time - 雙擊檢測允許的時間,以毫秒為單位。
triple_tap_distance - 三擊允許的最大距離,在0-1000範圍內歸一化。
triple_tap_time - 三擊檢測允許的時間,以毫秒為單位。
部分 [graphics]
fullscreen - 0、1、'fake'或'auto'之一。
height - 視窗的高度,如果fullscreen設定為auto則不使用。
left - 視窗的左側位置。
top - 視窗的頂部位置。
resizable - 0或1之一 - 0表示固定大小,1表示可調整大小。
width - 視窗的寬度,如果fullscreen設定為auto則不使用。
部分 [widgets]
scroll_distance - ScrollView小部件使用的scroll_distance屬性的預設值。
scroll_timeout - ScrollView小部件使用的scroll_timeout屬性的預設值。
Config物件的 方法
add_section() - 如果缺少該部分,則向配置中新增一個部分。例如:
Config.add_section('newsection')
get() - 獲取給定部分的選項值。例如:
Config.get('graphics', 'width')
set() - 為配置令牌分配值。例如:
Config.set('graphics', 'width', 720)
write() - 將配置寫入使用read()方法開啟的最後一個檔案。如果寫入成功完成,則返回True,否則返回False。
Kivy - 圖集
如果您的應用程式預計要使用許多影像,尤其是在遠端伺服器上,則需要最佳化它們的載入時間。Kivy框架中的Atlas有助於減少載入時間。使用Kivy Atlas,應用程式只需要載入一個影像檔案,這減少了錯誤的可能性,並且比載入多個影像使用更少的資源。Atlas通常用於Kivy遊戲應用程式中渲染影像。
Atlas類在“kivy.atlas”模組中可用。此模組可用於以程式設計方式構建Atlas物件,以及使用其命令列介面。
要能夠使用Atlas,當前的Kivy環境必須具有pillow包 - Python的影像庫。如果不可用,請使用以下命令安裝它:
pip3 install pillow
Atlas由兩個檔案組成:
一個json檔案(副檔名為“.atlas”),其中包含影像檔名和圖集的紋理位置。
包含“.atlas”檔案引用的紋理的影像檔案。
假設以下影像位於名為imges的目錄中:
C:\kivyenv\images目錄
forward.png pause.png play.png previous.png
這些影像中的每一個都是64×64畫素的尺寸。因此,我們指定一個256×256畫素大小的圖集檔案來容納所有四個檔案。開啟作業系統的命令終端並執行以下命令:
python -m kivy.atlas myatlas 256x256 *.png
終端顯示以下日誌資訊,最後會在images資料夾中建立這兩個檔案。
(kivyenv) C:\kivyenv\images>python -m kivy.atlas myatlas 256x256 *.png [INFO ] [Logger ] Record log in C:\Users\mlath\.kivy\logs\kivy_23-07-20_33.txt [INFO ] [deps ] Successfully imported "kivy_deps.gstreamer" 0.3.3 [INFO ] [deps ] Successfully imported "kivy_deps.angle" 0.3.3 [INFO ] [deps ] Successfully imported "kivy_deps.glew" 0.3.1 [INFO ] [deps ] Successfully imported "kivy_deps.sdl2" 0.6.0 [INFO ] [Kivy ] v2.2.0 [INFO ] [Kivy ] Installed at "c:\kivyenv\Lib\sitepackages\kivy\__init__.py" [INFO ] [Python ] v3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] [INFO ] [Python ] Interpreter at "c:\kivyenv\Scripts\python.exe" [INFO ] [Logger ] Purge log fired. Processing... [INFO ] [Logger ] Purge finished! [DEBUG ] STREAM b'IHDR' 16 13 [DEBUG ] STREAM b'sRGB' 41 1 [DEBUG ] STREAM b'gAMA' 54 4 [DEBUG ] STREAM b'pHYs' 70 9 [DEBUG ] STREAM b'IDAT' 91 1115 [DEBUG ] STREAM b'IHDR' 16 13 [DEBUG ] STREAM b'sRGB' 41 1 [DEBUG ] STREAM b'gAMA' 54 4 [DEBUG ] STREAM b'pHYs' 70 9 [DEBUG ] STREAM b'IDAT' 91 990 [DEBUG ] STREAM b'IHDR' 16 13 [DEBUG ] STREAM b'sRGB' 41 1 [DEBUG ] STREAM b'gAMA' 54 4 [DEBUG ] STREAM b'pHYs' 70 9 [DEBUG ] STREAM b'IDAT' 91 1230 [INFO ] [Atlas ] create an 256x256 rgba image Atlas created at myatlas.atlas 1 image has been created
您可以看到建立的兩個附加檔案是myatlas-0.png,它是一個包含所有影像的256×256檔案,以及一個圖集檔案。
forward.png myatlas-0.png myatlas.atlas pause.png play.png previous.png
“.atlas”檔案是一個JSON檔案,包含組成檔案的紋理位置資訊。
{"myatlas-0.png": {"forward": [2, 190, 64, 64], "pause": [68, 190, 64, 64], "play": [134, 190, 64, 64], "previous": [2, 124, 64, 64]}}
為了在Kivy語言中使用Atlas,我們必須使用以下格式:
atlas://path/to/atlas/atlas_name/id.
“id”檔案指的是不帶副檔名的影像檔名。
例如,如果要將影像檔案用作按鈕在正常狀態下的背景,則可以按如下方式操作:
B1 = Button(background_normal='images/play.png')
Now, aAfter generating the Atlas, you can use the URL 'atlas://images/myatlas/play' as the value.
B1=Button(background_normal='atlas://images/myatlas/play')
請注意,在圖集URL中,無需新增.atlas副檔名。它將自動附加到檔名。
示例
讓我們使用Atlas中的影像URL來設定應用程式視窗上四個按鈕(播放、暫停、快進和後退)的正常背景。
在執行以下程式碼之前,必須如上所述建立圖集檔案:
from kivy.app import App
from kivy.graphics import *
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.window import Window
Window.size = (720, 400)
class AtlasApp(App):
def build(self):
main = GridLayout(cols=1)
self.l1 = Label(text='Using Atlas', font_size=32)
main.add_widget(self.l1)
root = FloatLayout(size=(Window.width, 100))
with root.canvas:
Color(.2, .7, .1, 1)
Rectangle(pos=root.pos, size=root.size)
self.btn1 = Button(
size_hint=(None, None),
pos_hint={'center_x': .2, 'center_y': .2}
)
self.btn2 = Button(
size_hint=(None, None),
pos_hint={'center_x': .4, 'center_y': .2}
)
self.btn3 = Button(
size_hint=(None, None),
pos_hint={'center_x': .6, 'center_y': .2}
)
self.btn4 = Button(
size_hint=(None, None),
pos_hint={'center_x': .8, 'center_y': .2}
)
self.btn1.background_normal = 'atlas://images/myatlas/forward'
self.btn2.background_normal = 'atlas://images/myatlas/play'
self.btn3.background_normal = 'atlas://images/myatlas/pause'
self.btn4.background_normal = 'atlas://images/myatlas/previous'
root.add_widget(self.btn1)
root.add_widget(self.btn2)
root.add_widget(self.btn3)
root.add_widget(self.btn4)
main.add_widget(root)
return main
AtlasApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
Kivy - 資料載入器
Kivy框架中的Loader類是一個非同步資料載入器,它使即使資料尚未可用也能載入影像成為可能。當您想要從Internet URL載入影像時,此功能特別有用。
Loader類在kivy.loader模組中定義。Loader類的典型用法如下:
from kivy.loader import Loader
image = Loader.image('http://mysite.com/test.png')
使用loading_image屬性指定預設影像。
Loader.loading_image = Image(default.png')
Loader類配備了以下屬性:
error_image - 用於錯誤的影像。例如:
Loader.error_image = 'error.png'
image(filename) - 使用Loader載入影像。返回一個帶有載入影像的ProxyImage。
loading_image - 用於載入的影像。例如:
Loader.loading_image = 'loading.png'
max_upload_per_frame - 每幀上傳的影像數量。預設情況下,我們每幀僅將2張影像上傳到GPU。
num_workers - 載入時要使用的worker數量。此設定僅在初始化時影響載入器。載入器啟動後,該設定無效。
from kivy.loader import Loader Loader.num_workers = 4
預設值為“2”,以提供流暢的使用者體驗。
ProxyImage() - Loader.image()函式返回的影像。
proxyImage = Loader.image("test.jpg")
pause() - 暫停載入器。
resume() - 在pause()之後恢復載入器。
run() - 載入器的主迴圈。
start() - 啟動載入器執行緒/程序。
stop() - 停止載入器執行緒/程序。
當影像載入或更改時,將觸發“on_load”事件。類似地,當影像無法載入時,將觸發“on_error”。“error: 發生的異常資料”。
示例
在下面給出的程式碼中,Loader物件從Internet URL載入影像。Loader返回的ProxyImage物件繫結到其on_load事件上的方法。回撥方法使用其紋理作為Image物件的texture屬性。
from kivy.app import App
from kivy.uix.image import Image
from kivy.loader import Loader
from kivy.core.window import Window
Window.size = (720,400)
class MyApp(App):
title='Loader'
def _image_loaded(self, proxyImage):
if proxyImage.image.texture:
self.image.texture = proxyImage.image.texture
def build(self):
proxyImage = Loader.image('https://source.unsplash.com/user/c_v_r/640x480')
proxyImage.bind(on_load=self._image_loaded)
self.image = Image()
return self.image
MyApp().run()
輸出
執行時,將產生以下輸出:
Kivy - 快取管理器
在Kivy框架中,Cache類透過將它們分配為唯一鍵的值來儲存一個或多個Python物件。Kivy的Cache管理器透過對其中的物件施加限制(例如限制物件數量或設定訪問超時)來控制它們。
Cache類在“kivy.cache”模組中定義。它包含靜態方法:register()、append()、get()等。
首先,您需要透過設定物件的最大數量和超時來在Cache管理器中註冊一個類別。
from kivy.cache import Cache Cache.register(category='mycache', limit=10, timeout=5)
您現在最多可以新增10個Python物件,每個物件都有一個唯一的鍵。
key = 'objectid'
instance = Label(text=text)
Cache.append('mycache', key, instance)
get()方法從快取中檢索物件。
instance = Cache.get('mycache', key)
Cache類定義了以下方法和屬性:
register()方法
此方法使用指定的限制在快取中註冊一個新類別。它具有以下引數:
category - 類別的字串識別符號。
limit - 快取中允許的物件的最大數量。如果為None,則不應用任何限制。
timeout - 物件從快取中刪除之前的時間。
append()方法
此方法將新物件新增到快取中。定義了以下引數:
category - 類別的字串識別符號。
key - 要儲存的物件的唯一識別符號。
obj - 要儲存在快取中的物件。
timeout - 如果物件未被使用,則刪除物件之前的時間。如果將None用作鍵,則會引發ValueError。
get()方法
此方法用於從快取中獲取物件,具有以下引數:
category - 類別的字串識別符號。
key - 儲存中物件的唯一識別符號。
default - 如果未找到鍵,則返回的預設值。
示例
請檢視以下示例:
from kivy.cache import Cache
from kivy.uix.button import Button
from kivy.uix.label import Label
Cache.register(category='CacheTest', limit=5, timeout=15)
b1 = Button(text='Button Cache Test')
Cache.append(category='CacheTest', key='Button', obj=b1)
l1 = Label(text='Label Cache Test')
Cache.append(category='CacheTest', key='Label', obj=l1)
ret = (Cache.get('CacheTest', 'Label').text)
print (ret)
輸出
它將產生以下輸出 -
Label Cache Test
Kivy - 控制檯
Kivy 中的 Console 工具類似於 Inspector 工具,但額外提供了一個功能,可以透過其外掛架構新增按鈕和麵板。與 Inspector 一樣,“kivy.modules.console” 模組具有命令列介面,以及用於以程式設計方式使用該工具的 API。
在命令列使用時,使用 Python 可執行檔案的“-m”選項載入模組。
python main.py -m console
要啟用 Kivy Console,請使用 Window 和 App 物件作為引數,從 console 模組呼叫 create_console() 函式。您需要將以下語句放在 App 類的 build() 方法中。
from kivy.modules import console
class Demo(App):
def build(self):
button = Button(text="Test")
console.create_console(Window, self)
return button
假設您已經開發了一個名為“slider.py”的 Kivy 應用程式,其介面如下所示。
該應用程式具有三個滑塊控制元件,可幫助更改上面文字的顏色。在 slider.py 檔案的 build() 方法中新增對 create_console() 函式的呼叫(如上所述)並執行它。首先,將顯示上述介面。按 Ctrl+E 啟用 Console 工具。
定義了以下按鍵組合:
“Ctrl + e” - 切換控制檯
“Escape” - 取消視窗小部件查詢,然後隱藏 Inspector 檢視
“Up” - 選擇父視窗小部件
“Down” - 選擇當前選定視窗小部件的第一個子視窗小部件
“Left” - 選擇前一個同級視窗小部件
“Right” - 選擇下一個同級視窗小部件
啟用 Console 工具後,它會在中間顯示一個欄,左側有“Select”、“Properties”和“Tree”按鈕,右側有“FPS”按鈕。
單擊“Tree”按鈕,您將獲得介面的視窗小部件樹。從樹中選擇 Slider 控制元件。
現在按下“Properties”按鈕。將顯示 Slider 視窗小部件的所有屬性的可滾動列表。
向下滾動到 value 屬性,然後雙擊以獲取一個可編輯框,其中顯示當前值,您可以更改該值。
按 Escape 移除控制檯。您應該會看到 Slider 位於您從控制檯設定的值處。
外掛
Console 工具的重要功能之一是外掛架構,它允許您向其中新增按鈕和麵板。預設情況下啟用的外掛有:
ConsoleAddonFps - 在右上角顯示 FPS。
ConsoleAddonSelect - 啟用選擇模式。
ConsoleAddonBreadcrumb - 在底部顯示當前視窗小部件的層次結構。
ConsoleAddonWidgetTree - 用於顯示應用程式視窗小部件樹的面板。
ConsoleAddonWidgetPanel - 用於顯示所選視窗小部件屬性的面板。
要啟用外掛,必須在呼叫 create_console 之前將其新增到 Console.addons 中。
關於外掛
讓我們在 Console 工具中新增一個“About”按鈕。它在控制檯工具工作區中間顯示物件描述,包括其 ID。
在 slider.py 中,在 App 類定義之前新增以下程式碼:
from kivy.modules.console import Console, ConsoleAddon, ConsoleLabel
class ConsoleAddonAbout(ConsoleAddon):
def init(self):
self.console.add_panel(
"About", self.panel_activate,
self.panel_deactivate
)
def panel_activate(self):
self.console.bind(widget=self.update_content)
self.update_content()
def panel_deactivate(self):
self.console.unbind(widget=self.update_content)
def deactivate(self):
self.panel_deactivate()
def update_content(self, *args):
widget = self.console.widget
if not widget:
return
text = "Selected widget is: {!r}".format(widget)
lbl = ConsoleLabel(text=text)
self.console.set_content(lbl)
Console.register_addon(ConsoleAddonAbout)
如果您再次執行 slider.py 指令碼,您將看到“About”按鈕新增到“Tree”按鈕旁邊。從視窗小部件樹中找到 Slider,然後單擊“About”按鈕以顯示 Slider 視窗小部件的 Object ID。
Kivy - 動畫
將動畫效果應用於視窗小部件是 Kivy 框架最吸引人的功能之一。在 Kivy 中,動畫功能在 kivy.animation 模組中包含的 Animation 類中定義。同一個模組還包含 AnimationTransition 類。它是一組用於應用動畫過渡效果的函式。
要使用動畫效果,Kivy 應用程式應:
首先確定要為哪個視窗小部件屬性設定動畫,
設定 Animation 類的物件,
設定屬性的最終值,
呼叫 Animation 物件的 start() 方法,並將視窗小部件作為引數傳遞。
要為視窗小部件的 x 或 y 位置設定動畫,只需指定在動畫結束時希望視窗小部件位於其中的目標 x/y 值即可:
rom kivy.animation import Animation anim = Animation(x=100, y=100) anim.start(widget)
這將為視窗小部件的 x 和 y 位置設定動畫,從其原始位置到 100,100,預設持續時間為一秒。
您可以要求為多個屬性設定動畫。例如,要為位置和大小設定動畫,請使用:
anim = Animation(x=50, size=(80, 80)) anim.start(widget)
您還可以指定 Animation 物件的 transition(或 t)屬性以應用過渡效果。
在兩個 Animation 物件之間使用“+”運算子將動畫按順序連線起來。
anim = Animation(x=50) + Animation(size=(80, 80), duration=2)
這將為視窗小部件的 x=50 設定動畫,持續 1 秒,然後為大小設定動畫到 (80, 80),持續接下來的 2 秒。
另一方面,“&”運算子並行連線動畫。以下示例將在 1 秒內同時為位置設定動畫到 (80, 10),為大小設定動畫到 (800, 800):
anim = Animation(pos=(80, 10)) anim &= Animation(size=(800, 800), duration=2.)
如果程式正在實現“順序”動畫,可以透過設定 anim.repeat = True 使動畫迴圈重複。
Animation 類具有以下屬性和方法:
duration 或 d - 動畫持續時間(以秒為單位),預設為 1。
transition 或 t - 用於為屬性設定動畫的過渡函式。它可以是 AnimationTransition 中方法的名稱。
step 或 s - 浮點數。動畫的毫秒步長。預設為 0,這意味著動畫將為每一幀更新。如果要以 30 FPS 設定動畫,請使用 s=1/30。
cancel() - 取消之前應用於視窗小部件的動畫。
cancel_all() - 取消所有與特定視窗小部件/屬性列表相關的動畫。
start() - 在視窗小部件上啟動動畫。
stop() - 停止之前應用於視窗小部件的動畫,觸發 on_complete 事件。
stop_all() - 停止所有與特定視窗小部件/屬性列表相關的動畫。
示例
藉助以下“kv”指令碼,按鈕和標籤被放置在垂直框佈局中。按鈕繫結到animating()方法。
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Label:
id: my_label
text: "Hello World!"
font_size: 32
Button:
text: "Start"
font_size: 32
size_hint: .5, .5
pos_hint: {"center_x": 0.5}
on_release: root.animating(self)
此“kv”指令碼載入到 App 類中。animating() 方法在單擊按鈕時對按鈕應用位置、背景顏色和大小動畫效果。
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.animation import Animation
from kivy.core.window import Window
Window.size = (720, 400)
class MyLayout(Widget):
def animating(self, widget, *args):
animate = Animation(
pos=(widget.pos[0], Window.height - 50)
)
animate += Animation(pos=(widget.pos[0], 0))
animate += Animation(
background_color=(0, 0, 1, 1),
duration=1
)
animate += Animation(size_hint=(1, 1))
animate += Animation(size_hint=(.5, .5))
animate += Animation(pos_hint={"center_x": 0.1})
animate += Animation(pos_hint={"center_x": 0.5})
animate.start(widget)
# Create a callback
animate.bind(on_complete=self.my_callback)
def my_callback(self, *args):
self.ids.my_label.text = "Hello Kivy"
class AwesomeApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
AwesomeApp().run()
輸出
執行上述程式。您應該會看到一個標籤及其下方的按鈕。
單擊按鈕以啟動動畫效果。按鈕上下移動、左右移動、大小增大和縮小,以及顏色變化。
Kivy - 多筆畫
Kivy 中的多筆劃手勢是一組多個手勢物件。手勢構成一個單筆劃,由“touch_down”和“touch_up”事件之間的觸控點列表構成。多筆劃手勢是此類筆劃的集合。
“kivy.multistroke”模組實現了量角器手勢識別演算法。在此模組中定義的兩個重要類是MultistrokeGesture和Recognizer。
MultistrokeGesture 類維護一組筆劃,並生成用於稍後針對此手勢評估候選者的單筆劃(即 UnistrokeTemplate)排列。
可以使用以下語法獲得 MultriStroke 物件:
from kivy.vector import Vector
from kivy.multistroke import MultistrokeGesture
gesture = MultistrokeGesture('my_gesture', strokes=[
[Vector(x1, y1), Vector(x2, y2), ...... ], # stroke 1
[Vector(), Vector(), Vector(), Vector() ] # stroke 2
#, [stroke 3], [stroke 4], ...
])
即使所有筆劃都組合到單個列表(單筆劃)中,您仍然應該分別指定筆劃,並將 stroke_sensitive 屬性設定為 True。
Recognizer 儲存 MultistrokeGesture 物件列表。它類似於 GestureDatabase 的搜尋/資料庫 API。它維護一個列表,並允許您在其中搜索使用者輸入的手勢。
Recognizer 資料庫是 UnistrokeTemplate 物件的容器,並實現堆置換演算法以自動生成所有可能的筆劃順序。
Candidate 類的物件表示一組使用者輸入的單筆劃路徑。此物件由呼叫 Recognizer.recognize() 自動例項化。
from kivy.vector import Vector from kivy.multistroke import Recognizer gdb = Recognizer() gdb.recognize([ [Vector(x1, y1), Vector(x2, y2)], [Vector(x3, y3), Vector(x4, y4)]])
Recognizer 物件能夠生成以下事件:
on_search_start - 使用此 Recognizer 啟動新搜尋時觸發。
on_search_complete - 正在執行的搜尋以任何原因結束時觸發。
這些事件可以對映到回撥,以跟蹤 Recognizer.recognize() 方法執行的搜尋操作的進度。
gdb.bind(on_search_start=search_start) gdb.bind(on_search_complete=search_stop)
回撥方法的示例如下:
def search_start(gdb, pt):
print("A search is starting with {} tasks".format(pt.tasks))
def search_stop(gdb, pt):
best = pt.best
print("Search ended {}. Best is {} (score {}, distance {})".format(
pt.status, best['name'], best['score'], best['dist'] ))
最後,“kivy.multistroke”模組還提供了一個 ProgressTracker 類。它表示正在進行(或已完成)的搜尋操作。
跟蹤器物件由 Recognizer.recognize() 方法在呼叫時自動例項化並返回。results 屬性是一個字典,在識別操作進行時會更新該字典。
progress = gdb.recognize([ [Vector(x1, y1), Vector(x2, y2)], [Vector(x3, y3), Vector(x4, y4)]]) progress.bind(on_progress=my_other_callback) print(progress.progress) # = 0 print(result.progress) # = 1
您可以使用 export_gesture() 函式將多筆劃手勢儲存到檔案中。
export_gesture(filename=None) - 它將 MultistrokeGesture 物件列表匯出到一個 Base64 編碼的字串,該字串可以使用 parse_gesture() 函式解碼為 Python 列表。它也可以使用 Recognizer.import_gesture() 直接匯入到資料庫中。如果指定了 filename,則輸出將寫入磁碟。
import_gesture(data=None,filename=None) - import_gesture() 函式將手勢帶入 Recognizer 資料庫。使用此函式匯入由 export_gesture() 格式化的手勢列表。必須指定 data 或 filename 引數。此方法接受可選的 Recognizer.filter() 引數,如果沒有指定引數,則匯入指定資料中的所有手勢。
Kivy - 時鐘
Kivy 框架中的 Clock 物件是一個全域性事件排程器。它用於在特定時間間隔內計劃和觸發事件。要計劃重複或一次性發生的事件,它會繫結到一個回撥函式。您可以透過“dt”引數獲取計劃和呼叫回撥之間經過的時間,該引數是時間增量。
Clock 物件在“kivy.clock”模組中定義。它包含諸如“schedule_once()”和“schedule_interval()”之類的方法,以註冊要在一定延遲後或以定期間隔呼叫的函式或方法。此機制可用於處理計時事件、動畫更新以及應用程式中的其他重複任務。
“schedule_interval()”和“schedule_once()”這兩個函式都有兩個引數;一個回撥和以秒為單位的時間間隔。
from kivy.clock import Clock def clock_callback(dt): "Clock event occurred" # call clock_callback every 2 seconds Clock.schedule_interval(clock_callback, 2) # call clock_callback in 5 seconds Clock.schedule_once(clock_callback, 5)
timeout dt 引數的預設值為 0。因此,要儘快呼叫回撥函式,請將第二個引數設定為計劃事件為 0,或者透過不使用引數讓預設值被使用。
Clock.schedule_once(my_callback)
使用“-1”的超時會導致事件在下一幀之前發生,將其設定為 0 會導致事件在下一幀之後發生。
觸發的事件
Clock 物件可以使用以下函式觸發時鐘事件:
schedule_interval(callback, timeout) - 此函式計劃每隔指定的秒數呼叫一次事件。該函式返回一個 ClockEvent 物件。在返回的事件上呼叫 ClockEvent.cancel() 以取消計劃事件。
schedule_once(callback, timeout=0) - 此函式計劃一次執行事件,並在指定的秒數後執行,並返回 ClockEvent 物件。如果未指定 timeout 或為 0,則回撥將在渲染下一幀後呼叫。要取消事件,請在返回的事件上呼叫 ClockEvent.cancel()。
create_trigger(callback, timeout=0) - 此函式建立 Trigger 事件。與其他兩個函式不同,事件不會自動計劃,您需要呼叫它。與其他兩個一樣,在事件執行之前取消它,方法是呼叫 ClockEvent.cancel()。要再次計劃它,只需呼叫事件(event())。
create_trigger() 函式具有以下引數:
callback - 要執行的回撥。來自 kivy。它採用 timeout 引數來指定在呼叫回撥之前等待多長時間。
interval − 一個布林引數,指示回撥函式是否應該呼叫一次 (False) 或者重複呼叫。
from kivy.clock import Clock def clock_callback(dt): "Clock event occurred" triggerevent = Clock.create_trigger(clock_callback, 5) triggerevent()
要取消使用以上兩種方法建立的事件,可以使用 event.cancel() 或 event.unschedule() 方法。
示例
下面給出的程式碼在 Kivy 應用程式視窗上執行一個倒計時計時器。“kv”指令碼在一個單列網格佈局中放置了一個 TextInput 框、一個標籤和一個按鈕。
<clockwidget>:
GridLayout:
cols:1
size:root.size
TextInput :
font_size : '30pt'
id:t1
halign:'center'
valign:'center'
Label:
id: l1
text : 'Current Value: '
font_size : '20pt'
Button :
id:b1
text : 'Start Countdown'
font_size:20
佈局類 clockwidget 繼承 GridLayout 並將命令按鈕繫結到一個方法,該方法安排每隔一秒發生一次的週期性事件。
每次呼叫回撥函式時,標籤都會顯示遞減的數字,從使用者在文字框中輸入的值開始。當它達到 0 時,事件將透過其 cancel() 方法取消排程。
class clockwidget(GridLayout):
def __init__(self, *args):
super(*args).__init__()
self.ids.b1.bind(on_press=self.showtime)
def countdown(self, dt):
if self.val==0:
self.ids.l1.text="Countdown Stopped"
self.ids.l1.color=[1,0,0]
self.ev.cancel()
self.ids.b1.disabled=False
else:
self.ids.l1.text="Current Value: {}".format(self.val)
self.ids.l1.color=[1,1,1]
self.val=self.val-1
def showtime(self, *args):
self.val=int(self.ids.t1.text)
self.ev=Clock.schedule_interval(self.countdown, 1)
self.ids.b1.disabled=True
本練習的完整程式碼如下所示:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.clock import Clock
from kivy.core.window import Window
Window.size = (720, 400)
class clockwidget(GridLayout):
def __init__(self, *args):
super(*args).__init__()
self.ids.b1.bind(on_press=self.showtime)
def countdown(self, dt):
if self.val == 0:
self.ids.l1.text = "Countdown Stopped"
self.ids.l1.color = [1, 0, 0]
self.ev.cancel()
self.ids.b1.disabled = False
else:
self.ids.l1.text = "Current Value: {}".format(self.val)
self.ids.l1.color = [1, 1, 1]
self.val = self.val - 1
def showtime(self, *args):
self.val = int(self.ids.t1.text)
self.ev = Clock.schedule_interval(self.countdown, 1)
self.ids.b1.disabled = True
class clockdemoapp(App):
def build(self):
w = clockwidget()
w.cols = 1
return w
clockdemoapp().run()
輸出
執行此程式時,它將顯示以下應用程式視窗。輸入倒計時計時器的值,然後單擊“開始”按鈕。
標籤開始更新,遞減倒計時值的數字。
當它達到“0”時,按鈕將再次啟用。
Kivy - SVG
Kivy 框架支援顯示 SVG 檔案,儘管目前仍處於高度實驗階段。在計算機圖形學中,SVG 代表可縮放向量圖形,這是 W3C 制定的用於編碼影像資料的標準。
諸如 PNG 和 JPG 之類的影像格式基於光柵圖形,其中影像資料以點陣圖的形式儲存,點陣圖是畫素的顏色和位置的網格。這種格式的缺點是,如果影像被放大,則影像在達到一定程度後會開始變得模糊。
另一方面,向量圖形影像以一系列 XML 指令的形式以數學方式儲存,這些指令用於在螢幕上繪製圖像。這些指令告訴檢視程式如何在螢幕上“繪製”影像。繪製可以在任何尺寸進行,因為 SVG 檔案與解析度無關。它們可以放大或縮小,而不會降低質量或清晰度。
Kivy 庫在“kivy.graphics.svg”模組中定義了 Svg 類。要在任何小部件的畫布上繪製 SVG 影像,我們可以使用以下語法:
from kivy.graphics.svg import Svg
with widget.canvas:
svg = Svg("test.svg")
Svg 類具有以下屬性:
anchor_x − 用於縮放和旋轉的水平錨點位置。預設為 0。值 0、1 和 2 分別對應於“左”、“中”和“右”。
anchor_y − 用於縮放和旋轉的垂直錨點位置。預設為 0。值 0、1 和 2 分別對應於“左”、“中”和“右”。
color − 用於指定“currentColor”的 SvgElements 的預設顏色。
height − 'double'
source − 要載入的 SVG 檔名/源。
width − 'double'
示例
以下程式使用“kv”指令碼載入 Scatter 小部件。一個“svg”物件放置在一個 GridLayout 中。將檔名作為其 source 屬性。以下是“kv”檔案:
<SvgWidget>:
do_rotation: True
<FloatLayout>:
canvas.before:
Color:
rgb: (1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
Kivy App 類的 Python 程式碼:
from kivy.uix.scatter import Scatter
from kivy.app import App
from kivy.graphics.svg import Svg
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.core.window import Window
Window.size = (720,400)
class SvgWidget(Scatter):
def __init__(self, filename):
super(SvgWidget, self).__init__()
with self.canvas:
svg = Svg(source=filename)
self.size = Window.width, Window.height
class SvgDemoApp(App):
def build(self):
self.root = GridLayout(cols=1)
filename = "ship.svg"
svg = SvgWidget(filename)
self.root.add_widget(svg)
svg.scale = 4
SvgDemoApp().run()
輸出
執行此程式時,它將生成以下輸出視窗:
Kivy - UrlRequest
Kivy 框架中的 UrlRequest 類允許您在網路上發出非同步請求,並在請求完成後獲取結果。其功能與 JavaScript 中的 XHR 物件相同。
UrlRequest 類在“kivy.network.urlrequest”模組中定義。建構函式只需要一個名為“url”的必填引數。該類繼承了 Python 的 threading 模組中的 Thread 類。
UrlRequest 建構函式的引數為:
url − 表示要呼叫的完整 url 字串的字串。
on_success − 獲取結果後要呼叫的回撥函式。
on_redirect − 如果伺服器返回重定向,則要呼叫的回撥函式。
on_failure − 如果伺服器返回客戶端或伺服器錯誤,則要呼叫的回撥函式。
on_error − 如果發生錯誤,則要呼叫的回撥函式。
on_progress − 將被呼叫的回撥函式,用於報告下載的進度。
on_cancel − 如果使用者透過 .cancel() 方法請求取消下載操作,則要呼叫的回撥函式。
on_finish − 如果請求完成,則要呼叫的附加回調函式。
req_body − 表示要與請求一起傳送的資料的字串。如果包含此引數,則將執行 POST 操作。否則,將傳送 GET 請求。
req_headers − dict,預設為 None。要新增到請求的自定義標頭。
chunk_size − 要讀取的每個塊的大小,僅在設定了 on_progress 回撥時使用。
timeout − 一個整數,如果設定,阻塞操作將在這麼多秒後超時。
method − 要使用的 HTTP 方法,預設為“GET”(如果指定了 body,則為“POST”)。
decode − bool,預設為 True。如果為 False,則跳過響應的解碼。
debug − bool,預設為 False。
auth − HTTPBasicAuth,預設為 None。如果設定,請求將使用基本身份驗證進行身份驗證。
UrlRequest 物件的 cancel() 方法取消當前請求,並將呼叫回撥 on_cancel。
示例
首先,我們設計一個使用者介面,其中包含一個包含 httpbin.org URL(帶變數引數)的微調器,兩個只讀文字框 - 一個顯示獲取的 URL 的結果,另一個顯示響應標頭的 JSON 字串。在它們之間放置了一個 Image 小部件。如果 content_type 為影像型別,它將顯示影像。這些小部件放置在一個垂直的 Box 佈局中。
佈局使用以下 kv 語言指令碼構建。
#:import json json
BoxLayout:
orientation: 'vertical'
TextInput:
id: ti
hint_text: 'type url or select from dropdown'
size_hint_y: None
height: 48
multiline: False
BoxLayout:
size_hint_y: None
height: 48
Spinner:
id: spinner
text: 'select'
values:
[
'http://httpbin.org/ip',
'http://httpbin.org/headers',
'http://httpbin.org/delay/3',
'https://httpbin.org/image/png',
]
on_text: ti.text = self.text
Button:
text: 'GET'
on_press: app.fetch_content(ti.text)
size_hint_x: None
width: 50
TextInput:
readonly: True
text: app.result_text
Image:
source: app.result_image
nocache: True
TextInput
readonly: True
text: json.dumps(app.headers, indent=2)
Kivy App 類程式碼如下所示。它基本上向 httpbin.org 傳送不同的 HTTP 請求。httpbin.org 是一種簡單的 HTTP 請求和響應服務。應用程式將 UrlRequest 的結果儲存在三個字串變數中,並在小部件中顯示。
從下拉列表中選擇 URL 並按下 GET 按鈕後,它將呼叫 fetch_content() 方法並收集響應。
如果回覆標頭包含具有影像的 content_type,則 Image 小部件將載入影像。
from kivy.lang import Builder
from kivy.app import App
from kivy.network.urlrequest import UrlRequest
from kivy.properties import NumericProperty, StringProperty, DictProperty
import json
from kivy.core.window import Window
Window.size = (720,400)
class UrlExample(App):
status = NumericProperty()
result_text = StringProperty()
result_image = StringProperty()
headers = DictProperty()
def build(self):
pass
def fetch_content(self, url):
self.cleanup()
UrlRequest(
url,
on_success=self.on_success,
on_failure=self.on_failure,
on_error=self.on_error
)
def cleanup(self):
self.result_text = ''
self.result_image = ''
self.status = 0
self.headers = {}
def on_success(self, req, result):
self.cleanup()
headers = req.resp_headers
content_type = headers.get('content-type', headers.get('Content-Type'))
if content_type.startswith('image/'):
fn = 'tmpfile.{}'.format(content_type.split('/')[1])
with open(fn, 'wb') as f:
f.write(result)
self.result_image = fn
else:
if isinstance(result, dict):
self.result_text = json.dumps(result, indent=2)
else:
self.result_text = result
self.status = req.resp_status
self.headers = headers
def on_failure(self, req, result):
self.cleanup()
self.result_text = result
self.status = req.resp_status
self.headers = req.resp_headers
def on_error(self, req, result):
self.cleanup()
self.result_text = str(result)
UrlExample().run()
輸出
執行上述程式碼。從微調器下拉列表中選擇'http://httpbin.org/headers',然後按 GET 按鈕。您應該在文字框中看到響應標頭。
選擇'https://httpbin.org/image/png' URL。影像將如下所示顯示。
微調器下拉列表中的一個選項是指向客戶端 IP 地址的 URL。從列表中選擇'http://httpbin.org/ip'。IP 地址將如下所示顯示:
Kivy - 剪貼簿
Kivy 框架中的 Clipboard 物件可以訪問正在使用的作業系統的剪貼簿。藉助 Kivy 的 Clipboard 物件,可以以程式設計方式執行剪下、複製和貼上操作。
剪貼簿是計算機 RAM 中的臨時緩衝區,大多數作業系統都提供該緩衝區用於在應用程式之間和內部進行短期儲存和傳輸。在作業系統中,此剪貼簿是一個全域性物件。大多數作業系統都使用常規的鍵盤快捷鍵在應用程式之間執行剪下、複製和貼上資料。
通常,不需要透過剪貼簿顯式使用剪下-複製-貼上操作。但是,在某些情況下它可能很有用。
Clipboard 物件在“kivy.core.clipboard”模組中定義。Clipboard 物件可以使用以下方法:
copy() − 將引數資料中提供的值複製到當前剪貼簿。如果資料不是字串型別,它將被轉換為字串。
get() − 獲取剪貼簿中的當前資料,如果可能,使用 mimetype。不要直接使用此方法。請改用 paste 方法。
get_types() − 返回支援的 mimetype 列表。
paste() − 從系統剪貼簿獲取文字並將其返回為可用的字串。
put() − 將資料放入剪貼簿,並附加 mimetype。不要直接使用此方法。請改用 copy 方法。
示例
在以下示例中,我們有兩個多行文字框和兩個按鈕,它們排列在一個 BoxLayout 中。COPY 按鈕呼叫 gettext() 方法,該方法將上文字框中選定的文字複製到剪貼簿。
def gettext(self, instance): Clipboard.copy(data=self.text1.selection_text)
PASTE 按鈕呼叫回撥 insert(),該回調將在游標位置貼上選定的文字。
def insert(self, instance): txt = Clipboard.paste() print (txt) self.text2.insert_text(txt)
這兩個函式繫結到兩個按鈕:-
self.b1=Button(text='COPY') self.b1.bind(on_press=self.gettext) self.b2=Button(text='PASTE') self.b2.bind(on_press=self.insert)
build() 方法用於組裝文字框和按鈕。
本練習的完整程式碼如下:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.core.clipboard import Clipboard
from kivy.core.window import Window
Window.size = (720, 400)
class mydemoapp(App):
def gettext(self, instance):
Clipboard.copy(data=self.text1.selection_text)
def insert(self, instance):
txt = Clipboard.paste()
print(txt)
self.text2.insert_text(txt)
def build(self):
main = BoxLayout(orientation='vertical')
self.text1 = TextInput(multiline=True, font_size=32)
btns = BoxLayout(orientation='horizontal')
self.b1 = Button(text='COPY')
self.b1.bind(on_press=self.gettext)
self.b2 = Button(text='PASTE')
self.b2.bind(on_press=self.insert)
self.text2 = TextInput(
multiline=True, font_size=32,
foreground_color=[0, 0, 1, 1]
)
btns.add_widget(self.b1)
btns.add_widget(self.b2)
main.add_widget(self.text1)
main.add_widget(btns)
main.add_widget(self.text2)
return main
mydemoapp().run()
輸出
執行程式時,您將看到兩個文字框。在上框中輸入Simple is better than Complex,在下框中輸入Complex is Complicated。
然後,選擇子字串better than,然後單擊 COPY 按鈕將其儲存到剪貼簿。在下框中單擊“Complicated”一詞旁邊,然後單擊 PASTE 按鈕。剪貼簿上的文字將被插入。
Kivy - 工廠
Kivy 中的 factory 類用於自動註冊任何類或模組,並在專案的任何位置例項化其中的類。Factory 類在“kivy.factory”模組中定義。
工廠模式是面向物件程式設計中的軟體架構模式。工廠是用於建立其他物件的工具。它是一個函式或方法,它從某些方法呼叫返回物件或類,返回“新”物件的函式或方法可以稱為“工廠”,如工廠方法或工廠函式。
“kivy.factory.Factory”類建立類的例項並將它們新增到視窗部件樹中。視窗部件樹控制使用者介面上的元素。
以下是如何使用 Factory 註冊自定義按鈕類的示例。
from kivy.factory import Factory
from kivy.uix.button import Button
Factory.register('MyCustomButton', cls=Button)
btn = MyCustomButton( text: "Click me")
類似地,您可以使用 Factory 建立一個類:
from kivy.factory import Factory
from kivy.uix.label import Label
class MyLabel(Label):
pass
Factory.register('MyLabel', cls=MyLabel)
lbl = MyLabel(text: "Hello world")
預設情況下,透過工廠註冊的第一個類名是永久的。如果要更改註冊的類,則需要在重新分配它之前取消註冊類名。
from kivy.factory import Factory
Factory.register('NewWidget', cls=NewWidget)
widget = Factory.NewWidget()
Factory.unregister('NewWidget')
Factory.register('NewWidget', cls=CustomWidget)
customWidget = Factory.NewWidget()
示例
以下 Kivy 應用程式使用 Factory 註冊 MyPopup 類,該類是 Kivy 庫中的 Popup 小部件。
Kivy App 類程式碼如下:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
Window.size = (720,400)
Builder.load_file('popup.kv')
class MyLayout(Widget):
pass
class FactorydemoApp(App):
def build(self):
return MyLayout()
FactorydemoApp().run()
為了填充應用程式視窗,請使用以下“kv”指令碼 (popup.kv)
#:import Factory kivy.factory.Factory
<MyPopup@Popup>
auto_dismiss: False
size_hint: 0.6, 0.4
pos_hint: {"x":0.2, "top": 0.9}
title: "Popup Box"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Hello Kivy"
font_size: 24
Button:
text: "Close"
font_size: 24
on_release: root.dismiss()
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Factory Example"
font_size: 32
Button:
text: "Click here"
font_size: 32
on_release: Factory.MyPopup().open()
如您所見,MyPopup 類在 Factory 中註冊,並且當單擊按鈕時會呼叫其 open() 方法。
輸出
執行程式以顯示帶有“單擊此處”按鈕的視窗。單擊它時,彈出視窗將出現在應用程式視窗上。
Kivy - 手勢
Kivy 框架能夠記錄和識別手勢。手勢是由滑鼠指標或手指在多點觸控裝置上生成的一系列觸控操作。kivy.gesture 模組定義了 Gesture 類,其物件由在 Kivy 畫布上捕獲的連續觸控事件的 (x,y) 座標獲得。Kivy 中的手勢是 Oleg Dopertchouk 手勢識別演算法的 Python 實現。
同一個模組還包含 GestureDatabase 類。您可以在手勢資料庫中儲存一個或多個 Gesture 物件,並找出某個手勢是否與資料庫中已儲存的任何手勢匹配。
要建立 Gesture 物件,您需要一個 x,y 座標列表。例如 -
from kivy.gesture import Gesture g = Gesture() g.add_stroke(point_list=[(1,1), (3,4), (2,1)]) g.normalize()
add_stroke() 方法根據座標對構建手勢物件。normalize() 方法用於執行手勢歸一化演算法並計算與自身的點積。
此類 Gesture 物件儲存在 GestureDatabase 中。
from kivy.gesture import Gesture, GestureDatabase # Create a gesture gdb = GestureDatabase() gdb.add_gesture(g)
您可以針對儲存在此資料庫中的物件比較另一個特定物件,並查詢資料庫中的任何手勢是否匹配。
g2 = Gesture() # ... gdb.find(g2)
kivy.gesture 模組在 Gesture 類中定義了以下方法 -
add_stroke() - 從觸控點列表構造手勢的筆畫,並返回 Stroke 例項。
normalize() - 執行手勢歸一化演算法並計算與自身的點積。
get_score() - 當一個手勢與另一個手勢匹配時,此方法返回匹配分數。
GestureDatabase 類具有以下重要方法 -
add_gesture() - 向資料庫新增一個新的手勢。
find() - 在資料庫中查詢匹配的手勢。您可以使用 min_score 引數定義查詢的精度。它應該在 0 到 1 之間。
gesture_to_str(gesture) - 將手勢轉換為唯一的字串。
str_to_gesture(data) - 將唯一的字串轉換為手勢。
示例
我們定義 touch_down()、touch_move() 和 touch_up() 處理程式來捕獲觸控點並從中繪製圖案。所有帶 (touch.x 和 touch.y) 座標的點都收集在一個列表中。
按下“新增”按鈕時,該列表用於構造一個 Gesture。gesture_to_string() 方法返回一個二進位制字串。
if instance.text=='Add': g = Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() print (self.d.gdb.gesture_to_str(g)) self.d.gdb.add_gesture(g) print (str(g))
手勢字串的示例可能如下所示 -
b'eNprYJmayc4ABj082ZlllXrpqcUlpUWpU3rY3aGsyVM0G6fUTtHoYS3PTCnJmOLuYO9kuU766IwetozUzPSMEqCIC9NEhiUOGj38UO3xBUX5KaXJICmhWZ/F3Pse9LAXlxTlZ6cWT4mdksHQwws1PRgsiLCDrSA/M68EpEgDqIoHqioAJIhQxFgxxX3/LdkuHrnEhh7Gyinu9g9vmvlOTnlRmpQhCFGTIQJXkSHqbn9/U85stZMXcMrfxiZ/TfZI/b2QH8TIXydH/pLsv8/zPDJA8pfJkT9jU3RuT/kBYuTPp4ACaAGq/AmbtU412Qo45Q/YKmn+CRIAyR+nUP4wWD4BVX5DtZ7Sj8IHIPltJ4EeUHdAlY9n/VPH/4ABJL92MtAAvwaS5O3n8Z6ZJZ8Gkt9fDLK/hwGn/CJQ8G1E078eZP5TB5D8RlDyunEAp/xOkPxNNPO3N3WGd3CD/Lf/AND4TTlo5u9vEingUAHLnwDLo4aP/eED54+4yH3AKX/8wNSAFu0JIPkzYHnU8Lc/fSDqzhELUPzuvwBynpkBqvz5AwqZLC4LQPJXwPKo4W9/8f6nX4s0iJK/hk3+6v0dbY9MNUDyNyiUvwNzf2oPT3FyUWpqHqKccHdIcNSwvsgQ4+5QGrZn4XqNnLYpyGJOuwTWtWijiultr197/w2qGNum2DXTs8FiE3XfGfUrYRcrubfWerXfa7DYQ+MFU2RfAsW2rZBcxQZWl2hoGfR1zXocYn2Lvq/Y+wosFmmjo1YijCq20vFeB9NNoFja3KvLS7NQxYJmuyy7qAkWu+iyfccpW6CY3YzNy3Qgen+6T3g5cQFQTGua0tKOVSCxJE9fZ2+FdKCY2OSJS55kgsUKA2Sqn59ydyh+15e/ePZLVLFb3fcWfV8JFpsJcrIuUOxYp++i4ExUsU1toIAGix0MPXe3bCJQbF6L9kKuF2CxlxEr+Gy/AMXK6jnnH8oAiSULRjfas4ajilnGReWf2Q0US6qpmC+nDhZLTAQGqhxQzK/y+bzKF6hiVuVhc6+uAIt1pvBcjG4EiqmVHJ1rmA4W25j2jEnpKQ4xoSKTOb3qKGJF/4BB8OI5SCyFMWdG8sbVOMRe5QrNdlmOKnYtq3HWArAdKZr5hVMq+ZHEUkuTEns4S/JzUosS85JTgTXUzpkgMKs0SQ8Ayq8zuw=='
您可以新增任意數量的手勢。
然後,在畫布上繪製一個圖案,並嘗試找出是否有任何手勢與此圖案匹配。當按下“查詢”按鈕時,find() 方法會執行此操作。
if instance.text=='Find': g=Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() g1=self.d.gdb.find(g, 0.65) print (g1)
以下是手勢識別練習的完整程式碼 -
from kivy.app import App
from kivy.graphics import *
from kivy.uix.floatlayout import FloatLayout
from kivy.gesture import Gesture, GestureDatabase
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from random import random
from kivy.core.window import Window
Window.size = (720, 400)
class Drawgesture(Widget):
points = []
def __init__(self, *args, **kwargs):
super(Drawgesture, self).__init__()
self.gdb = GestureDatabase()
def on_touch_down(self, touch):
with self.canvas:
self.col = (random(), random(), random())
Color(self.col)
touch.ud["line"] = Line(points=(touch.x, touch.y), width=3)
Drawgesture.points.append((touch.x, touch.y))
def on_touch_move(self, touch):
with self.canvas:
Color(self.col)
touch.ud["line"].points += (touch.x, touch.y)
Drawgesture.points.append((touch.x, touch.y))
def on_touch_up(self, touch):
print('touch up')
class gestureApp(App):
def pressed(self, instance):
if instance.text == 'Add':
g = Gesture()
g.add_stroke(point_list=Drawgesture.points)
g.normalize()
print(self.d.gdb.gesture_to_str(g))
self.d.gdb.add_gesture(g)
print(str(g))
if instance.text == 'Find':
g = Gesture()
g.add_stroke(point_list=Drawgesture.points)
g.normalize()
g1 = self.d.gdb.find(g, 0.65)
print(g1)
if instance.text == 'Clear':
self.d.canvas.clear()
def build(self):
f = FloatLayout()
self.d = Drawgesture()
f.add_widget(self.d)
b1 = Button(
text='Add', pos_hint={'x': 0, 'y': 0},
size_hint=(None, None)
)
f.add_widget(b1)
b2 = Button(
text='Find', pos_hint={'x': .2, 'y': 0},
size_hint=(None, None)
)
f.add_widget(b2)
b3 = Button(
text='Clear', pos_hint={'x': .4, 'y': 0},
size_hint=(None, None)
)
f.add_widget(b3)
b1.bind(on_press=self.pressed)
b2.bind(on_press=self.pressed)
b3.bind(on_press=self.pressed)
return f
gestureApp().run()
輸出
如果匹配分數大於或等於 min_score 引數,則您將獲得以下結果 -
(0.7093289348205829, <kivy.gesture.Gesture object at 0x000001B817C70490>)
Kivy - 語言
本章解釋了 Kivy 設計語言的重要特性、語法和用法。Kivy 語言(也稱為“kv”語言)主要描述 Kivy 應用程式的使用者介面。它類似於 Qt 的 QML。 “kv”語言中的規則定義類似於 CSS 規則。
目的
Kivy 應用程式中視窗小部件的佈局和放置被編碼到 Kivy 的 App 類的 build() 方法中。對於使用者介面更簡單的應用程式,這可能效果很好。但是,隨著佈局設計的複雜性增加,它很快就會變得過於冗長且難以維護。因此,需要將應用程式的設計部分與處理邏輯分離。“kv”語言有助於實現這種關注點分離。
使用“kv”語言指令碼,您可以以宣告方式建立視窗小部件樹,並以更自然的方式將視窗小部件屬性繫結到回撥。以程式設計方式設計介面的缺點之一是,在應用程式執行之前無法檢視外觀。另一方面,kviewer 實用程式提供了設計和視窗小部件放置的互動式檢視,而無需在應用程式中載入指令碼。
載入“kv”指令碼
一旦視窗小部件的設計完成,它就會載入到 App 類中。這可以透過兩種方式完成。
使用命名約定
將“kv”指令碼儲存為“.kv”副檔名,並將其名稱與 App 類的名稱對應。如果 App 類名稱以 app 關鍵字結尾,則必須省略它。例如,如果 App 類命名為 DemoApp,如下所示,
Class DemoApp(App): ... ...
則 kv 檔案應命名為 demo.kv。Kivy 會自動將設計載入到 App 類的 build() 方法中。如果 kv 檔案定義了一個根視窗小部件,它將附加到 App 的 root 屬性,並用作應用程式視窗小部件樹的基礎。
使用 Builder 類
如果“kv”檔案的名稱不遵循上述約定,則可以使用“kivy.lang”模組中提供的 Loader 類的 load_file() 方法將指令碼載入到應用程式中。
from kivy.app import App
from kivy.lang import Builder
Builder.load_file('mykv.kv')
MydemoApp(App):
def build(self):
pass
MydemoApp().run()
您還可以將整個“kv”語言指令碼作為字串嵌入到 Python 程式碼中,並使用 Builder.load_string() 方法在 App 類中載入它。
from kivy.app import App
from kivy.lang import Builder
kv="""
#kv script goes here
"""
MydemoApp(App):
def build(self):
Builder.load_string(kv)
MydemoApp().run()
“kv”語言具有以下重要元素 -
規則 - “kv”中的規則類似於 CSS 規則。它適用於特定視窗小部件或繼承指定視窗小部件類的類。“kv”規則可以指定互動行為或用於新增它們所應用的視窗小部件的圖形表示。
根視窗小部件 - 您可以使用該語言建立整個使用者介面。“kv”檔案最多隻能包含一個根視窗小部件。
動態類 - 動態類允許您即時建立新的視窗小部件和規則,無需任何 Python 宣告。
kv 指令碼描述了視窗小部件的內容。您可以擁有一個根規則和任意數量的類或模板規則。根規則透過宣告根視窗小部件的類來宣告,不縮排,後跟“:”符號。它設定 App 例項的 root 屬性。
Widget:
要宣告類規則,請將視窗小部件類的名稱放在“< >”之間,後跟“:”符號。它定義了該類任何例項的外觀和行為 -
<MyWidget>:
Kv 語言規則使用縮排進行分隔,與 Python 原始碼相同。要記住的經驗法則是,帶有尖括號的是規則,沒有尖括號的是根視窗小部件。
示意圖示例 -
<MyClass>:
prop1: value1
prop2: value2
canvas:
CanvasInstruction1:
canvasprop1: value1
CanvasInstruction2:
canvasprop2: value2
AnotherClass:
prop3: value1
有三個特定於“kv”語言的關鍵字 -
self - 始終指當前視窗小部件。
Button: text: 'My state is %s' % self.state
root - 指當前規則中的基視窗小部件,並表示規則的根視窗小部件(規則的第一個例項) -
<MyWidget>:
custom: 'Hello world'
Button:
text: root.custom
app - 始終指應用程式的例項。
Label: text: app.name
Kivy 應用程式視窗只能包含一個小部件作為其根物件。但是,如果您需要使用多個控制元件來組合應用程式介面,則必須使用佈局小部件,並將多個 UX 小部件放置在其中,然後將佈局作為根小部件放在應用程式視窗上。
以下“kv”檔案指令碼定義了一個網格佈局,然後可以將其與 App 類一起使用 -
GridLayout:
cols:1
Label:
text:'Hello'
font_size:100
color:(1,0,0,1)
Button:
text='Ok'
font_size:100
在上述情況下,Label 視窗小部件和 Button 位於一個列的 GridLayout 中。但是,無法從 Python 程式碼中訪問物件及其屬性。要能夠這樣做,請在“kv”指令碼中定義 id 屬性。
GridLayout:
cols:1
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
Button:
id:b1
text='Ok'
font_size:60
當此佈局載入到 build() 方法中時,App 類可以透過此 id 訪問視窗小部件屬性。它有一個 ids 屬性,它是一個包含 id:value 鍵值對的字典。
print (self.ids.l1.text)
讓我們從以下 kv 指令碼開始,它包含網格佈局中的標籤和按鈕。
GridLayout:
cols:1
Label:
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
text:'Hello'
font_size:60
Button:
text:'Ok'
font_size:60
Kivy 應用程式程式碼載入上述“kvdemo.kv”指令碼 -
from kivy.app import App
from kivy.core.window import Window
Window.size = (720,400)
class KvDemoApp(App):
def build(self):
pass
KvDemoApp().run()
讓我們在 Kivy 應用程式中新增一個事件處理程式。要訪問視窗小部件屬性,我們為標籤、文字輸入和按鈕定義 id 屬性。我們在“kv”指令碼中定義了一個類規則,並在頂部用尖括號括住 MyWidget。
<MyWidget>:
cols:1
size:root.size
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
id:t1
text:'Hello'
font_size:60
Button:
id:b1
text:'Ok'
font_size:60
on_press:root.callback(*args)
請注意,按鈕的 on_press 屬性繫結到我們將在根類(即 MyWidget 類)中編寫的 callback() 方法。
MyWidget 類繼承 GridLayout 視窗小部件。在類內部,提供了一個 callback() 方法。當按下按鈕時,它會將標籤標題更新為文字框中輸入的文字。
在“kvdemoapp.py”程式碼中新增以下類 -
from kivy.uix.gridlayout import GridLayout
class MyWidget(GridLayout):
def callback(self, *args):
print ("hello")
self.ids.l1.text=self.ids.t1.text
執行程式後,在文字框中輸入一些文字,然後按下按鈕。標籤上的文字將相應更改。
我們也可以僅在“kv”指令碼中提供整個邏輯。我們不需要在 Python 類中定義回撥。從“kv”程式碼中使用標籤和文字輸入的 id 屬性。
<MyWidget>:
cols:1
size:root.size
Label:
id:l1
text:'Hello'
font_size:60
color:(1,0,0,1)
TextInput:
id:t1
text:'Hello'
font_size:60
Button:
id:b1
text:'Ok'
font_size:60
on_press: l1.text=t1.text
在這裡,on_press 事件將標籤(id 為 l1)的文字設定為 id 為“t1”的文字框中的文字。在 Python 程式碼端,MyWidget 類將只有一個 pass 語句。
因此,我們可以看到,使用“kv”設計語言使應用程式開發變得非常方便,因為程式設計部分和設計部分是隔離的。
Kivy - 圖形
Kivy 框架配備了強大的圖形功能,這些功能構建在 OpenGL 和 SDL 指令之上。Kivy 與許多圖形工具包一樣,提供了一個畫布來渲染圖形。但是,Kivy 的畫布與在其他框架中找到的 Canvas 物件不同,例如 HTML5 中的 Canvas,甚至 Python 的 TKinter 庫中的 Canvas。讓我們嘗試瞭解在 Kivy 中使用圖形的不同之處。
在 Kivy 中,圖形畫布是一組繪圖指令,用於定義視窗小部件的圖形表示,您可以將其視為無限的繪圖板。儘管 Kivy 庫中的每個 GUI 視窗小部件都有一個 Canvas,但所有 Kivy 視窗小部件共享相同的座標空間,您可以在其中繪製。座標空間不受視窗或應用程式視窗大小的限制,因此我們甚至可以在可見區域之外繪製。
Kivy 中有兩種型別的圖形指令 -
頂點指令 - 用於繪製基本幾何形狀(如線條、矩形、橢圓等)的指令稱為頂點指令。
上下文指令 - 這些指令不繪製任何內容,而是操縱整個座標空間,以便為其新增顏色、旋轉、平移和縮放它。
某個上下文指令對畫布物件的影響 - 例如,如果我們將旋轉指令應用於按鈕的畫布 - 將在所有後續圖形指令中可見,因為所有視窗小部件都共享座標空間。
頂點指令
OpenGL 使用頂點來描述其圖形物件。頂點指令是繪製圖形的指令。常見的頂點指令包括 Point、Line、Triangle、Rectangle、Ellipse、Mesh、Bezier 等。Kivy - 繪製章節詳細解釋了繪圖指令的使用。
上下文指令
Kivy 的圖形指令包括 Rotate、Translate 和 Scale 指令。它們是應用於頂點指令的上下文指令,這些指令顯示在座標空間中
旋轉
Rotate 指令在物件的畫布上下文中工作。物件以給定角度和沿給定軸旋轉。
with self.canvas: rotate = Rotate(angle=45)
旋轉是根據傳遞給它的引數執行的。
angle - 獲取/設定旋轉角度的屬性。範圍在 0 到 360 之間
axis - 獲取/設定旋轉軸的屬性。軸的格式為 (x, y, z)。
origin - 旋轉的原點。原點的格式可以是 (x, y) 或 (x, y, z)。
set(float angle, float ax, float ay, float az) - 此函式設定旋轉的角度和軸。
縮放
Scale 指令在物件的畫布上下文中工作。它根據縮放比例更改物件沿給定軸的大小。
with self.canvas: s=Scale(2,2,1)
Scale 指令可以使用一個或三個引數建立。
Scale(x, y, z)
Scale 指令接受以下引數:
origin - 縮放的原點。原點的格式可以是 (x, y) 或 (x, y, z)。
x - 獲取/設定 X 軸縮放比例的屬性。
y - 獲取/設定 Y 軸縮放比例的屬性。
z - 獲取/設定 Z 軸縮放比例的屬性。
xyz - 3D 中 x、y 和 z 軸上的 3 元組縮放向量。
特定物件畫布下的縮放和旋轉指令會導致整個畫布發生變化,因為畫布共享相同的座標空間。因此,為了檢索其他部件的位置和狀態,有 PushMatrix 和 PopMatrix 指令。
PushMatrix 儲存當前座標空間上下文。
PopMatrix 檢索最後儲存的座標空間上下文。
因此,由 PushMatrix 和 PopMatrix 包圍的變換指令(Scale、Rotate 和 Translate)不會影響介面的其餘部分。
示例
我們首先在應用視窗上放置一個標籤和兩個按鈕。我們使用 FloatLayout,它使我們能夠自由地在特定座標處放置部件並指定其大小。
透過在標籤的畫布上繪製一個彩色矩形,為標籤提供背景顏色。
self.lbl = Label( text= 'Hello World', font_size=24, halign='center',size_hint=(.2, .1), pos=(300, 250) ) with self.lbl.canvas: Color(0, 1, 0, 0.25) Rectangle(pos=self.lbl.pos, size=(200,50))
按鈕標題“Rotate”繫結到 update_rotate() 方法,該方法應用 45 度旋轉。請注意,PushMatrix 在旋轉前儲存座標空間,並在旋轉後呼叫 PopMatrix。
def update_rotate(self, instance):
with self.lbl.canvas.before:
PushMatrix()
rotate = Rotate(angle=45)
with self.lbl.canvas.after:
PopMatrix()
rotate.origin = self.lbl.center
當按下“Scale”按鈕時,會導致“Rotate”按鈕沿 X 和 Y 軸縮放。為此目的的 update_scale() 方法如下所示:
def update_scale(self, instance):
with self.btn.canvas.before:
PushMatrix()
s = Scale(2, 2, 1)
with self.btn.canvas.after:
PopMatrix()
s.origin = self.btn.center
完整的示例程式碼如下所示:
from kivy.app import App
from kivy.graphics import *
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.core.window import Window
Window.size = (720, 400)
class RotationApp(App):
def update_rotate(self, instance):
with self.lbl.canvas.before:
PushMatrix()
rotate = Rotate(angle=45)
with self.lbl.canvas.after:
PopMatrix()
rotate.origin = self.lbl.center
def update_scale(self, instance):
with self.btn.canvas.before:
PushMatrix()
s = Scale(2, 2, 1)
with self.btn.canvas.after:
PopMatrix()
s.origin = self.btn.center
def build(self):
root = FloatLayout()
self.lbl = Label(
text='Hello World', font_size=24,
halign='center', size_hint=(.2, .1),
pos=(300, 250)
)
with self.lbl.canvas:
Color(0, 1, 0, 0.25)
Rectangle(pos=self.lbl.pos, size=(200, 50))
self.btn = Button(
text='Rotate', size_hint=(None, None),
pos_hint={'center_x': .3, 'center_y': .1}
)
root.add_widget(self.lbl)
self.btn1 = Button(
text='Scale', size_hint=(None, None),
pos_hint={'center_x': .6, 'center_y': .1}
)
self.btn.bind(on_press=self.update_rotate)
self.btn1.bind(on_press=self.update_scale)
root.add_widget(self.btn)
root.add_widget(self.btn1)
return root
RotationApp().run()
輸出
執行以上程式碼。當您點選“Rotate”按鈕時,“Hello World”標籤將旋轉 45 度。
點選“Scale”按鈕。它將更改“Rotate”按鈕沿 X 和 Y 軸的尺寸。
Kivy - 繪製
Kivy 庫中的所有 GUI 部件都具有 Canvas 屬性。Canvas 是用於繪製各種物件(例如矩形、橢圓等)的地方。需要注意的是,Kivy 沒有單獨的 Canvas 部件用於繪製形狀。所有部件的畫布共享一個公共的座標空間。
在 Kivy 中,繪製是在與任何部件相關的 Canvas 上完成的,使用頂點指令和上下文指令。
頂點指令 - 用於繪製基本幾何形狀(如線條、矩形、橢圓等)的指令稱為頂點指令。
上下文指令 - 這些指令不繪製任何內容,而是操縱整個座標空間,以便為其新增顏色、旋轉、平移和縮放它。
頂點指令
這些指令以不同頂點物件的格式新增到 Canvas 中。頂點類在 kivy.graphics.vertex_instructions 模組中定義。如上所述,繪圖指令新增到 Canvas 的上下文中。
with self.canvas: vertex(**args)
vertex_instructions 模組包含以下類:
Bezier
BorderImage
Ellipse
Line
Mesh
Point
Quad
Rectangle
RoundedRectangle
SmoothLine
Triangle
Bezier
貝塞爾曲線由一些控制點加權,這些控制點包含在指令中。在 Kivy 中,Bezier 是一種頂點畫布指令,它根據作為引數提供給 Beizer 建構函式的一組點繪製此曲線。
from kivy.graphics import Beizer with self.canvas: Beizer(**args)
引數
Bezier 類中定義了以下引數:
points - 點列表,格式為 (x1, y1, x2, y2…)
loop - bool,預設為 False,將貝塞爾曲線設定為連線最後一個點到第一個點。
segments - int,預設為 180。定義繪製曲線所需的段數。更多的段數會導致更平滑的繪製。
dash_length - 段的長度(如果虛線),預設為 1。
dash_offset - 一段的末端與下一段的起始之間的距離,預設為 0。更改此值會使其成為虛線。
示例
self.w=Widget()
with self.w.canvas:
Color(0,1,1,1)
Bezier(
points=[700,400,450,300,300,350,350, 200,200,100,150,10],
segments=20
)
Color(1,1,0,1)
Point(
points =[700,400,450,300,300,350,350, 200,200,100,150,10],
pointsize= 3
)
輸出
它將生成以下輸出視窗:
此處顯示的點僅供參考。
Ellipse
在 Kivy 框架中,Ellipse 是一個頂點指令。根據所需的段數,它可以顯示多邊形、矩形或弧形。如果寬度和高度引數相等,則結果為圓形。
from kivy.graphics import Ellipse with self.canvas: Ellipse(**args)
引數
Ellipse 類中定義了以下引數:
pos - 給出橢圓中心 X 和 Y 座標值的兩個元素元組。
size - 定義橢圓寬度和高度(以畫素為單位)的兩個元素元組。
angle_start - float,預設為 0.0,指定起始角度(以度為單位)。
angle_end - float,預設為 360.0,指定結束角度(以度為單位)。
segments - 橢圓的段數。如果您有許多段,則橢圓繪製將更平滑。使用此屬性建立具有 3 個或更多邊的多邊形。小於 3 的值將不會顯示。
示例
self.w=Widget() with self.w.canvas: Color(0.5, .2, 0.4, 1) d = 250 Ellipse(pos=(360,200), size=(d+75, d))
輸出
它將生成以下輸出視窗:
Rectangle
此頂點指令根據作為引數給定的位置和尺寸在畫布上繪製一個矩形。
from kivy.graphics import Rectangle with self.canvas: Rectangle(**args)
引數
Rectangle 類中定義了以下引數:
pos - 整數列表,指定矩形的位置,格式為 (x, y)。
size - 整數列表,指定矩形的大小,格式為 (width, height)。
繪製填充有特定顏色的矩形是為標籤提供背景的推薦方法。
示例
def build(self):
widget = Widget()
with widget.canvas:
Color(0, 0, 1, 1)
Rectangle(
pos=(50, 300), size_hint=(None, None),
size=(300, 200)
)
lbl = Label(
text='Hello World', font_size=24,
pos=(Window.width / 2, 300), size=(200, 200),
color=(0, 0, 1, 1)
)
with lbl.canvas.before:
Color(1, 1, 0)
Rectangle(pos=lbl.pos, size=lbl.size)
widget.add_widget(lbl)
return widget
輸出
它將生成以下輸出視窗:
需要注意的是,Quad 是一個四邊形,是一個具有四個頂點的多邊形,不一定是矩形。類似地,圓角矩形是一個具有圓角頂點的矩形。
Line
在 Kivy 圖形中,Line 是一個基本的頂點指令。Line 物件建構函式的 points 屬性具有連續點的 x 和 y 座標。Kivy 繪製一條依次連線這些點的線。
from kivy.graphics import Line with self.canvas: Line(**args)
引數
Line 類中定義了以下引數:
points - 點列表,格式為 (x1, y1, x2, y2…)
dash_length - int,段的長度(如果虛線),預設為 1。
dash_offset - 一段的末端與下一段的起始之間的偏移量,預設為 0。更改此值會使其成為虛線。
dashes - 格式為 [ON 長度,偏移量,ON 長度,偏移量,…] 的整數列表。例如 [2,4,1,6,8,2] 將建立一個線條,第一個虛線長度為 2,然後偏移量為 4,然後虛線長度為 1,然後偏移量為 6,依此類推。
width - float - 定義線條的寬度,預設為 1.0。
示例
def build(self):
box = BoxLayout(orientation='vertical')
self.w = Widget()
with self.w.canvas:
Color(1, 0, 0, 1)
Line(
points=[700, 400, 450, 300, 300, 350, 350, 200, 200, 100, 150, 10],
width=4
)
box.add_widget(self.w)
return box
輸出
它將生成以下輸出視窗:
Line 類還具有 bezier、ellipse、circle、rectangle 屬性,線條點用於繪製相應的形狀。
Triangle
使用此頂點指令,Kivy 使用 points 列表繪製一個三角形。
from kivy.graphics import Triangle with self.canvas: Triangle(**args)
points 屬性是三角形三個頂點的 x 和 y 座標列表,格式為 (x1, y1, x2, y2, x3, y3)。
示例
self.w=Widget() with self.w.canvas: Color(1,1,1,1) self.triangle = Triangle(points=[100,100, 300,300, 500,100])
輸出
它將生成以下輸出視窗:
更新繪圖
需要注意的是,所有圖形指令類的列表屬性(例如 Triangle.points、Mesh.indices 等)不是 Kivy 屬性,而是 Python 屬性。因此,修改此列表不會更新繪圖。只有當列表物件本身發生更改時才會更新,而不是當列表值被修改時。
讓我們透過將點 (300,300) 更改為 (400,300) 來更改上述矩形的頂點。我們在上述佈局中新增一個按鈕,並將其繫結到一個更新方法。
示例
以下是完整程式碼:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
from kivy.properties import ObjectProperty
from kivy.core.window import Window
Window.size = (720, 400)
class mytriangleapp(App):
triangle = ObjectProperty(None)
title = "Drawing app"
def updating(self, *args):
self.triangle.points[3] = 400
self.triangle.points = self.triangle.points
def build(self):
box = BoxLayout(orientation='vertical')
self.w = Widget()
with self.w.canvas:
Color(1, 1, 1, 1)
self.triangle = Triangle(points=[100, 100, 300, 300, 500, 100])
self.b1 = Button(
text='update', on_press=self.updating,
size_hint=(None, .1)
)
box.add_widget(self.w)
box.add_widget(self.b1)
return box
mytriangleapp().run()
輸出
執行上述程式時,我們會看到一個三角形和一個按鈕。當點選按鈕時,“triangle.points”列表會更新,從而更新三角形的繪製。
Kivy - 打包
術語“打包”是指建立應用程式原始碼的單個包,以及所有依賴項,包括庫、資料檔案配置檔案等。
當您開發 Kivy 應用時,它需要各種資源。例如,常見的要求是 sdl2 包或 glew 包。當您安裝 Kivy 時,這些依賴項也會被安裝。
kivy-deps.glew kivy-deps.gstreamer kivy-deps.sdl2
到目前為止,您一直在從已安裝 Python 執行時的機器上執行 Kivy 應用。但是,當需要將此應用移植到另一臺未安裝 Python 的機器時,您需要構建一個包含程式以及 Python 執行時和依賴項的包。
PyInstaller 包可幫助您構建應用的可重新分發包。使用者無需安裝 Python、Kivy 或任何其他庫即可執行應用。
要構建這樣的可重新分發包,您應該首先使用 PIP 命令在當前的 Kivy 環境中安裝 PyInstaller。
pip3 install -U pyinstaller
下一步是將一個或多個 Python 原始檔(副檔名為 .py)以及其他資源(例如影像檔案等)收集到一個單獨的資料夾中。
在本練習中,我們將為 ImageButton 應用構建一個包。此應用的檔案儲存在 imgbtn 資料夾中。
Directory of C:\kivyenv\imgbtn forward.png main.py pause.png play.png previous.png
建立另一個資料夾 ImangBtnApp,該資料夾最終將儲存可重新分發包。在資料夾內,執行以下命令:
(kivyenv) C:\kivyenv\ImageBtnApp>pyinstaller -n ImageBtnApp c:\kivyenv\imgbtn\main.py
Kivy 應用有很多依賴項。因此,收集所有依賴項可能需要一段時間。最終,ImageButtonApp 資料夾將填充以下內容:
Directory of C:\kivyenv\ImageBtnApp 27-07-2023 21:25 <DIR> . 27-07-2023 21:07 <DIR> .. 27-07-2023 21:25 <DIR> build 27-07-2023 21:28 <DIR> dist 27-07-2023 21:25 970 ImageBtnApp.spec
dist 資料夾是可重新分發資料夾,其中您將找到 EXE 檔案“ImageBtnApp.exe”,以及所需的 DLL 庫(例如 sdl2 等)。
有一個與應用名稱相同的 spec 檔案。我們需要編輯 spec 檔案以新增依賴項鉤子以正確構建 exe。
使用您喜歡的編輯器開啟 spec 檔案,並在 spec 的開頭新增以下行:
from kivy_deps import sdl2, glew
向下滾動 spec 檔案以找到 COLLECT 部分,併為依賴項的每個路徑新增一個 Tree 物件。例如,*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)]。
coll = COLLECT(
exe, Tree('c:\\kivyenv\\imgbtn\\'),
a.binaries,
a.zipfiles,
a.datas,
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
strip=False,
upx=True,
upx_exclude=[],
name='ImageBtnApp',
)
現在,我們使用以下命令在 ImageBtnApp 中構建 spec 檔案:
python -m PyInstaller ImageBtnApp.spec
編譯後的包將位於 ImageBtnApp\dist\ImageBtnApp 目錄中。
您還可以將執行時、應用程式程式碼和依賴項放在一個檔案中(而不是可重新分發包中),方法是使用 Pyinstaller 命令列語法的 -onetime 開關:
pyinstaller --onefile -n ImageBtnApp
要構建針對 Android 的可重新分發包,您需要使用 Buildozer 工具。它會下載並設定 python-for-android 的所有先決條件,包括 android SDK 和 NDK,然後構建一個可以自動推送到裝置的 apk。
導航到您的專案目錄並執行:
buildozer init
這將建立一個控制構建配置的 buildozer.spec 檔案。使用您的應用名稱等編輯該檔案。您可以設定變數來控制傳遞給 python-for-android 的大部分或所有引數。最後,插入您的 Android 裝置並執行:
buildozer android debug deploy run
以構建、推送並在您的裝置上自動執行 APK。
Kivy - Garden
Kivy Garden 是個人使用者開發的 Kivy 部件的儲存庫。這是一個由使用者維護的專案,其目標是集中 Kivy 的附加元件。使用者貢獻的 Kivy 包託管在 Kivy Garden 儲存庫 https://github.com/kivy-garden 上。
使用者開發並上傳到 Garden 儲存庫的部件稱為 Flowers。Kivy Garden 中的花有兩種型別。在 Kivy 1.11.0 版本之前的花是舊版花。要安裝舊版花部件,您需要使用以下命令:
garden install flower-name
舊版花不是正確的 Python 包,並且名稱以 garden 字首附加。例如,用作 Kivy 的 Matplotlib 後端的部件是 garden.matplotlib。
另一方面,新花是 Python 包,它們託管在 PyPI 儲存庫上,因此可以使用常規的 pip 實用程式安裝。
pip install flower
現代的 Kivy 花(擴充套件)沒有 garden 字首。例如,mapview 控制元件提供了一個容器,用於在 Kivy 應用中顯示互動式地圖。
pip install mapview
您可以直接從 github 安裝 master 分支。例如,以下命令安裝 graph 花(擴充套件):
python -m pip install
https://github.com/kivy-garden/graph/archive/master.zip
示例
讓我們在 Kivy 應用中使用 mapview 花(擴充套件):
from kivy_garden.mapview import MapView
from kivy.app import App
from kivy.core.window import Window
Window.size = (720,400)
class MapViewApp(App):
def build(self):
mapview = MapView(zoom=11, lat=50.6394, lon=3.057)
return mapview
MapViewApp().run()
輸出
執行此程式碼時,它將生成以下輸出視窗:
Kivy - 儲存
Kivy 框架中的 Storage 類用於透過索引條目載入和儲存任意數量的鍵值對。 "kivy.storage" 模組定義了 AbstractStore 類。其實現 - **DictStore**、**JsonStore** 和 **RedisStore** - 提供了具體的類。
kivy.storage.dictstore.DictStore:使用 Python 字典作為儲存。
kivy.storage.jsonstore.JsonStore:使用 JSON 檔案作為儲存。
kivy.storage.redisstore.RedisStore:使用 Redis 資料庫和 redis-py 庫。
要使用上述任何儲存類,請匯入相關的類,宣告一個物件並呼叫其 put() 方法來儲存鍵值對。對於 JsonStore:
from kivy.storage.jsonstore import JsonStore
store = JsonStore('hello.json')
# put some values
store.put(name, key1=val1, key2=val2)
這將在當前目錄中建立 hello.json 檔案。您可以使用 get() 方法檢索資訊。
print (store.get(name)[key])
AbstractStore 類中定義了以下方法,這些方法需要由具體的實現(如 DictStore)覆蓋:
**clear()** - 清空整個儲存。
**count()** - 返回儲存中條目的數量。
**delete(key)** - 從儲存中刪除一個鍵。如果未找到該鍵,則會丟擲 KeyError 異常。
**exists(key)** - 檢查儲存中是否存在某個鍵。
**find(**filters)** - 返回與過濾器匹配的所有條目。條目透過生成器作為 (key, entry) 對列表返回,其中 entry 是鍵值對的字典。
**get(key)** - 獲取儲存在鍵處的鍵值對。如果未找到該鍵,則會丟擲 KeyError 異常。
**keys()** - 返回儲存中所有鍵的列表。
**put(key, **values)** - 將新的鍵值對(在 values 中給出)放入儲存中。任何現有的鍵值對都將被刪除。
這些方法 (get()、put()、exists()、delete()、find()) 都有非同步版本。這些方法可以帶或不帶回調引數呼叫。如果給出回撥引數,則請求將是非同步的,並在結果可用時將其返回給使用者。如果回撥引數為 None,則請求將是同步的,結果將直接返回。
示例
以下是一個示例:
# synchronous res=store.get(key) print (res) # asynchronous def my_callback(store, key, result): print (result) store.get(key)
回撥函式應具有以下引數:
**store** - 當前使用的 "Store" 例項。
**key** - 搜尋的鍵。
**result** - 對鍵進行查詢的結果。
示例
from kivy.storage.jsonstore import JsonStore
from kivy.storage.dictstore import DictStore
store = JsonStore('store.json')
# put some values
store.put('state', name='Maharashtra', capital='Mumbai',
population='Eleven Cr')
store.put('os', name='Windows', version=11, released=2021)
store.put('shape', type='circle', radius=5)
# using the same index key erases all previously added k-v pairs
# get a value using a index key and key
print('Population of ', store.get('state')['name'], 'is ',
store.get('state')['population'])
print (store.get('state').keys())
for k,v in store.get('state').items():
print (k,":",v)
# or guess the key/entry for a part of the key
for item in store.find(type='circle'):
print('Store:',item[0])
print('K-V pairs: ',str(item[1]))
輸出
它將產生以下輸出 -
Population of Maharashtra is Eleven Cr
dict_keys(['name', 'capital', 'population'])
name : Maharashtra
capital : Mumbai
population : Eleven Cr
Store: shape
K-V pairs: {'type': 'circle', 'radius': 5}
Kivy - 向量
在歐幾里得幾何中,向量是一個表示具有大小和方向的物理量的物件。Kivy 庫包含 Vector 類,並提供執行二維向量運算的功能。
Vector 類定義在 kivy.vector 模組中。Kivy 的 Vector 類繼承了 Python 的內建列表類。透過在笛卡爾座標系中傳遞 x 和 y 座標值來例項化 Vector 物件。
from kivy.vector import Vector v=vector(10,10)
這兩個引數可以透過下標運算子訪問。第一個引數是 v[0],第二個引數是 v[1]。
print (v[0], v[1])
它們也被識別為 Vector 物件的 x 和 y 屬性。
print (v.x, v.y)
您還可以透過將兩個值的列表或元組傳遞給建構函式來初始化向量。
vals = [10,10] v = Vector(vals)
示例
Kivy 中的 Vector 類支援由常見的算術運算子 +、-、/ 表示的向量運算。
兩個向量 (a,b)+(c,d) 的加法結果為向量 (a+c, b+d)。類似地,"(a,b) - (c,d)" 等於 "(a - c, b - d)"。
from kivy.vector import Vector
a = (10, 10)
b = (87, 34)
print ("addition:",Vector(1, 1) + Vector(9, 5))
print ("Subtraction:",Vector(9, 5) - Vector(5, 5))
print ("Division:",Vector(10, 10) / Vector(2., 4.))
print ("division:",Vector(10, 10) / 5.)
輸出
addition: [10, 6] Subtraction: [4, 0] Division: [5.0, 2.5] division: [2.0, 2.0]
Vector 類中的方法
以下方法定義在 Kivy 的 Vector 類中:
angle()
它計算向量與引數向量之間的角度,並以度為單位返回角度。
在數學上,向量之間的角度由以下公式計算:
$$\theta =cos^{-1}\left [ \frac{x\cdot y}{\left| x\right|\left|y \right|} \right ]$$
查詢角度的 Kivy 程式碼如下:
示例
a=Vector(100, 0)
b=(0, 100)
print ("angle:",a.angle(b))
輸出
angle: -90.0
distance()
它返回兩點之間的距離。兩個向量之間的歐幾里得距離由以下公式計算:
$$d\left ( p,q \right )=\sqrt{\left ( q_{1}-p_{1} \right )^{2}+\left ( q_{2}-p_{2} \right )^{2}}$$
distance() 方法更易於使用。
示例
a = Vector(90, 33)
b = Vector(76, 34)
print ("Distance:",a.distance(b))
輸出
Distance: 14.035668847618199
distance2()
它返回兩點之間的距離的平方。兩個向量 x = [ x1, x2 ] 和 y = [ y1, y2 ] 之間的平方距離是其座標的平方差之和。
示例
a = (10, 10)
b = (5,10)
print ("Squared distance:",Vector(a).distance2(b))
輸出
Squared distance: 25
dot(a)
計算 "a" 和 "b" 的點積。點積(也稱為標量積)是向量 b 的大小乘以 "a" 在 "b" 上的投影的大小。投影的大小為 $cos\theta$(其中 $\theta$ 是兩個向量之間的角度)。
示例
print ("dot product:",Vector(2, 4).dot((2, 2)))
輸出
dot product: 12
length()
它返回向量的長度。length2() 方法返回向量的長度的平方。
示例
pos = (10, 10)
print ("length:",Vector(pos).length())
print ("length2:",Vector(pos).length2())
輸出
length: 14.142135623730951 length2: 200
rotate(angle)
以度為單位旋轉向量。
示例
v = Vector(100, 0)
print ("rotate:",v.rotate(45))
輸出
rotate: [70.71067811865476, 70.71067811865476]
Kivy - 工具
Kivy 庫中的 "kivy.utils" 模組是各種類別(如數學、顏色、代數函式等)中通用實用函式的集合。
QueryDict
QueryDict 類的物件類似於 Python 的內建 dict 類。此外,它還提供了一個使用點 (.) 運算子查詢物件的機制。
要構造 QueryDict,您可以傳遞一個由兩個元素組成的元組列表,或者傳遞一個字典物件本身。
# list of tuples
qd = QueryDict([('a',1), ('b',2)])
print (qd)
列表的每個元組元素都應該有兩個專案。第一個專案是鍵,第二個專案是其值。
{'a': 1, 'b': 2}
另一方面,您可以將字典物件本身傳遞給 QueryDict 建構函式。
qd=QueryDict({'a':1, 'b':2})
雖然可以使用標準 dict 中定義的 [] 運算子獲取屬於某個鍵的值,但 QueryDict 提供了一個點運算子。因此,"qd.k" 與 "qd['k']" 相同。請注意,dict 類的 get() 方法也可以與 QueryDict 一起使用。
您可以使用傳統的切片運算子賦值或點運算子更新鍵的值。
qd.a=100 qd['b']=200
請嘗試以下 **示例**:
from kivy.utils import *
# list of tuples
qd=QueryDict([('a',1), ('b',2)])
print (qd)
print (qd.a, qd['a'])
qd=QueryDict({'a':1, 'b':2})
print (qd)
print (qd.b, qd['b'])
print (qd.get('a'))
qd.a=100
qd['b']=200
print (qd)
SafeList
Kivy 中的 SafeList 類繼承了內建的 list 類。除了從 list 繼承的方法之外,SafeList 類中還定義了一個新方法 - clear()。它刪除列表中的所有專案。
您可以將可變序列(列表)傳遞給建構函式以建立 SafeList 物件。如果未傳遞引數,則它將建立一個空列表。呼叫 clear() 方法將刪除所有專案。
示例
from kivy.utils import *
sl = SafeList([1,2,3,4])
print ("SafeList:",sl)
l = [1,2,3,4]
sl = SafeList(l)
print ("SafeList:",sl)
sl.clear()
print ("SafeList:",sl)
輸出
SafeList: [1, 2, 3, 4] SafeList: [1, 2, 3, 4] SafeList: []
difference()
此函式返回兩個列表之間的差集。更具體地說,它從第一個列表中刪除在第二個列表中找到的那些專案。
示例
from kivy.utils import *
l1=[1,2,3,4]
l2=[3,4,5,6]
print (l1, l2)
print ("l1-l2:",difference(l1,l2))
print ("l2-l1:",difference(l2,l1))
輸出
[1, 2, 3, 4] [3, 4, 5, 6] l1-l2: [1, 2] l2-l1: [5, 6]
escape_markup()
Kivy 應用視窗上的 Label 能夠顯示標記文字。但是,如果您希望標記符號的效果不生效,則可以轉義文字中找到的標記字元。這旨在用於在 Label 上啟用標記文字時使用。
在下面的示例中,要顯示在標籤上的文字包含 [b] 和 [/b] 標記標籤,這將使測試變為粗體。但是,要忽略此效果,文字將傳遞給 escape_markup() 函式。
示例
from kivy.app import App
from kivy.uix.label import Label
from kivy.utils import escape_markup
from kivy.core.window import Window
Window.size = (720,400)
class HelloApp(App):
def build(self):
text = 'This is an [b]important[/b] message'
text = '[color=ff0000]' + escape_markup(text) + '[/color]'
lbl=Label(text=text, font_size=40, markup=True)
return lbl
HelloApp().run()
輸出
get_color_from_hex()
將十六進位制字串顏色轉換為 kivy 顏色。顏色屬性的 RGBA 值在 0 到 1 之間。由於 RGB 值範圍為 0 到 255,因此 Kivy 顏色值將數字除以 255。因此,RGB 值 50、100、200 分別表示為 50/255、100/255 和 200/255。
十六進位制顏色值作為字串給出,每個 RGB 值都有 2 個十六進位制數字,並以 "#" 符號為字首。get_color_from_hex() 函式將十六進位制字串轉換為 Kivy 顏色值。
示例
from kivy.utils import *
c = get_color_from_hex("#00ff00")
print (c)
輸出
[0.0, 1.0, 0.0, 1.0]
get_hex_from_color(color)
將 kivy 顏色轉換為十六進位制值:
示例
from kivy.utils import * c = get_hex_from_color([0,1,0,1]) print (c)
輸出
#00ff00ff
rgba()
從十六進位制字串或 0-255 值列表返回 kivy 顏色(0-1 範圍內的 4 個值)。
示例
from kivy.utils import *
# from RGBA color values
c = rgba([100,150,200, 255])
print ("from RGBA:",c)
# from hex string
c = rgba('#3fc4e57f')
print ("from hex string:",c)
輸出
from RGBA: [0.39215686274509803, 0.5882352941176471, 0.7843137254901961, 1.0] from hex string: [0.24705882352941178, 0.7686274509803922, 0.8980392156862745, 0.4980392156862745]
Kivy - 檢查器
Kivy 提供了一個非常有用的工具,稱為 Inspector,它可以幫助您糾正使用 "kv" 指令碼或以程式設計方式實現設計的介面時遇到的問題。Inspector 工具具有命令列介面,也可以從程式碼中使用。
命令列用法如下:
python main.py -m inspector
要以程式設計方式使用它,請在 "kivy.modules.inspector" 模組中呼叫 create_inspector() 函式。
from kivy.modules import inspector
class Demo(App):
def build(self):
button = Button(text="Test")
inspector.create_inspector(Window, button)
return button
顯然,命令列用法更方便。讓我們瞭解一下此工具的實用性。
假設您已經開發了一個帶有 slider.py 程式的 Kivy 應用,該程式具有以下介面。
該應用有三個滑塊控制元件,可以幫助更改上面文字的顏色。
從命令提示符使用以下命令啟動程式:
python sliderdemo.py -m inspector
將顯示上述螢幕。按 ctrl+E 鍵顯示 Inspector 工具欄。
可以將工具欄移動到頂部或底部以方便使用。單擊視窗上的任何元件。寬按鈕顯示所單擊控制元件的物件 ID。現在按 Parent 按鈕。所選控制元件的父控制元件將被突出顯示。
雙擊寬按鈕。它現在將顯示三個帶分隔符的面板以調整大小。左窗格顯示控制元件樹,中間窗格顯示所選控制元件的所有屬性,右側窗格顯示所選屬性的值。
下圖顯示從控制元件樹中選擇了 BLUE 滑塊,其屬性顯示在中間窗格中,並且 max 屬性值顯示在右側窗格中。
您還可以從 Inspector 工具更改屬性值。向下滾動中間窗格以找到 value 屬性,並在右側窗格的文字框中更改其值。
Inspector 工具在對使用者介面進行故障排除時非常有用。
Kivy - 工具
"kivy.tools" 模組包含一些非常有用的指令碼、命令列實用程式和示例。
KV Viewer
Kivy 沒有任何官方的視覺化 GUI 設計器。因此,Kivy 應用的佈局設計變得很繁瑣,因為在建立 "kv" 檔案時計劃的控制元件放置在載入到應用中時往往不會產生預期的結果。
此 Kv-viewer 實用程式允許您動態顯示 "kv" 檔案,並考慮其更改。此實用程式的優點之一是,只有在您對佈局滿意時才能載入此 "kv" 指令碼。
KViewer 是一個命令列實用程式,需要 ".kv" 檔案作為引數。
python kviewer.py demo.kv
示例
以下 "kv" 檔案包含 Demo 應用的設計:
TabbedPanel:
size_hint: .8, .8
pos_hint: {'center_x': .5, 'center_y': .5}
do_default_tab: False
TabbedPanelItem:
text:"Register Tab"
GridLayout:
cols:2
Label:
text:"Name"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.75}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.65}
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
TabbedPanelItem:
text:'Login Tab'
GridLayout:
cols:2
Label:
text:"email"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.55}
TextInput:
size_hint:(.4, .1)
pos_hint:{'x':.3, 'y':.45}
Label:
text:"Password"
size_hint:(.2, .1)
pos_hint:{'x':.2, 'y':.35}
TextInput:
password:True
size_hint:(.4, .1)
pos:(400, 150)
pos_hint:{'x':.3, 'y':.25}
Button:
text:'Submit'
size_hint : (.2, .1)
pos_hint : {'center_x':.5, 'center_y':.09}
輸出
讓我們使用 kviewer 實用程式檢視設計:
python kviewer.py demo.kv
它將生成以下輸出視窗:
Benchmark
此指令碼執行並顯示一組基準測試的結果。這些提供了一組指標,主要旨在衡量您系統的 OpenGL 效能。
要執行實用程式,請使用以下命令:
Python benchmark.py
您將獲得以下 **輸出**:
GL Vendor: b'Intel' GL Renderer: b'Intel(R) Iris(R) Xe Graphics' GL Version: b'4.6.0 - Build 31.0.101.3959' Benchmark --------- 1/8 Core: button creation (10000 * 10 a-z) 4.246505 2/8 Core: button creation (10000 * 10 a-z), with Clock.tick [INFO ] [GL ] NPOT texture support is available 6.612230 3/8 Core: label creation (10000 * 10 a-z) 4.543708 4/8 Core: label creation (10000 * 10 a-z), with Clock.tick 9.790683 5/8 Widget: creation (10000 Widget) 0.308506 6/8 Widget: creation (10000 Widget + 1 root) 1.734984 7/8 Widget: event dispatch (1000 on_update in 10*1000 Widget) 0.088639 8/8 Widget: empty drawing (10000 Widget + 1 root) 0.000706 Result: 27.325960 Do you want to send benchmark to gist.github.com (Y/n) : n No benchmark posted.
Generate Icons
此工具將幫助您生成 Google Play 商店、App Store、Amazon 商店所需的所有圖示。
您需要提供要從中生成圖示的影像檔案的名稱,作為 tools 子目錄中 generate-icons.py 指令碼的引數。
python GPIcon.png
您將獲得以下 **輸出**:
Generate App store high resolution: 1024x1024 Generate App store normal resolution: 512x512 Generate iPhone (iOS 7): 120x120 Generate iPhone @2 (iOS 7): 120x120 Generate iPad (iOS 7): 76x76 Generate iPad @2 (iOS 7): 152x152 Generate iPhone (iOS >= 6.1): 57x57 Generate iPhone @2 (iOS >= 6.1): 114x114 Generate iPad (iOS >= 6.1): 72x72 Generate iPad @2 (iOS >= 6.1): 114x114 Generate iTunes Artwork (ad-hoc): 512x512 Generate iTunes Artwork @2 (ad-hoc): 1024x1024 Generate Google Play icon: 512x512 Generate Launcher icon MDPI: 48x48 Generate Launcher icon HDPI: 72x72 Generate Launcher icon XHDPI: 96x96 Generate Launcher icon XXHDPI: 48x48 Generate Launcher icon XXXHDPI: 192x192 Generate Small icon: 114x114 Generate Large icon: 512x512
此實用程式生成的圖示儲存在各自的資料夾中:
Report Tool
此工具是使用者的幫助工具。它生成在除錯過程中有用的轉儲資訊。
Python report.py
部分 **輸出** 如下所示:
==============================================================
Options
==============================================================
window = ('egl_rpi', 'sdl2', 'pygame', 'sdl', 'x11')
text = ('pil', 'sdl2', 'pygame', 'sdlttf')
video = ('gstplayer', 'ffmpeg', 'ffpyplayer', 'null')
audio = ('gstplayer', 'pygame', 'ffpyplayer', 'sdl2', 'avplayer')
image = ('tex', 'imageio', 'dds', 'sdl2', 'pygame', 'pil', 'ffpy', 'gif')
camera = ('opencv', 'gi', 'avfoundation', 'android', 'picamera')
spelling = ('enchant', 'osxappkit')
clipboard = ('android', 'winctypes', 'xsel', 'xclip',
'dbusklipper', 'nspaste', 'sdl2', 'pygame', 'dummy', 'gtk3')
The report will be sent as an anonymous gist.
Do you accept to send report to https://gist.github.com/
(Y/n) : n
No report posted.
Enter any key to leave.
Kivy - 日誌記錄器
Python 的標準庫包含 logging 模組,該模組有助於在 Python 應用中實現健壯的事件日誌系統。Kivy 的日誌記錄機制在其基礎上構建,並具有一些附加功能,例如在受支援的終端上進行顏色編碼的輸出、訊息分類等。
每次執行 Kivy 應用時,您都會在控制檯視窗中看到顯示的日誌。它看起來像這樣:
[INFO ] [Logger ] Record log in C:\Users\user\.kivy\logs\kivy_23-07-10_67.txt [INFO ] [deps ] Successfully imported "kivy_deps.gstreamer" 0.3.3 [INFO ] [deps ] Successfully imported "kivy_deps.angle" 0.3.3 [INFO ] [deps ] Successfully imported "kivy_deps.glew" 0.3.1 [INFO ] [deps ] Successfully imported "kivy_deps.sdl2" 0.6.0 [INFO ] [Kivy ] v2.2.0 [INFO ] [Kivy ] Installed at "c:\kivyenv\Lib\sitepackages\kivy\__init__.py" [INFO ] [Python ] v3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] [INFO ] [Python ] Interpreter at "c:\kivyenv\Scripts\python.exe" [INFO ] [Logger ] Purge log fired. Processing... [INFO ] [Logger ] Purge finished! [INFO ] [Factory ] 190 symbols loaded [INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil (img_ffpyplayer ignored) [INFO ] [Window ] Provider: sdl2 [INFO ] [GL ] Using the "OpenGL" graphics system [INFO ] [GL ] GLEW initialization succeeded [INFO ] [GL ] Backend used <glew> [INFO ] [GL ] OpenGL version <b'4.6.0 - Build 31.0.101.3959'> [INFO ] [GL ] OpenGL vendor <b'Intel'> [INFO ] [GL ] OpenGL renderer <b'Intel(R) Iris(R) Xe Graphics'> [INFO ] [GL ] OpenGL parsed version: 4, 6 [INFO ] [GL ] Shading version <b'4.60 - Build 31.0.101.3959'> [INFO ] [GL ] Texture max size <16384> [INFO ] [GL ] Texture max units <32> [INFO ] [Window ] auto add sdl2 input provider [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked [INFO ] [Text ] Provider: sdl2 [INFO ] [Base ] Start application main loop [INFO ] [GL ] NPOT texture support is available
這些訊息會告訴你哪些硬體和驅動程式已被檢測和初始化,哪些未能完成。
Kivy 庫中的 Logger 類提供了一個單例例項,並在 kivy.logger 模組中定義。除了 Python 的 logging 模組中的日誌記錄級別(debug、info、warning、error 和 critical)之外,Kivy 還增加了一個 trace 級別。
Logger 物件具有與上述日誌記錄級別相對應的方法。這些方法中的每一個都接受一個字串引數 - message - 分成兩部分,用冒號 ( : ) 符號分隔。第一部分用作標題,冒號後的字串是日誌訊息。
from kivy.logger import Logger
Logger.info('title: This is a info message.')
Logger.debug('title: This is a debug message.')
預設的日誌記錄級別在 Kivy 的配置檔案中設定為 info。因此,你會看到這麼長的日誌輸出。你可以透過 Logger 物件的 setlevel() 方法將其設定為任何所需的日誌記錄級別。
from kivy.logger import Logger, LOG_LEVELS Logger.setLevel(LOG_LEVELS["debug"])
Kivy 的日誌記錄機制由一個環境變數 KIVY_LOG_MODE 控制,它有三個可能的值:KIVY、PYTHON、MIXED。
預設的 KIVY_LOG_MODE 是 KIVY,因此係統中的所有日誌訊息都會輸出到 Kivy 日誌檔案和控制檯。
如果你將其設定為 PYTHON 模式,則不會新增任何處理程式,並且不會捕獲 sys.stderr 輸出。它留給客戶端新增合適的處理程式。
在 MIXED 模式下,處理程式直接新增到 Kivy 的 Logger 物件中,並且關閉傳播。sys.stderr 沒有被重定向。
所有與日誌記錄相關的配置引數都可以在 config.ini 檔案的 [Kivy] 部分找到。引數及其預設值如下:
log_dir = logs log_enable = 1 log_level = info log_name = kivy_%y-%m-%d_%_.txt log_maxfiles = 100
請注意,即使日誌記錄器未啟用,你也可以訪問最後 100 個 LogRecords。
from kivy.logger import LoggerHistory print(LoggerHistory.history)
Kivy - 幀緩衝區
Kivy 庫提供了一個名為“Fbo”的類,它代表幀緩衝區離屏。它是一個離屏視窗,你可以在上面繪製任何圖形指令,然後將其用作某個 Kivy 視窗小部件畫布的紋理。
Fbo 類在 kivy.graphics.fbo 模組中定義。第一步是建立 fbo 並將 fbo 紋理用於其他矩形。
from kivy.graphics import Fbo, Color, Rectangle with self.canvas: self.fbo = Fbo(size=self.size)
接下來,將圖形指令(如 Rectangle)新增到 Fbo 物件。例如:
with self.fbo: Color(1, 0, 0, .8) Rectangle(size=(256, 64)) Color(0, 1, 0, .8) Rectangle(size=(64, 256))
最後,將 Fbo 紋理應用於畫布。
self.texture = self.fbo.texture
請注意,如果 OpenGL 上下文丟失,則 FBO 會丟失。在這種情況下,你需要使用 Fbo.add_reload_observer() 方法重新上傳資料。
add_reload_observer(callback) − 在整個圖形上下文重新載入後,新增一個要呼叫的回撥函式。回撥引數將是上下文字身。
bind() 方法將 FBO 物件繫結到當前的 opengl 上下文。這樣,所有繪圖操作都將在幀緩衝區內進行,直到呼叫 release() 為止。release() 方法釋放或解除幀緩衝區的繫結。
self.fbo = FBO() self.fbo.bind() # do any drawing command self.fbo.release() self.canvas = self.fbo.texture
還有一個 remove_reload_observer(callback) 方法,它從觀察者列表中刪除之前由 add_reload_observer() 新增的回撥函式。
clear_buffer() 和 clear_color 方法清除幀緩衝區和清除顏色,顏色格式為 (red, green, blue, alpha)。
示例
以下程式碼演示了在 Kivy 應用程式中使用幀緩衝區的方法。程式碼的重要部分是一個名為 FboFloatLayout 的類,它繼承了 Kivy 的 FloatLayout 類。
建構函式(__init__() 方法)在浮動佈局的畫布上建立一個 Fbo 物件,在其上繪製一個矩形,並將其紋理設定為畫布的紋理。
def __init__(self, **kwargs):
self.canvas = Canvas()
with self.canvas:
self.fbo = Fbo(size=self.size)
self.fbo_color = Color(1, 1, 1, 1)
self.fbo_rect = Rectangle()
with self.fbo:
ClearColor(0, 0, 0, 0)
ClearBuffers()
self.texture = self.fbo.texture
super(FboFloatLayout, self).__init__(**kwargs)
我們將向此 FloatLayout 類新增一個按鈕,但在新增之前,需要重寫 add_widget() 方法,以便將圖形指令新增到 fbo 中,然後將其新增到畫布中。
def add_widget(self, *args, **kwargs): canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*args, **kwargs) self.canvas = canvas return ret
FboFloatLayout 類還具有響應大小、位置和紋理變化的回撥函式。
def on_size(self, instance, value): self.fbo.size = value self.texture = self.fbo.texture self.fbo_rect.size = value def on_pos(self, instance, value): self.fbo_rect.pos = value def on_texture(self, instance, value): self.fbo_rect.texture = value
現在到 App 類。build() 方法新增一個按鈕並應用一系列動畫效果,這些效果會反覆更改按鈕的位置,從上到下,從右到左。
def anim_btn(*args):
animate = Animation(pos=(b.pos[0], Window.height - 50))
animate += Animation(pos=(b.pos[0], 0))
animate += Animation(pos_hint={'center_x': 1})
animate += Animation(pos_hint={'center_x': 0})
animate += Animation(pos_hint={'center_x': .5})
animate.start(b)
animate.repeat = True
b.bind(on_press=anim_btn)
為了方便起見,這些程式碼片段都放在了完整程式碼列表中。
from kivy.graphics import Color, Rectangle, Canvas,
ClearBuffers, ClearColor
from kivy.graphics.fbo import Fbo
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty, NumericProperty
from kivy.app import App
from kivy.animation import Animation
from kivy.core.window import Window
Window.size = (720, 400)
class FboFloatLayout(FloatLayout):
texture = ObjectProperty(None, allownone=True)
def __init__(self, **kwargs):
self.canvas = Canvas()
with self.canvas:
self.fbo = Fbo(size=self.size)
self.fbo_color = Color(1, 1, 1, 1)
self.fbo_rect = Rectangle()
with self.fbo:
ClearColor(0, 0, 0, 0)
ClearBuffers()
self.texture = self.fbo.texture
super(FboFloatLayout, self).__init__(**kwargs)
def add_widget(self, *args, **kwargs):
canvas = self.canvas
self.canvas = self.fbo
ret = super(FboFloatLayout, self).add_widget(*args, **kwargs)
self.canvas = canvas
return ret
def on_size(self, instance, value):
self.fbo.size = value
self.texture = self.fbo.texture
self.fbo_rect.size = value
def on_pos(self, instance, value):
self.fbo_rect.pos = value
def on_texture(self, instance, value):
self.fbo_rect.texture = value
class FBOdemoApp(App):
def build(self):
f = FboFloatLayout()
b = Button(text="FBO", size_hint=(None, None), pos_hint={'center_x': .5})
f.add_widget(b)
def anim_btn(*args):
animate = Animation(pos=(b.pos[0], Window.height - 50))
animate += Animation(pos=(b.pos[0], 0))
animate += Animation(pos_hint={'center_x': 1})
animate += Animation(pos_hint={'center_x': 0})
animate += Animation(pos_hint={'center_x': .5})
animate.start(b)
animate.repeat = True
b.bind(on_press=anim_btn)
return f
FBOdemoApp().run()
輸出
應用程式以底部帶有 FBO 標題的按鈕開始。單擊時,它將開始執行定義的動畫效果。
Kivy - 繪圖應用
在本章中,我們將學習開發一個簡單的 Kivy 應用程式,該應用程式允許使用者透過拖動滑鼠按鈕來繪製不同尺寸和顏色的填充矩形和圓形(橢圓)。
使用者從預期矩形/橢圓的左上角拖動滑鼠指標到右下角。以下程式碼開發中使用的方法是在 touch_down 事件和 touch_up 事件中捕獲滑鼠座標。因此,我們在 App 類的 build() 方法中用此程式碼啟動程式:
def build(self): self.w= Widget() self.w.bind(on_touch_down=self.on_touch_down) self.w.bind(on_touch_up=self.on_touch_up) return(self.w)
我們希望允許使用者選擇繪製矩形或圓形。需要新增三個切換按鈕,用於選擇繪製哪種形狀或清除畫布。因此,我們將 App 視窗的佈局更改為 box 佈局,在頂部新增 Widget 物件,並在其下方放置三個按鈕。
lo = BoxLayout(orientation='vertical') self.w = Widget() self.w.bind(on_touch_down=self.on_touch_down) self.w.bind(on_touch_up=self.on_touch_up) lo.add_widget(self.w) hlo = BoxLayout(orientation='horizontal', size_hint=(1, .1)) self.b2 = ToggleButton(text='Circle', group='mode') self.b1 = ToggleButton(text='Rectangle', state='down', group='mode') self.b3 = ToggleButton(text='Clear', group='mode') hlo.add_widget(self.b1) hlo.add_widget(self.b2) hlo.add_widget(self.b3) lo.add_widget(hlo) return lo
要繪製所需的形狀,我們需要在觸碰按下和觸碰抬起時捕獲滑鼠位置。
on_touch_down() 方法很簡單:
def on_touch_down(self, *args): self.td = args[1].pos
所有處理都在 on_touch_up() 方法中進行。捕獲的按下事件和抬起事件的座標用於計算矩形或圓形的尺寸。
對於圓形,x 半徑、y 半徑和中心計算如下:
self.tu=args[1].pos xr = (self.tu[0]-self.td[0])/2 yr = (self.td[1]-self.tu[1])/2 c=(self.td[0]+xr, self.td[1]-yr)
我們需要寬度和高度以及繪製矩形的左上角座標。self.td 元組給出左上角點,xr*2 給出寬度,yr*2 給出高度。
形狀繪製在視窗小部件畫布上。我們選擇隨機顏色進行繪製。按下按鈕的 text 屬性告訴我們繪製的形狀:
color = (random(), random(), random())
with self.w.canvas:
Color(*color)
if self.btn=='Rectangle':
Rectangle(pos=self.td, size=(xr*2,yr*2))
if self.btn=='Circle':
Ellipse(pos=(c), size=(xr,yr))
三個切換按鈕繫結到一個方法。如果標題是 Clear,則清除視窗小部件畫布。
def clear_canvas(self, instance, value):
self.btn = instance.text
self.press = True
if value == 'down' and self.btn == 'Clear':
self.w.canvas.clear()
return True
示例
應用程式的完整程式碼如下:
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line, Rectangle
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (720, 400)
class MyPaintApp(App):
def clear_canvas(self, instance, value):
self.btn = instance.text
self.press = True
if value == 'down' and self.btn == 'Clear':
self.w.canvas.clear()
return True
def on_touch_down(self, *args):
self.td = args[1].pos
def on_touch_up(self, *args):
if self.press == True:
self.press = False
return True
self.tu = args[1].pos
xr = (self.tu[0] - self.td[0]) / 2
yr = (self.td[1] - self.tu[1]) / 2
c = (self.td[0] + xr, self.td[1] - yr)
color = (random(), random(), random())
with self.w.canvas:
Color(*color)
if self.btn == 'Rectangle':
Rectangle(pos=self.td, size=(xr * 2, yr * 2))
if self.btn == 'Circle':
Ellipse(pos=(c), size=(xr, yr))
def build(self):
self.press = False
self.btn = 'Rectangle'
lo = BoxLayout(orientation='vertical')
self.w = Widget()
self.w.bind(on_touch_down=self.on_touch_down)
self.w.bind(on_touch_up=self.on_touch_up)
lo.add_widget(self.w)
hlo = BoxLayout(orientation='horizontal', size_hint=(1, .1))
self.b2 = ToggleButton(text='Circle', group='mode')
self.b1 = ToggleButton(text='Rectangle', state='down', group='mode')
self.b3 = ToggleButton(text='Clear', group='mode')
self.b1.bind(state=self.clear_canvas)
self.b2.bind(state=self.clear_canvas)
self.b3.bind(state=self.clear_canvas)
hlo.add_widget(self.b1)
hlo.add_widget(self.b2)
hlo.add_widget(self.b3)
lo.add_widget(hlo)
return lo
MyPaintApp().run()
輸出
執行以上程式碼。選擇要繪製的形狀。從左上角拖動滑鼠到右下角。矩形/圓形以隨機顏色繪製在不同的位置。
單擊“清除”按鈕清除畫布上的圖形。
Kivy - 計算器應用
在本章中,我們將學習使用 Kivy 庫構建一個計算器應用程式。計算器包含每個數字和運算子的按鈕。它應該有一個帶有“=”標題的按鈕來計算運算,還有一個按鈕來清除結果。
讓我們從以下設計開始:
以上佈局顯示頂部有一個輸入框,後面跟著一個用於按鈕的 3 列布局,除此之外,四個運算子按鈕排列在一列中。
我們將使用一個頂部網格佈局,該佈局有一列,並在其下方新增一個右對齊的 TextInput,在 TextInput 下方我們將放置另一個 2 列網格。此網格的左側單元格包含三列中的數字、= 和 C 按鈕。第二列是另一個用於所有算術運算子的一列網格。
以下“kv”檔案採用了此邏輯:
<calcy>:
GridLayout:
cols:1
TextInput:
id:t1
halign:'right'
size_hint:1,.2
font_size:60
GridLayout:
cols:2
GridLayout:
cols:3
size:root.width, root.height
Button:
id:one
text:'1'
on_press:root.onpress(*args)
Button:
id:two
text:'2'
on_press:root.onpress(*args)
Button:
id:thee
text:'3'
on_press:root.onpress(*args)
Button:
id:four
text:'4'
on_press:root.onpress(*args)
Button:
id:five
text:'5'
on_press:root.onpress(*args)
Button:
id:six
text:'6'
on_press:root.onpress(*args)
Button:
id:seven
text:'7'
on_press:root.onpress(*args)
Button:
id:eight
text:'8'
on_press:root.onpress(*args)
Button:
id:nine
text:'9'
on_press:root.onpress(*args)
Button:
id:zero
text:'0'
on_press:root.onpress(*args)
Button:
id:eq
text:'='
on_press:root.onpress(*args)
Button:
id:clr
text:'C'
on_press:root.onpress(*args)
GridLayout:
cols:1
size_hint:(.25, root.height)
Button:
id:plus
text:'+'
on_press:root.onpress(*args)
Button:
id:minus
text:'-'
on_press:root.onpress(*args)
Button:
id:mult
text:'*'
on_press:root.onpress(*args)
Button:
id:divide
text:'/'
on_press:root.onpress(*args)
請注意,每個按鈕都在其 on_press 事件上綁定了 onpress() 方法。
onpress() 方法基本上讀取按鈕標題(其 text 屬性)並決定操作過程。
如果按鈕的標題是數字,則將其附加到 TextInput 框的 text 屬性。
self.ids.t1.text=self.ids.t1.text+instance.text
如果按鈕表示任何算術運算子(+、-、*、/),則此時文字框中的數字將儲存在一個變數中以供進一步操作,並且文字框將被清除。
if instance.text in "+-*/": self.first=int(self.ids.t1.text) self.ids.t1.text='0' self.op=instance.text
如果按鈕的 text 屬性是“=”,則此時文字框中的數字是第二個運算元。執行適當的算術運算,並將結果顯示在文字框中。
if instance.text=='=': if self.first==0: return self.second=int(self.ids.t1.text) if self.op=='+': result=self.first+self.second if self.op=='-': result=self.first-self.second if self.op=='*': result=self.first*self.second if self.op=='/': result=self.first/self.second self.ids.t1.text=str(result) self.first=self.second=0
最後,如果按鈕的標題是 C,則文字框將設定為為空。
if instance.text=='C': self.ids.t1.text='' self.first=self.second=0
示例
以上“kv”檔案載入到 App 類的 build() 方法中。以下是完整程式碼:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.size = (720,400)
class calcy(GridLayout):
def __init__(self, **kwargs):
super(calcy, self).__init__(**kwargs)
self.first=self.second=0
def onpress(self, instance):
if instance.text=='C':
self.ids.t1.text=''
self.first=self.second=0
elif instance.text in "+-*/":
self.first=int(self.ids.t1.text)
self.ids.t1.text='0'
self.op=instance.text
elif instance.text=='=':
if self.first==0: return
self.second=int(self.ids.t1.text)
if self.op=='+': result=self.first+self.second
if self.op=='-': result=self.first-self.second
if self.op=='*': result=self.first*self.second
if self.op=='/': result=self.first/self.second
self.ids.t1.text=str(result)
self.first=self.second=0
else:
self.ids.t1.text=self.ids.t1.text+instance.text
class calculatorapp(App):
def build(self):
return calcy(cols=3)
calculatorapp().run()
輸出
執行以上程式並使用此應用程式執行所有基本的算術計算。
Kivy - 計時器應用
在本章中,我們將使用 Python 的 Kivy GUI 框架構建一個秒錶應用程式。秒錶測量從開始事件到停止事件之間經過的時間。例如,用於測量運動員完成 100 米跑所需時間的秒錶。
應用程式的 GUI 設計應類似於下圖:
以下“kv”指令碼用於放置兩個標籤和兩個按鈕,如上圖所示。頂部標籤將用於顯示當前時間,底部標籤將用於顯示計時器啟動後經過的時間。左側按鈕用於啟動/停止秒錶。右側的按鈕將計時器重置為 0。
BoxLayout:
orientation: 'vertical'
Label:
id: time
font_size:40
markup:True
text: '[b]00[/b]:00:00'
BoxLayout:
orientation: 'horizontal'
padding: 20
spacing: 20
height: 90
size_hint: (1, None)
Button:
text: 'Start'
id: start_stop
on_press : app.start_stop()
Button:
id: reset
text: 'Reset'
on_press: app.reset()
Label:
id: stopwatch
font_size:40
markup:True
text:'00:00.[size=40]00[/size]'
在應用程式程式碼中,我們定義了一個 on_stop() 事件處理程式,該處理程式在 GUI 填充後立即呼叫。它安排一個時間事件處理程式,該處理程式每秒更新一次標籤的當前時間。
def on_start(self): Clock.schedule_interval(self.update_time, 0)
update_time() 方法更新顯示在上標籤(id 為 time)上的當前時間,以及顯示在下標籤(id 為 stopwatch)上的經過時間 - 如果計時器已啟動。
def update_time(self, t):
if self.sw_started:
self.sw_seconds += t
minutes, seconds = divmod(self.sw_seconds, 60)
part_seconds = seconds * 100 % 100
self.root.ids.stopwatch.text = "{:2d} : {:2d}.{:2d}".format(int(minutes), int(seconds), int(part_seconds))
self.root.ids.time.text = strftime('[b]%H[/b]:%M:%S')
id 為 start 的按鈕繫結到 start_stop() 方法,該方法儲存秒錶的狀態(已啟動還是已停止),並相應地更新 start 按鈕(id 為 start_stop)的標題。
def start_stop(self): self.root.ids.start_stop.text = 'Start' if self.sw_started else 'Stop' self.sw_started = not self.sw_started
右側的按鈕將時間計數器重置為 0,將另一個按鈕的標題設定為 start,並將底部標籤的標題重置為 0:0.0。
def reset(self):
if self.sw_started:
self.root.ids.start_stop.text = 'Start'
self.sw_started = False
self.sw_seconds = 0
示例
整個編碼邏輯在以下程式碼中給出:
from time import strftime
from kivy.clock import Clock
from kivy.app import App
from kivy.core.window import Window
Window.size = (720, 400)
class StopWatchApp(App):
sw_seconds = 0
sw_started = False
def update_time(self, t):
if self.sw_started:
self.sw_seconds += t
minutes, seconds = divmod(self.sw_seconds, 60)
part_seconds = seconds * 100 % 100
self.root.ids.stopwatch.text = "{:2d} : {:2d}.{:2d}".format(int(minutes), int(seconds), int(part_seconds))
self.root.ids.time.text = strftime('[b]%H[/b]:%M:%S')
def on_start(self):
Clock.schedule_interval(self.update_time, 0)
def start_stop(self):
self.root.ids.start_stop.text = 'Start' if self.sw_started else 'Stop'
self.sw_started = not self.sw_started
def reset(self):
if self.sw_started:
self.root.ids.start_stop.text = 'Start'
self.sw_started = False
self.sw_seconds = 0
StopWatchApp().run()
輸出
由於以上程式碼中 App 類的名稱是 StopWatchApp,因此其“kv”語言設計指令碼必須命名為“StopWatch.kv”,然後執行程式。
按下“開始”按鈕。計數器將開始,在底部標籤上顯示經過的時間。標題變為“停止”。再次按下它以停止時鐘執行。單擊“重置”按鈕將標籤恢復為“0”。
Kivy - 相機處理
Kivy 框架透過特定於平臺的提供程式支援相機硬體。“opncv-python”包可在大多數作業系統上為 Kivy 啟用相機支援。因此,建議在 Kivy 的工作環境中安裝 opencv-python 包。
在本章中,我們將使用 Kivy 庫的 Camera 類構建一個相機應用程式。相機視窗小部件以及一個 ToggleButton 和一個普通按鈕放置在垂直框佈局中以構建應用程式介面。
Camera 例項以初始播放狀態 True 開始,這意味著應用程式視窗將在載入後立即從相機啟動影片流。當 Toggle 按鈕按下時,它會停止相機。它繫結到 play() 方法。僅當相機正在播放時,Capture 按鈕才處於啟用狀態。
def play(self, instance):
if instance.state=='down':
self.mycam.play=False
instance.text='Play'
self.cb.disabled=True
else:
self.mycam.play=True
instance.text='Stop'
self.cb.disabled=False
Capture 按鈕透過呼叫 Camera 物件的 export_to_png() 方法將當前幀儲存到 PNG 檔案。
捕獲影像後,Kivy 會彈出一個標題為“影像已捕獲”的訊息框。
def capture(self, instance):
if self.tb.text == 'Stop':
self.mycam.export_to_png("IMG.png")
layout = GridLayout(cols=1)
popup = Popup(
title='Image Captured', title_size=24,
content=layout, auto_dismiss=True,
size_hint=(None, None), size=(300, 100)
)
popup.open()
其餘程式碼涉及在 build() 方法中組合應用程式介面。
示例
完整的程式碼如下:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.camera import Camera
from kivy.core.window import Window
Window.size = (720, 400)
class TestCamera(App):
def build(self):
box = BoxLayout(orientation='vertical')
self.mycam = Camera(play=True, resolution=(640, 480))
box.add_widget(self.mycam)
self.tb = ToggleButton(
text='Stop', size_hint_y=None,
height='48dp', on_press=self.play
)
box.add_widget(self.tb)
self.cb = Button(
text='Capture', size_hint_y=None, height='48dp',
disabled=False, on_press=self.capture
)
box.add_widget(self.cb)
return box
def play(self, instance):
if instance.state == 'down':
self.mycam.play = False
instance.text = 'Play'
self.cb.disabled = True
else:
self.mycam.play = True
instance.text = 'Stop'
self.cb.disabled = False
def capture(self, instance):
if self.tb.text == 'Stop':
self.mycam.export_to_png("IMG.png")
layout = GridLayout(cols=1)
popup = Popup(
title='Image Captured', title_size=24,
content=layout, auto_dismiss=True,
size_hint=(None, None), size=(300, 100)
)
popup.open()
TestCamera().run()
輸出
應用程式啟動時,相機例項載入。請注意,根據系統和相機裝置,啟動可能需要幾秒鐘。切換按鈕的標題為“停止”,捕獲按鈕已啟用。
如果按下“停止”按鈕,則捕獲按鈕將被停用。處於啟用狀態時,按下“捕獲”按鈕。當前幀將儲存為“img.png”,並彈出一個彈出框。
Kivy - 圖片檢視器
在本章中,我們將使用 Kivy 構建一個簡單的影像檢視器應用程式。以下程式碼使用 Kivy 的 Image 視窗小部件和按鈕來瀏覽所選資料夾中影像列表。還有一個按鈕可以開啟一個 FileChooser,讓使用者選擇不同的資料夾以檢視其中的影像。
首先,我們需要構建當前所選資料夾中所有影像檔案的列表。為此,我們使用 os.listdir() 方法。
import os
self.idx=0
self.fillist=[]
dir_path = '.'
for file in os.listdir(dir_path):
if file.endswith('.png'):
self.fillist.append(file)
應用程式介面的構建涉及一個垂直框佈局,其中 Image 物件放置在頂部,另一個水平框佈局包含三個按鈕。
lo=BoxLayout(orientation='vertical') self.img= Image(source=self.fillist[self.idx]) lo.add_widget(self.img) hlo=BoxLayout(orientation='horizontal', size_hint=(1, .1)) self.b1 = Button(text = 'Dir', on_press=self.onButtonPress) self.b2 = Button(text = 'Prev', on_press=self.previmg) self.b3 = Button(text = 'Next', on_press=self.nextimg) hlo.add_widget(self.b1) hlo.add_widget(self.b2) hlo.add_widget(self.b3) lo.add_widget(hlo)
影像部件(Image widget)開始時顯示第一個可用的影像。當點選標題為“Next”的按鈕時,指向檔案列表的索引會遞增;當點選“Previous”按鈕時,索引會遞減,並在影像物件中載入索引的影像檔案。
def previmg(self, instance): self.idx-=1 if self.idx<0: self.idx=0 self.img.source=self.fillist[self.idx] def nextimg(self, instance): self.idx+=1 if self.idx>=len(self.fillist): self.idx=len(self.fillist)-1 self.img.source=self.fillist[self.idx]
第三個按鈕(標題為Dir)會彈出一個檔案選擇器對話方塊。您可以選擇所需的資料夾進行檢視。
def onButtonPress(self, button):
layout=GridLayout(cols=1)
fw=FileChooserListView(dirselect=True, filters=["!*.sys"])
fw.bind(on_selection=self.onselect)
closeButton = Button(
text = "OK", size_hint=(None, None),
size=(100,75)
)
layout.add_widget(fw)
layout.add_widget(closeButton)
self.popup = Popup(
title='Choose Folder', content=layout,
auto_dismiss=False, size_hint=(None, None),
size=(400, 400)
)
self.popup.open()
示例
當前資料夾中的影像會填充檔案列表作為開始。以下是完整的程式碼:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.filechooser import FileChooserListView
from kivy.core.window import Window
Window.size = (720, 400)
class ImageViewerApp(App):
def previmg(self, instance):
self.idx -= 1
if self.idx < 0: self.idx = 0
self.img.source = self.fillist[self.idx]
def nextimg(self, instance):
self.idx += 1
if self.idx >= len(self.fillist): self.idx = len(self.fillist) - 1
self.img.source = self.fillist[self.idx]
def onButtonPress(self, button):
layout = GridLayout(cols=1)
fw = FileChooserListView(dirselect=True, filters=["!*.sys"])
fw.bind(on_selection=self.onselect)
closeButton = Button(
text="OK", size_hint=(None, None), size=(100, 75)
)
layout.add_widget(fw)
layout.add_widget(closeButton)
self.popup = Popup(
title='Choose Folder', content=layout,
auto_dismiss=False, size_hint=(None, None), size=(400, 400)
)
self.popup.open()
closeButton.bind(on_press=self.on_close)
def onselect(self, *args):
print(args[1][0])
def on_close(self, event):
self.popup.dismiss()
def build(self):
import os
self.idx = 0
self.fillist = []
dir_path = '.'
for file in os.listdir(dir_path):
if file.endswith('.png'):
self.fillist.append(file)
lo = BoxLayout(orientation='vertical')
self.img = Image(source=self.fillist[self.idx])
lo.add_widget(self.img)
hlo = BoxLayout(orientation='horizontal', size_hint=(1, .1))
self.b1 = Button(text='Dir', on_press=self.onButtonPress)
self.b2 = Button(text='Prev', on_press=self.previmg)
self.b3 = Button(text='Next', on_press=self.nextimg)
hlo.add_widget(self.b1)
hlo.add_widget(self.b2)
hlo.add_widget(self.b3)
lo.add_widget(hlo)
return lo
ImageViewerApp().run()
輸出
執行此程式碼時,它將顯示索引為“0”的影像:
點選導航按鈕向前或向後瀏覽。點選“Dir”按鈕選擇新的資料夾。
Kivy - 貝塞爾曲線
在本章中,我們將建立一個Kivy應用程式,該應用程式將沿著點列表互動式地繪製一條貝塞爾曲線。如果使用以下程式碼段計算出的x和y座標繪製閉合線,則生成的圖形類似於吃豆人角色:
from math import cos, sin, radians
x = y = 300
z = 200
self.points = [x, y]
for i in range(45, 360, 45):
i = radians(i)
self.points.extend([x + cos(i) * z, y + sin(i) * z])
with self.layout.canvas:
Color(1.0, 0.0, 1.0)
self.line = Line(
points=self.points + self.points[:2],
dash_offset=10, dash_length=100
)
它生成如下所示的線型圖案:
然後,我們使用相同的點列表繪製一條貝塞爾曲線。
Color(1.0, 0.0, 1.0) self.line = Line( points=self.points + self.points[:2], dash_offset=0, dash_length=100 )
線條和貝塞爾曲線將顯示如下:
現在我們想動態構建這兩條曲線。我們使用兩個滑塊來更改線指令和貝塞爾指令的虛線長度和偏移值,因為每個滑塊的值屬性會隨著以下事件處理程式的變化而變化:
def _set_bezier_dash_offset(self, instance, value): # effect to reduce length while increase offset self.bezier.dash_length = 100 - value self.bezier.dash_offset = value def _set_line_dash_offset(self, instance, value): # effect to reduce length while increase offset self.line.dash_length = 100 - value self.line.dash_offset = value
因此,更改滑塊值以檢視兩條曲線如何動態重新繪製。
示例
完整程式碼如下所示:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.slider import Slider
from kivy.graphics import Color, Bezier, Line
from kivy.core.window import Window
Window.size = (720,400)
class Main(App):
title='Bezier Example'
def _set_bezier_dash_offset(self, instance, value):
# effect to reduce length while increase offset
self.bezier.dash_length = 100 - value
self.bezier.dash_offset = value
def _set_line_dash_offset(self, instance, value):
# effect to reduce length while increase offset
self.line.dash_length = 100 - value
self.line.dash_offset = value
def build(self):
from math import cos, sin, radians
x = y = 300
z = 200
# Pacman !
self.points = [x, y]
for i in range(45, 360, 45):
i = radians(i)
self.points.extend([x + cos(i) * z, y + sin(i) * z])
print (self.points)
self.layout = FloatLayout()
with self.layout.canvas:
Color(1.0, 0.0, 0.0)
self.bezier = Bezier(
points=self.points, segments=150, loop=True,
dash_length=100, dash_offset=10
)
Color(1.0, 0.0, 1.0)
self.line = Line(
points=self.points + self.points[:2],
dash_offset=10,
dash_length=100)
l1=Label(
text='Beizer offset', pos_hint={'x':.1},
size_hint=(.1, None), height=50
)
self.layout.add_widget(l1)
s1 = Slider(
y=0, pos_hint={'x': .3},
size_hint=(.7, None), height=50
)
self.layout.add_widget(s1)
s1.bind(value=self._set_bezier_dash_offset)
l2=Label(
text='Line offset', y=50, pos_hint={'x':.1},
size_hint=(.1, None), height=50
)
self.layout.add_widget(l2)
s2 = Slider(
y=50, pos_hint={'x': .3},
size_hint=(.7, None), height=50
)
self.layout.add_widget(s2)
s2.bind(value=self._set_line_dash_offset)
return self.layout
if __name__ == '__main__':
Main().run()
輸出
以下螢幕截圖顯示了在兩個不同滑塊位置下的曲線:
Kivy - 畫布壓力測試
在本章中,我們將找出圖形引擎的效率如何。這可以透過向Kivy物件的畫布新增大量圖形指令來完成。
下面給出的程式測量圖形引擎在隨機位置和隨機選擇的顏色值下繪製一萬個矩形所需的時間。因此,它將評估畫布可以承受多少壓力。
語法
矩形指令在任何Kivy部件的畫布上繪製,語法如下:
with self.root.canvas: Color(r,g,b,a) Rectangle(pos, size)
我們將為RGB以及矩形的x和y座標生成隨機值,並顯示10,000個矩形。所需時間由perf_counter()函式計算。
t1=perf_counter()
with self.root.canvas:
for i in range(10000):
Color(r,g,b,a)
Rectangle(pos, size)
t2=perf_counter()
繪製所需的時間將是“t2 - t1”。它將顯示在Kivy應用程式視窗的標題欄上。
示例
完整的程式如下:
from kivy.app import App
from kivy.graphics import *
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from random import random as r
from time import perf_counter
from kivy.core.window import Window
Window.size = (720, 400)
class StresstestApp(App):
def add_rects(self, *args):
self.t1 = perf_counter()
with self.root.canvas:
for i in range(10000):
Color(r(), 1, 1, mode='hsv')
Rectangle(
pos=(r() * self.root.width + self.root.x, r() * self.root.height + self.root.y),
size=(20, 20)
)
self.t2 = perf_counter()
self.title = str(self.t2 - self.t1) + "Sec. to draw 10000 rectangles"
def build(self):
main = GridLayout(cols=1)
self.root = FloatLayout(size=(Window.width, 100))
self.btn1 = Button(
text='start', size_hint=(1, None),
pos_hint={'center_x': .5, 'center_y': .1}
)
self.btn1.bind(on_press=self.add_rects)
self.root.add_widget(self.btn1)
main.add_widget(self.root)
return main
StresstestApp().run()
輸出
執行程式並點選“start”按鈕。
您將在標題欄上看到繪製所需的時間,如下圖所示:
Kivy - 圓形繪製
在本章中,我們將動態地在Kivy應用程式視窗上繪製一個圓形。其思想是使用四個Kivy滑塊部件設定圓形的寬度、高度和中心點值,並在盒佈局畫布上重新整理大小和位置。
“kivy.graphics”模組包含Ellipse類。圓形實際上是寬度和高度相等的橢圓。
語法
在任何部件的畫布上繪製橢圓的語法如下:
with widget.canvas:
Color(1, 1, 1)
Ellipse(
pos=(w, h), size=(cx, cy),
angle_start=0, angle_end=360
)
滑塊用於選擇“w”、“h”、“cx”和“cy”的值。我們應用程式視窗的預期外觀如下:
主佈局使用垂直盒佈局。它包括兩個水平盒,每個盒包含兩個滑塊和兩個標籤。在第一個盒中放置了寬度和高度選擇器;在第二個盒中,可以選擇橢圓的X和Y座標。然後,頂部垂直盒添加了一個FloatLayout,其畫布是繪製的目標。
以下“kv”檔案組裝了上述部件結構。
示例
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: sp(50)
BoxLayout:
orientation: 'horizontal'
Slider:
id: wd
min: 100
max: 300
value: 200
Label:
text: 'Width: {}'.format(int(wd.value))
Slider:
id: ht
min: 100
max: 300
value: 200
Label:
text: 'Height: {}'.format(int(ht.value))
BoxLayout:
size_hint_y: None
height: sp(50)
BoxLayout:
orientation: 'horizontal'
Slider:
id: cx
min: 10
max: 600
value: 360
Label:
text: 'cx: {}'.format(int(cx.value))
Slider:
id: cy
min: 10
max: 300
value: 50
Label:
text: 'cy: {}'.format(int(cy.value))
FloatLayout:
canvas:
Color:
rgb: 1, 1, 1
Ellipse:
pos: cx.value, cy.value
size: wd.value, ht.value
angle_start: 0
angle_end: 360
您需要做的就是在我們的Kivy App程式碼中載入此“kv”檔案。在build()方法內部呼叫“kivy.lang.Builder”類的load_file()方法。
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
Window.size = (720,400)
class CircleApp(App):
def build(self):
return Builder.load_file('circledemo.kv')
CircleApp().run()
就是這樣。執行程式,您將看到圓形繪製在起始位置。滑動控制元件以獲取不同的值,並檢視圓形如何改變其位置和大小。
如果您希望使用純Python程式碼來組合應用程式視窗外觀,您可以透過手動將所需的部件放置在build()方法內部來實現,如下所示:
def build(self):
# main layout
lo = BoxLayout(orientation='vertical', size=Window.size)
# for width and height sliders
sliders_wh = BoxLayout(size_hint_y=None, height=50)
slb1 = BoxLayout(orientation='horizontal')
self.sl1 = Slider(min=100, max=300, value=200)
l1 = Label(text='Width: {}'.format(int(self.sl1.value)))
slb1.add_widget(self.sl1)
slb1.add_widget(l1)
self.sl2 = Slider(min=100, max=300, value=200)
l2 = Label(text='Height: {}'.format(int(self.sl2.value)))
slb1.add_widget(self.sl2)
slb1.add_widget(l2)
sliders_wh.add_widget(slb1)
# for cx and cy sliders
sliders_xy = BoxLayout(size_hint_y=None, height=50)
slb2 = BoxLayout(orientation='horizontal')
self.sl3 = Slider(min=10, max=600, value=360)
l3 = Label(text='cx: {}'.format(int(self.sl3.value)))
slb2.add_widget(self.sl3)
slb2.add_widget(l3)
self.sl4 = Slider(min=10, max=300, value=50)
l4 = Label(text='cy: {}'.format(int(self.sl4.value)))
slb2.add_widget(self.sl4)
slb2.add_widget(l4)
sliders_xy.add_widget(slb2)
lo.add_widget(sliders_wh)
lo.add_widget(sliders_xy)
self.flo = FloatLayout() # circle canvas
lo.add_widget(self.flo)
# redraw cicle
self.ev = Clock.schedule_interval(self.callback, .3)
return lo
但是,為了不斷重新整理畫布上圓形的外觀和位置,我們需要安排一個週期性事件,清除畫布以擦除現有的圓形,並使用寬度、高度、cx和cy的瞬時值重新繪製它。
以下回調方法必須新增到App類中:
def callback(self, dt):
self.flo.canvas.clear()
with self.flo.canvas:
Color(1, 1, 1)
Ellipse(
pos=(self.sl3.value, self.sl4.value),
size=(self.sl1.value, self.sl2.value),
angle_start=0, angle_end=360
)
您現在可以執行程式碼了。將獲得與“kv”檔案版本完全相同的結果。
Kivy - 控制元件動畫
Kivy工具包中的任何部件都可以進行動畫處理。您需要做的就是定義一個Animation類的物件,選擇目標部件的至少一個屬性進行動畫處理,並指定動畫效果完成後要達到的最終值。呼叫Animation物件的start()方法,並將目標部件傳遞給它。
anim = Animation(property1=value1, property2=value2, ..) anim.start(widget)
在以下示例中,我們放置了四個Kivy按鈕。兩個按鈕沿X軸放置,保持“y”座標為0並隨機化“x”座標,以便一個按鈕放置在前半部分,另一個放置在後半部分。
類似地,另外兩個按鈕沿Y軸放置,它們的“x”座標為0,“y”座標值隨機分配。
沿X軸放置的按鈕被設定為上下移動動畫。“y”座標值從其初始值一直到視窗的最大高度,然後返回到原始位置。由於repeat屬性設定為True,所以上下移動是迴圈的。兩個水平放置的按鈕都繫結到以下方法:
def animate1(self, instance): animation = Animation(pos=(instance.pos[0], Window.height)) animation += Animation(pos=(instance.pos[0], 0)) animation.repeat=True animation.start(instance)
類似地,垂直排列的按鈕b3和b4繫結到以下方法。它們的“x”座標值從當前值更改為最大寬度,然後返回。
def animate2(self, instance): animation = Animation(pos=(Window.width, instance.pos[1])) animation += Animation(pos=(0, instance.pos[1])) animation.repeat=True animation.start(instance)
雖然可以透過按下每個按鈕來開始每個按鈕的動畫,但我們可以在觸控按下事件上同時啟動所有四個按鈕的動畫。上述回撥由trigger_action()方法觸發。
def on_touch_down(self, *args): self.b1.trigger_action(5) self.b2.trigger_action(10) self.b3.trigger_action(15) self.b4.trigger_action(20)
其餘程式碼只是在App類的build()方法中設定四個按鈕的UI。
示例
以下是完整的程式碼 -
import kivy
kivy.require('1.0.7')
import random
from kivy.animation import Animation
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Window
Window.size = (720,400)
class TestApp(App):
def animate1(self, instance):
animation = Animation(pos=(instance.pos[0], Window.height))
animation += Animation(pos=(instance.pos[0], 0))
animation.repeat=True
animation.start(instance)
def animate2(self, instance):
animation = Animation(pos=(Window.width, instance.pos[1]))
animation += Animation(pos=(0, instance.pos[1]))
animation.repeat=True
animation.start(instance)
def on_touch_down(self, *args):
self.b1.trigger_action(5)
self.b2.trigger_action(10)
self.b3.trigger_action(15)
self.b4.trigger_action(20)
def build(self):
box=FloatLayout()
# create a button and attach animate() method
# as a on_press handler
self.b1 = Button(
size_hint=(.15, .08), text='BTN1',
pos=(random.randint(Window.width/2, Window.width), 0),
on_press=self.animate1
)
self.b2 = Button(
size_hint=(.15, .08), text='BTN2',
pos=(random.randint(0, Window.width/2), 0),
on_press=self.animate1
)
self.b3 = Button(
size_hint=(.15, .08), text='BTN3',
pos=(0, random.randint(0, Window.height/2)),
on_press=self.animate2
)
self.b4 = Button(
size_hint=(.15, .08), text='BTN4',
pos=(0, random.randint(Window.height/2, Window.height)),
on_press=self.animate2
)
box.add_widget(self.b1)
box.add_widget(self.b2)
box.add_widget(self.b3)
box.add_widget(self.b4)
box.bind(on_touch_down=self.on_touch_down)
return box
if __name__ == '__main__':
TestApp().run()
輸出
程式以隨機的按鈕位置開始。點選應用程式視窗上的任意位置。按鈕b1和b2將開始上下移動。按鈕b3和b4將開始來回移動。
這是初始位置:
下圖是按鈕在移動過程中的螢幕截圖:
Kivy - 雜項
Kivy - 異常處理
在程式設計中,異常處理指的是防止程式在遇到執行時錯誤時崩潰的機制。Kivy提供了一個名為ExceptionHandler的類,可以管理由Kivy或您自己的程式碼引發的異常。
ExceptionManager類在“kivy.base”模組中定義。您需要從“kivy.base”中匯入它並訪問處理Kivy異常的例項。您可以使用此類為不同型別的異常新增自定義處理程式,或在發生異常時覆蓋Kivy的預設行為。例如,您可以使用handle_exception方法記錄異常、向用戶顯示訊息或優雅地退出應用程式。
from kivy.base import ExceptionHandler, ExceptionManager
from logging import Logger
class handler(ExceptionHandler):
def handle_exception(self, inst):
Logger.exception('Exception caught by ExceptionHandler')
return ExceptionManager.PASS
ExceptionManager.add_handler(handler())
一個處理程式函式,它將異常作為引數並返回以下值之一:
ExceptionManager.PASS - 異常應被忽略,因為它已由處理程式處理。
ExceptionManager.RAISE - 異常應重新引發。
ExceptionManager.USER_HANDLED - 異常已由使用者處理,不應記錄。
您還可以使用handle_exception方法使用已註冊的處理程式手動處理異常。
Kivy - 資源管理
“kivy.resources”模組包含用於在路徑列表中搜索特定資源的功能,特別是當您的應用程式處理多個路徑和專案時。
當Kivy查詢任何資源(例如影像檔案或“kv”檔案)時,它會在預先確定的一組資料夾中搜索。您可以使用resource_add_path()和resource_remove_path()函式修改此資料夾列表。
如果您想使用defaulttheme0.png或style.kv的任何替代方案,您可以透過resource_add_path()方法將路徑新增到您首選的替代方案。
以下函式在“kivy.resources”模組中定義:
resource_add_path(path) - 新增要搜尋的自定義路徑。
resource_find(filename, use_cache=False) - 在路徑列表中搜索資源。查詢結果會快取60秒。可以使用use_cache=False停用此功能。
resource_remove_path(path) - 刪除搜尋路徑。
Kivy - 弱代理
Python使用引用計數演算法進行垃圾回收,透過計算有多少物件引用某個物件。如果垃圾回收器發現某個物件被另一個物件引用,則無法對其進行垃圾回收。如果計數器達到零,垃圾回收器將釋放該物件。
弱引用是不保護物件免於被垃圾回收的引用。為了建立弱引用,Python為我們提供了一個名為weakref的模組。
Kivy在kivy.weakproxy模組中定義了WeakProxy類。為了允許垃圾回收,WeakProxy類提供對物件的弱引用。它透過新增比較支援有效地增強了weakref.proxy。
Kivy - 上下文
Kivy物件Clock、Cache和Builder是全域性物件。要在當前應用程式的上下文中使用它們,您必須註冊它。kivy.context模組定義了一個Context類,它繼承了Python內建的dict類的屬性。
除了dict方法外,我們還在此模組中定義了以下函式:
get_current_context() - 返回當前上下文。
register_context(name, cls, *args, **kwargs) - 註冊新的上下文。