Windowsコマンドプロンプトもどきプログラム(まとも版)
前回(その3)で予告した、Text Widgetのみでコマンドプロンプトもどきを実現(より近づく)できたので、その記録をここに記す。
作成したもの
ここでは、「> 」がプロンプトである。
コマンドを入力すると実行された結果が表示される。スクロールもあり。
ソースコード
# -*- coding: utf-8 -*-
import subprocess
import sys
import tkinter as tk
def func(event):
current = result.get('1.0', tk.END)
lastline = current.rsplit('\n')[-2]
laststr = lastline.split(' ', 1)[1] # removal of prompt('> ')
cmd_arg = laststr.split(' ') # make it to be list
cmd = cmd_arg[0].lower() # take "command"
if cmd == "exit": # exit program
sys.exit()
output = subprocess.run(cmd_arg, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout
output = output.decode('shift_jis')
result.insert(tk.END, '\n' + output + '\n> ')
result.see('end')
return "break" # prevent cursor from going to the next line
root = tk.Tk()
root.geometry('600x500')
root.title('Like command prompt 2')
frm = tk.Frame()
frm.place(x = 40, y = 20)
result = tk.Text(frm, font=("", 10), width=70, height=35, wrap="word")
ysc = tk.Scrollbar(frm, orient=tk.VERTICAL, command=result.yview)
ysc.pack(side=tk.RIGHT, fill="y")
result["yscrollcommand"] = ysc.set
result.insert(tk.END, '> ') # insert prompt('> ')
result.pack()
result.bind('<Return>', func)
root.mainloop()
コマンドを実行するSubprocess、Text Widget、スクロールバーについては、前回(その3)を参照。ここでは、それ以外のポイントとなる点を順不同で記載。
result.insert(tk.END, '> ') # insert prompt('> ')
result.pack()
result.bind('<Return>', func)
初期処理として、ボックス(Text Widget)にプロンプト「> 」を入れ、Return(Enter)が押されたときの関数(func)を登録。
def func(event):
current = result.get('1.0', tk.END)
lastline = current.rsplit('\n')[-2]
laststr = lastline.split(' ', 1)[1] # removal of prompt('> ')
cmd_arg = laststr.split(' ') # make it to be list
cmd = cmd_arg[0].lower() # take "command"
if cmd == "exit": # exit program
sys.exit()
- 現在のボックス内のデータをすべて「current」に格納
- 最終行にコマンドが含まれているので、最後の行をrsplit()で取得(改行コード'\n'を区切り文字、Indexである"-2"はTry&Errorで見つけた)し、「lastline」に格納
- その行の最初にはプロンプトがあるので、split()でそれを削除し、最後にSubprocessに渡すために、split()でリスト化
- 最初の空白までがコマンド
- それが「exit」であれば本プログラムを終了
なお、rsplit()やsplit()については、下記サイトを参照した。
output = subprocess.run(cmd_arg, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout
output = output.decode('shift_jis')
result.insert(tk.END, '\n' + output + '\n> ')
result.see('end')
return "break" # prevent cursor from going to the next line
- Subprocessによりコマンドを実行し、その結果をボックスに追加
- プロンプトを追加
- 最後の「return "break"」が重要。これがないと、コマンドプロンプトの次の空白が改行されてしまい、ボックス内のカーソルが次の行に移動してしまう。
「return "break"」については調べたが、正直この行の効果はよくわからなかった。これに関して参考としたサイトは次のもの。
おまけ
今回、カーソルの移動を防ぐ「return "break"」を見つけるのに最も苦労した。それにたどり着くまでに有益と思った情報を記す。
TextWidget内でカーソルを戻す
result = tk.Text(frm, font=("", 10), width=70, height=35, wrap="word")
......
result.mark_set("insert", "insert-1c") # 1文字戻す
result.mark_set("insert", "insert-2c") # 2文字戻す
TextWidget内でカーソルを特定の場所に移動
result.mark_set("insert", "%d.%d" % (2, 10)) # 2行目&10文字目(”0”が最初)
最終行番号
int(float(result.index('end')))
'end'とtk.ENDとは同じのようだ。
HEX dump
# 変数「sss」が「str」型とする
print(''.join([f'{ord(c):02x}' for c in sss]))
EOF