今回はKivyというPythonのGUIライブラリを使って、画像をスライドショー表示するピクチャービューワーを作成してみました。前回、icrawlerを使って画像を自動的にダウンロードするプログラムを作りましたが、それと組み合わせることで、好みの画像をスライドショーできるようになります。

プログラムを実行した様子はこちらです。

準備

今回のプログラムでは当然ながらkivyモジュールを使います。以下のコマンドでインストールしてください。

またメッセージボックスの表示にpyautoguiモジュールを使っているので、こちらもインストールしてください。

プログラムの内容

ソースコードはこちら。

main.py

mykivy.kv

ソースコードはこちらからダウンロードできます。

KivyではPythonプログラムは必ずmain.pyというファイル名でプログラムを作ります。また、Appクラスを継承したクラス(今回はMyKivyAppクラス)の「App」を除いた名前を小文字にしたもの(今回はmykivy)をファイル名にしたkvファイル(mykivy.kv)ファイルを作成します。こちらにGUIについての記述をします。

また今回のプログラムは、プログラム(main.pyおよびmykivy.kv)と同じディレクトリにある「images」フォルダ内にある画像をスライドショーで表示します。
さらに(必須ではありませんが)前回作った画像をダウンロードするプログラム(get_images_GUI.py)と組み合わせて使うことを想定しています。

先に示した映像では以下のように動作させています。

  1. 前回作成した画像をダウンロードするプログラム(get_images_GUI.py)を実行して、画像をダウンロードする。
  2. 今回のKivyプログラムを実行して、imagesフォルダにある画像を表示する。

このようにすれば、その日の気分で見たい画像をダウンロードして、スライドショーすることができます。

get_images_GUI.pyのソースコードはこちら。

プログラムの説明(main.py)

それでは簡単に内容を説明していきます。

main.pyではImageViewerという名前のWidgetクラスと、MyKivyAppというAppクラスを作成しています。Appクラスがプログラムの大枠(ウィンドウの表示など)で、その中での個々の動作(画像の表示やボタンに対する処理など)をWidgetクラスが担っているという感じでしょうか。

まずアプリ起動時のウィンドウサイズを1024 x 768に指定しています(3,4行目)。

必要なモジュールをインポートしたあと、日本語が表示できるようにフォントを指定しています(19,20行目)。ここではメイリオ(meiryo.ttc)を使っています。

また画像があるフォルダのパスを指定しています(22行目)。このあと説明しますが、実際にはこのフォルダ名を含めてファイル名をリストにしていますので、ここでのパス指定は不要かもしれません。

ImageViewerクラスでは、コンストラクタ(__init__関数)で、「images」フォルダにある画像ファイル(拡張子がjpg、jpeg、pngのもの)をリスト変数 filenames に格納しています(34~39行目)。

もしも「images」フォルダに画像がない場合はメッセージを出してプログラムを終了させています(41~43行目)。画像があった場合は最初の画像ファイルを変数 source に指定しています(45行目)。変数 current_pict は現在表示されている画像ファイルのリスト内での番号です(46行目)。その後、ViewModeToggle 関数を呼び出しています(47行目)。

ViewModeToggle関数では、ブール変数 b_slideshow をチェックして、FalseであればTrueに変えてスライドショーを実行します。TrueであればFalseに変えて画像を固定します(スライドショーの中断)。またボタンの表記も変化させています。

画像のスライドショーはClockモジュールの schedule_interval 関数を使って、2秒ごとに RandomPictureSchedule 関数を呼び出すようにしています(53行目)。

RandomPictureSchedule 関数は RandomPicture 関数を呼び出しています。なぜ直接 RandomPicture 関数をClock.schedule_interval関数で指定しなかったのだろうと思われる人がいるかと思います。その理由は、Clock.schedule_interval関数で定期的な呼び出しを指定する関数は、前回呼び出し時間からの経過時間を表す引数 dt を取る必要があるのですが、RandomPicture 関数はGUIでボタンが押されたときにも呼び出しに使っていて、引数を(self以外に)もたないからです。そのため引数 dt を持つ RandomPictureSchedule 関数を間に挟んでいます(もっとスマートな書き方があれば教えてください)。

RandomPicture 関数では、「images」フォルダに画像が複数枚ある場合は、現在表示されている画像とは違う画像をランダムに選んで、画像ファイルを示す変数source を更新しています(67~73行目)。

MyKivyAppクラスはAppクラスを継承して、コンストラクタ(__init__関数)を呼び出しているだけです。変数 titleにプログラムのメインウィンドウに表示されるアプリ名を指定しています。

プログラムの説明(mykivy.kv)

つぎにkvファイルについて説明していきます。

まず、不透明な灰色(RGBA = 0.7, 0.7, 0.7, 1.0)で、ウィンドウの位置にウィンドウと同じサイズの矩形(Rectangle)を描画しています。これでウィンドウの背景色が灰色になります。

次にBoxLayoutを使って、いくつかのWidget(Imageウィジェットおよび2つのButtonウィジェット)を追加しています。イメージで説明すると以下のような配置になります。縦方向(vertical)のBoxLayoutの上の段にImageウィジェット、下の段に横方向(horizontal)のBoxLayoutが配置されています。下の段のBoxLayoutの中に2つのButtonウィジェットが横方向に配置されています(BoxLayoutのデフォルト方向がhorizontalなので、2つ目のBoxLayoutではorientationは省略してあります)。また size_hint_y によって縦方向の比率を指定しています。

また、下の段のBoxLayoutpaddingによって下図のように間が空いています(単位はピクセルです)。左右で幅がズレているのは単なるミスです(笑)。(20, 30, 20, 20)と指定すれば左右のpaddingが20ピクセルになります。
もしも2つのButtonの間にもスペースを空けたければ、「spacing : 10」などのように記述を追加すればOKです。

さらにそれぞれのButtonウィジェットにおいて、on_press によってボタンが押されたときに呼び出される関数を指定しています。ここで「root」とはImageViewerクラスを指します。

さいごに

これまでいくつかPythonのGUIプログラムを紹介しましたが、いずれもtkinterというGUIライブラリを使ったものでした。今回使ったKivyを使えばiOSやAndroidのプログラムもPythonで作れるというので、魅力を感じています。私も勉強し始めたばかりであまり詳しいことは分かっていませんが、これから勉強していきたいと思っています。今回の内容が誰かのお役に立てば幸いです。