跳轉到

使用相機

幾乎每部現代電腦裝置都有某種相機。在本教程中,我們將編寫新的應用程式,能夠要求存取此相機、拍攝照片,然後在使用裝置相機的新應用程式中顯示該照片。

本教學不會在所有平台上運作!

不幸的是,目前本教學只適用於 macOS 和 Android。

雖然 iPhone 都有相機,但 iOS Simulator 並沒有可用的相機。Windows 和 Linux 裝置也有攝影機,但 Toga 目前無法在這些平台上存取攝影機。

這裡提出的程式碼可以在 Windows 或 Linux 上 * 執行;但當您嘗試拍照時,它會產生錯誤。

如果在實際的 iOS 裝置上執行,程式碼將會正常運作,但如果部署到 iOS 模擬器上,則會無法拍照。

開始新專案

在本教程中,我們不打算在核心教程中的應用程式上進行建置 - 我們要開始一個全新的專案。您可以使用與第一個專案相同的虛擬環境;但我們需要重新執行 briefcase new 精靈。

變回包含專案資料夾 helloworld 的目錄,並開始一個名為「Hello Camera」的新專案:

(beeware-venv) $ cd ..
(beeware-venv) $ briefcase new
...
[hellocamera] Generated new application 'Hello Camera'

To run your application, type:

    $ cd hellocamera
    $ briefcase dev

(beeware-venv) $ cd hellocamera

新增代碼以拍攝照片

精靈已產生一個新的空 Toga 專案。現在我們可以加入拍攝和顯示照片的程式碼。編輯新應用程式的 app.py,使其具有以下內容:

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


class HelloCamera(toga.App):
    def startup(self):
        main_box = toga.Box()

        self.photo = toga.ImageView(height=300, margin=5)
        camera_button = toga.Button(
            "Take photo",
            on_press=self.take_photo,
            margin=5,
        )

        main_box.add(self.photo)
        main_box.add(camera_button)

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = main_box
        self.main_window.show()

    async def take_photo(self, widget, **kwargs):
        try:
            if not self.camera.has_permission:
                await self.camera.request_permission()

            image = await self.camera.take_photo()
            if image:
                self.photo.image = image
        except NotImplementedError:
            await self.main_window.dialog(
                toga.InfoDialog(
                    "Oh no!",
                    "The Camera API is not implemented on this platform",
                )
            )
        except PermissionError:
            await self.main_window.dialog(
                toga.InfoDialog(
                    "Oh no!",
                    "You have not granted permission to take photos",
                )
            )


def main():
    return HelloCamera()

與 Briefcase 所產生的預設應用程式相比,此程式碼有兩項變更。這些新增內容將在上文強調:

  1. 第一個突出顯示的程式碼區塊(在 startup() 方法中)新增了控制攝影機所需的兩個 widget:顯示相片的 ImageView,以及觸發攝影機的 Button
  2. 第二個反白顯示的程式碼區塊(take_photo() 方法)定義了按鈕被按下時的事件處理程式。此處理器會首先確認應用程式是否有拍照的權限;如果沒有權限,則會請求權限。然後拍攝照片。請求權限和拍攝照片的請求都是異步請求,因此需要使用 await;當應用程式在等待使用者確認權限或拍攝照片時,應用程式的事件循環可以在背景中繼續。

如果相機成功拍攝了照片,它會返回一個 Image 物件,這個物件可以指定為 ImageView 的內容。如果拍照請求被使用者取消,self.camera.take_photo() 呼叫將返回 None,結果可以被忽略。如果使用者沒有允許使用照相機,或是照相機沒有在目前的平台上實作,將會產生錯誤,並顯示對話框給使用者。

新增裝置權限

我們剛剛加入的這段程式碼,有一部分是要求取得使用攝影機的權限。這是現代應用程式平台的常見功能 - 不先明確詢問用戶的許可,就無法存取硬體功能。

不過,這個要求分為兩部分。第一部分在我們剛剛看到的程式碼中;但在應用程式要求權限之前,它需要先宣告它要要求的權限。

每個平台所需的權限略有不同,但 Briefcase 對許多常見的硬體權限都有跨平台的表示。在您應用程式的 pyproject.toml 檔案的 [tool.briefcase.app.hellocamera]配置區段中,新增下列內容 (就在 sources 宣告的上方):

permission.camera = "App will take mugshots."

這宣告您的應用程式需要存取攝影機,並提供簡短的說明,說明為何需要使用攝影機。在某些平台 (最顯著的是 macOS 和 iOS) 上需要此說明,並會在顯示權限對話框時,以附加資訊的形式顯示給使用者。

現在我們可以產生並執行應用程式:

(beeware-venv) $ briefcase create
(beeware-venv) $ briefcase build
(beeware-venv) $ briefcase run
(beeware-venv) $ briefcase create android
(beeware-venv) $ briefcase build android
(beeware-venv) $ briefcase run android

當應用程式執行時,您會看到一個按鈕。按下按鈕,平台的預設相機對話框將會顯示。拍張照片;相機對話框會消失,照片會顯示在應用程式中,就在按鈕上方。然後您可以再拍一張照片;這張照片會取代第一張照片。

新增更多權限

權限是在原始呼叫 briefcase create 時產生的檔案中宣告的。不幸的是,Briefcase 無法在初始產生這些檔案後更新它們;所以如果您想要在應用程式中加入新的權限,或是修改現有的權限,您需要重新建立應用程式。您可以重新執行 briefcase create 來做到這一點;這會警告您現有的應用程式將會被覆寫,然後用新的權限重新產生應用程式。