sonic_youth
@sonic_youth
бла-бла-бла

Как в PyQt4 сделать, чтобы поток слышал сигнал от GUI?

Пишу простенькое приложение для автоматической проверки работоспособности прокси из заданного списка. Есть класс GUI, есть класс бизнес-процесса. Хочу, чтобы кнопками старт/стоп процесс спокойно запускался и прекращался.
Как я понял со stackoverflow бизнес процесс следует создать объект QThread, а в него уже помещать сам процесс. Но тогда никакой реакции на нажимание "стоп" не происходит.
Я явно что-то делаю не так, но что?
Часть кода, имеющую отношение к делу, прилагаю. Понимаю, что туплю, но прошу быть снисходительными))

Вот простыня:
import ... #импортируем все, что нужно

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self)
        # создаем гуи
        self.ui = Ui_MainWindow()
        # устанавливаем пользовательские настройки в гуи
        self.ui.setupUi(self)
        self.worker = Worker() # создаем класс, отвечающий за бизнес-процесс
        self.thread = QtCore.QThread() 
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.ui.stopButton.clicked.connect(self.stop)"
        self.ui.stopButton.setEnabled(False)

        # подключаем сигналы/слоты:
        # соединяем кнопку Start и функцию, проверяющую имеющийся список прокси
        self.ui.startButton.clicked.connect(self.startChecking)
        # соединяем кнопку Stop и вызов функции stopProxy
        self.ui.stopButton.clicked.connect(self.worker.stopFlag)
        # окончание сканирования одного прокси связываем с отображением текущего результата
        self.connect(self.worker, QtCore.SIGNAL('threadDone()'), self.showResult)
        # окончание сканирования одного прокси связываем с отображением текущеЙ истории запросов
        self.connect(self.worker, QtCore.SIGNAL('threadDone()'), self.showLog)
        # остановку сканирования связываем с изменением состояния виджетов гуи и счетчика
        self.connect(self.worker, QtCore.SIGNAL('finished()'), self.doneChecking)
        # прерывание сканирования связываем с изменением состояния виджетов гуи и счетчика
        self.connect(self.worker, QtCore.SIGNAL('terminated()'), self.doneChecking)
        self.connect(self.worker, QtCore.SIGNAL('show()'), self.showResult)

        self.connect(self, QtCore.SIGNAL('stop()'), self.worker.stopFlag)
        self.ui.searchButton.clicked.connect(self.searchMain)
        self.ui.clearButton.clicked.connect(self.clear)

    def startChecking(self):  # стартуем))
        self.thread.start()  # вызов потока, проверюяющего прокси
        self.ui.startButton.setEnabled(False)  # отключаем кнопку "Start"
        self.ui.stopButton.setEnabled(True)  # делаем доступной кнопку "Stop"
        self.ui.addButton.setEnabled(False)  # отключаем кнопку "Add"
        self.ui.deleteButton.setEnabled(False)  # отключаем кнопку "Delete"
        self.ui.statusbar.showMessage('Proxies are checking...')  # сообщаем о начатом процесее в статусбаре

    def stop(self):  # остановка
        self.emit(QtCore.SIGNAL('stop()'))
        self.doneChecking()  # изменяем состояние виджетов гуи
        
    def doneChecking(self):  # изменение виджетов гуи при остановке сканирования

class Worker(QtCore.QObject):  # поток, выполняющий проверку

    def __init__(self):
        super().__init__()  # инициализируем свойства родительского класса
        self.proxies = []  # инициализируем список прокси
        self.headers = {}
        self.exiting = False  # флаг выхода
        self.log = []  # инициализируем журнал запросов
        self.configure()
        self.emit(QtCore.SIGNAL('showSettings()'))

    def configure(self): # устанавливаем настройки запросов

    def run(self):  # главная функция, которая вызывается кнопкой Start
        self.exiting = False
        print(self.exiting)
        self.main()  # выполняем проверку прокси
        self.checkLogLength()  # проверка длины журнала
        time.sleep(3600 - len(self.proxies)*self.timeout)  # делаем паузу (час минус потраченное время)

    def main(self):  # цикл, который обходит список прокси
        for proxy in range(len(self.proxies)):
            if not self.exiting:  # пока не нажали кнопку Stop.
                currentProxy = self.proxies[proxy]  # текущий прокси
                self.proxies[proxy]['available'] = 'Checking'
                self.saveTemp()
                self.emit(QtCore.SIGNAL('show()'))
                proxyTested = self.checkProxy(currentProxy)  # результат запроса
                self.proxies.pop(proxy)  # удаляем из списка старые данные по текущему прокси
                self.proxies.insert(proxy, proxyTested)  # вставляем в список новые данные
                self.log.insert(0, proxyTested)  # вставляем в историю (в начало) результаты запроса
                self.checkLogLength()  # проверяем длину журнала
                self.saveTemp()  # сохраняем список прокси
                self.saveLog()  # сохраняем историю
                self.emit(QtCore.SIGNAL('threadDone()'))  # сигналим гуи, что данные обновлены

    def checkProxy(self, proxy):  # проверка текущего прокси
        ...

    def stopFlag(self):
        self.exiting = True
        self.fixProxies()
        self.saveTemp()
        self.saveLog()
        self.emit(QtCore.SIGNAL('fin()'))
        self.emit(QtCore.SIGNAL('show()'))

    def openTemp(self):  # открытие текущего списка прокси

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = MainWindow()
    myapp.show()
    sys.exit(app.exec_())
  • Вопрос задан
  • 989 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Sergey6661313
код не смотрел но:
self.emit - переводя на русский получается послать сигнал себе.
self.worker.emit - должно сработать...

А вообще на до делать по современному (в reference guide отлично расписано, жалко что только по английски. ):
class MainWindow(QtGui.QMainWindow):
    ...ваша простыня...
    def stop(self):  # остановка
        self.worker.stoping.emit() # да-да просто обрящяемся к сигналу stoping
        self.doneChecking()  # изменяем состояние виджетов гуи
    ... остальные куски вашей простыни...


class Worker(QtCore.QObject): 
    stoping = pyqtSignal()   # сообственно наш сигнал. инициализировать нужно именно тут а не в init это важно, но я хз почему. Может ругнутся на то что не видит  pyqtSignal - тут зависит от того как вы импортировали qt и какая у вас версия его. QtCore.pyqtSignal() или QtCore.Qt.pyqtSignal() пробуйте сами короче.
    
    def __init__(self):
        super().__init__() 
        self.stoping.connect(self.stopFlag) # соединяем наш сигнал с вашим методом.

    ...остальная часть вашего кода...

другие сигналы аналогично.
и последнее мне кажется что в методе run нужно
while self.exiting:
иначе через час работы процесс просто завершится. (хотя может так и задумано?)

и вообще в проверке if not self.exiting: # пока не нажали кнопку Stop.
если не сделать
else:
    return

то выше назначенный цикл for продолжит свою работу просто игнорируя все записи.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы