10 件 見つかりました。

CHALOW Search - hiChangeLog ChangeLog INDEX

Acrobatを用いて外部プロセスからPDFにリンクを設定 [COM][python][PyWin32][PDF]

[2007-01-31-01]に「javascriptによるPDFリンク制御は上書きのみ」などと書いたが、やってみたらできた。また、[2007-01-08-01]にCOMからのリンク作成は無理っぽいなどと書いたが、これもjavascriptを経由しできた。顛末をメモする。WinXP SP3 Acrobat 9.1.3 pro

まずは結論。以下のスクリプトが動いた。
python(PyWin32):

import win32com.client
import winerror
win32com.client.dynamic.ERRORS_BAD_CONTEXT.append(winerror.E_NOTIMPL) # omajinai

doc = win32com.client.Dispatch("AcroExch.App").GetActiveDoc().GetPDDoc()
jso = doc.GetJSObject() # <= this requires omajinai
link = jso.addLink(0, (70,70,225,50))
link.borderWidth = 3
link.borderColor = (u'RGB', 0, 0, 255)
link.setAction("this.pageNum = 2")

javascript: (コンソールにペーストして全部選択しCtrl+Enterすれば実行できる)
var linkRect = [70,70,225,50];
var link1= this.addLink(0, linkRect);
link1.borderWidth = 3;
link1.borderColor = color.blue;      
link1.setAction("this.pageNum = 2")

--

Acrobatには豊富なjavascript APIが提供されている。COMインターフェースもあるが、これよりも充実している。
Adobe - Acrobat Developer Center - JavaScript for Acrobat
Adobe - Acrobat Developer Center - Interapplication Communication <= COM
Acrobatを完全操作するにはJavaScriptオブジェクト(JavaScriptAPI)を覚えないとダメ!?

Adobe Acrobat 7.0例文辞典にも文例が豊富。

さてCOMによるAcrobatの操作のためには、上記理由により、COMからのjavascript呼出しが勘所となる。このためのJSObjectなるインターフェースが用意されており、VBによる例文が上のリンク中"Developing Applications Using Interapplication Communication"に出ている。(C/C++からの利用方法は多少異なるようである。JS オブジェクトを C / C++ から利用する方法についてなるそのものズバリの記述もあるがこちらは試してない。

あとはこれをpythonから呼ぶだけだが、GetJSObjectメソッドは、戻り値がちょっと特殊でLPDISPATCH*となっており、そのままではエラーが出て実行できない。回避のためには、ERRORS_BAD_CONTEXTに上記の通り値をappendしてやればよい。[python-win32] COM, Acrobat and JavaScript

COMクライアントで利用する定数(やメソッド)を知るためにmakepy.pyを使ってStaticDispatch用モジュールを作成する [PyWin32]

pywin32のwin32comでCOMクライアントを作成する際必要となる定数やメソッドをどう取得するか?
makepy.pyによってStaticDispatch用モジュールを作成すれば良い。
タイプライブラリ名が判っている場合は以下でOK。C:\Python25\Lib\site-packages\win32com\gen_py 中に作成されたモジュール(ファイル)中に記載されている。

C:\Python25\Lib\site-packages\win32com\client>python makepy.py "Igor Pro 6.0 Type Library"
DLLや実行ファイルを以下のように直接指定してもOK。
C:\Python25\Lib\site-packages\win32com\client>python makepy.py typelib, "C:\Program Files\hoge\fuga.exe"

タイプライブラリ名は C:\Python25\Lib\site-packages\win32com\client\combrowse.py を起動して、出てくるウィンドウの中から見つけられる。上記makepy.pyを直接起動しても探す用インターフェースが出てくるそうだが、私の環境では引数なしのmakepy.pyは起動できなかった。これは、Adobe Illustrator CSをインストールしていたため。バージョンが数値でなく'CS'となっているので、makepy.py的になんじゃこりゃとなってしまう模様(勿論、makepy.pyの修正によって回避できる)。

VisualStudio + VB だと、こんな手間は不要なばかりか補完まで行ってくれるのが羨しい。

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)を利活用する2 [PyWin32][Windowsプログラミング]

