Pythonista 3 で Google 翻訳を使いやすく (2) ロジック部分
前回の記事では、UI の準備まで行った。
今回はアプリケーションのロジック部分の作成と、UI との結合について解説する。なお、GitHub Gist にアップロードした全コードは前回示したので、今回は省略する。
.pyui ファイルのロード・UI の表示
UI ファイルの名前が translate_set.pyui
で、かつ Python スクリプトと同じディレクトリにある場合、最低限次のように記述すれば .pyui ファイルの読み込み・UI の表示が行われる(なお、最後の行の ui.View.present
関数の引数 'sheet'
は iPad の場合に意味のあるものだが、iPhone 版でこのように記述しても実行自体はうまく行く)。
import ui v = ui.load_view('translate_set') v.present('sheet')
ここまで問題なく実行できることを確認した上で、次のステップに進む。
ウィジェットへのアクセス方法
今表示される画面では、WebView が真っ白なので、何か Web サイトを表示させてみよう。
先ほどの ui.load_view
関数で取得した ui.View オブジェクトを通して、.pyui ファイルにある全てのウィジェットにアクセスできる。方法はかなり簡単で、先ほどのスクリプトであれば v['widget_name']
と辞書のようにウィジェット名をキーにしてウィジェットオブジェクトを参照できる。
v['webview1']
として webview1 を参照し、変数 webview1
でアクセスできるようにする。Pythonista の WebView のドキュメント を読むと、load_url
メソッドで指定の URL 先を表示できることがわかるので、それを使う。さらに、今手前にある WebView は webview2 の方なので、webview1 を手前に出すために bring_to_front
メソッドを呼ぶ。
import ui v = ui.load_view('translate_set') webview1 = v['webview1'] webview1.load_url('http://omz-software.com/pythonista/docs/') webview1.bring_to_front() v.present()
これで Pythonista のドキュメントが表示されるようになった。
ウィジェットに関数をひもづける
ここまでの状態でも、リンクを踏めばそのリンク先を表示できる。
ここからさらにブラウザ的な使い勝手にするためには、進むボタンと戻るボタンにそれぞれ ui.WebView
の go_back
メソッド、go_forward
メソッドをひもづけたい。
まずは、ボタンから呼び出すための関数を次のように書く。
def page_back(sender): webview = sender.superview['webview1'] webview.go_back() def page_forward(sender): webview = sender.superview['webview1'] webview.go_forward()
ここで、それぞれの関数の引数 sender
には、ボタン操作によって関数が呼ばれた時に、呼び出し元のボタンへの参照が入る。sender
を通してアクセスしたいのはボタンではなく WebView なので、一旦ボタンが所属している上の階層の View を参照するために superview
属性を呼び出し、先ほどまでと同じように辞書と同じ方式で webview1
をキーとして webview1 を取得する。あとは go_back
, go_forward
メソッドをそれぞれ使用する。
最後に、一旦 Python スクリプトを離れて .pyui ファイルに戻る。button2(戻るボタン)と button3(進むボタン)それぞれの Action 項目に、ひもづけたい関数の名前を書けば、ボタンを押した時にそれぞれの関数が実行されるようになる。
WebView の Delegate を設定する
今回のスクリプトでは、先ほどの要領で button1(虫眼鏡ボタン)に jump_to_link
関数、segmentedcontrol1(「サイトビュー | Google翻訳」切替ボタン)に switch_webview
関数をひもづけていけば、Pythonista 内で完結したアプリケーションの動作は大体できたことになる。webview1 に任意の Webサイト、webview2 に Google 翻訳のページを表示すれば、切替ボタンで両者間を素早く行き来できる。
残ったのは、webview1 で新しい URL 先を表示した時に、連動して textfield1 にそのサイトの URL を表示させる機能である。これには、WebView オブジェクトが持っている delegate
属性に、自分で定義した delegate オブジェクトを渡す方法が使える。ただし、多少ややこしい問題もあった。
そのややこしい問題はひとまず置いておいて、まとめも兼ねて、ここまでの内容分のスクリプトを全て書き出してみた。
import ui user_action = True class MyWebViewDelegate(object): def webview_should_start_load(self, webview, url, nav_type): global user_action if nav_type == 'link_clicked' or user_action: textfield = webview.superview['textfield1'] textfield.text = url user_action = False return True def webview_did_start_load(self, webview): pass def webview_did_finish_load(self, webview): pass def webview_did_fail_load(self, webview, error_code, error_msg): pass def page_back(sender): global user_action user_action = True webview = sender.superview['webview1'] webview.go_back() def page_forward(sender): global user_action user_action = True webview = sender.superview['webview1'] webview.go_forward() def jump_to_link(sender): global user_action user_action = True textfield = sender.superview['textfield1'] if textfield.text: webview = sender.superview['webview1'] webview.load_url(textfield.text) def switch_webview(sender): idx = sender.selected_index webview1 = sender.superview['webview1'] webview2 = sender.superview['webview2'] if idx == 0: webview2.alpha = 0.0 webview1.alpha = 1.0 webview1.bring_to_front() else: webview1.alpha = 0.0 webview2.alpha = 1.0 webview2.bring_to_front() v = ui.load_view('translate_set') textfield = v['textfield1'] textfield.clear_button_mode = 'unless_editing' webview1 = v['webview1'] webview1.delegate = MyWebViewDelegate() webview1.load_url('http://omz-software.com/pythonista/docs/') textfield.text = 'http://omz-software.com/pythonista/docs/' webview2 = v['webview2'] webview2.load_url('https://translate.google.co.jp/?hl=ja&tab=wT') webview2.alpha = 0.0 webview1.bring_to_front() v.present('sheet')
delegate オブジェクトのテンプレートは、先ほどの WebView のドキュメントに記載されている。webview_should_start_load
メソッドはページを読み込み始める時に呼ばれるメソッドで、引数にはそれぞれ、この delegate を持っている WebView オブジェクト、新しく読み込まれる URL、ページの読み込みが始まった原因を示すナビゲーションタイプが渡される。ナビゲーションタイプについては今回初めて知ったが、おそらく本家 Apple の WebKit のドキュメントにあったこれの記載に対応していると思われる。ただしこの nav_type
に渡される文字列は、その記載と若干異なるものが渡されるので、print デバッグであらかじめ渡される文字列を確認してから使用した。
nav_type
が 'link_clicked'
のときと、自前のグローバル変数 user_action
が True のときに限り、textfield1 に URL を反映させることにした。user_action
変数は、ボタン操作の時に呼び出される関数内で True にしておき、直後のページ読み込みで URL を textfield1 に反映させるためのものである。それが終わったらすかさず False にしている。
それ以外のケースではそのページのアドレス以外のURL(SNSボタンに関連するものなど)が読み込まれていることが多く、反映された URL が意味をなさないため、これらのケースは除外することにした。この nav_type まわりの処理をどうするかが一番ややこしかった。もっとうまい方法もあるのかもしれない。
ここまでで、基本的な機能が概ね完成した。スクリプト起動時のコンソールアラート表示や、iOS のショートカットアプリを経由する方法などがまだ残っているが、例によってこれらは次回説明することにする。