0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonista3Advent Calendar 2022

Day 9

ui モジュールとscene モジュールの組み合わせ

Last updated at Posted at 2022-12-08

この記事は、pythonista3 advent calendar 2022 の09日目の記事です。

一方的な偏った目線で、Pythonista3 を紹介していきます。

ほぼ毎日iPhone(Pythonista3)で、コーディングをしている者です。よろしくお願いします。

以下、私の2022年12月時点の環境です。

sysInfo.log
--- SYSTEM INFORMATION ---
* pythonista 3.3 (330025), default interpreter 3.6.1
* ios 16.1.1, model iphone12,1, resolution (portrait) 828.0 x 1792.0 @ 2.0

他の環境(ipad や端末の種類、ios のバージョン違い)では、意図としない挙動(エラーになる)なる場合もあります。ご了承ください。

ちなみに、model iphone12,1 は、iphone11 です。

どっちも好きだから1番なんて決められないよぉ、、、

ネイティブアプリのgui を提供してくれるui モジュール。

ゲームなど2d グラフィックスに特化したscene モジュール。

ui ちゃん

  • 強み
    • ios アプリのような見た目で実装可能
    • slider やswitch などgui を気軽に呼び出せる
    • view を跨いだ画面変遷も可能
    • touch 以外のインタラクティブな処理も気軽
  • 苦手なところ
    • グラフィック処理
    • 毎フレーム決まった処理

scene ちゃん

  • 強み
    • グラフィック処理
    • 全画面前提の設計
    • フレーム処理を前提
    • 経過時間やフレーム時間が管理されている(取得ができる)
    • コントローラー操作も可能
  • 苦手なところ
    • gui パーツ的なものがないので、自作が必須
    • 画面変遷も自作

やれやれだぜ

そのどちらにも一長一短があるので、合体させましょう!

アプリの見た目でグラフィックスをゴリゴリやりましょう!

早速コード紹介

img221126_221345.gif

.py
import scene
import ui


def create_button(icon_name):
  button_icon = ui.Image.named(icon_name)
  button = ui.ButtonItem(image=button_icon)
  return button


class mainview(ui.View):
  def __init__(self, canvas):
    self.bg_color = tint_color
    self.tint_color = title_color
    self.name = title
    self.height_ratio = 0.96  # todo: safe area

    self.canvas = canvas
    self.scene_view = None

    self.setup_navigationbuttons()
    self.setup_scene()
    self.show_scene()

  def draw(self):
    # todo: init background color
    w = self.width
    h = self.height * self.height_ratio
    wrap = ui.Path.rect(0, 0, w, h)
    ui.set_color(bg_color)
    wrap.fill()

  def layout(self):
    self.scene_view.width = self.width
    self.scene_view.height = self.height * self.height_ratio
    self.scene_view.x = self.width / 2 - self.scene_view.width / 2

  def setup_scene(self):
    scene_view = scene.SceneView()
    scene_view.frame_interval = 2
    scene_view.shows_fps = True
    scene_view.alpha = 0
    scene_view.scene = self.canvas
    self.add_subview(scene_view)
    self.scene_view = scene_view

  @ui.in_background
  def show_scene(self):
    def dissolve():
      self.scene_view.alpha = 1

    ui.animate(dissolve, duration=.3)

  def setup_navigationbuttons(self):
    show_console_icon = 'iob:ios7_download_outline_32'
    show_console_button = create_button(show_console_icon)
    show_console_button.action = self.show_console

    self.right_button_items = [show_console_button]

  @ui.in_background
  def show_console(self, sender):
    raw_image = self.canvas.view._debug_quicklook_()
    image = ui.image.from_data(raw_image, 2.0)
    image.show()


class canvas(scene.Scene):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.background_color = bg_color

  @ui.in_background
  def setup(self):
    self.set_line(128)

  def set_line(self, dire):
    w2, h2 = self.size / 2
    path = ui.Path()
    path.move_to(w2 - dire, h2 - dire)
    path.line_to(w2 + dire, h2 + dire)
    line = scene.ShapeNode(parent=self)
    line.path = path
    line.stroke_color = 'red'
    line.position = self.size / 2

  @ui.in_background
  def update(self):
    #print(f'{self.t}')  # 画面左下にlog として表示される
    pass


if __name__ == '__main__':
  title = 'プログラミングでお絵描き'

  bg_color = 0.872
  tint_color = 0.128
  title_color = 0.872
  af_color = tint_color

  canvas = canvas()

  view = mainview(canvas)
  view.present(
    style='fullscreen',
    orientations='portrait',
    title_bar_color=tint_color,
    title_color=title_color)


