停止一个pygtk进程

3 投票
1 回答
781 浏览
提问于 2025-04-18 13:42

我正在尝试用pygtk制作一个简单的应用程序,用来播放和停止一个midi文件。

这是我目前的进展:

import pygtk
pygtk.require('2.0')
import gtk
import subprocess


class Teacher:

    def __init__(self):

        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.set_size_request(400, 200)
        window.set_title("Music Teacher")
        window.connect("delete_event",
                   lambda w,e: gtk.main_quit())

        table = gtk.Table(4, 4, True)
        window.add(table)

        play = gtk.Button("Play")
        play.connect("clicked", self.clicked_play)
        play.show()

        stop = gtk.Button("Stop")
        stop.show()

        table.attach(play, 0, 1, 0, 1)
        table.attach(stop, 0, 1, 1, 2)

        window.show_all()

    def clicked_play(self, widget):
        subprocess.Popen(["timidity", "~/somefile.mid"])

    def main(self):
        gtk.main()
        return 0


Teacher().main()

我可以从停止和删除事件中发送中断来结束这个进程吗?我应该使用线程吗?

1 个回答

3

你可以这样处理接收到的 SIGTERM 信号、按下 Ctrl+C 或者点击停止按钮的情况:

import pygtk
pygtk.require('2.0')
import gtk
import subprocess
import signal


class Teacher:

    def __init__(self):
        self.proc = None  # Initialize the handle to our subprocess
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.set_size_request(400, 200)
        window.set_title("Music Teacher")
        window.connect("delete_event",
                   lambda w,e: gtk.main_quit())

        table = gtk.Table(4, 4, True)
        window.add(table)

        play = gtk.Button("Play")
        play.connect("clicked", self.clicked_play)
        play.show()

        stop = gtk.Button("Stop")
        stop.connect("clicked", self.clicked_stop)
        stop.show()

        table.attach(play, 0, 1, 0, 1)
        table.attach(stop, 0, 1, 1, 2)

        window.show_all()

    def clicked_play(self, widget):
        self.proc = subprocess.Popen(["timidity", "~/somefile.mid"])

    def clicked_stop(self, widget=None):
        if self.proc:
            self.proc.terminate()
            self.proc.wait()

    def handle_sigterm(self, *args):
        self.clicked_stop()
        sys.exit()

    def main(self):
        signal.signal(signal.SIGTERM, self.handle_sigterm)
        try:
            gtk.main()
        except KeyboardInterrupt:
            self.clicked_stop()
            raise
        return 0


Teacher().main()

我们在 clicked_play 函数中保存了一个我们创建的 Popen 对象的引用,然后在 click_stop 函数中用这个引用来发送 SIGTERM 信号给这个进程,方法是调用 terminate。接着,我们调用 wait(这个调用应该很快完成,除非 timidity 在接收到 SIGTERM 时没有正常关闭),这样可以处理掉被终止的进程,避免留下“僵尸进程”。

我还在调用 gtk.main() 的地方加了一个 try/except,这样如果你按下 Ctrl+C,clicked_stop 就会被调用。同时,如果接收到 SIGTERM 信号,也会调用一个处理函数来做同样的事情。

撰写回答