Python:バイナリでコンソールを表示しないようにするには?
Pythonのコードをwindows用exeにするには当然、py2exeを使います。
で、そのとき、 python setup.py py2exe --windows とすれば、コンソールを表示しないようにできます。
Note:これはもう古いやり方で、現在のバージョンのpy2exeでは動きません・・・。現在はターゲットファイルの拡張子を.pywにする、もしくはwindows = [{'script' : 'script.py', "icon_resources": [(1,"script.ico")]}]というオプションをsetupに渡す、という方法になっています。
今日、昔py2exeで作ったファイルが出てきたんですが、困ったことにpythonのソースファイルはない。いや、別に改良とかもうしないしいいんだけど。
ふと起動してみるとGUI with console。かっちょわりい。
コンソールが表示される、というのは単純にPEファイルのオプションなわけで。

この部分を変更してやればとりあえずは直る。ちなみに、
00 00:未知のサブシステム
01 00:デバイス ライバおよびWindowsNTネイティブプロセス用
02 00:GUIで実行されるファイル
03 00:コンソールで実行されるファイル
07 00:Posixコンソールで実行されるファイル
09 00:WindowsCEで実行されるファイル
なので02h 00hにしてやればオッケー。
Pythonでバイナリファイルの読み書きとかしたことないので練習もかねて。
- # vim: fileencoding=utf-8
- import sys
- from struct import *
- target_file = len(sys.argv)> 1 and sys.argv[1] or sys.exit("Target file is not specified.")
- target_file = unicode(target_file, "mbcs")
- out_file = open(target_file + "_gui", "wb")
- io = open(target_file, "rb")
- while 1 :
- if io.read(1) == "P" and io.read(1) == "E" : break
- subsystem_pos = io.tell() +90
- io.seek(0)
- out_file.write(io.read(subsystem_pos))
- io.seek(4, 1)
- out_file.write(pack('hh', 2, 0))
- out_file.write(io.read())
- io.close()
- out_file.close()
こんな感じ。引数にexeファイルを渡せばオッケー。でも、適当なので全部のケースで動くかはあやしいw
pythonではバイナリを扱うときはstructモジュールを使う、ということが分かりました(笑
Python:Tkを使って気軽にコンソールアプリ?
Windowsの小物はほぼPythonで作っているわけですが。
WindowsにPythonをインストーラーを使ってインストールすると*.pyにデフォルトだとpython.exeを関連付けしてくれます。
これは非プログラマな人にプログラムを渡すとき非常に便利で、とりあえずPythonをインストールして、このファイルをダブルクリックしろ、というだけでオッケー。exe化して無駄な容量を食わなくても大丈夫なのです。
んで、作るのはだいたいコンソールで実行するもの。
これがダブルクリックで実行できるのはいいんですが、当然、プログラムが終了するとウインドウ(DOSプロンプト)が閉じちゃうから結果が見れない。
いちいちDOSプロンプトから実行するのもめんどくさい。しかも見た目的に非プログラマにはいかつい。
なんとかならないかなー、と思ってTkを使ってコンソールアプリを作るためのライブラリを作ってみた。
guiconsole.py
- # vim: fileencoding=utf-8
- from Tkinter import *
- from ScrolledText import ScrolledText
- import sys
- import thread
- import time
- class GUIConsole(Frame):
- def init(self):
- self.init_input()
- self.init_output()
- def init_input(self):
- self.input_var = StringVar()
- self.input = Entry(self, width=100, textvariable=self.input_var)
- self.input.pack(side=TOP)
- self.input.bind('<return>', self.input_enter)
- self.input_var.readline = self.readline
- sys.stdin = self.input_var
- def init_output(self):
- self.out = ScrolledText(self, width=100, height=30)
- self.out.pack(side=TOP)
- self.out.write = self.write
- sys.stdout = self.out
- def write(self, str):
- self.out.insert(END, str)
- time.sleep(0.0001)
- self.out.yview_scroll(str.count("\n") + 1, "units")
- def readline(self, size=None):
- self.input.focus()
- self.input_entered = False
- while True:
- time.sleep(0.5)
- if self.input_entered == True:
- break
- result = self.input_var.get()
- self.input_var.set("")
- return result
- def input_enter(self, event):
- self.input_entered = True
- def __init__(self, title, master=None):
- self.input_entered = False
- Frame.__init__(self, master)
- self.pack()
- self.master.title(title)
- self.init()
- def start(main_func, title="Python") :
- app = GUIConsole(title)
- thread.start_new_thread(main_func, ())
- app.mainloop()
使い方はこんなかんじ。
- import guiconsole
- def main():
- while True:
- var = raw_input()
- print var
- guiconsole.start(main, "GUIコンソールのテスト")
でこんな風にみえる。
Pythonの場合、stdoutはwriteというメソッド、stdinはreadlineというメソッドさえもっていればどんなオブジェクトでもオッケー。
なので単純にstdoutとstdinをTkのウィジットに置き換えてメインループに入り、別スレッドでメインの処理を実行してやっているだけ。
見栄えも生のDOSプロンプトよりはいいし、処理が終わってもウィンドウを閉じない限り結果を見ることができる。
プチ便利なので、はやくも自分で使いまくりです(笑