Привет всем!

Опять же... Может кому интересно?..
Эх и не спится же мне! Полцарства за глубокий сон! Только нету у меня полцарства...
Решил для себя систематезировать эту тему, прежде чем продолжать рефакторинг этой части гуйни.
Буду рад здравой критике.

# -*- coding: utf-8 -*-

import sys
import time
from PyQt4.Qt import *

def func_1(wait):
    '''Стандартная функция, которая ничего не знает о выполняемой программе\n.'''\
    '''Не имеет никакой возможности доложить о прогрессе выполнения.'''
    time.sleep(wait)
    return True


def func_2(wait):
    '''А вот теперь, собственно вывод.\n'''\
    '''Эту проблему можно решить многими способами.\n'''\
    '''Здесь функция возвращает итератор прогрессa в процентах.\n'''\
    '''Последнее значение есть возврат собственно вызываемой функции.\n'''\
    '''Само собой все функции, использующие этод метод, должны подчинятся этому api.\n'''\
    '''Удобно использовать при чётком разбиении частей выполнения.'''
    for p in xrange(0, 100, 100/int(wait/0.2)):
        time.sleep(0.2)
        yield p
    yield True


class CallObject_3(QObject):
    '''Серьёзный вариант.\n'''\
    '''Для каждого вызова создаётся объект, обеспецивающий определённый api.\n'''\
    '''Может как сам отрисовывать что-нить, так и выдавать сигналы объекту, занимающимся этим.\n'''\
    '''Мне оказалось удобно создать глобальный объект (Progress), который передаётся каждому объекту-обработчику выполнения (CallObject), '''\
    '''который регистрируется в Progress и говорит ему о своём выполнении/завершении. '''\
    '''Progress сам решает что, куда и когда выводить, на основе способа регистрации CallObject и пришедшей информации.\n'''
    '''Например некоторые вещи выводятся модальным QDialog, а некоторые в фоне на статусБар.\n'''\
    '''Вариант удобен при большом количестве разнородных "ожиданий". Довольно быстро реализуется определённый набор этих классов.'''
    def __init__(self, Progress):
        QObject.__init__(self)
        self.Progress = Progress

    def start(self, *Args, **Kw):
        class T(QThread):
            def run(self):
                '''Собственно тело функции.'''
                for p in xrange(0, 100, 100/int(self.Wait/0.2)):
                    time.sleep(0.2)
                    self.emit(SIGNAL("progress(int)"), p)
                self.Result = True

            def start(self, Wait):
                self.Wait = Wait
                QThread.start(self)

        self.Progress.ProgressBar.setMaximum(100)
        self.Progress.show()
        t = T()
        self.connect(t, SIGNAL("progress(int)"), self.Progress.ProgressBar.setValue)
        t.start(*Args, **Kw)
        while not t.isFinished():
            time.sleep(0.013)    ## Чтобы не сильно нагружать просессор.
            qApp.processEvents()
        self.Result = t.Result
        self.Progress.hide()
        self.Progress.ProgressBar.setMaximum(0)
        return self.Result


'''
Возможен ещё один вариант, похожий на CallObject_3.
Объекту, занимающемуся отрисовкой, передаётся _класс_ CallObject, реализующий строго определённый api
и параметры. Progress, используя тот самый api создаёт из этого класса объект, передаёт параметры,
коннектится к определённым сигналам... работает, короче...
Тоже иногда может оказаться довольно удобным.

Уже нет сил для примера. Думаю, что всё ясно.
'''


class ProgressDialog(QDialog):
    def __init__(self, Parent):
        QDialog.__init__(self, Parent)
        self.Layout = QVBoxLayout(self)
        self.ProgressBar = QProgressBar(self)
        self.Layout.addWidget(self.ProgressBar)
        self.ProgressBar.setRange(0, 0)

    def exec_1(self, Func, *Args, **Kw):
        class T(QThread):
            def run(self):
                self.Result = Func(*self.Args, **self.Kw)

            def start(self, Func, *Args, **Kw):
                self.Func = Func
                self.Args = Args
                self.Kw = Kw
                QThread.start(self)

        self.show()
        t = T()
        t.start(Func, *Args, **Kw)
        while not t.isFinished():
            time.sleep(0.013)    ## Чтобы не сильно нагружать просессор.
            qApp.processEvents()
        self.hide()
        return t.Result


    def exec_2(self, Func, *Args, **Kw):
        class T(QThread):
            def run(self):
                last = 0
                for p in Func(*self.Args, **self.Kw):
                    if type(p) is int and last < p <= 100:
                        self.emit(SIGNAL("progress(int)"), p)
                        last = p
                    else:
                        last = p
                self.Result = last

            def start(self, Func, *Args, **Kw):
                self.Func = Func
                self.Args = Args
                self.Kw = Kw
                QThread.start(self)

        self.ProgressBar.setMaximum(100)
        self.show()
        t = T()
        self.connect(t, SIGNAL("progress(int)"), self.ProgressBar.setValue)
        t.start(Func, *Args, **Kw)
        while not t.isFinished():
            time.sleep(0.013)    ## Чтобы не сильно нагружать просессор.
            qApp.processEvents()
        self.hide()
        self.ProgressBar.setMaximum(0)
        return t.Result





class MainWindow(QDialog):
    def __init__(self, Parent = None):
        QDialog.__init__(self, Parent)
        self.Layout = QVBoxLayout(self)

        self.Button_1 = QPushButton("func_1", self)
        self.Layout.addWidget(self.Button_1)
        self.connect(self.Button_1, SIGNAL("clicked()"), self.start_1)

        self.Button_2 = QPushButton("func_2", self)
        self.Layout.addWidget(self.Button_2)
        self.connect(self.Button_2, SIGNAL("clicked()"), self.start_2)

        self.Button_3 = QPushButton("CallObject_3", self)
        self.Layout.addWidget(self.Button_3)
        self.connect(self.Button_3, SIGNAL("clicked()"), self.start_3)

    def start_1(self):
        '''Без прогресса, но без тормоза GUI.'''\
        '''Думаю, что тут всё ясно и без лишних комментариев.'''
        print 'Start.'
        Progress = ProgressDialog(self)
        print Progress.exec_1(func_1, 5.0)
        print 'Stop.'


    def start_2(self):
        '''См. func_2.'''
        print 'Start.'
        Progress = ProgressDialog(self)
        print Progress.exec_2(func_2, 5.0)
        print 'Stop.'

    def start_3(self):
        print 'Start.'
        Progress = ProgressDialog(self)
        O = CallObject_3(Progress)
        print O.start(5.0)
        print 'Stop.'



App = QApplication(sys.argv)
MW = MainWindow()
MW.show()
App.setQuitOnLastWindowClosed(True)
sys.exit(App.exec_())
...так кто ж ты, наконец?
-- Я -- часть той силы, что вечно хочет зла
и вечно совершает благо.
писал бы уже в блог
Be easy, stay cool
Да ладно... Не так уж часто я чё-нить пишу...
Хотя такая мысть ко мне приходила. :-)
Да и здесь, больше шансов, что кому-то понадобится.
...так кто ж ты, наконец?
-- Я -- часть той силы, что вечно хочет зла
и вечно совершает благо.