PythonのKivyで音楽プレイヤー その2 ファイル分割




# はじめに

[PythonのKivyで音楽プレイヤー](https://qiita.com/mkgask/items/dcd0f173998168fe5614)

の続きです。

前回記事には書きませんでしたが、前回のコードには一つ大きな問題点があって、main.pyファイルに全部の処理を書いてしまっています。

今はコード量が少ないので大丈夫ですが、更に拡張していくことを考えると、一つのファイルに全部の処理が書いてあるのは、各処理の責任範囲が明確にしにくい、どの処理をどこに書いたのか覚えてられなくなり、見通しが悪化する等の弊害が出てきます。

結果、拡張すればするほど拡張出来なくなる悪循環に陥るので（やったことのある人には分かってもらえると思います。筆者も体験済みです）、出来る限り早期にファイルを分割しておくと、あとあと大変楽になります。

なので今回は、アプリとしての機能を保ったままファイルを分割することを目標とします。

今回分のソースコードもGitHubに上げてあります。

[https://github.com/mkgask/kivySimplePlayer/tree/v0.2](https://github.com/mkgask/kivySimplePlayer/tree/v0.2)



### 想定環境

- Windows 10  
  （Pythonでkivyなので他OSでもほぼ同等です）
- Python 3.6.5
- kivy 1.10.0
- Nuitka 0.5.30  
  （基本的には出てきませんが、実行ファイル形式出力が可能な状態を維持します）



# ファイルの分割

本当はデザインパターン等に則ってそれに見合った分割をしていくのがいいのですが、
まずは「ファイル分割はどうすれば出来るのか」に集中したいので、分かりやすくクラス毎に分割しておきます。

Pythonでは from と import を使って、
`from ファイル名 import ファイル内のクラス名`
で外部ファイルの読み込みを行うことが出来ます。
実際のファイル名は.pyついてていいのですが、ここに書くファイル名には拡張子（.py）は不要です。

この機能を使って、PopupChooseFileクラスとMusicPlayerクラスをファイルに分割しました。



### PopupChooseFileクラス

```python:popupchoosefile.py
# coding: utf-8

from os.path import dirname, abspath

from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty

class PopupChooseFile(BoxLayout):
    # クラスの中身は同一
    current_dir = dirname(abspath(__file__))
    select = ObjectProperty(None)
    cancel = ObjectProperty(None)
```

PopupChooseFileクラスを丸ごともらってきて、必要なimportもmain.pyから移植しています。



### MusicPlayerクラス

```python:musicplayer.py
# coding: utf-8

from os.path import basename

from kivy.core.audio import SoundLoader
from kivy.core.window import Window

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup

from kivy.clock import Clock
from decimal import Decimal, ROUND_HALF_UP

from popupchoosefile import PopupChooseFile

class MusicPlayer(BoxLayout):
    # クラスの中身は同一なので割愛
```

こちらも同じくクラスの移設を行い、必要なimportを移植しています。
また、PopupChooseFileクラスはMusicPlayerクラスから呼び出すため、そのimportも追加しています。



### main.py

```python:main.py
# coding: utf-8

from os import environ

from kivy.app import App

from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.resources import resource_add_path

resource_add_path('{}\\{}'.format(environ['SYSTEMROOT'], 'Fonts'))
LabelBase.register(DEFAULT_FONT, 'MSGOTHIC.ttc')

from musicplayer import MusicPlayer

class MainWindow(App):
    def build(self):
        return MusicPlayer()

if __name__ == "__main__":
    MainWindow().run()
```

main.pyがずいぶんすっきりしました。
これで、起動後の処理をMusicPlayerクラスに全部任せることが出来るようになったので、main.pyはアプリの起動処理のみに専念することが出来ます。



### 下位ディレクトリに移動

このままファイルを増やしていった時に、最上位ディレクトリに.pyファイルが並んでいくのもあまり美しくないです。
ディレクトリ配置についても適切に分けてあると、後の作業効率に影響が大きいです。

ということで、`simpleplayer` ディレクトリを作成し、その中に`musicplayer.py`ファイルと`popupchoosefile.py`ファイルを移動しました。

```
/main directory
　├─ main.py
　├─ mainwindow.kv
　│
　└─ /simpleplayer
　　　　├─ musicplayer.py
　　　　└─ popupchoosefile.py
```

importの記述は、 . （ドット）で繋げることでディレクトリ構成を表すことが出来ます。

```python:main.py
# 変更前
from musicplayer import MusicPlayer
# 変更後
from simpleplayer.musicplayer import MusicPlayer
```

```python:musicplayer.py
# 変更前
from popupchoosefile import PopupChooseFile
# 変更後
from simpleplayer.popupchoosefile import PopupChooseFile
```

`python main.py` または `nuitka --mingw --recurse-non --run main.py` 等のコマンドで動作確認出来ます。


# 不具合修正

不具合という単語を聞くだけで身構えてしまうのはプログラマの性だと思いますが、今回のものは「ちょっと具合が悪い」くらいの意味での不具合です。

下記スクリーンショットは、起動直後でまだ触っていない画面です。

![clipboard01](https://user-images.githubusercontent.com/8291395/41188986-2b96a586-6c02-11e8-8eb6-e97c89e2a23a.jpg)

標準の音量を50%としていて、数値は50を表示、実際の音量も50%に出来ていて、
でもスライドバーの初期位置が0のままです。

```yml:mainwindow.kv
    #変更前
        Slider:
            id: volume_bar
            max: 100
            value: 0
            on_value: root.volume_change(self.value)
    #変更後
        Slider:
            id: volume_bar
            max: 100
            value: 50
            on_value: root.volume_change(self.value)
```

kvファイルで初期値を50に修正すれば直ります。



# 参考文献

[Python3のimport・下位/上位階層のモジュールをインポートしたい【import】【Python3】 - DRYな備忘録]
(http://otiai10.hatenablog.com/entry/2013/08/13/215034)