如何在gtk3-python中执行后台任务?

2023-11-23

我有这个主线:

Gui.py

from gi.repository import Gtk, Gdk
import Process
import gobject

class gui():
    def __init__(self):
        self.window = Gtk.Window()
        self.window.connect('delete-event', Gtk.main_quit)

        self.box = Gtk.Box()
        self.window.add(self.box)

        self.label = Gtk.Label('idle')
        self.box.pack_start(self.label, True, True, 0)

        self.progressbar = Gtk.ProgressBar()
        self.box.pack_start(self.progressbar, True, True, 0)

        self.button = Gtk.Button(label='Start')
        self.button.connect('clicked', self.on_button_clicked)
        self.box.pack_start(self.button, True, True, 0)

        self.window.show_all()
        gobject.threads_init()

        Gdk.threads_enter()
        Gtk.main()
        Gdk.threads_leave()

    def working1():
        self.label.set_text('working1')
        t = Process.Heavy()
        t.heavyworks1() 
        self.label.set_text('idle') 

    def on_button_clicked(self, widget):
        Gdk.threads_enter()
        working1()
        Gdk.threads_leave()

if __name__ == '__main__':
    gui = gui()

This code will generate this gui: img

我有第二个模块来执行逻辑。

进程.py

import threading

class Heavy(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def heavyworks1(self):
        #doing heavy works1
        #return result

   def heavyworks2(self, *param):
        #doing heavy works2
        #return result

当我执行此操作时,操作有效,但 gui 冻结了。怎样才能做好呢?

EDIT:

正如 user4815162342 所说,我将代码更改为:

from gi.repository import Gtk, Gdk, GLib
import Process
import gobject
import threading

class gui():
def __init__(self):
    self.window = Gtk.Window()
    self.window.connect('delete-event', Gtk.main_quit)

    self.box = Gtk.Box()
    self.window.add(self.box)

    self.label = Gtk.Label('idle')
    self.box.pack_start(self.label, True, True, 0)

    self.progressbar = Gtk.ProgressBar()
    self.box.pack_start(self.progressbar, True, True, 0)

    self.button = Gtk.Button(label='Start')
    self.button.connect('clicked', self.on_button_clicked)
    self.box.pack_start(self.button, True, True, 0)

    self.window.show_all()

    gobject.threads_init()
    GLib.threads_init()
    Gdk.threads_init()
    Gdk.threads_enter()
    Gtk.main()
    Gdk.threads_leave()

def init_progress(self, func, arg):
    self.label.set_text('working1')
    self.worker = threading.Thread(target=func, args=[arg])
    self.running = True
    gobject.timeout_add(200, self.update_progress)
    self.worker.start()

def update_progress(self):
    if self.running:
        self.progressbar.pulse()
    return self.running

def working(self, num):
    Process.heavyworks2(num)    
    gobject.idle_add(self.stop_progress)

def stop_progress(self):
    self.running = False
    self.worker.join()
    self.progressbar.set_fraction(0)
    self.label.set_text('idle') 

def on_button_clicked(self, widget):
    self.init_progress(self.working, 100000)

if __name__ == '__main__':
    gui = gui()

使用该代码,程序有时可以工作,但有时会出现此错误。

1.

**
Gtk:ERROR:/build/buildd/gtk+3.0-3.4.2/./gtk/gtktextview.c:3726:gtk_text_view_validate_onscreen: assertion failed: (priv->onscreen_validated)
Aborted (core dumped)

2.

*** glibc detected *** python: free(): invalid next size (fast): 0x09c9f820 ***

3.

Segmentation fault (core dumped)

你实际上并没有start对于线程,您只实例化了一个可用于启动它的对象。完整的解决方案需要仔细分离 GUI 线程和工作线程之间的职责。您想要执行的操作如下:

  1. 在由 GUI 代码生成和连接的单独线程中进行繁重的计算。计算不应产生自己的线程,也不需要了解线程(当然,线程安全除外)。

  2. 当线程完成后,使用gobject.idle_add()告诉 GUI 可以撤回进度指示器。 (gobject.idle_add是唯一可以从另一个线程安全调用的 GTK 函数。)

通过这样的设置,无论计算做什么,GUI 都保持完全响应并更新进度条,并且保证 GUI 线程能够注意到计算何时完成。关于您当前代码的另外两点:

  • 实例化threading.Thread而不是继承它。这样你就不需要费心实施run()。在这两种情况下,您都必须致电thread.start()不过,要开始线程。

  • 不要打电话threads_enter() and threads_leave(), 除非你really知道你在做什么。请记住,只要您从单个线程(与初始化 GTK 相同的线程)调用所有 GTK 函数,就可以了。

以下是实现上述建议的概念验证代码:

    def working1(self):
        self.label.set_text('working1')
        self.work_thread = threading.Thread(self.run_thread)
        self.running = True
        gobject.timeout_add(200, self.update_progress)
        self.work_thread.start()
        # the GUI thread now returns to the mainloop

    # this will get periodically called in the GUI thread
    def update_progress(self):
        if self.running:
            self.progressbar.pulse()   # or set_fraction, etc.
        return self.running

    # this will get run in a separate thread
    def run_thread(self):
        Process.heavyworks1()      # or however you're starting your calculation
        gobject.idle_add(self.stop_progress)

    # this will get run in the GUI thread when the worker thread is done
    def stop_progress(self):
        self.running = False
        self.work_thread.join()
        self.label.set_text('idle')
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在gtk3-python中执行后台任务? 的相关文章

随机推荐

  • C# 如何检查两个值之一是否为 TRUE?

    对于 C 专家来说这应该是一个简单的问题 我基本上想检查一个值或另一个值是否为 TRUE 代码如下 if Boolean Parse staff getValue Male Boolean Parse staff getValue Fema
  • 更改 DataGridView 中按钮的颜色

    我到处寻找这个问题的答案 这篇文章的答案 更改 DataGridView 单元格中按钮的颜色没有回答我关于字体的问题 我已经尝试过以下方法 DataGridViewRow r dataGridView Rows 0 r Cells 1 St
  • 用于 PHP 的 Microsoft sqlsrv 驱动程序在查询“SELECT SCOPE_IDENTITY() AS id”时不返回任何结果

    使用 php mssql 驱动程序 此查询工作正常 INSERT INTO Table columnName VALUES text SELECT SCOPE IDENTITY AS id 表确实有一个 id 列 它是一个标识 我将执行该查
  • MVC - 模型与同一页面上的多个实体绑定

    我想知道如何在从页面上多个实体返回信息的场景中使用模型绑定 我想显示来自两个单独实体的字段组合 即客户 地址 我正在为我的模型使用 Microsoft 的 DAAB 和自定义业务实体 有任何想法吗 如果您尝试在回发时绑定到多个模型 则应尝试
  • 如何在 MS SQL Server 2008 上设置日期格式

    我想根据模式格式化日期 例如 22 01 2015 或 2016 12 15 在 NET Framework 中 我们有 DateTime gt ToString 方法 它接受格式作为参数 甚至接受 string Format 它的作用相同
  • 在 Web 应用程序中处理时区

    在我们的网络应用程序中 我们需要显示并输入 不同时区不同国家的日期时间信息 目前 我们正在为每个国家 地区维护单独的 Web 服务器和单独的数据库 oracle 11g 我们计划将所有内容合并到一个具有单一数据库 Oracle 11g 的门
  • 如何在此 SSRS 表达式中“指定数据集聚合”?

    我的 SSRS 报告中需要一个行值 该值是根据报告中已使用的几个字段计算得出的 我希望它显示在名为 textboxPercentageValue 的文本框中 用半简单的英语来说 表达式 公式是 If the value of the Wee
  • Android 自定义 ArrayAdapter 在过滤后不刷新

    所以我有一个习惯ArrayAdapter所以我可以使用标题 副标题视图ListView 我有一个EditText它接受一个字符串并过滤适配器 过滤器的工作原理是过滤正确的对象 我可以通过单击它来判断 它以正确的 附加 开始意图 但是 即使过
  • Javascript:关于如何定义新数据类型有哪些指导原则?

    假设您正在创建数据类型并公开其行为 您能否举例说明何时使用 一个功能和新功能 define new data type var CustomDataType function this a whatever this doX functio
  • 设置内联元素的宽度

    您可以设置内联元素的宽度 例如 span em and strong 但在放置它们之前您不会注意到任何效果 a 我以为内联元素的宽度不能设置 b 假设可以设置宽度 在我们定位内联元素之前 我们不会注意到任何效果 因此我们指定的宽度 位置如何
  • “撤消”功能的最佳设计模式[重复]

    这个问题在这里已经有答案了 可能的重复 撤消引擎的设计模式 一般来说 您如何处理应用程序中支持 撤消 功能的问题 我曾经开发过网络应用程序和桌面应用程序 但我从来没有真正对我制作的任何 撤消 系统感到满意 我相信应该是Command设计模式
  • Angular2.js 与 Angular2.dev.js

    我想知道之间的差异angular2 js and angular2 dev js 当然还有更多文件 例如 router dev js and router js还有 我的问题是为什么有两个版本 它们之间有什么区别 angular2 dev
  • Ruby on Rails 使用外键删除固定装置

    我在使用使用外键的装置设置测试时遇到问题 如果有人能帮助我理解这一点 我将不胜感激 比方说 user type模型有一个参考 role模型 当测试执行时 测试数据库中的所有数据都被删除并再次重新插入 Rails 首先从角色模型中删除数据 而
  • 在 JS 中访问 Asp.Net Session 变量

    我无法访问 js 文件中的变量 我在页面顶部的代码是 然后我想访问我的 js 文件中的权限 我现在只想提醒您这一点 我能做到吗 thanks 您必须将会话值存储在隐藏字段中 之后您可以在 JS 中访问隐藏的 FieldValue
  • php中的应用范围

    我需要在所有请求之间共享相同的数组对象 无论来自同一浏览器 用户的请求如何 php 中是否有任何应用程序范围可以存储该数组对象 我正在使用 php 5 x 如果您想在每个用户的所有请求中共享它 使用会话可能是要走的路 如果您想在所有用户的所
  • 从 dict 创建 ORM 对象并添加到会话中

    假设我有一个User具有属性的模型id name email和一段关系languages 是否有可能创建一个User来自现有数据的实例 其行为就像我查询它一样dbsession query User get 42 我的意思特别是我希望能够访
  • 在 Qt MainWindow 上设置 WA_DeleteOnClose 属性时,删除 ui 指针时程序崩溃

    我已经设置了WA DeleteOnClose主窗口中的小部件属性 setAttribute Qt WA DeleteOnClose 但是 每当我关闭该主窗口时 我都会在其析构函数中遇到段错误 该析构函数只包含delete ui 简而言之 在
  • Pandas:将日期范围解压缩为单个日期

    Dataset 我有一个 1GB 的股票数据集 其中包含日期范围内的值 日期范围没有重叠 数据集按 股票代码 开始日期 排序 gt gt gt df head start date end date val ticker AAPL 2014
  • SonarQube 重构此方法以降低其认知复杂性

    我有以下实用方法 并且我正在使用多个 if 语句并遇到认知复杂性问题 我浏览了一些链接 但我无法理解应该如何更改代码而不影响此方法的用户 public static boolean isWrapperValid WrapperClass w
  • 如何在gtk3-python中执行后台任务?

    我有这个主线 Gui py from gi repository import Gtk Gdk import Process import gobject class gui def init self self window Gtk Wi