[2008-08-16]の続き。ちょっと実際に試してわかったことをメモする。

結論:ResEditを使う際、win32rcparser.pyを変更した方が良い。変更箇所はこのメモ後半に示す。

ResEditで配置する場合、いくつか「地雷」なコントロールがある。

(1) チェックボックス、ラジオボタン
チェックボックスやラジオボタンを配置したリソーススクリプトを使うと、pythonスクリプト実行時ダイアログ自体も表示されなかった。
ResEditでチェックボックス(ラジオボタンも同様)を配置すると以下のようなリソーススクリプトとなる。win32rcparser.pyはこれをちゃんと解釈してくれないようだ。

AUTOCHECKBOX    "Check1", IDC_CHECKBOX1, 10, 43, 40, 10
C:\Python25\Lib\site-packages\win32\test\win32rcparser\test.rc を見ると以下の記述は正しく解釈されているようだった。
CONTROL         "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,52,68,12
両者はリソーススクリプト的には等価だが、前者の記述はwin32rcparser.pyは想定してなかった、といったところか。

(2) コモンコントロールとピクチャコントロール
スピン、プログレスバーも同様、使用するとダイアログが表示されなかった。
ResEdit、上記test.rcによるリソーススクリプトの記述を順に示す。
CONTROL         "", IDC_SPIN1, UPDOWN_CLASS, UDS_ARROWKEYS, 10, 119, 9, 14
CONTROL         "Spin1",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,7,71,14,22
というわけで、ResEditのウィンドウクラスの表現(UPDOWN_CLASS)がwin32rcparserに解釈できなかった、という感じ。ピクチャコントロールも同様に躓いた模様。

凝ったUIは趣味ではないが、チェックボックスやスピンが自由に使えないとなると結構つらい。
これらをどう解決するか?
win32rcparser.pyに修正を施すのがあるべき対処。明快だし、多分比較的難しくない。
もうひとつの方法は、リソーススクリプト読み込み時に、win32rcparserが解釈できる形式に変換すること。ちょっと面倒だが、既存物を変更する必要が無いので、役割分担が明確で、変化にも柔軟に対応できるだろう。
ここでは安直に前者を選択した。場当たり的な対処を施したパッチが以下(前メモの、ヘッダ解釈にまつわる変更も含む)。これにより、プッシュボタン、チェックボックス、ラジオボタン、グループボックス、スタティックテキスト、ピクチャコントロール、スクロールバー、エディットボックス、リストボックス、コンボボックス、スピン、スライダー、プログレスバー、タブ、リストビュー、ツリービュー、IPアドレスコントロール、日付選択、カレンダー、を配置したダイアログボックスを無事に解釈し表示できた。イベントを割当ててどうのこうのはまだ行っていないが、多分問題ないだろう。
--- C:/Python25/Lib/site-packages/win32/lib/win32rcparser_orig.py	Thu Jul 29 00:25:22 2004
+++ C:/temp/e/f/win32rcparser.py	Sun Aug 17 14:25:20 2008
@@ -199,10 +199,12 @@
 
     def parseH(self, file):
         lex = shlex.shlex(file)
         lex.commenters = "//"
         token = " "
+        lex.whitespace += '()'
+        lex.wordchars += '-'
         while token is not None:
             token = lex.get_token()
             if token == "" or token is None:
                 token = None
             else:
@@ -456,10 +458,17 @@
             self.getCommaToken()
 
             if control.controlType == "CONTROL":
                 self.getToken()
                 control.subType = self.token[1:-1]
