2008年5月30日金曜日

wx.PyEvent, wxPyCommandEvent

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
丁寧にドキュメントを読めば書いてあるのでざっくりと。

* wx.PyEvent
- Keyが押されたとか、マウスボタンがdownしたとか、低水準のイベントのためのモノ
* wxPyCommandEvent
- アプリケーションレベルで意味のある高水準のイベントを作るためのモノ

なので、処理のされ方に差がある。前者はwindowを超えて伝播しない(ResumePropagateとかで明示的に指定すれば別だが。ShouldPropagate, StopPropagateも参照のこと)
後者は、ハンドラが存在しなかった場合は親ウィンドウをどんどんさかのぼっていく。最終的にはアプリのハンドラが試される。

* イベントは同一ウィンドウに複数のハンドラを持ちうる事に注意

同じイベントを複数回処理したいことがある。そのときはEvent::Skipを使い、次のイベントハンドラに処理の機会を与える。ウィンドウのデフォルトのハンドラが処理する機能を後からフックしたいが、デフォルトのハンドラの処理を妨げたくないときなどに使う。

2008年5月27日火曜日

idea: VirtualHostTraingTool

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
練習に使うサーバのglobal IPを教えてあげるとテストケースにしたがってgetするclientとか作ると面白いかも。urlごとの挙動の仕様として出題して、回答に使うサーバのIPを指定してあげるとclientが走って結果をpageに表示してくれる。

2008年5月26日月曜日

プログラムにtreeのrevisionを埋め込む。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
fileのrevisionは$revとかをsvnで使えるようにすればいい。しかし、binary releaseする場合にはtreeとしてのrevisionがほしい。そんなわけでやる気のないscriptを書いてmakeの時に実行するようにしました。treeのupdate後、binaryのビルド前に実行するようにします。

あー、このコードは好きに使ってよいです。オリジナリティを主張できるほど長いとは思えないし。誰かもっとスマートにやる方法、教えてください。

#!/usr/bin/env python
# -*- coding: us-ascii -*-
# vim: syntax=python
#
# Copyright 2006-2008 Noriyuki Hosaka nori@backgammon.gr.jp
#
import sys
import os
import re
import subprocess

regexp = re.compile('[0-9]+')

print "os.getcwd() = ", os.getcwd()
print 'svn update ', sys.argv[1]
p = subprocess.Popen(['svn', 'update', sys.argv[1]], stdout=subprocess.PIPE)
p.wait()
svn_update = p.stdout.read()
print svn_update
m = regexp.search(svn_update)
assert m
revision = int(m.group())


py = file('revision.py', 'w')

template = """
#!/usr/bin/env python
# -*- coding: us-ascii -*-
#
# Copyright 2006-2008 Noriyuki Hosaka nori@backgammon.gr.jp
# This source is generated by mkrevision.py
#
def get():
return %i
"""

py.write(template%revision)
py.close()

2008年5月25日日曜日

一回目のリリース間近

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
8000行近い。2回目のリリースのころには10Kをこえるだろうなぁ。

[nori@Asama]~/Desktop/work/wxpygammon% find . | grep py$ | xargs wc
179 362 4073 ./src/model.py
38 74 1119 ./src/gui/splash.py
84 207 2066 ./src/gui/aboutdlg.py
72 175 2256 ./src/gui/passworddlg.py
6 18 134 ./src/gui/__init__.py
41 75 889 ./src/test_model.py
371 1033 10358 ./src/bglib/model/move.py
26 41 337 ./src/bglib/model/model.py
69 188 1252 ./src/bglib/model/util.py
36 131 669 ./src/bglib/model/constants.py
214 578 6136 ./src/bglib/model/board.py
9 18 137 ./src/bglib/model/__init__.py
6 3 50 ./src/bglib/model/test.py
239 537 5710 ./src/bglib/protocol/networkplayer.py
525 2819 24051 ./src/bglib/protocol/fibs.py
144 302 3694 ./src/bglib/protocol/session.py
6 18 134 ./src/bglib/protocol/__init__.py
67 163 1582 ./src/bglib/depot/cfg.py
113 261 2601 ./src/bglib/depot/base.py
6 18 134 ./src/bglib/depot/__init__.py
57 122 1148 ./src/bglib/depot/lines.py
49 118 1136 ./src/bglib/depot/dict.py
199 403 4975 ./src/bglib/gui/viewer.py
88 189 2676 ./src/bglib/gui/wysiwygeditor.py
233 525 6746 ./src/bglib/gui/player.py
90 198 2413 ./src/bglib/gui/testframe.py
78 182 2385 ./src/bglib/gui/ideditor.py
6 18 134 ./src/bglib/gui/__init__.py
11 14 266 ./src/bglib/gui/testcases.py
102 276 3476 ./src/bglib/image/context.py
24 34 369 ./src/bglib/image/resource/convert.py
212 418 6909 ./src/bglib/image/renderer.py
339 831 11125 ./src/bglib/image/PIL.py
203 546 6543 ./src/bglib/image/wxpython.py
6 18 134 ./src/bglib/image/__init__.py
145 353 3795 ./src/bglib/encoding/FIBS.py
151 381 3834 ./src/bglib/encoding/gnubg.py
344 954 7747 ./src/bglib/encoding/base.py
8 18 136 ./src/bglib/encoding/__init__.py
50 120 1109 ./src/bglib/encoding/urlsafe.py
6 18 134 ./src/bglib/__init__.py
115 241 2683 ./src/fibs/frameprogress.py
312 742 9997 ./src/fibs/client.py
115 249 3155 ./src/fibs/session.py
55 144 1456 ./src/fibs/tricks.py
151 288 4434 ./src/fibs/lobby.py
379 845 10500 ./src/fibs/table.py
150 326 4147 ./src/fibs/chat.py
70 139 2052 ./src/fibs/debugger.py
6 18 134 ./src/fibs/__init__.py
30 61 664 ./setup.py
159 187 6503 ./packaging/MacOSXSetup.py
43 66 1388 ./packaging/win32setup.py
6237 16063 181685 total
[nori@Asama]~/Desktop/work/wxpygammon% find . | grep test$ | xargs wc
16 73 313 ./src/bglib/model/board.test
387 2038 12682 ./src/bglib/model/move.test
68 96 1019 ./src/bglib/model/util.test
290 833 4421 ./src/bglib/encoding/base.test
108 779 4200 ./src/bglib/encoding/gnubg.test
21 228 1041 ./src/bglib/encoding/urlsafe.test
95 331 1986 ./src/bglib/encoding/FIBS.test
985 4378 25662 total
[nori@Asama]~/Desktop/work/wxpygammon% find . | grep Makefile$ | xargs wc
154 333 3668 ./packaging/Makefile
[nori@Asama]~/Desktop/work/wxpygammon% find . | grep nsi$ | xargs wc
319 668 15857 ./packaging/wxPyGammon.nsi

