如何从不同进程修改TextView?

1 投票
3 回答
1211 浏览
提问于 2025-04-17 12:59

我正在制作一个图形界面(GUI)来获取推文。我创建了一个事件框,可以接收信号并更改文本视图。我使用多进程来更新文本视图,但它就是不改变。我甚至尝试过调整窗口的大小,但都没有效果。我可以获取文本视图的文本缓冲区,但就是无法修改它。

import pygtk
pygtk.require('2.0')
import gtk
from multiprocessing import Process

class multi:
    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_size_request(800,400)
        self.window.set_title("Twitter Box")
        self.window.set_border_width(4)
        self.window.connect("destroy", self.close_application)

        self.vbox1 = gtk.EventBox()
        self.vbox1.set_size_request(750,450)
        self.vbox1.connect('leave_notify_event',self.go_multi)
        self.window.add(self.vbox1)
        self.vbox1.show()

        self.tweetview = gtk.TextView()
        self.tweetbuffer = self.tweetview.get_buffer()
        self.tweetbuffer.set_text('Why not working?')
        self.vbox1.add(self.tweetview)
        self.tweetview.show()

        self.window.show()

    def close_application(self, widget):
        gtk.main_quit()

    def go_multi(self, widget, data=None):
        p = Process(target = self.change_textview)
        p.start()
        p.join()

    def change_textview(self):
        print 'changing text'
        startiter = self.tweetbuffer.get_start_iter()
        enditer = self.tweetbuffer.get_end_iter()
        text = self.tweetbuffer.get_text(startiter, enditer)
        print text
        if text:
            self.tweetbuffer.set_text('Changed....')
        else:
            self.tweetbuffer.set_text('')
        return 

def main():
    multi()
    gtk.main()

if __name__ == '__main__':
    main()

我正在制作一个图形界面来获取推文。有时候,由于网络连接慢,获取时间线会非常耗时,这导致图形界面卡住。因此,我想让它创建一个进程来获取时间线并设置推文缓冲区。但我无法在推文缓冲区中设置文本。

3 个回答

0

如果你在看完所有回答后还是想继续这个方向:
免责声明:
我不知道这个回答有多有用。
解释:
我试着用你的思路。我还导入了 Queue 来在不同的进程之间共享一些数据。我觉得这是必要的,因为我在文档中看到过。你可以在下面的代码示例中找到一些其他信息。

import pygtk
pygtk.require('2.0')
import gtk
from multiprocessing import Process, Queue

class multi:
    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_size_request(800,400)
        self.window.set_title("Twitter Box")
        self.window.set_border_width(4)
        self.window.connect("destroy", self.close_application)

        self.vbox1 = gtk.EventBox()
        self.vbox1.set_size_request(750,450)
        self.vbox1.connect('leave_notify_event',self.go_multi)
        self.window.add(self.vbox1)
        self.vbox1.show()
        self.tweetview = gtk.TextView()
        self.tweetbuffer = self.tweetview.get_buffer()
        self.tweetbuffer.set_text('Why not working?')
        self.vbox1.add(self.tweetview)
        self.tweetview.show()

        self.window.show()

    def close_application(self, widget):
        gtk.main_quit()

    def go_multi(self, widget, data=None):
        q = Queue()
        p = Process(target = self.change_textview, args=(q,))
        p.start()
        self.tweetbuffer.set_text(q.get())
        p.join()

    def change_textview(self, q):
        print 'changing text'
        startiter = self.tweetbuffer.get_start_iter()
        enditer = self.tweetbuffer.get_end_iter()
        text = self.tweetbuffer.get_text(startiter, enditer)
        print text
        if text:
            q.put(('Changed....'))
        else:
            q.put((''))
def main():
    multi()
    gtk.main()

if __name__ == '__main__':
    main()
2

你必须运行主循环,才能处理渲染事件,这样东西才会显示出来。

另外,你不能在第二个线程中调用GTK的函数。

想要入门的话,可以看看这个:多线程GTK应用程序 - 第1部分:误解

这里有关于如何将这些知识应用到PyGTK的内容:PyGTK中的线程

2

我不太明白你为什么要这样做:

def go_multi(self, widget, data=None):
    p = Process(target = self.change_textview)
    p.start()
    p.join()

因为,即使在极小的可能性下它能工作,你实际上是在调用 change_textview 函数,并等待这个过程完成。

说到这里,我觉得你根本不需要使用多进程,应该改用多线程来处理你的图形界面。

一开始让 Gtk 支持多线程可能会有点棘手,但其实并不难。
你可以通过两种方式来实现:

  1. 使用 GLib.idle_add(或者 GObject.idle_add,我从来没完全搞明白为什么有时候它们不一样)来更新你的控件。
  2. 或者按照 [这里] 的说明来做。基本上它说:

    • 在你调用 Gtk.main() 之前,先调用以下方法:

       GObject.threads_init()
       Gdk.threads_init()
      
    • 在你的线程中,用以下代码包裹更新 Gtk 控件的代码:

       Gdk.threads_enter()
       # your code here
       Gdk.threads_leave()
      

撰写回答