+
+                # ad hoc handling for ResEdit's common-controls by H.Itoh
+                # ex. 'UPDOWN_CLASS' => 'UPDOWN_CLASSA' => "msctls_updown32" (see commctrl l.731) etc.
+                try: control.subType = getattr(commctrl, self.token+'A')
+                except AttributeError: pass
+                if self.token=='WC_STATIC': control.subType = 'Static'
+
                 thisDefaultStyle = defaultControlStyle | \
                                    _addDefaults.get(control.subType, 0)
                 # Styles
                 self.getCommaToken()
                 self.getToken()
@@ -483,10 +492,21 @@
                 self.getToken()
                 control.style, control.styles = self.styles([], thisDefaultStyle)
             if self.token==",":
                 self.getToken()
                 control.styleEx, control.stylesEx = self.styles([], defaultControlStyleEx)
+
+            # ad hoc handling for ResEdit by H.Itoh
+            f = lambda s: control.controlType.endswith(s)
+            if f('CHECKBOX') | f('RADIOBUTTON'):
+                for s in ['BS_'+control.controlType, 'WS_TABSTOP']:
+                    control.styles.append(s)
+                    control.style |= getattr(win32con, s)
+                control.controlType = 'CONTROL'
+                control.subType = 'Button'
+                control.style |= defaultControlStyle
+
             #print control.toString()
             dlg.controls.append(control)
 
 def ParseStreams(rc_file, h_file):
     rcp = RCParser()

上記の修正は関係ないが、win32rcparser.pyは下記のように使う(下記はダイアログを表示させるだけ。イベントハンドラの記述については[2008-06-07-1]を参照)。my.rcが作成したリソーススクリプト。
from pywin.mfc import dialog
import win32rcparser

class Mydialog(dialog.Dialog):

    def __init__(self, ddef):
        dialog.Dialog.__init__(self, ddef)
        
    def OnInitDialog(self):
        return dialog.Dialog.OnInitDialog(self)

if __name__=='__main__':
    rc = win32rcparser.Parse('my.rc')
    ddef = rc.dialogs['IDD_DIALOG1']
    w = Mydialog(ddef)
    w.DoModal()

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)を利活用する [PyWin32][Windowsプログラミング]

[2008-06-09-2]で、pythonによるwindowsプログラミングにおいてリソース(スクリプト/エディタ)が使えそうである旨メモした。
その時はリソーススクリプトをパースする在野のpythonスクリプトを見つけ出したと思っていたが、実は手元のpywin32(-211)に同様のものが含まれていた。
本体は C:\Python25\Lib\site-packages\win32\lib\win32rcparser.py にあり、C:\Python25\Lib\site-packages\win32\Demos\win32rcparser_demo.py でその動作っぷりが確かめられる。これで、個人的には、pythonによるwindowsプログラミングの敷居がぐっと下がったのではと感じる。

ただこれをResEditで利用する場合、そのままでは動かない。以下を参照。

- ANSI版のResEditを使うべき。Unicode版はUTF16のリソーススクリプトを吐くが、win32rcparser.py はこれをうまく読んでくれなかった。本来はwin32rcparser.pyに修正を施すべきだが、これは面倒。作成後にリソーススクリプトをANSIに変換しても良いけれど、そんなことするくらいなら最初からANSI版を使うのが良い。
- ResEditの吐くヘッダ中の

#define IDC_STATIC (-1)
が、そのままでは通らない。これは、カッコと負号がちゃんとパースされていないため。この行を編集(消すなり、カッコ無しの正数にしたり)するのがひとつの対策。即ちアプリケーション本体の実行時に動的にこの行をフィルタしてwin32rcparserに渡す、など。もうひとつの対策は、win32rcparser.pyに修正を施すこと。場当たり的だが以下のような簡単に修正できるので、こちらの方が良さそう。
@@ -199,10 +199,12 @@
 
     def parseH(self, file):
         lex = shlex.shlex(file)
         lex.commenters = "//"
         token = " "
+        lex.whitespace += '()'
+        lex.wordchars += '-'
         while token is not None:
             token = lex.get_token()
             if token == "" or token is None:
                 token = None
             else:

