如何使用Gtk.events_pending? [英] How to use Gtk.events_pending?

查看:80
本文介绍了如何使用Gtk.events_pending?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基本的测试"应用程序,其中我想在它进行漫长的启动过程(具有数据库请求的功能)时显示微调框,以使用户知道它不是在调试而是在启动.我在其他帖子中已经读到,可以使用Gtk.events_pending()函数执行此操作,但我不知道如何/在何处使用它. 我已经尝试了很多方法,但是主窗口始终仅在请求完成时显示:

I've got this basic "test" application, in which I would like to display a spinner while it is doing its long launching process (functions with database requests) to let the user know that it is not bugging but launching. I've read in other posts that it is possible to do this with Gtk.events_pending() function but I don't know how/where to use it. I've tried many ways, but the main window always displays only when requests are done :

这是主要的.py文件:

Here is the main .py file:

#!/usr/bin/python3
# -*- coding: Utf-8 -*-

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf, GObject

import Mng,os.path

path = os.path.dirname(os.path.realpath(__file__))

# MAIN WINDOW ######################################################################################
class PyApp:
    def __init__(self):
        builder = Gtk.Builder()
        builder.add_from_file(path + "/test.glade")
        self.obj = builder.get_object

        """
        I would like to display on main window a
        spinner while doing requests. There is a
        self.obj('spinner') in main window,
        in glade file to do so.
        """ 
        self.do_requests()

        self.obj('main').show_all()

    def do_requests(self):
        mng = Mng.Grab([
            [1,'getPlayers'],
            [2,'getFactions'],
            [3,'getBoards']
        ])
        data = mng.grab_data()
        players, nb = data[1]
        factions, nb = data[2]
        boards, nb = data[3]

        """
         Here will be the code to display data in GUI,
         like for example : self.obj('label_players').set_text(str(players))
        """

if __name__ == "__main__":
    app = PyApp()
    Gtk.main()

这里是Mng.py文件,我将在该文件中管理一个类中的所有请求(我不知道它的编码是否正确,因为我刚刚发现了多线程.但这确实有用):

Here is the Mng.py file in which I will manage all my requests within a class (I don't know if it is well coded because I just discovered multiple threading. But it does the trick):

#!/usr/bin/python3
# -*- coding: Utf-8 -*-
import os.path, DB
import concurrent.futures

path = os.path.dirname(os.path.realpath(__file__))


class Grab:    
    """
    Retrieves multiple database requests datas
    & returns results in a dict : {name of request: [result, lenght of result]}
    """
    def __init__(self, req_list):
        self.req_list = req_list

    def grab_data(self):

        def do_req(var, funct_name, args):
            if None in args:
                funct = getattr(self, str(funct_name))()
            else:
                #print("function",name,"*args : ", *args)
                funct = getattr(self, str(funct_name))(*args)
            res = [var, funct]
            return res

        with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
            res_list = {}
            future_to_req = {executor.submit(do_req, req[0], req[1], req[2:]): req for req in self.req_list}
            for future in concurrent.futures.as_completed(future_to_req):
                req = future_to_req[future]
                try:
                    data = future.result()
                except Exception as exc:
                    print('%r generated an exception: %s' % (req, exc))
                else:
                    res_list[data[0]] = data[1]

        return res_list

    def getFactions(self, ext1=False):
        req = DB.DB('SELECT * FROM factions')
        res = req.res
        nb = len(res)
        return res, nb

    def getBoards(self, ext1=False):
        req = DB.DB('SELECT * FROM boards')
        res = req.res
        nb = len(res)
        return res, nb


    def getPlayers(self):
        req = DB.DB('SELECT * FROM players')
        res = req.res
        nb = len(res)
        return res, nb

然后执行请求的DB.py文件:

And the DB.py file doing requests:

#!/usr/bin/python3
# -*- coding: Utf-8 -*-

import mysql.connector as sql

class DB(object):    
    """DB initializes and manipulates MySQL databases."""

    def __init__(self, query):
        """Initialize a new or connect to an existing database.
        Accept setup statements to be executed.
        """
        self.database = '******'
        self.host = '**********'
        self.port = '********'
        self.user = '******'
        self.password = '***********'
        self.connect()
        self.execute(query)
        self.close()            

    def connect(self):
        """Connect to the MySQL database."""

        self.connection = sql.connect(host=self.host,port=self.port,user=self.user,password=self.password, database=self.database)
        self.cursor = self.connection.cursor()
        self.connected = True

    def close(self): 
        """Close the MySQL database."""

        self.connection.close()
        self.connected = False

    def execute(self, query):
        """Execute complete SQL statements. """
        res = close = False
        if not self.connected:
            self.connect()
            close = True

        try:
            self.cursor.execute(query)
            if query.upper().startswith('SELECT'):
                res = self.cursor.fetchall()

        except sql.Error as e:
            try:
                print ("MySQL Error [%d]: %s" % (e.args[0], e.args[1]))
            except IndexError:
                print ("MySQL Error: %s" % str(e))

        if close:
            self.close()   

        self.res = res    

能否请你告诉我该怎么做?

Could you please tell me how to do this?

推荐答案

这可以帮助您了解应该如何进行多处理.抱歉,但是我无法为您提供内置代码的完整演示,但希望您能弄清楚.

This may help you understand how multiprocessing is supposed to work. Sorry, but I can't give you a full demo with your code built in, but hopefully you can figure it out.

#!/usr/bin/env python3

from gi.repository import Gtk, GLib, Gdk
from multiprocessing import Queue, Process
from queue import Empty
import os, sys, time

UI_FILE = "src/pygtk_foobar.ui"

class GUI:
    def __init__(self):

        self.builder = Gtk.Builder()
        self.builder.add_from_file(UI_FILE)
        self.builder.connect_signals(self)

        self.window1 = self.builder.get_object('window1')
        self.window1.show_all()
        self.builder.get_object('spin1').start()

        self.data_queue = Queue()
        thread = Process(target=self.thread_start)
        thread.start()

        GLib.timeout_add(100, self.get_result )

    def thread_start (self):
        time.sleep(5)
        self.data_queue.put("done")

    def get_result (self):
        try:
            result = self.data_queue.get_nowait()
            print (result)
            self.builder.get_object('spin1').stop()
        except Empty:
            return True

    def on_window_destroy(self, window):
        Gtk.main_quit()

def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

编辑

说明:只要get result返回True,GLib.timeout_add()就会继续轮询.当超时返回None或False时,它将退出轮询. get result将尝试从data_queue获取结果,但是如果未找到任何内容,它将返回True.

An explanation: GLib.timeout_add() will keep on polling as long as get result returns True. When the timeout gets returned None or False, it will quit polling. get result will try to get results from the data_queue, but if nothing is found, it will return True.

在您的情况下,您将使用def thread_start打开数据库请求,并使用def get_result检查队列,直到信息被加载.因此,多处理将在一个线程中加载数据库信息,而Gtk可以在另一个线程中进行窗口绘制,同时定期检查多处理db线程是否完成.完成加载后,通过不返回True来取消超时,并使用db数据执行操作.

In your case, you would open the database requests with def thread_start and check the queue with def get_result until the info has been loaded. So multiprocessing will load the db info in one thread, while Gtk can do its window drawing in another thread, while periodically checking if the multiprocessing db thread is finished. When it is finished loading, cancel the timeout by not returning True, and do your thing with the db data.

例如,当用户可以操作GUI时,我经常使用它来填充扫描仪.

I use this a lot to populate scanners, for example, while the user can operate the GUI.

希望这会有所帮助.

这篇关于如何使用Gtk.events_pending?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