python Gui程式設計工具詳解:beeware

2023-02-24 21:01:43

各個gui開發工具對比

Flexx: 可以使用Flexx建立桌面應用程式和web應用程式,同時可以將程式匯出到獨立的HTML檔案中,GitHub推薦
Kivy&BeeWare: 只需編寫一套程式碼便可輕鬆執行於各大行動平臺和桌面上,像Android,iOS,Linux,OS X和Windows,https://blog.csdn.net/ZNJIAYOUYA/article/details/126553693,兩者各有特別,kivy更靈活,後者相容性好
Pyforms:  旨在提高開發效率,用於開發可以在Windows GUI模式、Web模式或終端模式下執行的應用程式
PyQt: 目前最強大的庫之一,可以使用Python做任何C++能做的事
PyAutoGUI:  利用它可以實現所有GUI自動化,無需機械性操作
wxPython: wxPython具有非常優秀的跨平臺能力,可以在不修改程式的情況下在多種平臺上執行

為啥選擇beeware

1.支援跨平臺開發
2.相對Kivy更簡單,相容性更好,kivy靈活性更高,所以建議結合實際情況選擇

beeware官方教學:https://docs.beeware.org/en/latest/tutorial/tutorial-0.html
中文檔案:https://github.com/xianchengyue/Beeware--

搭建步驟

1.設定虛擬環境

1.mkdir beeware-tutorial
2.python3 -m venv beeware-venv #建立虛擬環境
3.source beeware-venv/bin/activate (windows:使用git bash工具執行) #切換至虛擬環境
4.beeware-venv\Scripts\activate.bat (windows:cmd執行)#切換至虛擬環境

2.建立第一個應用

1.安裝briefcase: pip install briefcase
2.新建專案:briefcase new ,之後的內容按需填寫即可,Pyproject.toml 檔案描述瞭如何對應用程式進行打包以便發行
3.在開發者模式下執行應用程式: cd project_dir && briefcase dev
4.專案結構說明:__init__.py:標記專案目錄是一個python包,__main__.py 將專案目錄標記為一個特殊的可執行模組,app.py:建立app視窗的邏輯

打包以便釋出

1.建立應用程式腳手架: briefcase create
2.搭建應用程式: 編譯:briefcase build 
3.執行app: briefcase run
4.搭建安裝包: macos: briefcase package --no-sign;Linux&Windows:briefcase package,詳細說明:https://briefcase.readthedocs.io/en/latest/how-to/code-signing/macOS.html

更新app

1.briefcase dev: 每次執行都能看到修改後最新的效果
2.briefcase run:則不會,需要先執行:briefcase update,然後在執行briefcase run,最後使用briefcase package 命令重新打包app 以便分發
3.macOS 的使用者記住在第三章中提到的使用 briefcase package 命令時帶上 --no-sign 標誌避免設定程式碼簽名標識的複雜工作並使教學儘可能簡單
4.一步更新和執行: briefcase run -u,會自動觸發更新,重新打包:briefcase package -u

使之成為移動 app

1.IOS:
    1.安裝xcode
    2.briefcase create iOS #建立app
    3.briefcase build iOS #編譯
    4.briefcase run iOS ,執行時指定裝置名稱&選擇特定版本的iOS,-d "裝置名稱::ios 版本號",使用特定裝置的UDID名稱: -d 4768AA69-497B-4B37-BD0C-3961756C38AC
