1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import tkinter
from tkinter import messagebox, scrolledtext
import subprocess
import select
import os
import signal
WINDOW_SIZE = "600x400"
# Run Button
btn_upd = None
# Output textbox
txt_out = None
# current script job/process
cur_process = None
# mark if Tk is closing
close_flag = False
# Tk root
root = tkinter.Tk()
def disable_allbtn():
global close_flag
global btn_upd
if close_flag:
return
btn_upd.configure(state=tkinter.DISABLED)
def enable_allbtn():
global close_flag
global btn_upd
if close_flag:
return
btn_upd.configure(state=tkinter.NORMAL)
def cb_runbash_withoutput(script):
global cur_process
global txt_out
global root
global close_flag
# clear output
txt_out.delete(1.0, tkinter.END)
# create subprocess
process = subprocess.Popen(script, shell=True, preexec_fn=os.setsid,
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
# read subprocess stderr/stdout in non-blocking
outpoll = select.poll()
errpoll = select.poll()
outpoll.register(process.stdout, select.POLLIN)
errpoll.register(process.stderr, select.POLLIN)
# store current subprocess
cur_process = process
while True:
output = ""
errput = ""
# poll stdout, timeout 2ms
if outpoll.poll(2):
output = process.stdout.readline().decode()
# insert stdout to txt_out
if output and not close_flag:
txt_out.insert(tkinter.INSERT, output)
# poll stderr, timeout 2ms
if errpoll.poll(2):
errput = process.stderr.readline().decode()
# insert stderr to txt_out
if errput and not close_flag:
txt_out.insert(tkinter.INSERT, errput)
# scroll text if have output
if (output or errput) and not close_flag:
txt_out.see(tkinter.END)
# do eventloop when not closing
if not close_flag:
root.update()
# process end
if output == "" and process.poll() is not None:
break
# get process return code
code = process.poll()
# reset current subprocess
cur_process = None
return code
# callback 函数
def cb_update():
global close_flag
disable_allbtn()
code = cb_runbash_withoutput("./bash_script_sample.sh")
# exit when closing
if close_flag:
return
if code != 0:
messagebox.showerror(title="Error", message="run bash script failed")
else:
messagebox.showinfo(title="Info", message="run bash script success")
enable_allbtn()
def on_closing():
global cur_process
global root
global close_flag
# if cur_process still running
if cur_process:
if messagebox.askokcancel("Quit", "There is task running, do you want to quit?"):
# kill subprocess
os.killpg(os.getpgid(cur_process.pid), signal.SIGTERM)
cur_process = None
else:
return
# mark closing
close_flag = True
# close window
root.destroy()
root.title("Hello world")
root.geometry(WINDOW_SIZE)
# register cloing event callback
root.protocol("WM_DELETE_WINDOW", on_closing)
btn_upd = tkinter.Button(root, text="Update", command = cb_update)
btn_upd.pack(fill=tkinter.X, pady=10)
txt_out = scrolledtext.ScrolledText(root)
txt_out.pack(fill=tkinter.BOTH, expand=True, padx=20, pady=20)
tkinter.mainloop()
|