い章ユーザインタフェース n = 10 def X(self, t) : print ・ Done ・ app. run( ) myWindow. orderFrontRegardless( ) myWindow. display( ) myWindow. setDelegate (myDelegate) myDelegate = AppDelegate. a110C ( ). init( ) myWind0W. setContentView (myView) myView = DemoView. a110C( ). initWithFrame_(graphicsRect) myWindow. setTitle C Tiny App1ication Window') Fa1se) NSBackingStoreBu 幵 ered, ー NSMiniaturizableWindowMask, ー NSResizabIeWindowMask ー NSCIosableWindowMask NSTitledWindowMask graphicsRect, myWindow = NSWindow. a110 ( ( ). initWithContentRect styleMask backing defer ( graphicsRect = NSMakeRect(100.0, 350.0 , 450.0 , 400. の = NSApplication. sharedApplication( ) global app def main( ) : app. terminate (self) def windowWi11C10se (self, notification) : class AppDelegate(NS0bject) : NSBezierPath. strokeLineFromP0int t0P0int (pl, p2) = NSMakePoint(se1f. x(g), self. Y(g)) for g in 100P : = NSMakePoint(seIf. x(f), self. Y(f)) for f in 100P : 100P = i * step for i in range(self. n)] step = pi/self. n NS 〔 010 て . bIackColor ( ). set( ) NSRectFiII(seIf. bounds( ) ) NSC010て . whiteC010r( ). set( ) self. height = self. bounds( ) [ 1 Ⅱ 1 ] self. width = self. bounds( ) [ 1 Ⅱ 0 ] def drawRect (self, rect) : return (cos(t) + 1 ) * self. height * 0.5 def Y(seIf, t): return (sin(t) + 1 ) * self. width * 0.5 name main( ) maln
い .8 self. start = self. elapsedtime = self. running = Fa1se = StringVar( ) self. timestr self. makeWidgets( ) def makeWidgets(self) : " 時間のラベルを作成“ = Label(self, textvariable=self. timestr) 1 self. setTime(se1f. elapsedtime) 1. pack(fi11=X, expand=N0, pady=2, padx=2) def update(self) : 経過時間でラベルを更新” self. elapsedtime = time. time( ) self. setTime(self. elapsedtime) - self. start Tkinte 「によるストップウォッチ ー 443 = self. after(self. msec, self. update) self. timer def setTime(se1f, elap) : 一分 : 秒 : 1 / 100 秒の時間を表す文字列をセット = int(elap/60) minutes = int(elap - minutes*60. の seconds - minutes*60.0 - seconds)*100) = int((elap hseconds self. timestr. set('%02d:%02d:%02d ・ % (minutes, seconds, hseconds)) def Start(seIf) : ーストップウォッチのスタート。すでに動いていたら無視 " ・ if not self. running: self. start = time. time( ) - self. elapsedtime self. update( ) self. running = True def Stop(self) : " ストップウォッチをとめる。すでに止まっていたら無視 if self. running: self. after cancel(self. timer) self. elapsedtime = time. time( ) self. setTime(self. elapsedtime) self. running = False def Reset(self) : " ストップウォッチのリセット " self. start = time. time( ) self. elapsedtime = 0.0 sel 千 . setTime(seIf. elapsedtime) - self. start 考察 プログラムとして実行することも可能である。 main ・を使っている。そのおかげで、このモジュールをインポートして使うことも、スタンドアロンの name 以下にこのストップウォッチのウイジェットの使用例を挙げておく。 こではおなじみの if
480 ー , 1 ) return self. て 00t ParserStatus = Parser. Parse(open(filename). read( ) # XML ファイルをバースする Parser. CharacterDataHandler = self. CharacterData Parser. EndElementHandler = self. EndElement Parser. StartElementHandler = self. StartElement # Expat のイベントハンドラ群をメソッドとしてセット Parser = expat. ParserCreate( ) # Expat バーサの生成 def Parse(seIf, filename) : element. cdata + = data element = self. nodeStack[-1] data = data. encode( ) if data. strip( ) : 'Expat のキャラクタデータイベントハンドラ・ def CharacterData(se1f, data): self. nodeStack. pop( ) ・ Expat の end 要素イベントハンドラ ' def EndEIement(self, name) : self. nodeStack. append(element) self. て 00t = element else: parent. addChi1d(element) parent = self. n0deStack[-1] if self. nodeStack: # 要素をスタックに積みこれを parent の child とする element = E1ement(name. encode( ) , attributes) # E1ement オプジェクトをインスタンス化する 'Expat の start 要素イベントハンドラ ' def StartElement(seIf, name, attributes): 12 章 XML の処理 考察 て 00t element = parser. Parse('sample. xml ・ ) parser = Xm120bj ( ) 元々の Die レ e のアイディアとの大きな違いは、こちらのレシピが XML 文書を ( ディクショナリとリストの スを使っても難しくない。これはレシピでシンプルなスタックにより実現しているのを見ても分かるだろう。 まったく何も得られないからである。親子間のコネクションの構築は、たとえイベントドリプンインタフェー インタフェースから本当の意味で得られるものはないし、その低速でメモリ食いな DOM アプローチからは、 こちらのレシピでは速度を最大化するために、低レベルの expat パーサを直接使っている。 SAX のリッチな アだと思った。ここで示したレシピは、あのアイディアのバリエーションだが、あちこち違った箇所がある。 (http://aspn.activestate.com/ASPN/C00kb00k/Python/Recipe/116539) を見て、こいつはホントにいいアイディ 私は XML 文書の構造をディクショナリとリストのシンプルな組み合わせにする Christ 叩 hDie レ e のレシピ
460 ーい章ユーサインタフェース 11.14 wxPython でタブを Credit: Mark Nenadov 訳 : 鴨澤眞夫 パックグランドで走る複数の python スクリプトをそれぞれバネルとして持ち、切り替えられる ようになっている wxPythonGU Ⅱすなわち wxPython ノートブック ) を設計したい。 問題 解法 ノートブックは、ユーザが直感的にボタンを押すことで、さまざまな選択肢から望みのビューがすぐ得ら れるという、効果的な GUI アプローチである。 wxPython は wxNotebook ウイジェットによりこれをサポートし ている。以下はノートブックを保持する「フレーム」のクラスで、それぞれ別々の thon モジュール ( コー ドには示さす ) から runPaneI 関数を通じて駆動される、 3 つのペインを配したものだ・ 行 om wxPython. wx import * class MainFrame(wxFrame): # 省略 : mainframe class 属性群 init_(self, parent, id, title) : def # 省略 : フレーム特有の初期化処理 # ノートブックオブジェクトの生成 self. nb = wxNoteb00k(se1f, -1 , wxP0int(0,0), wxSize(0,0), wxNB FIXEDWIDTH) # ノートブックにページ ( バネル ) を置く。それそれのバネル用に # import した異なる Python モジュールにより駆動される panel names = "First Panel" "Second Pane1" panel scripts = panell" pane12" ・ pane13" for name, script in zip(panel names, panel_scripts) : # 名前が 'name' の ('script ・ . py で駆動される ) バネルを生成 import_(script, globals( ) ) self. module = self. window = self. module. runPaneI(seIf, self. nb) if self. window: self. nb. AddPage(seIf. window, name) # 省略 : フレーム初期化の残部 "The Third 0ne" 考察 wxPython はパワフルなユーザインタフェースオプジェクトであるノートブックを提供する。ノートブック はそれぞれ別の thon スクリプト ( 実際はモジュールで「メインスクリプト」ではない ) が駆動する複数のパ
562 ー 1 4 章ウェブプログラミング def printStatus(self, data=None) : print "Starting feed group ・・ def start(self, data=None, standalone=True) : = defer. succeed(self. printStatus( ) ) d for feed in data: if self. isCached(feed) : d. addCallback(self. getPageFromMemory, feed) d. addErrback(self. gotError, (feed, getting from memory ・ ) ) # キャッシュされていない。ウエプから直接取得 d. addCallback(self. getPage, feed) d. addErrback(self. gotError, (feed,'getting' ) ) # 以前に取得。フィードをバースし工ラー診断 d. addCallback(self. parseFeed) # ノ←スした構造体をキャッシュに入れて渡す d. addCallback(seIf. memoize, feed) d. addErrback(self. gotError, (feed, # これでどうにかノ←ス済みストラクチャを得たので # もっとも適切なやり方でティスプレイできる d. addCallback(self. work0nPage, feed) d. addErrback(self. gotError, (feed, 'working on page')) else: d. addErrback(self. gotError, (feed, ・ parsing ・ ) ) memoizing ' ) ) return d if not standalone: d. addErrback(se1f. gotError, (feed,'while stopping' ) ) d. addCallback(self. stopWorking) if standalone : # テスト専用。各フィードを一度処理したら停止 class FeederFactory(protocol. ClientFactory) : protocol = FeederPr0toc01( ) init_(self, standalone=False) : def = self. getFeeds( ) self. feeds self. standalone = standalone self. Pr0t0(01. factory = self url_groups = [ [addr[o]] for addr in addresses] else: url_groups[i%DEFERRED GROUPS]. append(addr[o]) for i, addr in enumerate(addresses) : url groups = [ [ ] for x in xrange(DEFERRED GROUPS)] if len(addresses) > DEFERRED GROUPS: # ダウンロードするフィードを全てグループ分け def start(self, addresses) : self. start(self. feeds) if standalone: self. Pr0t0(01. END VALUE = len(self. feeds) # テスト用
] 2.5 XML 文書を python のオブジェクトツリーに変換ー 479 薦めである。詳しくは http://www.menteith.com/unicode/primer/ を参照。この他、ライプラリリファレンス および「 python クイックリファレンス』のピルトイン str, unicode の各タイプ、モジュール unidata 、 codec の各モジュールについての解説、「レシピ 1.21Unicode と通常の文字列を相互変換」および「レシピ 1.22 標 準出力に Unicode 文字を出力」。 125 XML 文書を Python のオプジェクトツリーに変換 Credit: John Bair, Christoph Die レ e 訳 : 鴨澤眞夫 問題 XML 文書をメモリ内にロードしたいが、 DOM の複雑なアクセス手続きはいやだ。なにかもっと バイソニックなやり方がいい。具体的には P hon オブジェクトのツリーにマップしたい。 def self. nodeStack = = None self. root init_(self) : ー XML →オプジェクトの変換器ー class Xm120bj(0bject) return list(self. children) else: def return [c for ( in self. children if c. name = if name: def getElements(self, name return self. cdata def getData(self) : return self. attributes. get(key) def getAttribute(se1f, key) : self. children. append(element) def addChiId(seIf, element) : self. children = self. cdata = # 要素の cdata と children を empty に初期化 self. attributes = attributes = name self. name # タグ名と属性をディクショナリに記録 init (self, name, attributes) : ーバース済の XML エレメン、 class Element(0bject) : 行 om xml. parsers import expat 高速な expat パーサを直接ラップしてオプジェクトのツリーを構築に使うという手がある : 解法 = name]
448 ー 1 1 章ユーザインタフェース def init_(self) : # キューの生成 self. queue ・ put(msg) msg = rand. random( ) time. sleep(rand. random( ) # 次の 2 行を実際のもので置き換えるべし # 非同期 1/0 のシミュレーションとしてランダムな間隔で乱数を生成 while self. running: 時々制御を渡さはならない、とは覚えておくべき重要事項。 非同期 I / 0 を扱う部分。たとえばこれは sele ( t ( ) である。スレッドが def workerThreadI(self) : self. running = False def endApplication(self) : root. quit( ) if not self. running: self. gui. processlncoming( ) 200 ms ことにキューをチェックする def peri0dicCa11(se1f) : self. threadl. start( ) self. threadl = threading. Thread(target=se1f. workerThread1) self. running = True # 非同期 I / 0 を行うスレッドのセットアップ。必要ならもっと作れる self. timer. St訂t(200) # タイマーの開始 - - - これが periodicCaII の最初のコールの代わり self. peri0dicCa11) qt. Q0bject. connect(self. timer, qt. SIGNAL("timeout( ) " ) , self. timer = qt. QTimer( ) # peri0dicCa11 を定期的にコールするためのタイマー self. gui ・ show( ) self. gui = GuiPart(se1f. queue, self. endApplication) # GUI 部分のセットアップ self. queue = Queue. Queue( ) = random. Random( ) rand = qt. QApplication(sys. argv) て 00t client = ThreadedCIient( ) root. exec 10 叩 ( ) 見ての通り、この塚 Qt バージョンは " Ⅸ inter バージョンと気持ち悪いくらい似た構造で、違いはほんの少 ししかない ( 乱暴な sys. exit の代わりに QAppli ( ation. quit を使っていたり、スレッドの結果をコンソールでな く GUI 自体に表示しているなど、ちょっとした拡張はしてあるけど ) 。
6. ] 4 State デザインパターンを実装する def emitString(self, s) : self. nstr + = 1 self. characters + = len(s) def endMessage(self) : print '%d characters in %d strings ・ % (self. characters, self. nstr) class TraceChatty(0bject) : ・詳細な情報を出力する状態ー def startMessage(self) : self. msg = def emitString(self, s) : self. msg. append(repr(s)) ー 273 def endMessage(se1f) : print ・ Message: class TraceQuiet(0bject) : ー全く出力しない状態ー . join(self. msg) def startMessage(se1f) : pass def emitString(se1f, s) : pass def endMessage(self) : pass class Tracer(object) : init (self, state) : self. state def def setState(seIf, state) : self. state def emitStrings(self, strings) : self. state. startMessage( ) = state = state f0 て s in strings: self. state. emitString(s) self. state. endMessage( ) name maln = Tracer(TraceNormal( ) ) t t. emitStrings('some example strings here'. split( ) ) # 出力 : 22 characters in 4 strings t. setState(TraceQuiet( ) ) t. emitStrings('some example strings here' . split( ) ) # 出力無し t. setState(TraceChatty( ) ) t. emitStrings(' some example strings here'. split( ) ) example ' 'strings ・ # 出力 : Message: 考察 イルの巻き戻し」で紹介した ) にも関係する。つまり、このデザインパターンは、 thon でよく行われる関連 を書き換えるやり方と、特定のメソッドだけを書き換えるやり方 ( 「レシピ 2.14 ストリームデータ入力ファ ことで実現する。このデザインパターンは「レシピ 6.11 リングバッフアを実装する」で行っている class クトは「状態」によって変わる振る舞いを、それぞれの「状態」を表すオプジェクトのメソッドを呼び出す ればデータも ) を抽出し、それぞれの「状態」を表すオプジェクトに任せることができる。主体となるオプジェ State デザインパターンでは、状態によって振る舞いが変化するオプジェクトの関連する振る舞い ( 必要であ
い章ユーサインタフェース self. rb fr. pack(side=side, fiII=BOTH) = Frame(master, borderwidth=2, reIief=RIDGE) self. screen fr self. screen_fr. pack(fill=BOTH) def call_(self) : return self. screen fr def add screen(self, 行 , title): b = Radi0button(seIf. rb 行 , text=title, indicatoron=o, variable=self. choice, value=self. count, command=lambda: self. display(fr)) fr. pack(fiII=BOTH, expand=l) if not self. active fr: b. pack(fiII=BOTH, side=self. side) self. active fr = fr self. count + = 1 def display(self, (r) : self. active fr. forget( ) fr. pack(fiII=BOTH, expand=l) self. active 行 = fr このコードを notebook. py という名でセープして、 sys. path のど 使えるようにすればよい。 考察 from Tkinter import * 行 om notebook import * こかにモジュ ールとして置き、 import して 上の notebook クラスの動作を示すには、簡単なデモプログラムを使うのが一番楽だ・ b3. pack(fi11=BOTH, expand=l) b2. pack(fiII=BOTH, expand=l) = Button(f2, text='Beep 2 ' , command=lambda: Tk. bell(root)) = Button(f2, text='Button 2 り = Frame(nb( ) ) el. pack(fi11=BOTH, expand=l) bl. pack(fiII=BOTH, expand=l) # フレーム自体を pack してはならない ! # フレーム内のウイジェットはフレームをノートブックに追加する前に pack すること el = Entry(f1) = Button(f1, text="Button 1 " ) = Frame(nb( ) ) # さまざまなフレーム ( バネル ) を生成。各バネルは notebook を master とする : = notebook(root, LEFT) て 00t = Tk( ) # 左タブの notebook を入れるトップレベルを生成する :
520 ー 1 3 章ネットワークプログラミング if f: f = String10( ) 'text/html' ) def getMenu(self) : return f f. seek(0) f. write()A test %s\n" % self. path) f = String10( ) self. end headers( ) self. send header("Content-type" self. send_response(200) return None self. send er て or ( 404 , msg) msg = head + self. getMenu( ) 'Command "%s" not found. Try one of these: く ul> ' % path head = if not path in [ ・ / ・ ] + self. cmds. keys( ) : path = self. path def send head(self) : f. close( ) b0dy = 、く a href="/">Main Menu く /a> く pre 〉 %s く /pre>\nt % \ cmd f = self. send head( ) HEAD リクエストへのサービス def do HEAD(seIf) : return f f. close( ) self. copyfile(), self. wfile) f. seek(0) f. write(' く /bodY> く /html>\n' ) f. write(body) f. write( ・く body > く HI > % s く / HI 〉 \ n ' % (heading)) f. write(" く html> く head> く title>%s く /title> く /head>\n" % heading) b0dy = b0dy. decode( ' ( P437 ・ ). encode( 'latinl ・ ) # スウェーデン語版 Windows に必要な CP437 - > Latin 1 変換 os ・ popen(cmd). read( ) = self. cmds[self. path] self. cmds[self. path], machine) heading = "Execution 0f 、、 % s ・・ on %s" % ( else: command has finished. PIease be patient. ") " く P>The screen won ・ t update until the selected " body = (self. getMenu( ) + heading = "Select a command t0 run on %s" % (machine) if self. path = machine = os. popen('hostname' ). readlines( ) 回