PythonでMVVMパターンを使用したGUIアプリケーションのサンプルを以下に示します。この例では、Tkinterを使用して簡単なカウンターアプリケーションを作成します。
import tkinter as tk
# モデル
class CounterModel:
def __init__(self):
self._counter = 0
@property
def counter(self):
return self._counter
def increment(self):
self._counter += 1
def decrement(self):
self._counter -= 1
# ビューモデル
class CounterViewModel:
def __init__(self, model):
self.model = model
self._observers = []
@property
def counter_text(self):
return str(self.model.counter)
def increment(self):
self.model.increment()
self.notify_observers()
def decrement(self):
self.model.decrement()
self.notify_observers()
def add_observer(self, observer_func):
self._observers.append(observer_func)
def notify_observers(self):
for observer in self._observers:
observer()
# ビュー
class CounterView(tk.Frame):
def __init__(self, root, viewmodel):
super().__init__(root)
self.viewmodel = viewmodel
self.label = tk.Label(self, text=self.viewmodel.counter_text)
self.label.pack()
self.increment_button = tk.Button(self, text="増加", command=self.increment)
self.increment_button.pack(side=tk.LEFT)
self.decrement_button = tk.Button(self, text="減少", command=self.decrement)
self.decrement_button.pack(side=tk.RIGHT)
self.viewmodel.add_observer(self.update_view)
def increment(self):
self.viewmodel.increment()
def decrement(self):
self.viewmodel.decrement()
def update_view(self):
self.label.config(text=self.viewmodel.counter_text)
# メインアプリケーション
def main():
root = tk.Tk()
root.title("MVVM カウンターサンプル")
model = CounterModel()
viewmodel = CounterViewModel(model)
view = CounterView(root, viewmodel)
view.pack()
root.mainloop()
if __name__ == '__main__':
main()
説明:
CounterModel
クラスはカウンターの値を保持し、増加や減少の操作を行います。CounterViewModel
クラスはモデルとビューの間の仲介役で、モデルのデータを提供し、モデルの状態が変化したときにビューに通知します。CounterView
クラスはユーザーインターフェースを構築し、ビューモデルを通じてデータと操作を管理します。この構造により、ビューとモデルの間の結合度が低くなり、コードの再利用性とテストの容易性が向上します。
実行方法:
mvvm_example.py
)にコピーします。python mvvm_example.py
を実行します。PythonでMVVMパターンを使用して、最大5つのカウントダウン処理を並行して実行するGUIアプリケーションのサンプルを作成しました。各カウントダウンは1から10秒の乱数で決定され、ボタンを押すたびに新しいカウントダウン処理が追加されます。
import tkinter as tk
import random
# モデル
class CountdownModel:
def __init__(self, duration):
self.duration = duration
self.remaining = duration
self.is_running = True
def tick(self):
if self.is_running and self.remaining > 0:
self.remaining -= 1
return True
else:
self.is_running = False
return False
# ビューモデル
class CountdownViewModel:
MAX_COUNTDOWNS = 5
def __init__(self):
self.countdowns = []
self._observers = []
def add_countdown(self):
if len(self.countdowns) < self.MAX_COUNTDOWNS:
duration = random.randint(1, 10)
model = CountdownModel(duration)
self.countdowns.append(model)
self.notify_observers()
return model
else:
return None
def tick_all(self):
for model in self.countdowns:
model.tick()
self.remove_finished()
self.notify_observers()
def remove_finished(self):
self.countdowns = [c for c in self.countdowns if c.is_running]
def add_observer(self, observer_func):
self._observers.append(observer_func)
def notify_observers(self):
for observer in self._observers:
observer()
# ビュー
class CountdownView(tk.Frame):
def __init__(self, root, viewmodel):
super().__init__(root)
self.viewmodel = viewmodel
self.add_button = tk.Button(self, text="カウントダウン追加", command=self.add_countdown)
self.add_button.pack(pady=10)
self.countdown_frames = []
self.viewmodel.add_observer(self.update_view)
self.update_view()
self.schedule_tick()
def add_countdown(self):
self.viewmodel.add_countdown()
def update_view(self):
# 既存のフレームをクリア
for frame in self.countdown_frames:
frame.destroy()
self.countdown_frames.clear()
# 新しいカウントダウンフレームを作成
for model in self.viewmodel.countdowns:
frame = tk.Frame(self)
label = tk.Label(frame, text=f"残り時間: {model.remaining} 秒")
label.pack()
frame.pack(pady=5)
self.countdown_frames.append(frame)
def schedule_tick(self):
self.viewmodel.tick_all()
self.after(1000, self.schedule_tick)
# メインアプリケーション
def main():
root = tk.Tk()
root.title("MVVM カウントダウンサンプル")
viewmodel = CountdownViewModel()
view = CountdownView(root, viewmodel)
view.pack(padx=20, pady=20)
root.mainloop()
if __name__ == '__main__':
main()
説明:
CountdownModel
クラスはカウントダウンの一つ一つを表し、残り時間やカウントダウンの進行を管理します。CountdownViewModel
クラスは複数のCountdownModel
を管理し、カウントダウンの追加や時間経過の処理を行います。CountdownView
クラスはユーザーインターフェースを構築し、カウントダウンの表示や新しいカウントダウンの追加ボタンを提供します。