LoginSignup
1
0

More than 1 year has passed since last update.

ろうとるがPythonを扱う、、(その4:まとも版コマンドプロンプトもどき)

Posted at

Windowsコマンドプロンプトもどきプログラム(まとも版)

前回(その3)で予告した、Text Widgetのみでコマンドプロンプトもどきを実現(より近づく)できたので、その記録をここに記す。

作成したもの

最初.png
ここでは、「> 」がプロンプトである。
結果1.png
結果2.png
コマンドを入力すると実行された結果が表示される。スクロールもあり。

ソースコード

# -*- 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

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0