これでpythonによるwindowsアプリの量産態勢に入れるだろうか。

pythonからSendInput [Windowsプログラミング][python][PyWin32]

下記は、windowsのAPIのSendInputをpythonから呼ぶ例。
Adobe Readerに右矢印入力を10発送りこむ(開いてるPDFを10ページ進める)。エラー処理は省略。
この手のことはAutoHotKeyが専門だけど、pythonでできるにこしたことはない。
AppendKeyInput で win32con.KEYEVENTF_KEYUP を入れないと、同じキーの連続入力が出来ない。
http://mail.python.org/pipermail/python-win32/2005-April/003131.html を参照。

from ctypes import *
import win32ui, win32con

PUL = POINTER(c_ulong)
class KeyBdInput(Structure):
    _fields_ = [("wVk", c_ushort),
                ("wScan", c_ushort),
                ("dwFlags", c_ulong),
                ("time", c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(Structure):
    _fields_ = [("uMsg", c_ulong),
                ("wParamL", c_short),
                ("wParamH", c_ushort)]

class MouseInput(Structure):
    _fields_ = [("dx", c_long),
                ("dy", c_long),
                ("mouseData", c_ulong),
                ("dwFlags", c_ulong),
                ("time",c_ulong),
                ("dwExtraInfo", PUL)]
               
class Input_I(Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(Structure):
    _fields_ = [("type", c_ulong),
                ("ii", Input_I)]


def AppendKeyInput(vk):
    ret = []
    extra = c_ulong(0)
    ii_ = Input_I()
    scan = windll.user32.MapVirtualKeyA(vk, 0)
    ii_.ki = KeyBdInput(vk, scan, 0, 0, pointer(extra) )
    ret.append( ( win32con.INPUT_KEYBOARD, ii_ ) )

    ii2_ = Input_I()
    scan = windll.user32.MapVirtualKeyA(vk, 0)
    ii2_.ki = KeyBdInput(vk, scan, win32con.KEYEVENTF_KEYUP, 0, pointer(extra) )
    ret.append( ( win32con.INPUT_KEYBOARD, ii2_ ) )
    return ret

def ExecSendInput(inputs):
    num = len(inputs)
    FInputs = Input * num
    x = FInputs(*inputs)
    windll.user32.SendInput(num, pointer(x), sizeof(x[0]))
    

if __name__ == '__main__':
    inputs = []
    for i in range(10):
        inputs += AppendKeyInput(win32con.VK_RIGHT)
    
    acrobat = win32ui.FindWindowEx(None, None, 'AdobeAcrobat', None)
    acrobat.SetForegroundWindow()
    ExecSendInput(inputs)

pywin32でビットマップを扱う際のメモ [python][PyWin32]

なんちゃってwin32api(あるいはMFC)環境であるpywin32でビットマップを扱う際、意外と手間取ったのでメモ。

やりたかったことは、キャプチャしたビデオ信号のリアルタイム表示。つまり頻繁にやってくるビットマップのデータ列を頻繁に描画したいという状況。Windowsでのビットマップの描画方法は、私の理解では、多分、(有効な)ビットマップハンドルの取得方法に帰着する。なのでデータ列からビットマップハンドルを如何に作るかがここでのお題となる。今のところ、ctypesでCreateDIBSectionを呼出すのが良いと思っており、実際問題なく動作している。

win32gui.LoadImage や PyCBitmap.LoadBitmapFile は単純で簡単だが、リアルタイム表示においていちいちファイルを介するのは速度的に論外。StringIOでメモリ上にファイルオブジェクトを作成すれば速度の問題は解決するかと思い PyCBitmap.LoadBitmapFile でやってみたが、しばらくすると「このコマンドを実行する記憶域がありません」と例外が飛んでくるので、この方法も無理。

そもそもこんな状況ではwin32apiのCreateDIBSectionの使用が定石のひとつと思うが、残念なことにpywin32にこれは定義されていない。(Windows のデバイスコンテキストをビットマップファイルに変換する。Python でも参照)なのでctypesを介してこれを呼出すことにした。

とはいえ私はctypesの動作を深く理解していない(なので下記にいちいちメモをする)。そこでpygletのソースから該当部分を拝借する方法をとった。

CreateDIBSectionにはBITMAPINFOHEADERを渡す必要がある。これを定義するには如何のようにする(window/win32/types.py より)。

from ctypes import *
from ctypes.wintypes import *
class BITMAPINFOHEADER(Structure):
    _fields_ = [
        ('biSize', DWORD),
        ('biWidth', LONG),
        ('biHeight', LONG),
        ('biPlanes', WORD),
        ('biBitCount', WORD),
        ('biCompression', DWORD),
        ('biSizeImage', DWORD),
        ('biXPelsPerMeter', LONG),
        ('biYPelsPerMeter', LONG),
        ('biClrUsed', DWORD),
        ('biClrImportant', DWORD),
    ]

実際の値は下記のように作る(window/win32/__init__.py, Win32Window.get_icon より)。勿論、ヘッダの内容はデータ列の内容に依存する。DirectShowを使うなら AM_MEDIA_TYPE 内の VIDEOINFOHEADER 内に BITMAPINFOHEADER そのものがあるので、それをそのまま使えばよい。
def GetBitmapInfoHeader(w, h):
        header = BITMAPINFOHEADER()
        header.biSize = sizeof(header)
        header.biWidth = w
        header.biHeight = h
        header.biPlanes = 1
        header.biBitCount = 24
        header.biCompression = 0
        header.biSizeImage = w*h*3
        header.biXPelsPerMeter = 0
        header.biYPelsPerMeter = 0
        header.biClrUsed = 0
        header.biClrImportant = 0
        return header

そして以下のようにCreateDIBSectionを呼ぶ。(上と同じく__init__.pyより)
dataptr = c_void_p()
bitmap = windll.gdi32.CreateDIBSection(self.GetDC().GetHandleOutput(),
                                            byref(GetBitmapInfoHeader(w, h)),
                                            win32con.DIB_RGB_COLORS, byref(dataptr), None, 0)

あとはメモリデバイスコンテキストにbitmapをSelectObjectすれば準備完了。実際のデータを流すには下記のようにする。type(buf)はstr。(VideoCaptureモジュールのgetBufferより取得)
memmove(dataptr, buf, len(buf))

以上で問題なく動いている模様。

ctypesは以下に記述があった。
ctypesによるDLL内の関数の呼び出し
mtamaki.com : #47 (pythonからctypesで任意のDLLの関数を使う。)
2007年 11月 (1)。

描画(GDI、デバイスコンテキスト)にまつわるメモ [python][PyWin32]

GDIオブジェクト、デバイスコンテキスト、メモリデバイスコンテキストといった単語は作業中はなんとなく解ったつもりでいるが、少し間をおくと木端微塵に忘れる。pywin32で描画のコードを書こうとしたが、やっぱりすっかり忘れていて参った。動いたコードをメモしておく。

from pywin.mfc import dialog
import win32con, win32ui

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_DLGFRAME | win32con.DS_MODALFRAME | win32con.WS_POPUP |
                win32con.WS_VISIBLE |  win32con.WS_CAPTION  | win32con.WS_SYSMENU )
    tmpl = [ ["my dialog", (0, 0, 200, 100), dlgstyle], ]
    def __init__(self): dialog.Dialog.__init__(self, self.tmpl)

    def OnPaint(self):
        dc = self.GetDC()

        # copy itself
        dc.BitBlt((0,0), (20,20), self.GetWindowDC(), (0,0), win32con.SRCCOPY)

        # line
        dc.LineTo((30,30))

        # line with a customized pen
        cpen = win32ui.CreatePen(win32con.PS_SOLID, 5, 10000000)
        dc.SelectObject(cpen)
        dc.LineTo((50,50))

        # drawing on memory device context
        dcmem = dc.CreateCompatibleDC()
        cbmp = win32ui.CreateBitmap()
        cbmp.CreateCompatibleBitmap(dc, 100, 100)
        dcmem.SelectObject(cbmp)
        dcmem.SelectObject(cpen)
        dcmem.LineTo((30,30))
        dc.BitBlt((50,0), (50,50), dcmem, (0,0), win32con.SRCCOPY)
        
        self._obj_.OnPaint()

d = Mydialog()
d.DoModal()

pywin32のMFCプログラミングでリソース(スクリプト/エディタ)が利活用できるか? [PyWin32][Windowsプログラミング]

[2008-06-07]でPyWinのMFC(GUI)プログラミングが有望っぽい事をメモした。
さてGUIプログラミングではコントロールの配置がキモである。ソース内にベタ書きするのは、ファイルが1つで済むので好きだけど、ある程度の規模に膨れるとそうも言ってられなくなる。Visual Studioによるwin32/MFC開発ではリソースエディタでもってコントロールの配置を行い、それをリソーススクリプトに保存するが、これが中々具合が良い。これをPyWin32にも活用できないものだろうか?

ResEditなるものがあるようだ。ちょっと導入してみたけど中々良い。リソースの作成はこれで大丈夫そう。(Visual Studioが使えない時という意味で)

では如何にそれをpythonに喰わせるか?という話になる。[Spambayes-checkins] spambayes/Outlook2000/dialogs/resources rcparser.py, NONE, 1.1.2.1 にそれっぽいコードがある。今度試してみよう。

Referrer (Inside): [2008-08-16-1]

pywin32によるMFCアプリケーションの雛形 [python][PyWin32][Windowsプログラミング]

pywin32のmfcラッパを試している。pythonで結構簡単にWindowsのダイアログが作れて、良さそう。
とりあえず手元で試して動いたコードをメモ。

とにかくダイアログを出す、という例が以下。拡張子をpywにして保存しダブルクリックすればOK。

from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_DLGFRAME | win32con.DS_MODALFRAME | win32con.WS_POPUP |
                win32con.WS_VISIBLE |  win32con.WS_CAPTION  | win32con.WS_SYSMENU )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)    
    dlgButton = 0x0080
    tmpl = [
        ["my dialog", (0, 0, 200, 100), dlgstyle], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5, 55, 190, 40), btnstyle], # button
        ]
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)


