5

pygtkを使用してPythonアプリを構築しています。これは、いくつかの無限ループプロセスをアクティブ化/非アクティブ化するいくつかのボタンと、各プロセス内で何が起こっているかを表示し続ける必要があるテキストビューで構成されています。冗長なもののように。

これらのプロセスは終わりではありません。ユーザーが対応するボタンを押したとき(またはアプリを閉じたとき)にのみ停止します。

何が問題になっていますか:これらのプロセスからのテキストビューにあるものを印刷できません。多分彼らは終わりがないので...

実際、アプリは大きすぎてここにコード全体を表示できません。だから私は自分がしていることの簡単で小さな例を作りました。

import pygtk
pygtk.require("2.0")
import gtk
import time
import glib
from multiprocessing import Process
gtk.threads_init()

class Test(gtk.Window):
    def delete_event(self, widget, event, data=None):
        if isinstance(self.my_process, Process):
            if self.my_process.is_alive():
                self.my_process.terminate()
        gtk.main_quit()
        return False

    def __init__(self):

        gtk.Window.__init__(self)
        self.set_default_size(500, 400)
        self.set_title(u"Test")
        self.connect("delete_event", self.delete_event)

        self.mainBox = gtk.VBox(False, 5)

        self.text = gtk.TextView()
        self.text.set_wrap_mode(gtk.WRAP_WORD)
        self.button = gtk.Button("Start")

        self.add(self.mainBox)
        self.mainBox.pack_start(self.text, True, True, 0)
        self.mainBox.pack_start(self.button, False, True, 0)

        self.button.connect("clicked", self.start_clicked)

        self.show_all()

    def start_clicked(self, widget):
        self.register_data("Starting...")
        self.my_process = Process(target=self.do_something)
        self.my_process.start()

    def do_something(self):
        while True:
            time.sleep(0.5)
            #get a list of a lot of things
            #Do stuff with each item in the list
            #show me on the gui whats going on
            glib.idle_add(self.register_data, "Yo! Here I'm")
            print "Hello, boy."

    def register_data(self, data):
        data = data + "\r\n"
        #gtk.gdk.threads_enter()
        buff = self.text.get_buffer()
        biter = buff.get_start_iter()
        buff.insert(biter, data)
        #gtk.gdk.threads_leave()


if __name__ == "__main__":
    mnc = Test()
    mnc.set_position(gtk.WIN_POS_CENTER)
    gtk.threads_enter()
    gtk.main()
    gtk.threads_leave()
4

3 に答える 3

5

.threads_init()すべての.threads_enter()、、を削除します.threads_leave()multiprocessingではありませんthreading

表示したいデータをmultiprocessing.Queue()子プロセスに入れます。

def do_something(self):
    while True:
        #get a list of a lot of things
        #Do stuff with each item in the list
        #show me on the gui whats going on
        self.data_queue.put("Yo! Here I'm")

GUIループでポーリングします。

def __init__(self, ...):
    # ...
    self.data_queue = Queue()
    gobject.timeout_add(100, self.update_text) 

どこ:

def update_text(self):
    # receive updates from the child process here
    try:
        data = self.data_queue.get_nowait()
    except Empty:
        pass # nothing at this time
    else:
        self.register_data(data)
    return True

ポーリングを回避するにmultiprocessing.Pipeは、子プロセスで書き込みを行い、を使用してGUIコールバックを設定しますgobject.io_add_watch()。完全なコード例は次のとおりです。

#!/usr/bin/python3
from multiprocessing import Pipe, Process
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gtk

# create GUI to show multiprocessing output
win = Gtk.Window()
win.set_default_size(640, 480)
label = Gtk.Label('process output')
win.add(label)

# start dummy infinite loop in a child process
def loop(conn):
    import itertools, sys, time
    for i in itertools.count():
        conn.send(i)
        time.sleep(0.1 - time.monotonic() % 0.1)

parent_conn, child_conn = Pipe(duplex=False)
Process(target=loop, args=[child_conn], daemon=True).start()
child_conn.close()

# read values from the child
def read_data(source, condition):
    assert parent_conn.poll()
    try:
        i = parent_conn.recv()
    except EOFError:
        return False # stop reading
    # update text
    label.set_text('Result from the child: %03d' % (i,))
    return True # continue reading
# . configure the callback
GObject.io_add_watch(parent_conn.fileno(), GObject.IO_IN, read_data)

win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()

(Pythonの子プロセスだけでなく)任意のサブプロセスを使用して実行することもできます。

于 2012-11-22T19:43:00.400 に答える
0

gtkを呼び出すたびにスレッド内にいるときは、gtk.threads_enter()を使用し、呼び出した後はgtk.threads_leave()で閉じる必要があります。何かのようなもの:

def do_something(self):
        while True:
            time.sleep(0.5)
            gtk.threads_enter()
            #get a list of a lot of things
            #Do stuff with each item in the list
            #show me on the gui whats going on
            glib.idle_add(self.register_data, "Yo! Here I'm")
            gtk.threads_leave()
            print "Hello, boy."

そして時々あなたは使用する必要があります:

gtk.gdk.threads_init()
gtk.gdk.threads_enter()
#code section
gtk.gdk.threads_leave()
于 2012-11-22T19:18:54.057 に答える
0

これがスレッド化された例です。ただし、GTK3ではthreads_enter/ threads_leaveが非推奨になり、プログラムをGTK 3 + PyGObjectに移植するのが難しくなるため、スレッド化されていない、ポーリングされていないアプローチの方が適しています。

Cでは、おそらくg_spawn_async_with_pipesを使用します。Pythonでの同等のものは、私が推測するglib.spawn_asyncであり、標準出力で読み取るデータがあるときに通知されるようにglib.io_add_watchを使用ます

于 2012-11-23T09:47:36.633 に答える