2008年5月23日金曜日

memo of idea for wxPython 2.8.7.1 on Mac OS X

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
creating macports port file for pythonw with 2.5.2 from macports python portfile.
adding variant to support ./configure --framework.

2008年5月18日日曜日

still far away to get out of mess

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
version string.

Yakumo% /opt/local/bin/python2.5
Python 2.5.2 (r252:60911, May 16 2008, 19:28:33)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
Yakumo% /usr/local/bin/python
Python 2.5.2 (r252:60911, Feb 22 2008, 07:57:53)
[GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
Yakumo% /usr/bin/python
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>


sys.path

Yakumo% /opt/local/bin/python2.5 -c "import sys; print sys.path"
['', '/opt/local/lib/python25.zip', '/opt/local/lib/python2.5', '/opt/local/lib/python2.5/plat-darwin', '/opt/local/lib/python2.5/plat-mac', '/opt/local/lib/python2.5/plat-mac/lib-scriptpackages', '/opt/local/lib/python2.5/lib-tk', '/opt/local/lib/python2.5/lib-dynload', '/opt/local/lib/python2.5/site-packages']
Yakumo% /usr/local/bin/python -c "import sys; print sys.path"
['', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/setuptools-0.6c8-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/py2app-0.3.6-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/bdist_mpkg-0.4.3-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/modulegraph-0.7-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/altgraph-0.6.7-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/macholib-1.2.1.dev_r23-py2.5.egg', '/Library/Python/2.5/site-packages/setuptools-0.6c8-py2.5.egg', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python25.zip', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-darwin', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-mac', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-mac/lib-scriptpackages', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-tk', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages', '/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/wx-2.8-mac-unicode', '/Users/nori/Library/Python/2.5/site-packages', '/Users/nori/Library/Python/2.5/site-packages/wx-2.8-mac-unicode']
Yakumo% /usr/bin/python -c "import sys; print sys.path"
['', '/Library/Python/2.5/site-packages/readline-2.5.1-py2.5-macosx-10.5-i386.egg', '/Library/Python/2.5/site-packages/buildbot-0.7.6-py2.5.egg', '/Library/Python/2.5/site-packages/setuptools-0.6c8-py2.5.egg', '/Library/Python/2.5/site-packages/py2app-0.3.6-py2.5.egg', '/Library/Python/2.5/site-packages/macholib-1.1-py2.5.egg', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python25.zip', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-mac', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/plat-mac/lib-scriptpackages', '/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-tk', '/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-dynload', '/Library/Python/2.5/site-packages', '/Library/Python/2.5/site-packages/PIL', '/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python/PyObjC', '/Users/nori/Library/Python/2.5/site-packages', '/Users/nori/Library/Python/2.5/site-packages/wx-2.8-mac-unicode']
Yakumo%

wxPython, Python, Carbon, X11 and MacOSX

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
I'm so puzzled.
Let me make this straight.

There are some distributions for using Python on Mac OS X(10.5)

  1. version 2.5.1 Apple "Native" python comes with OS X

  2. version 2.5.2 @ fink

  3. version 2.5.2 @ macports


There is an other way: easy_install. Mac OS X "User" Installation... but it fails with "error: Couldn't find a setup script in xxxxxxx"


Drawing System/API Choice

  1. Quartz/Cocoa

  2. Quartz/Carbon

  3. X11/GTK(? not sure)




selector


py2app


macholib


modulegraph


bdist-mpkg


wxPython.

  1. version 2.8.4.0 comes with OS X

  2. version 2.8.7.1 available at wxpython.org

  3. version 2.8.3(?!) avaibable at wxmac 28-2.8.3 @ fink

  4. version 2.8.7.1 available as py-wxpython @ mac ports



buildbot

2008年5月16日金曜日

wxPython on Mac OS X

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
元から入っているらしきwxPython: 2.8.4.0
ど~~しても2.8.7.1になりませぬ。いったいなんだこれは。

pythonとまったく関係ないですが・・・。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
パン焼きました。






まったくでもないか。パンの置いてある皿の下にある本はwxPython in Actionです。無水鍋のようなコンピュータ言語ってpythonのことかな?

このエントリをみてパンを焼きたくなった人のための参考リンク。無水鍋はアマゾンで買えます。

2008年5月15日木曜日

cross platform事例

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
これ
ここではpy2appとpy2exeをsetup.pyに同居させている。

relative path to open in py2app'ed.

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
can't open file even if

$py2app test.py ./hello/world.txt

to build test.app .
Can not use relative path?!
But wx.Image can handle relative path. why??
test.py

#!/usr/bin/env python
# -*- coding: us-ascii -*-
# vim: syntax=python
#

f = file('./hello/world.txt')
print f.read()
f.close()

2008年5月14日水曜日

mac win兼用makefile

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
とりあえず、現状こんな感じになりました。pythonなのにbdist_winistしてないのはなぜとか聞かないように。しかしmacとwinのmakefileを1つのファイルで済ます方針はどうなんでしょうね?releaseのためのbuildツリーを作る方法はそのためのmakefileを作って呼ぶようにすればいいので、このコードでの共有は本質的ではないです。ビルドステップの共有化(抽象化?)というべきか同じ名前のターゲットが用意されていることぐらいですか?改行はdosだし。びみょ~~~。

人様からみて参考になりそうなのはdmgまわりとかかな。


# Makefile for M$ Windows platform with MinGW make, mingw32-make to build
#

.PHONY: clean Release Develop useReleaseConfig useDevelopConfig abstRelease abstDevelop

all: installer
installer: Release
abstRelease: RelaseExecutable useReleaseConfig
abstDevelop: DevelopExecutable useDevelopConfig
clean: clean_installer clean_config clean_executable clean_workspace
#do not remove tree.


ifeq ($(PLATFORM),win32)
Release: abstRelease wxPyGammon.nsi
d:\bin\NSIS\makensis.exe wxPyGammon.nsi
copy workspace\wxPyGammon-installer.exe Release.exe
Develop: abstDevelop wxPyGammon.nsi
d:\bin\NSIS\makensis.exe wxPyGammon.nsi
copy workspace\wxPyGammon-installer.exe Develop.exe
clean_installer:
-del /Q Release.exe
-del /Q Develop.exe
-del /Q workspace\wxPyGammon-installer.exe
endif

ifeq ($(PLATFORM),darwin)

define create-dmg
hdiutil create -size $(word 1,$(shell du -sk workspace))k -type UDIF -fs HFS+ -volname 'wxPyGammon' -layout None $@
endef

define mount-dmg
hdiutil attach $^ -mountpoint dmg
endef

define unmount-dmg
WC_DEV=`hdiutil info | grep dmg | grep "^/dev" | awk '{print $$1}'` && \
hdiutil detach $$WC_DEV
endef

define dmgify
-mkdir dmg
$(mount-dmg)
cp -R workspace/dist/wxPyGammon.app dmg/wxPyGammon.app
$(unmount-dmg)
rm -rf dmg
endef

Release: Release.dmg
$(dmgify)
Develop: Develop.dmg
$(dmgify)

Release.dmg: abstRelease
$(create-dmg)
Develop.dmg: abstDevelop
$(create-dmg)

clean_installer:
-$(unmount-dmg)
-rm -rf dmg
-rm Release.dmg
-rm Develop.dmg
endif



ifeq ($(PLATFORM),win32)
DevelopExecutable: wxPyGammon.exe
RelaseExecutable: wxPyGammon.exe
wxPyGammon.exe: wxPyGammon.spec workspace
python D:\bin\pyinstaller-1.3\Build.py workspace/wxPyGammon.spec
wxPyGammon.spec: source workspace
python D:\bin\pyinstaller-1.3\Makespec.py -w -F -n wxPyGammon -o workspace tree/wxPyGammon
clean_executable:
-del /Q workspace\wxPyGammon.exe
endif


ifeq ($(PLATFORM),darwin)
DevelopExecutable: wxPyGammon.py MacOSXSetup.py useDevelopConfig workspace
python MacOSXSetup.py py2app

RelaseExecutable: wxPyGammon.py MacOSXSetup.py useReleaseConfig workspace
python MacOSXSetup.py py2app

wxPyGammon.py: source
mv tree/wxPyGammon tree/wxPyGammon.py
clean_executable:
-rm -rf workspace/wxPyGammon.app
endif

useReleaseConfig: source
ifeq ($(PLATFORM),win32)
copy tree\release\connection.cfg tree\config\connection.cfg
endif
ifeq ($(PLATFORM),darwin)
cp tree/release/connection.cfg tree/config/connection.cfg
endif

useDevelopConfig: source
ifeq ($(PLATFORM),win32)
copy tree\develop\connection.cfg tree\config\connection.cfg
endif
ifeq ($(PLATFORM),darwin)
cp tree/develop/connection.cfg tree/config/connection.cfg
endif

clean_config:
ifeq ($(PLATFORM),win32)
-del /Q tree\config\connection.cfg
endif
ifeq ($(PLATFORM),darwin)
-rm tree/config/connection.cfg
endif


#Get Latest from SVN
source: tree update_tree
tree:
svn co http://svn.tonic-water.com/projects/proprietary/wxpygammon/trunk/src/ tree
svn co http://svn.tonic-water.com/projects/proprietary/bglib/trunk/src/ tree/bglib
update_tree:
svn update tree
svn update tree/bglib

clean_tree:
ifeq ($(PLATFORM),win32)
-rmdir /S /Q tree
endif
ifeq ($(PLATFORM),darwin)
-rm -rf tree
endif


workspace:
mkdir workspace
clean_workspace:
ifeq ($(PLATFORM),win32)
-rmdir /S /Q workspace
endif
ifeq ($(PLATFORM),darwin)
-rm -rf workspace
endif

2008年5月13日火曜日

dmg関係

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
hdiutil @ developper.apple.com
hdid @ developper.applie.com

hdiutil attachであって、mount/umountではないらしい。
ditto
なんでこんなもんがあるのかよくわからん。びみょうな比較エントリ
mac wikiのMac OSX独自コマンドのページ、後者からリンクされているdmg関係のページ

「リモートにあるイメージファイルをローカルにマウントする」ことができるらしいwww。

hdid http://www.some.where/path/to/test.dmg

おいおい。webDAVで書き込みも可とかいったら発狂しそう。

ditto@ developper.apple.com

やはりumountとhdiutil umountは違うらしい。ここの20050913を参照のこと。


dmgに背景をいれる方法つーかこれはvolumeに背景をいれる方法では?ま、いいけど。

mac os xでないunix系のosでdmgを作る方法

mac os x上でdmgを作るmakefile
なんかwcがrm -rfできなくなったんですけど。リリースしたいコピーしなくてもいい。dmg作るだけでいいのに。典型的なやりすぎ。部品として振舞わない悪い例。


makedmg release--size=40m --mountas=dmg

とかすると./dmgに作ったdmgがマウントされるスクリプトがあればいいのだ。容量は40MegaByte.

Make a .dmg from any directoryが結構近そう。ただ2002のポストなので古い・・・。

python on mac

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ipythonとpythonでversionが違う!!ipythonだとsetuptoolsが入っているのにpythonだと入っていないくて動かない。一体全体なにがおきていることやら。
ez_installはipythonと同じpythonをつかっているらしく、systemのpythonにはインストール不能。ぐにゃー。

/usr/local/bin/python2.5

/Library/Framework/Python.framework/Versions/Current/bin/python
があるようだし。

あ~~python2.5で実行すればいいのかな?そうすると/usr/local/binのやつが実行されるような気がする。

mac の.dmgファイル。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Makefile
いやあgoogleっていいなぁ。

cwdとlnk

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
M$ windowsはよくわからない。
lnkってリンクファイルね。

Start->Menu->Programs

Start->Menu->Programs->Hoge
におかれているlnkで実行したときのcwdが違うような気がするのですが気のせい?前者だとprogramの実体がおかれているdirがcwdになるが、後者だとHoge dirがcwdになる。どういうことなんでしょう?ご存知のかた教えてください。

2008年5月12日月曜日

NSIS

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
だれかがかいたインストーラ

本家のsampleみてもFileで指定ファイルをsetOutPathしたところに書き込むなんてすぐわからないんだよね。結局rpmのspec fileと同じことすることになる。インストールしたいファイルを列挙して、アンインストールしたいファイルも列挙する。しかしそのときに先頭にコマンドを書かされるし、testするときにテスト用のルートディレクトリをしてできない。だるい。

2008年5月11日日曜日

Why do wx.App::SetTopWindow?

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Is there any thing beyond adding member for reference from original implementation of app? such as like this.

In another word: does widgets system any special thing to SetTopWindow'ed window?
The answer is Yes. It does.

src/common/appcmn.cpp

wxWindow* wxAppBase::GetTopWindow() const
{
wxWindow* window = m_topWindow;
if (window == NULL && wxTopLevelWindows.GetCount() > 0)
window = wxTopLevelWindows.GetFirst()->GetData();
return window;
}

Without setting, you gets nothing. :p


src/common/dlgcmn.cpp

wxWindow *wxDialogBase::GetParentForModalDialog(wxWindow *parent) const
{
// creating a parent-less modal dialog will result (under e.g. wxGTK2)
// in an unfocused dialog, so try to find a valid parent for it:
if ( parent )
parent = wxGetTopLevelParent(parent);

if ( !parent || !CanBeUsedAsParent(parent) )
parent = wxTheApp->GetTopWindow();

if ( parent && !CanBeUsedAsParent(parent) )
{
// can't use this one, it's going to disappear
parent = NULL;
}

return parent;
}

Setting TopWindow to app affects Modal state.


src/common/cshelp.pp

/ Begin 'context help mode'
bool wxContextHelp::BeginContextHelp(wxWindow* win)
{
if (!win)
win = wxTheApp->GetTopWindow();
if (!win)
return false;

wxCursor cursor(wxCURSOR_QUESTION_ARROW);
wxCursor oldCursor = win->GetCursor();
win->SetCursor(cursor);

It affects context help too.

src/msw/msgdlg.cpp

int wxMessageDialog::ShowModal()
{
if ( !wxTheApp->GetTopWindow() )
{
// when the message box is shown from wxApp::OnInit() (i.e. before the
// message loop is entered), this must be done or the next message box
// will never be shown - just try putting 2 calls to wxMessageBox() in
// OnInit() to see it
while ( wxTheApp->Pending() )
wxTheApp->Dispatch();
}

2008年5月10日土曜日

building executables from .py files

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク


There tools are based on same strategy.

  1. resolve dependencies in your app

  2. generate .pyc .pyo

  3. bundle them with python interpreter.



PyInstaller
  • Pros: you don't have to write your own setup.py

  • Cons: it is tricky to access data files

How to produce target:

python Build.py exe_name.spec

How to produce .spec file:

python Makespec.py -w -F -n exe_name yourscript.py

will produce exe_name.spec.
  • -w for window application, surpress console window to come up.

  • -F for produce a single file deployment

  • -n for specify exe filename.

How to access Data Files from Manual. It is too much.

import sys, carchive
this = carchive.CArchive(sys.executable)
data = this.extract('mystuff')[1]

if you are using intaller, you can have data dir but end users may change them.


py2exe
most widespread tool. To use, you have to write a setup.py file.
kw of setup: packages, package_dir, py_modules affect your exe (of cause), package_data does not. So need to use data_files instead. Make sure to specify zipfile=None, otherwise you'll have small exe with big .lzh usually this is not what you want.


from setuptools import setup, find_packages
import py2exe
import sys

sys.argv.append('py2exe')

setup(
name="blah",
version='alpha-0.1',
zip_safe=False,
description="blah",
long_description="""blah blah blah""",
url='http://www.py2exe.org',
license='python license',
author='AUTHOR',
author_email='email@email',
packages=find_packages('./src'),
package_dir={'':'./src'},
py_modules=['one'],
package_data={'.':['myjpeg.jpg'],
},
scripts=["your_script",],


#py2exe options
options={'py2exe':{'bundle_files':1}},
windows=[{'script':'your_script'},],
data_files=[('.',['myjpeg.jpg'], ),],
zipfile=None,
)

then,

python setup.py py2exe

and you'll find exe in .dist



py2app
How to produce target:

python setup.py py2app

How to produce setup.py for py2app

py2applet --make-setup yourscript.py -r your_resouce

Very easy to incluide resource. I guess it is because MacOS X provides application as a sort of directory.

2008年5月9日金曜日

今日のブツブツ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
select.select() @ select module
最初の 3 つの引数は `待機可能なオブジェクト' からなるシーケンスです: ファイル記述子を表す整数値、または引数を持たず、整数を返すメソッド fileno() を持つオブジェクトです。

poll@ select module

register(fd[, eventmask])
ファイル記述子をポーリングオブジェクトに登録します。これ以降の poll() メソッド呼び出しでは、そのファイル記述子に処理待ち中の I/O イベントがあるかどうかを監視します。fd は整数か、整数値を返す fileno() メソッドを持つオブジェクトを取ります。ファイルオブジェクトも通常 fileno() を実装しているので、引数として使うことができます。

poll([timeout])
登録されたファイル記述子に対してポーリングを行い、報告すべき I/O イベントまたはエラーの発生したファイル記述子に毎に 2 要素のタプル (fd, event) からなるリストを返します。

つ~~かなんでpollはオブジェクトかえさねーんだ?!寿命管理に問題が生じるからか?
おかげでmapを用意して管理する必要が出てくる。
たとえばasyncore.pyの131行目

r = poll.poll (l, timeout)
for fd, flags in r:
try:
obj = map[fd]
try:

2008年5月7日水曜日

erlangはじめました。その3

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ものすごく短い説明。「レコード=名前つきタプル」
なのでレコードの中身を知るのにマッチが使える。
レコードをシェルから定義して使うことはできない。
インポートして使うことはできるが。いけてないなぁ。
ipythonはclassを使えるのに。

case/ifはともにパターンのならびからなる。

case Expression of
pattern [when guard] -> expr_seq;
...
pattern [when guard] -> expr_seq
end

ifはguardにhitしないとエラーになる。まあすべての状況をちゃんと網羅するように条件を考えてコードしなさいという言語設計者の意図が見えますね。

if
Guard ->
expr_seq;
Guard ->
expr_seq
end

なんでも式である。try ... endも値を返す。

erlangはじめました。その2

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
なんかshellが重い。vimが快適に動いているので。

リスト内包表記

erl$ [X*X || X <- [1 ,2 ,3, 4]].
[1,4,9,16]
erl$ [X || {a ,X} <- [{a , 1} , {b ,2}, {c, 3}, {a, 4}, hello, "wow", {a, "boo"}]].
[1,4,"boo"]



ガード。ファイル上の出現順にマッチしていくのでwhenでマッチしたら次の行には処理が進まない。なのでX>Yじゃないケースだけ->Yに到達してmaxの機能が実現できる。

-module(mylists).
-export([sum/1, map/2, max/2]).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.

map(_, []) -> [];
map(F, [H|T]) -> [F(H) | map(F, T)].

max(X, Y) when X > Y -> X;
max(X, Y) -> Y.

erlangはじめました。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ちまたではやっている?らしいerlangを触ってみました。前回のpostでpythonのecho serverを作ったので、こんどはerlangでも作ってみたいと思います。

いきなりメモ:(後日整理するかも?)

erl$ code:get_path().



ipython$ sys.path

と多分同じ。モジュールの検索パスが表示される。

[Car|Cdr]
なのだ!
7. car, cdr, cons:基本関数 @ lispを参照のこと。


pythonで、

hoge, piyo = some_sequence

と書くと、some_sequenceが分解される、(hoge, piyo)か、[hoge, piyo]の場合ね。

これをもっと推し進めたようなこと(パターンマッチという)ができて、

erl${X, Y, Z} = {222, def, "cat"}.
{222, def, "cat"}

とかすると、

erl$X.
222

となる。
この機能によって階層を作れる。(Cでの構造体みたいなもの、ただ、名前をつけなくていいし、フィールドに名前も不要。というか名前がついてしまうと、参照透過性の兼ね合いからよくないのだろう。)

コテコテの関数言語であるのは

-module(mylists).
-export([sum/1]).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.

からもよくわかる。
この内容をfileとしてmylists.erlとしてcwdにセーブしたら

erl$ c(mylists).
{ok,mylists}

となり、コンパイルができるはず。んで、

erl$ L = [1, 3, 10].
[1,3,10]
erl$ mylists:sum(L).
14
erl$

とかできる。
myを打ったところで、tabを押すとlists:が補完され、さらにtabを打つとsum(が補完される。erlのシェルがmoduleについて知っているからに他ならない。この辺の使い勝手はipythonと大してかわらない。まあ?はないだろうけど、それに類似した機能拡張はできるか存在する貸しているはず。そのうち探そう。


-module(mylists).
-export([sum/1, map/2]).
sum([H|T]) -> H + sum(T);
sum([]) -> 0.

map(_, []) -> [];
map(F, [H|T]) -> [F(H) | map(F, T)].

二つの関数を1つのファイルに書くとこうなる。exportの構文ダサい気が・・・。

2008年5月5日月曜日

echoをpythonで書く。その2

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
SockServerバージョン。なんかmix-inしているがうまく機能していない。mix-inの順番間違えていてsingle threadになっていた。しかしまだctrl-cが効かないし、loadも跳ね上がってしまう。(while loopのせい)


#!/usr/bin/python
import SocketServer
import time

class EchoServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
allow_reuse_address = 1 # Seems to make sense in testing environment

class EchoRequestHandler(SocketServer.StreamRequestHandler):

def handle_one_request(self):
raw_requestline = self.rfile.readline()
self.wfile.write(raw_requestline)

def handle(self):
"""Handle multiple requests if necessary."""
while True:
self.handle_one_request()

server = EchoServer(('127.0.0.1', 20000), EchoRequestHandler)

server.serve_forever()

echoをpythonで書く。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
SFCの授業の課題をpythonする。

まずはselectなしバージョン。

#!/usr/bin/python

import socket
import time

sock = socket.socket()
sock.bind(('127.0.0.1', 20000))
sock.listen(1)
conn, address = sock.accept()
print 'got connection @', address
while True:
buf = conn.recv(40)
conn.send(buf)
time.sleep(1)


selectありバージョン。リストsocksのアイテムがどんどん増えるがそういうものです。

#!/usr/bin/python

import socket
import select

msock = socket.socket()
msock.bind(('127.0.0.1', 20000))
msock.listen(1)

socks = [msock]
while True:
ready, o, e = select.select(socks, [], [])
for sock in ready:
if sock == msock:
conn, address = sock.accept()
print 'got connection from', address
socks.append(conn)
else:
buf = sock.recv(40)
sock.send(buf)

2008年5月4日日曜日

コードサイズ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
一ヶ月で3000Line程度成長。ど~~なんでしょう。

[nori@Asama]~/Desktop/work/wxpygammon/src% find . | grep py$ | xargs wc
175 354 4002 ./model.py
87 174 2163 ./config.py
173 353 4745 ./main.py
75 175 2401 ./passworddlg.py
41 75 889 ./test_model.py
462 1304 11910 ./bglib/model.py
502 2767 23384 ./bglib/protocol/fibs.py
140 291 3558 ./bglib/protocol/session.py
6 18 134 ./bglib/protocol/__init__.py
46 102 1023 ./bglib/depot/cfg.py
113 261 2601 ./bglib/depot/base.py
12 22 173 ./bglib/depot/xml.py
6 18 134 ./bglib/depot/__init__.py
57 122 1148 ./bglib/depot/lines.py
49 118 1136 ./bglib/depot/dict.py
207 420 5152 ./bglib/gui/viewer.py
100 206 2909 ./bglib/gui/wysiwygeditor.py
99 239 2638 ./bglib/gui/player.py
88 202 2620 ./bglib/gui/ideditor.py
6 18 134 ./bglib/gui/__init__.py
91 248 3065 ./bglib/image/context.py
24 34 369 ./bglib/image/resource/convert.py
167 387 5950 ./bglib/image/renderer.py
29 47 495 ./bglib/image/style.py
149 365 4513 ./bglib/image/SVG.py
211 501 6360 ./bglib/image/PIL.py
173 459 5378 ./bglib/image/wxpython.py
6 18 134 ./bglib/image/__init__.py
144 352 3616 ./bglib/encoding/FIBS.py
141 342 3587 ./bglib/encoding/gnubg.py
345 951 7731 ./bglib/encoding/base.py
8 18 136 ./bglib/encoding/__init__.py
50 120 1109 ./bglib/encoding/urlsafe.py
25 63 660 ./bglib/pubsubproxy.py
6 18 134 ./bglib/__init__.py
115 241 2683 ./fibs/frameprogress.py
313 744 9952 ./fibs/client.py
113 249 3146 ./fibs/session.py
55 144 1456 ./fibs/tricks.py
186 353 5399 ./fibs/lobby.py
183 398 4946 ./fibs/table.py
150 326 4147 ./fibs/chat.py
70 139 2052 ./fibs/debugger.py
6 18 134 ./fibs/__init__.py
7 18 135 ./__init__.py
5211 13792 150141 total

re.compileの結果をcacheする。

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
タイプを減らしたいからクラス変数に固定的初期化するという手抜きをしていたが、数行核だけでre.compile済みのものを使えるようにした。ネットワークの通信内容をパースする正規表現だけに劇的に軽くなった。
nameエラーがraiseされたときにcompileするのも手だが、yieldとは併用できない。

前にもscaleした画像をcacheするコードを実装したが、この手のメモ化はコーディングコスト(数行)の割に効果が大きく(10倍オーダー)うれしい。

あ・・・クラスでcacheをもったほうがいいなぁ、これ。そうすればキャッシュをインスタンス間で共有できる。

class State(object):
def __init__(self):
self.regexp_cache = dict()

def __iter__(self):
for name, value in self.__class__.__dict__.items():
if name.startswith('CLIP') or name.startswith('FIBS'):
if name not in self.regexp_cache:
self.regexp_cache.update({name: [re.compile(regexp) for regexp in valu
e]})
for regexp in self.regexp_cache[name]:
yield name, regexp

中略

class LoginState(State):
FIBS_LoginPrompt = ["^login:", ]
CLIP_WELCOME = ["^1 [a-zA-Z_<>]+ [0-9]+ ",]
CLIP_OWN_INFO = ["^2 [a-zA-Z_<>]+ [01] [01]"]
CLIP_MOTD_BEGIN = ["^3$"]

2008年5月3日土曜日

バグの原因がわからないときは

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
関係する部分のスケルトンを書き直して比較するのが一番。
書いているコードではcheckableなmenu itemの状態とwindowの有無が一致しないが、下のコードでは一致する。

正確にはdisableされた場合にenableされるまでに何かが起こらないと一致しないって現象なんだけどね。(child windowをdeleteするのにネットワークの切断を待つので)

う~~ん、でもこれって読むより書くほうが「楽」ということの証明でないか??!!

import wx
import wx.aui


class MainWindow(wx.aui.AuiMDIParentFrame):
def __init__(self):
wx.aui.AuiMDIParentFrame.__init__(self, None, -1,
"parent",
size=(400, 300),
style=wx.DEFAULT_FRAME_STYLE,
)
self.children = {'alpha':None, 'bravo':None, 'chalie':None}
self.SetMenuBar(self.make_menu_bar())

def UpdateMenubar(self):
self.SetMenuBar(self.make_menu_bar())

def make_menu_bar(self):
menuBar = wx.MenuBar()

menuItem = wx.Menu()
for name, window in self.children.items():
item = menuItem.AppendCheckItem(-1, name, '???')
item.Check(window is not None)
self.Bind(wx.EVT_MENU, self.OnToggle, item)
menuBar.Append(menuItem, 'Items')
return menuBar

def OnToggle(self, evt):
Id = evt.GetId()
item = self.GetMenuBar().FindItemById(Id)
check = item.IsChecked()# check is done by wx before we read value.
label = item.GetLabel().encode('us-ascii') #ugh!
if check:
self.CreateChild(label)
else:
self.DeleteChild(label)

def CreateChild(self, name):
cw = ChildWindow(self, name)
self.children.update({name:cw})
self.UpdateMenubar()

def DeleteChild(self, name):
cw = self.children[name]
self.children.update({name:None})
cw.Destroy()
self.UpdateMenubar()


class ChildWindow(wx.aui.AuiMDIChildFrame):
def __init__(self, parent, name):
wx.aui.AuiMDIChildFrame.__init__(self, parent, -1, name)
self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.name = name

def OnClose(self, evt):
p = self.GetMDIParent()
p.DeleteChild(self.name)

def OnActivate(self, evt):
self.UpdateMenubar()

def UpdateMenubar(self):
self.SetMenuBar(self.make_menu_bar())

def GetMDIParent(self):
return self.GetParent().GetParent()

def make_menu_bar(self):
parent = self.GetMDIParent()
mb = parent.make_menu_bar()
menuFile = wx.Menu()
menuFile.Append(-1, 'child menu', 'help!')
mb.Append(menuFile, self.GetTitle())
return mb


app = wx.PySimpleApp()
mdi_parent = MainWindow()
mdi_parent.Show()

2008年5月2日金曜日

ProgressDialog(その6)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
対策。たいしたコードではないが一応参考までに。
panelでspacingしているすさまじくだるいコードですが。

class ProgressFrame(wx.Frame):
'''
Unlike Progress Dialog, it DOES NOT Yield.
So, it can be destroyed safely on Event from other thread.
'''
def __init__(self, parent, title, message, maximum):
assert(parent)
wx.Frame.__init__(self, parent, -1, title)

self.disabler = wx.WindowDisabler(self)


sizer = wx.BoxSizer(wx.VERTICAL)

# FIXME
# How to add edge in BoxSizer?
blank = wx.Panel(self, size=(100, 5))
sizer.Add(blank, 0, flag=wx.ALIGN_CENTER)

self.gauge = wx.Gauge(self, range=maximum)
sizer.Add(self.gauge, 0, flag=wx.ALIGN_CENTER)

blank = wx.Panel(self, size=(100, 5))
sizer.Add(blank, 0, flag=wx.ALIGN_CENTER)

self.text = wx.StaticText(self, label=message)
sizer.Add(self.text, 0, flag=wx.ALIGN_CENTER)

blank = wx.Panel(self, size=(100, 5))
sizer.Add(blank, 0, flag=wx.ALIGN_CENTER)

abort = wx.Button(self, -1, 'Abort')
self.Bind(wx.EVT_BUTTON, self.OnAbort, abort)
sizer.Add(abort, 0 , flag=wx.ALIGN_CENTER)

blank = wx.Panel(self, size=(100, 5))
sizer.Add(blank, 0, flag=wx.ALIGN_CENTER)

self.SetSizer(sizer)
sizer.Fit(self)
sizer.SetSizeHints(self)

def Update(self, new_count):
self.gauge.SetValue(new_count)

def Pulse(self):
self.gauge.Pulse()

def OnAbort(self, evt):
raise



if __name__ == '__main__':
class MyPF(ProgressFrame):
def OnAbort(self, evt):
p = self.GetParent()
p.stop()


class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='frame')
start = wx.Button(self, -1, 'Start')

self.pf = None
self.Bind(wx.EVT_TIMER, self.TimerHandler)
self.Bind(wx.EVT_BUTTON, self.OnButton, start)
self.timer = wx.Timer(self)
self.count = 0
self.Show()

def __del__(self):
sefl.stop()

def start(self):
self.pf = MyPF(self, 'test title', 'test message', 100)
self.timer.Start(100)
self.pf.Show()

def stop(self):
if self.pf:
self.pf.Destroy()
self.pf = None
self.count = 0
self.timer.Stop()

def OnButton(self, evt):
self.start()
def TimerHandler(self, evt):
self.count += 1
if self.pf:
self.pf.Pulse()
if self.count > 50:
self.stop()

app = wx.PySimpleApp()
frame = TestFrame()
app.MainLoop()

2008年5月1日木曜日

CallAfterとYield

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
積み残しだったYieldとCallAfterの調査。EventとしてPostされてますね。ということはYieldの中で処理されてしまいうるので、CallAfterで実行するメソッドがDlg::Destroyを呼ぶと落ちますね。これですっきり。気持ちよくねられます。
wxPython/src/_core_ex.py

def CallAfter(callable, *args, **kw):
"""
Call the specified function after the current and pending event
handlers have been completed. This is also good for making GUI
method calls from non-GUI threads. Any extra positional or
keyword args are passed on to the callable when it is called.

:see: `wx.CallLater`
"""
app = wx.GetApp()
assert app is not None, 'No wx.App created yet'

if not hasattr(app, "_CallAfterId"):
app._CallAfterId = wx.NewEventType()
app.Connect(-1, -1, app._CallAfterId,
lambda event: event.callable(*event.args, **event.kw) )
evt = wx.PyEvent()
evt.SetEventType(app._CallAfterId)
evt.callable = callable
evt.args = args
evt.kw = kw
wx.PostEvent(app, evt)

ProgressDialog(その5)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
::wxSafeYield

bool wxSafeYield(wxWindow* win = NULL, bool onlyIfNeeded = false)

This function is similar to wxYield, except that it disables the user input to all program windows before calling wxYield and re-enables it again afterwards. If win is not NULL, this window will remain enabled, allowing the implementation of some limited user interaction.

Returns the result of the call to ::wxYield.

で、実装はこうなっている。

// Yield to other apps/messages and disable user input to all windows except
// the given one
bool wxSafeYield(wxWindow *win, bool onlyIfNeeded)
{
wxWindowDisabler wd(win);

bool rc;
if (onlyIfNeeded)
rc = wxYieldIfNeeded();
else
rc = wxYield();

return rc;
}


あとはwxYieldだが次のようになっている。

bool wxYield()
{
return wxTheApp && wxTheApp->Yield();
}

bool wxYieldIfNeeded()
{
return wxTheApp && wxTheApp->Yield(true);
}


で、wxApp::Yieldに帰結する。あー、ながかった。

Yieldするとイベントがプロセスされるが、その中でYieldしたDialogを殺したら当然、戻ってきたときにthisがNULLなのでアプリがクラッシュしてしまいます!

今回の場合はDialogのEventHandlerがYield中であることは知らないのでこれに該当するでしょう。ネットワークから届いたデータが引き金となって受信スレッドからwx.CallAfterで呼ばれている。CallAfterはイベントの処理が終わった後に実行されるので、CallAfterの処理がYieldで行われている可能性は否定できない(どこを読めばいいのだ?)。

windowを開いたままイベントハンドラを抜けてしまうなら、そのwindowはwxのDialogである必要がなく(Yieldしてもらいたくない)て、親のWindow側からpollできることになるので親をプログラム的にDisableしてprogress barを自前で描くwindowを作るというのがひとつの解。

もうひとつは、前の可能性が正しいとしてYield中だったらもういちどCallAfterかなんかしてYieldを抜けてから処理が行われるようにする。wxの側でこの手のガードをすることも考えられるが、微妙な気がする。

ProgressDialog(その4)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
長くなってしまったのエントリを変えた。まえのエントリではDestroyをちょっと追った。
こんどはProgressDialogを実装しているsrc/generic/progdlgg.cpp

まずは::Updateの中でbarがいっぱいになるようなvalueを渡したときの処理が行われる部分。

if ( value == m_maximum )
{
if ( m_state == Finished )
{
// ignore multiple calls to Update(m_maximum): it may sometimes be
// troublesome to ensure that Update() is not called twice with the
// same value (e.g. because of the rounding errors) and if we don't
// return now we're going to generate asserts below
return true;
}

// so that we return true below and that out [Cancel] handler knew what
// to do
m_state = Finished;
if( !(GetWindowStyle() & wxPD_AUTO_HIDE) )
{
EnableClose();
DisableSkip();
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
EnableCloseButton();
#endif // __WXMSW__

if ( newmsg.empty() )
{
// also provide the finishing message if the application didn't
m_msg->SetLabel(_("Done."));
}

wxYieldIfNeeded() ;

(void)ShowModal();
}
else // auto hide
{
// reenable other windows before hiding this one because otherwise
// Windows wouldn't give the focus back to the window which had
// been previously focused because it would still be disabled
ReenableOtherWindows();

Hide();
}
}
else // not at maximum yet if ( value == m_maximum )


デストラクタとReenableOtherWindows

// ----------------------------------------------------------------------------
// destruction
// ----------------------------------------------------------------------------

wxProgressDialog::~wxProgressDialog()
{
// normally this should have been already done, but just in case
ReenableOtherWindows();
}

void wxProgressDialog::ReenableOtherWindows()
{
if ( GetWindowStyle() & wxPD_APP_MODAL )
{
delete m_winDisabler;
m_winDisabler = (wxWindowDisabler *)NULL;
}
else
{
if ( m_parentTop )
m_parentTop->Enable();
}
}


でいくつか気になるメンバ変数があるが、m_parentTopはコンストラクタの中で

m_parentTop = wxGetTopLevelParent(parent);

となっている。

wxGetTopLevelParentの実装は、src/common/wincmn.cpp

// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------

wxWindow* wxGetTopLevelParent(wxWindow *win)
{
while ( win && !win->IsTopLevel() )
win = win->GetParent();

return win;
}


関連は不明だがなにかあるのかもしれない。一応よんでみた。
  • ::wxGetTopLevelParent() returns NULL @ wx-users
    要点:wxTopLevelWindowはDestroyの過程でwxWindowに成り下がった後、自分の子をDestroyし、最後になくなる。なので、Destroyされる子の側でよぶとNULL返すことになる

  • Why does wxGetTopLevelParent() not return a wxTopLevelWindow?



  • wxWindowDisablerも気になる。実装はsrc/common/utilscmn.cppにある。
    概要としてはwxTopLevelWindows.GetFirstでTopWindowのリストにあるwindowにたいしてdisableを呼んでいる。


    // ----------------------------------------------------------------------------
    // wxSafeYield and supporting functions
    // ----------------------------------------------------------------------------

    void wxEnableTopLevelWindows(bool enable)
    {
    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    node->GetData()->Enable(enable);
    }

    wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
    {
    // remember the top level windows which were already disabled, so that we
    // don't reenable them later
    m_winDisabled = NULL;

    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    {
    wxWindow *winTop = node->GetData();
    if ( winTop == winToSkip )
    continue;

    // we don't need to disable the hidden or already disabled windows
    if ( winTop->IsEnabled() && winTop->IsShown() )
    {
    winTop->Disable();
    }
    else
    {
    if ( !m_winDisabled )
    {
    m_winDisabled = new wxWindowList;
    }

    m_winDisabled->Append(winTop);
    }
    }
    }

    wxWindowDisabler::~wxWindowDisabler()
    {
    wxWindowList::compatibility_iterator node;
    for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
    {
    wxWindow *winTop = node->GetData();
    if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
    {
    winTop->Enable();
    }
    //else: had been already disabled, don't reenable
    }

    delete m_winDisabled;
    }

    ProgressDialog(その3)

    このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
    src/gtk/window.cppwxWindowGTK::~wxWindowGTK

    wxWindowGTK::~wxWindowGTK()
    {
    SendDestroyEvent();

    src/common/wincmn.cppwxWindowBase::SendDestroyEvent

    void wxWindowBase::SendDestroyEvent()
    {
    wxWindowDestroyEvent event;
    event.SetEventObject(this);
    event.SetId(GetId());
    GetEventHandler()->ProcessEvent(event);
    }

    src/common/event.cpp


    #if wxUSE_GUI
    ...
    IMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent)
    ...
    #endif // wxUSE_GUI
    ...

    // System events
    ...
    DEFINE_EVENT_TYPE(wxEVT_DESTROY)
    ...

    wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win)
    {
    SetEventType(wxEVT_DESTROY);
    SetEventObject(win);
    }

    で、IMPLEMENT_DYNAMIC_CLASSはなにか?というとRTTI 関数なんですよ。Run Time Type Identificationだっけ?RTTIとSWIGの関係がどうなっているのかを追うのも面白そうですが脱線なのでしません。
    wx/object.h

    #define IMPLEMENT_DYNAMIC_CLASS(name, basename) \
    wxIMPLEMENT_CLASS_COMMON1(name, basename, name::wxCreateObject) \
    wxObject* name::wxCreateObject() \
    { return new name; }



    wx/event.h
    で、wxEVT_DESTROYは何者か?というと

    DECLARE_EVENT_TYPE(wxEVT_DESTROY, 411)
    ...
    // Window creation/destruction events: the first is sent as soon as window is
    // created (i.e. the underlying GUI object exists), but when the C++ object is
    // fully initialized (so virtual functions may be called). The second,
    // wxEVT_DESTROY, is sent right before the window is destroyed - again, it's
    // still safe to call virtual functions at this moment
    /*
    wxEVT_CREATE
    wxEVT_DESTROY
    */
    ...
    #define EVT_WINDOW_DESTROY(func) wx__DECLARE_EVT0(wxEVT_DESTROY, wxWindowDestroyEventHandler(func))
    ...


    WindowDestroyEventのドキュメント(wxPython)

    The EVT_WINDOW_DESTROY event is sent from the wx.Window destructor when the GUI window is destroyed.

    When a class derived from wx.Window is destroyed its destructor will have already run by the time this event is sent. Therefore this event will not usually be received at all by the window itself. Since it is received after the destructor has run, an object should not try to handle its own wx.WindowDestroyEvent, but it can be used to get notification of the destruction of another window.

    src/common/toplvcmn.cpp
    これだけブランチじゃなくてトランクから持ってきてます。トランクとブランチでなんか内容が違う。

    // ----------------------------------------------------------------------------
    // event table
    // ----------------------------------------------------------------------------

    BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
    EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
    EVT_SIZE(wxTopLevelWindowBase::OnSize)
    EVT_WINDOW_DESTROY(wxTopLevelWindowBase::OnChildDestroy)
    WX_EVENT_TABLE_CONTROL_CONTAINER(wxTopLevelWindowBase)
    END_EVENT_TABLE()
    ...

    void wxTopLevelWindowBase::OnChildDestroy(wxWindowDestroyEvent& event)
    {
    event.Skip();

    wxWindow * const win = event.GetWindow();
    if ( win == m_winDefault )
    m_winDefault = NULL;
    if ( win == m_winTmpDefault )
    m_winTmpDefault = NULL;
    }


    ブランチでの内容

    // ----------------------------------------------------------------------------
    // event table
    // ----------------------------------------------------------------------------

    BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
    EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
    EVT_SIZE(wxTopLevelWindowBase::OnSize)
    END_EVENT_TABLE()