d = Mydialog()
d.DoModal()

ボタンを作成しハンドラを割当てた例が以下。アプリケーション作成にあたっての出発点的なもの。
from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
                win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
                win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)    
    IDC_MYBUTTON = 1025
    dlgButton = 0x0080
    tmpl = [
        ["my dialog", (0, 0, 200, 100), dlgstyle], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5,  5, 190, 40), btnstyle], # button
        [dlgButton, "my button", IDC_MYBUTTON,  (5, 55, 190, 40), btnstyle], # button
        ]
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)
        
    def OnInitDialog(self):
        rc = dialog.Dialog.OnInitDialog(self)
        self.HookCommand(self.OnMyButton, self.IDC_MYBUTTON)
        self.btn = self.GetDlgItem(self.IDC_MYBUTTON)
        return rc

    def OnMyButton(self, id, cmd):
        if cmd==win32con.BN_CLICKED:
            ret = self.MessageBox('hello, my button', 'my caption', win32con.MB_YESNO)
            if ret==win32con.IDYES: cap = 'yes'
            else: cap = 'no'
            self.btn.SetWindowText(cap)
        
    def OnOK(self):
        rc = dialog.Dialog.OnOK(self)
        self.MessageBox('OnOK!', 'farewell')
        return rc

    def OnCancel(self):
        rc = dialog.Dialog.OnCancel(self)
        self.MessageBox('OnCancel!', 'farewell')
        return rc