まるでprocessing のように

canvas class 内で、scene を使いprocessing 風の書き味にしつつ、外側をui で包みアプリライクな見た目にしました。

ui モジュールが使えることにより、navigationview よりタイトルを追加し、右側アイコンをタップすると、押したタイミングの描画状況を保存できるようにしています。

img221126_224103.png

実行中の画面をスクリーンショットすれば、タイトルを含んだ情報がキャプチャできますし、アイコンをタップすれば、描画内の画像を一枚絵として取得できます。

img221126_225028.png

残したい形式を自ら選択し、sns でシェアしてみるのもいいでしょう。大バズり間違いなし(実例なし)!!

コードの解説

scene.sceneview を使う

まず、uiscene オブジェクトが個別のものなので、それらを繋ぎ合わせる必要があります。

scene.sceneview | scene — 2d games and animations — python 3.6.1 documentation

ui のview となるscene.sceneview で、scene.sceneview.scene にてscene を指定してあげることになります。

scene.sceneview のインスタンスに、scene 実行時(run())の処理たちを設定します。

def setup_scene(self):
  scene_view = scene.sceneview()  # ui.view
  
  # todo: run() の時に設定する引数たち
  scene_view.frame_interval = 2
  scene_view.shows_fps = true
  
  scene_view.alpha = 0  # サイズ確定まで見えなくしておく(特別必要な設定ではない)
  scene_view.scene = self.canvas  # 実際表示させたい scene
  self.add_subview(scene_view)
  self.scene_view = scene_view

uiview.present が実行されるタイミングで、scenerun() が呼ばれている。というイメージで問題ないと思います。

各オブジェクトのサイズ連携

ui のview となる関係で、scene のsize がview 依存になっています。

layout メソッド呼び出し時に、scene のsize をfix させることとします(下部では、セーフエリアの設定もしています)。

ui.view のsize が確定、続いてscene のsize が確定の流れになると、コード実行時にview が「ガチャ」ついてしまいます。

そのままでも、もちろん問題はないのですが、グラフィックスのアウトプットなので、いい感じにガチャつき感を誤魔化す方法をとっています。

「ガチャ」となっている場面をフェードインで表示させましょう。全体のlayout がfix する頃合いでscene_view をフワッと登場させれば、ガチャついたイメージは軽減されそうですね。

ui.animate を使い、scene_view.alpha = 0 だった透過状態をduration=.3 後に、scene_view.alpha = 1 と、完全に見える状態にしました。

@ui.in_background のデコレータにより、ガチャガチャui が構築してる中で、処理を止めずにいい具合にscene_view を登場させることができています。

@ui.in_background の使い道は奥が深いので、今回のコードよりコメントアウトし、結果を見比べるのも面白いです。

複数の場所で使用しています。

canvas

scene モジュールの記述方法で、専念して処理が書けます。

最初のフレームでsetup が呼ばれて、以降update が毎フレーム実行されます。

今回のset_line メソッドは、自分用に線を引くために実装したものです。このように関数を独自に作り用意したり、setupupdate にゴリゴリ書いてしまっても問題ありません。

次回は

自分の中で「こうありたい」と思い描く内容が実際にカタチになると、モチベーションがあがりますよね。

基本scene モジュールで完結するものなのですが、なんとなく自分としてモヤっとしてしまっていた部分をui モジュールを組み合わせることで、幾分か解消できたような気がしています。

私はグラフィックスのプログラミングが好きで、processing 入門勢なので、こんな感じに実装してみました。

ui モジュール初回から、グラフィックスプログラミングをするための思想強めの紹介誘導となってしまっていたのは、そのためです。。。

グラフィックスプログラミングハラスメント。大変失礼したしました🙇

次回は、ガラッと趣きを変えてiPhone やPythonista3 のデータ構造の捜索探検を行う予定です。

ここまで、読んでいただきありがとうございました。

せんでん

Discord

Pythonista3 の日本語コミュニティーがあります。みなさん優しくて、わからないところも親身に教えてくれるのでこの機会に覗いてみてください。

書籍

iPhone/iPad でプログラミングする最強の本。

その他

  • サンプルコード

Pythonista3 Advent Calendar 2022 でのコードをまとめているリポジトリがあります。

コードのエラーや変なところや改善点など。ご指摘やPR お待ちしておりますー

  • Twitter

なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー

  • GitHub

基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?