V
V
Vitalik2016-03-04 16:01:57
Python
Vitalik, 2016-03-04 16:01:57

How to make a thread hear a signal from the GUI in PyQt4?

I am writing a simple application for automatically checking the performance of a proxy from a given list. There is a GUI class, there is a business process class. I want the start / stop buttons to start and stop the process quietly.
As I understood from stackoverflow, a business process should create a QThread object, and the process itself should already be placed in it. But then no reaction to pressing "stop" occurs.
I'm clearly doing something wrong, but what?
Attached is the relevant part of the code. I understand that I'm stupid, but please be indulgent))
Here is the sheet:

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_())

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey6661313, 2016-07-25
@Sergey6661313

I didn't look at the code, but:
self.emit - translating into Russian, it turns out to send a signal to yourself.
self.worker.emit - should work...
But in general, do it in a modern way (in the reference guide it's perfectly painted, it's a pity that it's only in English. ):

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) # соединяем наш сигнал с вашим методом.

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

other signals are similar.
and the last thing, it seems to me that
while self.exiting is needed in the run method:
otherwise, after an hour of work, the process will simply end. (although maybe that's how it was intended?)
and in general in the if not self.exiting: # check until the Stop button is pressed.
if not done
else:
    return

then the above designated for loop will continue its work simply ignoring all records.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question