d = Mydialog()
d.DoModal()

上では、Mydialogのコンストラクタに渡す引数でもってボタンを作成している。
でも以下をOnInitDialogに仕込んでも良い。
(こちらで指定するサイズは(たぶん)ピクセル単位で、一方tmplで指定したサイズはダイアログユニットなので、
大きさに関する数値は異なる。変換はself.MapDialogRectで行える。)
self.btn = win32ui.CreateButton()
self.btn.CreateWindow('my button', self.btnstyle, (10, 75, 340, 140), self, self.IDC_MYBUTTON)



上の例で、ダイアログのフォントを変え、タイマーを仕込んだ例が以下。
from pywin.mfc import dialog
import win32con

class Mydialog(dialog.Dialog):

    dlgstyle = (win32con.WS_MINIMIZEBOX | win32con.WS_DLGFRAME |
                win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE |
                win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT )
    btnstyle = (win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP |
                win32con.WS_CHILD | win32con.WS_VISIBLE)
    staticstyle = (win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.SS_LEFT)
    IDC_MYBUTTON = 1025
    IDC_MYSTATIC = 1026
    dlgButton = 0x0080
    dlgStatic = 0x0082
    tmpl = [
        ["my dialog", (0, 0, 200, 130), dlgstyle, None, (14,'Arial')], # dialog
        [dlgButton, "my OK",     win32con.IDOK, (5,  5, 190, 40), btnstyle], # button
        [dlgButton, "my button", IDC_MYBUTTON,  (5, 55, 190, 40), btnstyle], # button
        [dlgStatic, "my static", IDC_MYSTATIC,  (5,105, 190, 20), staticstyle], # static
        ]
    timerid = 1
    def __init__(self):
        dialog.Dialog.__init__(self, self.tmpl)
        
    def OnInitDialog(self):
        rc = dialog.Dialog.OnInitDialog(self)
        self.HookCommand(self.OnMyButton, self.IDC_MYBUTTON)
        self.static = self.GetDlgItem(self.IDC_MYSTATIC)
        self.timerflag = False
        self.timercount = 0
        return rc

    def OnMyButton(self, id, cmd):
        if cmd==win32con.BN_CLICKED:
            if self.timerflag: self.KillTimer(self.timerid)
            else: self.SetTimer(self.timerid, 500) # 0.5s
            self.timerflag = not self.timerflag

    def OnTimer(self, nIDEvent):
        self.timercount += 1
        self.static.SetWindowText('timer! %d' % self.timercount)

        
    def OnOK(self):
        rc = dialog.Dialog.OnOK(self)
        self.MessageBox('OnOK!', 'farewell')
        return rc

    def OnCancel(self):
        rc = dialog.Dialog.OnCancel(self)
        self.MessageBox('OnCancel!', 'farewell')
        return rc



d = Mydialog()
d.DoModal()


上記はpywin32に付属のsliderdemo.pyが基なので、致命的な間違いは無いと思うし、実際手元ではちゃんと動いている。
ここまでくれば、後はMFCの知識だけでグリグリ書き進められそう。

Referrer (Inside): [2008-08-17-1]

簡易入力ダイアログ [PyWin32][python][Windowsプログラミング]

pythonでCOMを使うためPython for Windows extensions (see also: Mark Hammond's Free Stuff)を導入した。他の機能にも触れてみようとしている。mfcまわりもラップされているのでGUIアプリケーションも書けるようだ。windowsに特化するなら、MFCへの慣れを勘案すれば、wxPythonよりこっちを使う方がラクかな?

とりあえず簡易な入力ダイアログが非常に簡単に作成できるようなのでメモ。後々重宝しそうな気がする。

import pywin.mfc.dialog
print pywin.mfc.dialog.GetSimpleInput("my textbox title", 'my default value', 'my window title')

ChangeLog INDEX
Powered by chalow