MENU

tkinter実践編 ~ Pythonでデスクトップアプリを構築するライブラリ「tkinter」で実装するMVCアーキテクチャ

目次

前編では、MVCアーキテクチャの解説と、簡単なサンプルを紹介しました。
後編では、本格的なMVCアーキテクチャのコードサンプルを見ていきます。

サンプル2:MVCの導入

では、実際にMVCアーキテクチャを大々的に導入したサンプルについて見ていきます。

全体構造

これはゲームアプリのシステムです。
tkinterの作法に従うcontoller(102.py)と画面を描画するView(CanvasData.py)、データを示すModel(MapData.py)から成っています。

実は、このシステムは既に出来上がっていたシステムを、筆者がリファクタリング(コードの改良)を行ったものです。
一応バグがなく動いていましたので、最小限のリファクタリングに留めました。
したがって、本来であればもっとViewやModelからContollerに権限が移譲できるのですが、敢えてしなかったという経緯があります。
それでも、MVCを勉強する上では分かりやすいお手本だと判断しているので、掲載します。

Contoroller

102.py

#通常tkinterはtkと略して使う
import tkinter as tk

#使うクラスのimport
from MapData import MapData
from CanvasData import CanvasData

#コントローラークラス
class Application(tk.Frame):

    #コンストラクタ。クラスを作ったときに呼ぶ。masterはtk.Tk()
    def __init__(self,master):
        super().__init__(master)

        …システムの制御変数の初期化…

        #MapDataの初期化。背景と、アイテムの配列を別々に渡す。
        self.mapdata = MapData([
            [0,0,0,0,0,0,0,0,0,0],
            [0,2,2,2,0,0,2,2,2,0],
            [0,2,0,0,0,0,0,0,2,0],
            [0,2,0,0,0,0,0,0,2,0],
            [1,2,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,2,0,0,0,0,0,0,2,0],
            [0,2,0,0,0,0,0,0,2,0],
            [0,2,2,2,2,0,2,2,2,0],
            [0,0,0,0,0,0,0,0,0,0]
        ],[
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0]
        ])

        #CanvasDataの初期化。masterを渡す。
        self.canvasdata = CanvasData(master)
        #CanvasDataのアイテムの初期化
        self.canvasdata.init_item(self.orange_hake_count, self.kuro_hake_count, self.orange_roller_count, self.kuro_roller_count, self.small_hummer_count, self.big_hammer_count, self.orange_colorball_count, self.kuro_colorball_count)

        …ウインドゥタイトルなど…

        #初期描画
        self.canvasdata.paint(self.mapdata, self.cx, self.cy)
        self.canvasdata.pack()

    …入力キーに応じた処理…
    ※一例
    def orange_hake_sub(self, y, x):
        #背景をオレンジに
        self.mapdata.back_to_orange(y, x)
        …以下略…

    ※Canvasと関係した関数の例
    #タイル及び自キャラ再描画関数
    def repaint(self):
        self.canvasdata.delete("sai")
        #CanvasDataのペイントは描画関数
        self.canvasdata.paint(self.mapdata, self.cx, self.cy)

#メイン。クラスを作って呼んでいるだけ。
win = tk.Tk()
app = Application(master=win)
app.mainloop()

大枠は前編で紹介したシステムと一緒なので、説明は割愛します。
MapData、CanvasDataのインスタンスを作り、自身のメンバとして保持します。
MapDataは地図のデータです。CanvasDataはtkinterのCanvasに関係した処理をパックしたクラスで、だから初期化の際にFrameを渡しています。

Model

MapData.py

class MapData:

    #コンストラクタ。背景を10の配列×10、アイテムを10の配列×10でもらう。
    def __init__(self, back, item):
        #backは背景、itemはアイテム
        self.back = back
        self.item = item

    …backとitemを閲覧したり操作したりする関数群…
    ※一例
    #背景が黒ならTrue、オレンジか煉瓦ならFalse
    def is_back_kuro(self, y, x):
        if self.back[y][x] == 0:
            return True
        else:
            return False

これは比較的分かりやすいと思います。
コンストラクタでは単純に二つの二次元配列をもらうだけです。
例として挙げたのは、その座標の背景が黒かどうかを返す関数ですね。
このように、データがtkinterから分離されパックされているので分かりやすいです。

View

CanvasData.py

import tkinter as tk

#MapDataを使うのでインポート
from MapData import MapData

class CanvasData:

    def __init__(self, master):
        #Tk.Canvasはこのクラスで所持する。そのためにtk.Tk()をもらう。
        self.canvas = tk.Canvas(master, width=700, height=500, bg="skyblue")
        …画像ファイルのロード…

    …以下、tkinter.Canvasを操作する関数…

このクラスは、Tkinter.Canvas周りの処理をパックしたものです。
これにより、Contollerから描画が消えて、ずいぶんContorollerがすっきりしました。

CanvasDataではMapDataを参照しています。
これは、Modelを直接見て画面を描画したほうが効率が良いとの判断に基づく例外的なものです。
このように、ModelとViewが直接対話するときもあります。

以上が、MVCアーキテクチャの例です。

まとめ:なぜMVCアーキテクチャを導入する必要があるのか?

この2つのサンプルを見て分かることは、
「MVCアーキテクチャを導入するとシステムの構造がすっきりする」
ということです。
使うクラス、使うメンバが局所化され、どこで何をしているのか見通しが良くなります。

これがMVCアーキテクチャの利点です。

MVCアーキテクチャは、この2つのサンプルのように比較的小規模なシステムから大規模なシステムまで適用できます。
システム構築の基本となる考え方だと言えます。
Djangoだと、元よりMVCアーキテクチャなので何も考えなくてもMVCになるのですが、tkinterの場合、自分で構造を組み立てなくてはなりません。
ただ、MVCにする利点はかなりあります。
あなたもMVCアーキテクチャでtkinterを利用してみてください。

1 2
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

管理人のよしぞと申します。
フリーランス業界で働いている管理人が、業界で働く様々な視点からフリーランスエンジニアに挑戦するためのノウハウを掲載。独立を考えている方にとって手助けになるサイトを目指しています。

目次