2.安卓
    1.MacOs&Liunx&windows: briefcase create android ,首次執行會比較慢,會自動下載java jdk與安裝sdk #建立app
    2.briefcase build android ,Gradle可能停止工作:將會列印CONFIGURING:100%,但看起來什麼事也沒做,此時它在下載更多安卓SDK元件 #編譯app
    4.模擬裝置上執行app: 
        1.briefcase run android ,執行此命令會提示你可執行app的裝置清單,最後一個選項始終是建立一個新的安卓模擬器 #執行app
        2.如果模擬器沒啟動: 執行briefcase run檢查一下終端找到錯誤資訊
        3.如果你想不使用選單在裝置上執行app: briefcase run android -d @beePhone
    5.實體裝置上執行app: 
        1.啟用開發者選項;2.啟用USB偵錯;3.briefcase run android,直接執行:briefcase run android -d 裝置標識號
        2.我的裝置沒有出現: 要麼你沒有啟動 USB 偵錯,要麼裝置根本沒插進去
        3.顯示為「未知裝置(不是未授權開發): 1.重新啟用開發者模式;2.然後重新執行 briefcase run android 命令

開始使用第三方庫

1.存取 API:使用jsonplaceholder(https://jsonplaceholder.typicode.com)作為資料來源
2.安裝第三庫,例如:pip install httpx
3.briefcase dev #本地執行
4.briefcase update : 更新app程式碼
5.briefcase build : 編譯app
6.briefcase run : 執行app 
7.啟動時提示module not found: 
    1.修改app全域性依賴: key:[tool.briefcase.app.appname]
        1.修改pyproject.toml,修改requires,將依賴新增至requires
        2.新增時可以指定版本與版本範圍,例如:httpx==0.19.0,httpx>=0.19
        3.指定克隆倉庫的路徑: 如"git+https://github.com/encode/httpx"
    2.修改指定平臺的依賴: key:[tool.briefcase.app.appname.macOS、windows、linux、iOS、web、android]
        1.修改pyproject.toml,修改requires,將依賴新增至requires
8.Python只在行動端:
    1.在桌面平臺: 任何pip能安裝的都可以被新增到你的需求中
    2.在行動平臺: 只能使用純Python包及包中不能包含二進位制模組,numpy、scikit-learn、cryptography等不能在行動平臺上使用
9. briefcase update -d #更新依賴
10.briefcase build #編譯
11. briefcase run # 執行

讓app執行更流暢

1.GUI事件迴圈: 當app正在處理一個事件,不能重繪也不能處理其他事件
2.非同步程式設計: 使用 async 和 await 關鍵字實現
3.製作非同步教學
    ![img.png](img.png)
    ![img_1.png](img_1.png)

測試app

1.briefcase dev -r #自動檢查依賴安裝情況
2.briefcase dev --test #執行測試
3.test_app.py #編寫測試用例
4.briefcase run --test -r #執行時測試
5.briefcase run iOS --test、 briefcase run android --test #指定平臺執行測試用例

實戰:開始擼程式碼

專案組態檔詳解

1.https://briefcase.readthedocs.io/en/latest/reference/index.html

Toga小部件工具詳解

1.https://toga.readthedocs.io/en/latest/tutorial/index.html
2.安裝toga依賴: pip install toga

1.編寫應用程式

1.程式碼範例:

import toga

def button_handler(widget):
    print("hello")

def build(app):
    box = toga.Box()
    button = toga.Button("Hello world", on_press=button_handler)
    button.style.padding = 50
    button.style.flex = 1
    box.add(button)
    return box

def main():
    return toga.App("First App", "org.beeware.helloworld", startup=build)

if __name__ == "__main__":
    main().main_loop()

2.細節介紹

1.button_handler方法:widget引數,該函數將啟用的小部件作為第一個引數
2.build方法: app引數,為toga.app範例,用於自定義app啟動的方法
3.toga.Box: 盒子是一個物件,可用於容納多個小部件,並定義小部件周圍的填充
4.toga.Button: 定義一個按鈕,引數1:按鈕的展示名稱;2.on_press:點選按鈕後觸發的行為(函數物件)
5.button.style: 定義按鈕在視窗中的顯示方式,預設情況下,Toga 使用一種名為 的樣式演演算法Pack,有點像「CSS-lite」
    1.button.style.padding = 50 #按鈕的所有邊都有 50 畫素的填充
    2.padding_top = 20 padding = (20, 50, 50, 50) #在按鈕頂部定義20畫素的填充
    3.button.style.flex = 1 #使按鈕佔據所有可用寬度
6.box.add(button): 將按鈕新增到框中
7.return box: 返回包含所有 UI 內容的外部盒子,此框將是應用程式主視窗的內容

故障排除

1.建議首先建立一個虛擬環境
2.Toga 有一些最低要求:
    如果您使用的是 macOS,則需要使用 10.10 (Yosemite) 或更高版本。
    如果您使用的是 Linux,則需要 GTK+ 3.10 或更新版本。這是從 Ubuntu 14.04 和 Fedora 20 開始釋出的版本。
    如果您使用的是 Windows,則需要安裝 Windows 10 或更新版本。
3.執行指令碼: cd 專案/src && python -m 專案名稱

2.來寫一個更復雜一點的頁面:華氏度到攝氏度轉換器

程式碼範例

import toga
from toga.style.pack import COLUMN, LEFT, RIGHT, ROW, Pack


def build(app):
    c_box = toga.Box()
    f_box = toga.Box()
    box = toga.Box()

    c_input = toga.TextInput(readonly=True)
    f_input = toga.TextInput()

    c_label = toga.Label("Celsius", style=Pack(text_align=LEFT))
    f_label = toga.Label("Fahrenheit", style=Pack(text_align=LEFT))
    join_label = toga.Label("is equivalent to", style=Pack(text_align=RIGHT))

    def calculate(widget):
        try:
            c_input.value = (float(f_input.value) - 32.0) * 5.0 / 9.0
        except ValueError:
            c_input.value = "???"

    button = toga.Button("Calculate", on_press=calculate)

    f_box.add(f_input)
    f_box.add(f_label)

    c_box.add(join_label)
    c_box.add(c_input)
    c_box.add(c_label)

    box.add(f_box)
    box.add(c_box)
    box.add(button)

    box.style.update(direction=COLUMN, padding=10)
    f_box.style.update(direction=ROW, padding=5)
    c_box.style.update(direction=ROW, padding=5)

    c_input.style.update(flex=1)
    f_input.style.update(flex=1, padding_left=160)
    c_label.style.update(width=100, padding_left=10)
    f_label.style.update(width=100, padding_left=10)
    join_label.style.update(width=150, padding_right=10)

    button.style.update(padding=15)

    return box


def main():
    return toga.App("Temperature Converter", "org.beeware.f_to_c", startup=build)


if __name__ == "__main__":
    main().main_loop()

詳細說明

1.此範例展示了 Toga 的 Pack 風格引擎的更多功能。在這個範例應用程式中,我們設定了一個垂直堆疊的外框;在那個盒子裡,我們放了 2 個水平盒子和一個按鈕。
2.由於水平框上沒有寬度樣式,它們將嘗試將它們包含的小部件放入可用空間。
3.小TextInput 部件的樣式為flex=1,但是Label小部件的寬度是固定的;
4.結果,TextInput小部件將被拉伸以適應可用的水平空間。然後,邊距和填充項確保小部件將垂直和水平對齊。
5.toga.TextInput: 定義一個文字輸入框,readonly=True:設定為不可編輯
6.toga.Label: 定義表頭,text_align:文字對齊方式,LEFT:居左,RIGHT:居右
7.box.style: 定義按鈕在視窗中的顯示方式,預設情況下,Toga 使用一種名為 的樣式演演算法Pack,有點像「CSS-lite」
    1.box.style.padding = 50 #按鈕的所有邊都有 50 畫素的填充
    2.padding = (20, 50, 50, 50) #在按鈕頂部定義20畫素的填充
    3.box.style.flex = 1 #使按鈕佔據所有可用寬度
    4.box.style.update: 更新頁面佈局,direction:指定方向
    5.box、button、input、label均可設定style

把盒子放在另一個盒子裡:涉及佈局、卷軸和其他容器內的容器

程式碼範例

import toga
from toga.style.pack import COLUMN, Pack

def button_handler(widget):
    print("button handler")
    for i in range(0, 10):
        print("hello", i)
        yield 1
    print("done", i)


def action0(widget):
    print("action 0")


def action1(widget):
    print("action 1")


def action2(widget):
    print("action 2")


def action3(widget):
    print("action 3")


def action5(widget):
    print("action 5")


def action6(widget):
    print("action 6")


def build(app):
    brutus_icon = "icons/brutus"
    cricket_icon = "icons/cricket-72.png"

    data = [("root%s" % i, "value %s" % i) for i in range(1, 100)]

    left_container = toga.Table(headings=["Hello", "World"], data=data)

    right_content = toga.Box(style=Pack(direction=COLUMN, padding_top=50))

    for b in range(0, 10):
        right_content.add(
            toga.Button(
                "Hello world %s" % b,
                on_press=button_handler,
                style=Pack(width=200, padding=20),
            )
        )

    right_container = toga.ScrollContainer(horizontal=False)

    right_container.content = right_content

    split = toga.SplitContainer()

    # The content of the split container can be specified as a simple list:
    #    split.content = [left_container, right_container]
    # but you can also specify "weight" with each content item, which will
    # set an initial size of the columns to make a "heavy" column wider than
    # a narrower one. In this example, the right container will be twice
    # as wide as the left one.
    split.content = [(left_container, 1), (right_container, 2)]

    # Create a "Things" menu group to contain some of the commands.
    # No explicit ordering is provided on the group, so it will appear
    # after application-level menus, but *before* the Command group.
    # Items in the Things group are not explicitly ordered either, so they
    # will default to alphabetical ordering within the group.
    things = toga.Group("Things")
    cmd0 = toga.Command(
        action0,
        text="Action 0",
        tooltip="Perform action 0",
        icon=brutus_icon,
        group=things,
    )
    cmd1 = toga.Command(
        action1,
        text="Action 1",
        tooltip="Perform action 1",
        icon=brutus_icon,
        group=things,
    )
    cmd2 = toga.Command(
        action2,
        text="Action 2",
        tooltip="Perform action 2",
        icon=toga.Icon.TOGA_ICON,
        group=things,
    )

    # Commands without an explicit group end up in the "Commands" group.
    # The items have an explicit ordering that overrides the default
    # alphabetical ordering
    cmd3 = toga.Command(
        action3,
        text="Action 3",
        tooltip="Perform action 3",
        shortcut=toga.Key.MOD_1 + "k",
        icon=cricket_icon,
        order=3,
    )

    # Define a submenu inside the Commands group.
    # The submenu group has an order that places it in the parent menu.
    # The items have an explicit ordering that overrides the default
    # alphabetical ordering.
    sub_menu = toga.Group("Sub Menu", parent=toga.Group.COMMANDS, order=2)
    cmd5 = toga.Command(
        action5, text="Action 5", tooltip="Perform action 5", order=2, group=sub_menu
    )
    cmd6 = toga.Command(
        action6, text="Action 6", tooltip="Perform action 6", order=1, group=sub_menu
    )

    def action4(widget):
        print("CALLING Action 4")
        cmd3.enabled = not cmd3.enabled

    cmd4 = toga.Command(
        action4, text="Action 4", tooltip="Perform action 4", icon=brutus_icon, order=1
    )

    # The order in which commands are added to the app or the toolbar won't
    # alter anything. Ordering is defined by the command definitions.
    app.commands.add(cmd1, cmd0, cmd6, cmd4, cmd5, cmd3)
    app.main_window.toolbar.add(cmd1, cmd3, cmd2, cmd4)

    return split

詳細說明

注意: 為了呈現圖示,您需要將圖示資料夾移動到與應用程式檔案相同的目錄中。
1.toga.Table: 定義一個表格,引數詳細說明:
    1.headings(表頭)=["Hello", "World","desc"], data(內容)=data
    2.id:唯一識別符號;3.style:指定樣式
    3.accessors:存取器,multiple_select:支援多選框,
    4.on_select:提供的回撥函數必須接受兩個參數列(obj:「表」)和行(' '行' '或' '沒有' '),on_double_click:雙點選提供的回撥函數必須接受兩個參數列(obj:「表」)和行(' '行' '或' '沒有' '),
    5.missing_value:預設值,factory:已經棄用
2.toga.ScrollContainer: 定義一個卷軸,引數詳細說明:
    1.horizontal:True(為水平,即橫向卷軸),False(為垂直,即縱向卷軸)
3.toga.SplitContainer: 定義一個拆分控制元件,分別展示,引數詳細說明:
        1.id:指定唯一識別符號,style:指定樣式,
        2.direction:是否水平展示,預設垂直展示,content:切換的內容,
        例如:[(left_container, 1), (right_container, 2)]
        3.factory:已經棄用
4.toga.Group:定義一個頂部索引標籤(選單),引數詳細說明:
    1.text:選單名稱,order:指定排序,section:是否部件,
    2.parent:指定父級索引標籤,label:目前已經棄用
    4.系統預設可呼叫的物件:
        Group.APP = Group("*", order=0)
        Group.FILE = Group("File", order=1)
        Group.EDIT = Group("Edit", order=10)
        Group.VIEW = Group("View", order=20)
        Group.COMMANDS = Group("Commands", order=30)
        Group.WINDOW = Group("Window", order=90)
        Group.HELP = Group("Help", order=100)
5.toga.Command: 需要呼叫命令時使用,引數詳細說明:
    1.action:函數物件,text:標題,shortcut:命令描述,icon:指定展示圖示,
    2.group:所屬的索引標籤,section:是否部件,order:指定排序,enabled:是否啟用,factory&label:已經棄用
6.app.commands.add: 新增一組命令到commands索引標籤中
7.app.main_window(程式主執行視窗).toolbar:工具列操作,add新增
8.app.main_window.info_dialog: 正常提示彈窗,error_dialog:錯誤提示彈窗

構建一個瀏覽器

儘管可以構建複雜的 GUI 佈局,但您可以使用現代平臺上原生的豐富元件,用很少的程式碼獲得很多功能

範例程式碼

import toga
from toga.style.pack import CENTER, COLUMN, ROW, Pack


class Graze(toga.App):
    def startup(self):
        self.main_window = toga.MainWindow(title=self.name)

        self.webview = toga.WebView(
            on_webview_load=self.on_webview_loaded, style=Pack(flex=1)
        )
        self.url_input = toga.TextInput(
            value="https://beeware.org/", style=Pack(flex=1)
        )

        box = toga.Box(
            children=[
                toga.Box(
                    children=[
                        self.url_input,
                        toga.Button(
                            "Go",
                            on_press=self.load_page,
                            style=Pack(width=50, padding_left=5),
                        ),
                    ],
                    style=Pack(
                        direction=ROW,
                        alignment=CENTER,
                        padding=5,
                    ),
                ),
                self.webview,
            ],
            style=Pack(direction=COLUMN),
        )

        self.main_window.content = box
        self.webview.url = self.url_input.value

        # Show the main window
        self.main_window.show()

    def load_page(self, widget):
        self.webview.url = self.url_input.value

    def on_webview_loaded(self, widget):
        self.url_input.value = self.webview.url


def main():
    return Graze("Graze", "org.beeware.graze")


if __name__ == "__main__":
    main().main_loop()

在此範例中,您可以看到一個應用程式被開發為一個類,而不是一個構建方法。
您還可以看到以宣告方式定義的框 - 如果您不需要保留對特定小部件的參照,您可以內聯定義一個小部件,並將其作為引數傳遞給框,它將成為那個盒子。

詳細說明

1.toga.WebView: 指定一個web頁面

打造獨家app

1.新增圖示
2.下一步