第3章 Command パターン 2/4, IronPython
IronPython で学ぶ WPF プログラミングの世界《IronPython2.6》
■ 概要
WPF の特徴を活かして、デザインパターン
イベントに呼応するアクションを規定したいときには〈GoF〉Command パターンを導入します。すると、密接に関係する「イベント/アクション」対を、再利用可能な「部品」として扱えます。
《Note》IronPython1.x 用に作成したセミナー課題を、IronPython2.6 で再構成しました。
2a)機能の要求:Command
Command::Command では、対象となる要素に共通するプロトコルを規定します。
class Command: # Command::Command
def execute(self, sender, e):
raise NotImplementedError("%s.execute"
%self.__class__.__name__)
ここで規定したメソッド execute を、子孫クラスで再定義しないと、実行時に例外 NotImplementedError を生成するとともに、そのクラス名を出力します。たとえば、実行時に次のようなメッセージ
NotImplementedError: PaintColor.execute
が出力されるので、子孫クラス PaintColor でメソッド execute を再定義していないのが分かります。
2b)機能の実現:ConcreteCommand
Command::ConcreteCommand では、Command::Command で規定されたプロトコルに従って、各機能を実現します。
■ クラス PaintColor
class PaintColor(Button, Command): # Command::ConcreteCommand def __init__(self, Content, panel): self.panel = panel self.Content = Content self.Click += self.execute def execute(self, sender, e): e = sender.Content self.panel.Background = getattr(Brushes, e)
メソッド execute では、パネル panel の背景色を設定します。選択した項目(ボタン).Content に設定された値をもとに、背景 Background となるブラシ Brushes の色を設定します。
■ クラス FileOpen
class FileOpen(Button, Command): # Command::ConcreteCommand def __init__(self, panel): self.panel = panel self.Content = "Open..." self.Click += self.execute def execute(self, sender, e): dialog = OpenFileDialog() dialog.ShowDialog() e = dialog.FileName.split("\\")[-1] brush = ImageBrush( ImageSource=BitmapImage(Uri("Flags/%s"%e, UriKind.Relative)) ) self.panel.Children.Add(Rectangle( Width=50, Height=50, Fill=brush, ))
メソッド execute では、選択したファイル内の画像を、パネル panel に追加します。
《付録》CommandToolBar.py
# -*- coding: utf-8 -*- #=============================================================================== # Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部 # # History: WPF examples # 2008/01/25, IronPython 1.1.1 (download) # 2008/08/22, IronPython 1.1.2 (download) # 2008/03/16, ver.2.0, WPF # 2008/00/00, ver.2.1, IronPython 1.1.2 #=============================================================================== from _ant import * from System import * from System.Windows import * from System.Windows.Controls import * from System.Windows.Media import * from System.Windows.Media.Imaging import * from System.Windows.Shapes import * clr.AddReference("System.Windows.Forms") from System.Windows.Forms import OpenFileDialog ## -------------------- # Command::Command class Command: def execute(self): raise NotImplementedError("%s.execute" %self.__class__.__name__) ## -------------------- # Command::ConcreteCommand class FileOpen(Button, Command): def __init__(self, panel): self.panel = panel self.Content = "Open..." self.Click += self.execute def execute(self, sender, e): dialog = OpenFileDialog() dialog.ShowDialog() e = dialog.FileName.split("\\")[-1] brush = ImageBrush( ImageSource=BitmapImage(Uri("Flags/%s"%e, UriKind.Relative)) ) self.panel.Children.Add(Rectangle( Width=50, Height=50, Fill=brush, )) ## -------------------- # Command::ConcreteCommand class FileClose(Button, Command): def __init__(self, window): self.window = window self.Content = "Close" self.Click += self.execute def execute(self, sender, e): self.window.Close() ## -------------------- # Command::ConcreteCommand class PaintColor(Button, Command): def __init__(self, Content, panel): self.panel = panel self.Content = Content self.Click += self.execute def execute(self, sender, e): e = sender.Content self.panel.Background = getattr(Brushes, e) ## -------------------- class ExWindow(Window): # Command::Client def __init__(self, Content=None, **args): self.InitializeComponent(Content) self.init() def InitializeComponent(self, Content): self.Content = LoadXaml(Content) def init(self): target = "toolBarTray", "panel", self._Controls(target) target = "fileToolBar", "colorToolBar", for e in self.toolBarTray.ToolBars: if e.Name in target: setattr(self, e.Name, e) for e in FileOpen(self.panel), FileClose(self): self.fileToolBar.Items.Add(e) for e in "Red", "Green", "Blue": e = PaintColor( Content=e, panel=self.panel) self.colorToolBar.Items.Add(e) def _Controls(self, target): controls = xaml_controls(self) for e in target: setattr(self, e, controls[e]) ## -------------------- if __name__ == "__main__": xaml = __file__.replace(".py",".xaml") win = ExWindow( Title=__file__, Width=260, Height=120, Content=xaml, ) Application().Run(win)