2 回答
TA贡献1856条经验 获得超11个赞
为了回答我自己的问题,我通过如下示例解决了这个问题:
import os
import signal
import time
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gtk, GObject
from multiprocessing import Pipe, Process
proc = 0
class GUI(Gtk.Window):
def run_process(self, target, **kwargs):
iterator = kwargs.get('iterator')
option = kwargs.get('option')
pid = kwargs.get('pid')
parent_conn, child_conn = Pipe(duplex=False)
if target == capture:
Process(target=target, args=[child_conn, iterator], daemon=True).start()
if target == manager:
Process(target=target, args=[child_conn, option, pid], daemon=True).start()
child_conn.close()
def read_data(source, condition):
assert parent_conn.poll()
try:
i = parent_conn.recv()
except EOFError as E:
print(E)
return False
if isinstance(i, list) and not isinstance(i[0], str):
self.update_progress(f"Photo {i[0]} of {i[1]} taken!\n")
elif isinstance(i, str):
self.update_progress(i)
elif isinstance(i, list) and i[0] == "PID":
global proc
proc = i[1]
return True
GLib.io_add_watch(parent_conn.fileno(), GObject.IO_IN, read_data)
def update_progress(self, text):
output = builder.get_object("txtview_console")
textviewbuffer = output.get_buffer()
start_iter = textviewbuffer.get_start_iter()
textviewbuffer.insert(start_iter, text)
return False
def on_capture_clicked(self, button):
btn_capture = builder.get_object("start_capture_button")
btn_capture.set_sensitive(False)
self.run_process(capture, iterator=[1, 11])
def on_cancel_clicked(self, button):
global proc
btn_capture = builder.get_object("start_capture_button")
btn_capture.set_sensitive(True)
if proc == 0:
self.update_progress("No capture running!\n")
else:
self.run_process(manager, option=1, pid=proc)
proc = 0
def capture(c_conn, iterator):
proc = os.getpid()
c_conn.send(['PID', proc])
for i in range(iterator[0], iterator[1]):
# blocking method or subprocess
time.sleep(2)
c_conn.send([i, iterator[1]-1])
c_conn.send(['PID', 0])
def manager(c_conn, option, pid):
if pid == 0:
c_conn.send("No capture running!\n")
return False
else:
if option == 1:
os.kill(pid, signal.SIGKILL)
c_conn.send("Capture cancelled!\n")
if __name__ == "__main__":
builder = Gtk.Builder()
builder.add_from_file("example.glade")
builder.connect_signals(GUI())
win = builder.get_object("GUI")
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
使用 glade 文件提供 GUI,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="GUI">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_homogeneous">True</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkButton" id="start_capture_button">
<property name="label" translatable="yes">Capture</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_capture_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_capture_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="txtview_console">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
<property name="height">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
上面的示例创建了一个带有捕获和取消按钮的窗口。如果捕获进程正在运行,则捕获按钮的灵敏度变为False并且阻塞进程使用管道中的进程运行以提供打印到文本视图中的反馈。在捕获过程中的任何时候,如果按下取消按钮,它将尝试获取捕获过程的全局 pid 号并将其终止。
TA贡献1829条经验 获得超4个赞
以下是一些关于如何停止线程的示例: https: //www.google.at/amp/s/www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/amp/
添加回答
举报