WindowsプログラミングはVBを使って仕事上必要なアプリを作成した事はありますが,Windowsのプログラミング経験はあまりありません。 引き出しを増やすためにIronPythonを使ったプログラミングを試し、情報をまとめる事にしました。
できるだけ実際に動かすことができるように、各サンプルコード単体で動くように心がけています。
今回作成した環境は以下の通りです。
テストした環境のフォルダ構造は次のようになっています。
作業フォルダの構造
C:\IronPython26\proj.test\ |-- 01_form.ipy |-- 02_form_menustrip.ipy |-- 03_04_form_flowlayout.ipy |-- 05_form_databinding.csv |-- 05_form_databinding.ipy |-- 06_form_tooltip.ipy |-- 07_form_filedialog.csv |-- 07_form_filedialog.ipy |-- 08_csvparser.csv |-- 08_csvparser.ipy |-- form_button.ipy `-- messagebox.ipy
IronPythonの本体であるipy.exe
やipyw.exe
は作業フォルダの上(C:\IronPython26\)にあるため、作成したスクリプト(*.ipyファイル)は次のようにコマンドプロンプトから実行しました。
> cd C:\IronPython26\proj.test > ..\ipy 01_form.ipy
ファイルの拡張子をpyではなくipyにしているのは、CPythonとの見分けをつけるためで深い意味はありません。
書籍「オープンソース×Windowsスクリプティング IronPythonの世界」を手元に置いていますが、 この本で説明されていないところをまとめて行こうと思います。
またCPythonとの連携については マイコミジャーナルの記事が参考になると思います。
IronPythonで.NETなVBやC#のコードを動かす時には、だいたいそのまま書き換える事ができます。 注意しておくのは次のような事でしょうか。
C#のサンプルをみていると、true
とfalse
が出てきますが、IronPythonではVisualBasicと同様にTrue
、False
が使えます。
MSDNの.NET APIリファレンスにあるコード例では引数にイベントハンドラを指定していますが、その部分の引数は省いて、次の行で.Clickプロパティ
にメソッドへのリファレンスを追加しています。
オリジナルのVisualBasicコード抜粋
... Dim windowNewMenu As New ToolStripMenuItem("New", Nothing, New EventHandler(AddressOf windowNewMenu_Click)) ...
変更後
... windowNewMenu = ToolStripMenuItem("New", None) windowNewMenu.Click += windowNewMenu_onclick ...
ただしToolStripMenuItemクラスのコンストラクタは0〜3つの引数を取ります。
無理にNoneを渡さなくともToolStripMenuItem("New")
で十分です。
いくつかの実現方法があるようですが、まったく同じ値を取り出す方法としてSystem.IntPtr.Zero
を使う方法が以前からあるようです。
先ほどのSystem.Windwos.Forms.ToolStripItemクラスのコード例には、VisualBasicでNothing
、C#でnull
を渡しています。
IronPythonで試したところNone
で期待通りの動きをしています。
もしAPIで明示的にIntPtr型のnull値を渡す必要がある場合には、System.IntPtr.Zero
が使えるはずですが、評価した場合にIntPtrを想定していない場合にどんな動きをするのかわからないので、まずはNone
を試すのが良さそうです。
Microsoftの.NET APIリファレンス( http://msdn.microsoft.com/ja-jp/library/system.windows.forms(VS.80).aspx)をみると、アプリケーションを作成する際に使用する要素は次のように分類できるようです。
コントロールが2箇所に出てきますが、前者はButtonBaseは含むがButtonは含まないなど純粋に描画に関するもので、後者はGUIとして操作する対象を主に表わしているようです。 担当が違うために分かれているだけなのでしょうか。あまり気にせず先に進みます。
ここから先はこの分類に従ってサンプルプログラムを作成して行きます。
次のようなタイトルバーに"Hello World!"と表示するだけのフォームを作成して、これからいろいろ試すための土台を作ります。。
01_form.ipy
# # IronPython Example: Form # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: Form Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") import System from System.Windows.Forms import Form from System.Drawing import Size form = Form() form.Size = Size(300,200) form.Text = "Hello World!" System.Windows.Forms.Application.Run(form)
Sizeオブジェクトを使用してウィンドウサイズを指定してみました。
直接form.Size.Width = 300
のように入力をしても変更を反映することはできませんでした。
まだ画面に表示できただけですが、次からいろいろ追加していきます。
Formのサンプルにメニューを追加してみます。 メニューを表示して"New"を選択すると、ポップアップメニューを表示します。
MSDNのC#のサンプルそのままではありませんが、イベントハンドラのdef windowNewMenu_onclick(sender, arge)
を登録するところは明確に違うところです。
サンプルではイベントハンドラをToolStripMenuItemのコンストラクタの引数に指定しますが、IronPythonでは.Clickに代入します。
02_form_menustrip.ipy
# coding=Shift_JIS # IronPython Example: MenuStrip # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: MenuStrip Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") import System from System.Windows.Forms import Form from System.Windows.Forms import DockStyle from System.Windows.Forms import MenuStrip from System.Windows.Forms import MessageBox from System.Windows.Forms import ToolStripMenuItem from System.Drawing import Size ## setup form object form = Form() form.Text = "Hello World!" form.Size = Size(300,200) form.IsMdiContainer = True ## setup windowMenu object windowMenu = ToolStripMenuItem("Window") ## setup windowNewMenu windowNewMenu = ToolStripMenuItem("New", None) def windowNewMenu_onclick(sender, arge): MessageBox.Show("Thank you for clicking on me!", "windowNewMenu_onclick") pass windowNewMenu.Click += windowNewMenu_onclick windowMenu.DropDownItems.Add(windowNewMenu) ## setup windowMenu object ms = MenuStrip() ms.MdiWindowListItem = windowMenu ms.Items.Add(windowMenu) ms.Dock = DockStyle.Top ## formオブジェクトへのms変数の追加は最後にします form.MainMenuStrip = ms form.Controls.Add(ms) System.Windows.Forms.Application.Run(form) ## end ##
ここでは"Window"->"New"メニューを追加して、"New"メニューにイベントハンドラをセットしています。 form.IsMdiContaineはサンプルから引き継いだ記述で、コメントアウトしても動くのですが効果について理解していないのでそのままにしてあります。
サンプルからToolStripについての記述は削除してしまいましたが、基本的にはサンプルを引き継ぐ事で可能だと思います。>
普通に日本語を含めると、次のようなエラーメッセージが表示されます。
File "02_menustrip.ipy", line SyntaxError: Non-ASCII character '\x83' in file 02_menustrip.ipy on line 40, but no encoding declared; see http://www.python.org/peps/pep-0263.ht ml for details
先頭に# coding=Shift_JIS
を入れることで回避できます。
コントロールにはTextBoxやButtonなどユーザに対する操作を提供するクラスが含まれます。 単独で使うものでもないので、次のパートから他のクラスと組み合せて使うことにします。
FlowLayoutPanelレイアウトとButtonコントロールを使ったプログラムを作成します。
"Add"ボタンを押す事で、FlowLayoutPanelのデフォルトルールに沿ってボタンが配置されます。 ウィンドウの形を変えながら、ボタンを増減させると左から右に向かって(フロー方向LeftToRight)ボタンが増えていく様子がわかると思います。
MSDNのAPIリファレンスにあるサンプルコードを元にしました。 MSDNの例ではフロー方向をTopDownなどに変更する事もできるようになっていますが、そこは省略しています。
03_04_form_flowlayout.ipy
# coding=Shift_JIS # IronPython Example: FlowLayoutPanel # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: FlowLayoutPanel Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") import System from System.Windows.Forms import Form from System.Windows.Forms import FlowLayoutPanel from System.Windows.Forms import Button from System.Windows.Forms import MessageBox from System.Windows.Forms import DockStyle from System.Drawing import Size ## init Form object form = Form() form.Text = "Hello World!" form.Size = Size(300,200) ## init FlowLayoutPanel object flowLayout = FlowLayoutPanel() flowLayout.Size = form.Size flowLayout.Dock = DockStyle.Fill flowLayout.AutoScroll = True ## 生成したButtonオブジェクトを記憶するリストです buttonList = [] ## setup add button addButton = Button() addButton.Text = "Add" def addButton_click(sender, arge): b = Button() b.Text = "No. " + str(len(buttonList)) buttonList.append(b) flowLayout.Controls.Add(b) pass addButton.Click += addButton_click flowLayout.Controls.Add(addButton) ## setup del button delButton = Button() delButton.Text = "Delete" def delButton_click(sender, arge): if(len(buttonList) == 0): return b = buttonList.pop() flowLayout.Controls.Remove(b) pass delButton.Click += delButton_click flowLayout.Controls.Add(delButton) form.Controls.Add(flowLayout) System.Windows.Forms.Application.Run(form)
FlowLayoutPanelのインスタンスを単純にFormオブジェクトに追加しただけではサイズがおかしくなるので、flowLayout.Size = form.Size
で初期サイズをウィンドウの大きさと同じに設定しています。
さらにウィンドウのリサイズに合わせて動くためにflowLayout.Dock = DockStyle.Fill
を追加しています。
ここではCSVファイルからデータを読み込み、DataGridViewに表示します。 SQLを使った方が本格的で良いのかもしれませんが、冗長ですし、いろいろな参考書にも具体例が載っているので今回はお手軽な方法を取る事にしました。
今回は次のようなCSVファイル(05_form_databinding.csv)をあらかじめ作成しておきました。
05_form_databinding.csv
name,age,address yasu,20,AizuWakamatsu abe,25,Yokohama
"05_form_databinding.csv"ファイルを読み込み、DataGridViewに表示するアプリケーションを作成します。
05_form_databinding.ipy
# coding=Shift_JIS # IronPython Example: DataGridView # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: DataGridView Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") clr.AddReferenceByPartialName("System.Data") import System from System.Windows.Forms import Form from System.Windows.Forms import DataGridView from System.Data import DataTable from System.IO import StreamReader from System.Drawing import Size form = Form() form.Size = Size(400,180) form.Text = "Hello World!" ## 静的にファイル名を指定します filename = "05_form_databinding.csv" ## setup DataTable object dt = DataTable() reader = StreamReader(filename) cols = [] for c in reader.ReadLine().split(","): dt.Columns.Add(c, System.Type.GetType("System.String")) cols.append(c) l = reader.ReadLine() while(l != None): row = dt.NewRow() counter = 0 for item in l.split(","): row[cols[counter]] = item counter += 1 dt.Rows.Add(row) l = reader.ReadLine() reader.Close() ## setup DataGridView object datagridview = DataGridView() datagridview.DataSource = dt datagridview.Size = form.Size form.Controls.Add(datagridview) System.Windows.Forms.Application.Run(form) ## end ##
コードをみれば単純にカンマで区切っただけで、いわゆるRFC4180なCSVファイルの処理ができるわけではありません。 残念ながらIronPythonにはCPythonでは使えるcsv.pyが附属しないため、IronPythonで使えるCSVファイルの取り扱いについては、また後で試すつもりです。
ToolTipが代表に挙げられているので、これを使ってみようと思います。 継承しているクラスがControlクラスから継承していないクラスを分類する方法がないので、どこからどこまでがこのカテゴリに入るのかいまいち不明です。
マウスをボタンの上に載せると、"My button"というToolTipが表示されます。
06_form_tooltip.ipy
# coding=Shift_JIS # IronPython Example: ToolTip # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: ToolTip Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") import System from System.Windows.Forms import Form from System.Windows.Forms import Button from System.Windows.Forms import ToolTip from System.Drawing import Size form = Form() form.Size = Size(300,200) form.Text = "Hello World!" button = Button() button.Text = "OK" toolTip = ToolTip() toolTip.AutoPopDelay = 5000 toolTip.InitialDelay = 1000 toolTip.ReshowDelay = 500 toolTip.ShowAlways = True toolTip.SetToolTip(button, "My button") form.Controls.Add(button) System.Windows.Forms.Application.Run(form)
コモンダイアログボックスにはいろいろありますが、ここではOpenFileDialogを使ってみます。 CSVファイルの指定がコードで行なわれていた部分で、任意のファイルを指定できるように作り替えてみました。
実行するとOpenFileDialogが起動し、CSVファイルの入力を促します。
今回は次のような新しいCSVファイルを読み込ませる事にしました。
07_form_filedialog.csv
name,age,address,phone yasu,20,AizuWakamatsu,22-xxxx abe,25,Yokohama,982-xxxx hoge,30,somewhere,xxx-xxxx
CSVファイルを変数filenameに指定する部分を書き換えて次のようになりました。 CSVファイルを処理する部分は変更していません。
07_form_filedialog.ipy
# coding=Shift_JIS # IronPython Example: OpenFileDialog + DataGridView # - # @author: YasuhiroABE <yasu@yasundial.org> # @see: OpenFileDialog Class Example from MSDN API Reference # import clr clr.AddReferenceByPartialName("System.Windows.Forms") clr.AddReferenceByPartialName("System.Drawing") clr.AddReferenceByPartialName("System.Data") import System from System.Windows.Forms import Form from System.Windows.Forms import DataGridView from System.Windows.Forms import DockStyle from System.Data import DataTable from System.IO import StreamReader from System.Drawing import Size from System.Windows.Forms import OpenFileDialog from System.Windows.Forms import DialogResult from System.Windows.Forms import MessageBox form = Form() form.Size = Size(400,180) form.Text = "Hello World!" ## 静的にファイル名を指定します #filename = "05_form_databinding.csv" filename = "" fdialog = OpenFileDialog() fdialog.InitialDirectory = "C:\\IronPython26" fdialog.Filter = "CSV file (*.csv)|*.csv|All files (*.*)|*.*" fdialog.FilterIndex = 1 fdialog.RestoreDirectory = True if fdialog.ShowDialog() == DialogResult.OK: filename = fdialog.FileName else: MessageBox.Show("Please input proper filename.","Error Dialog") sys.exit(1) ## setup DataTable object dt = DataTable() reader = StreamReader(filename) cols = [] for c in reader.ReadLine().split(","): dt.Columns.Add(c, System.Type.GetType("System.String")) cols.append(c) l = reader.ReadLine() while(l != None): row = dt.NewRow() counter = 0 for item in l.split(","): row[cols[counter]] = item counter += 1 dt.Rows.Add(row) l = reader.ReadLine() reader.Close() ## setup DataGridView object datagridview = DataGridView() datagridview.DataSource = dt datagridview.Dock = DockStyle.Fill datagridview.Size = form.Size form.Controls.Add(datagridview) System.Windows.Forms.Application.Run(form) ## end ##
.NETライブラリのドキュメントに従って、GUIプログラミングの概要について触れてきました。 しかし.NET寄りの内容でIronPython特有の事象にはほとんど触れてきませんでした。
次に作成する文書では、解説書でわざわざ取り上げられないようなIronPythonに特化したTipsをまとめていこうと思います。
Created: 2010-03-11, Last modified: 2010-03-19
www.yasundial.org by
Yasuhiro ABE
is licensed under a Creative Commons Attribution 2.1 Japan License.
Permissions beyond the scope of this license may be available at http://www.yasundial.org/info/license.html.