Отправка сигнала в QApplication

Я отправляю signal.CTRL_BREAK_EVENT в подпроцесс QApplication, и обработчику подпроцесса удается поймать сигнал (и выполнить некоторую магию перед выходом). Однако, когда сигнал отправляется, он не обрабатывается до тех пор, пока я не взаимодействую с окном QApplication (заставляя его каким-то образом использовать циклы ЦП, LOL), и только тогда он будет обрабатывать сигнал.

E.g.

  1. Я запускаю QApplication как подпроцесс
  2. Я отправляю signal.CTRL_BREAK_EVENT (с сервера, который запустил подпроцесс).
  3. Ничего не произошло.
  4. Я нажимаю на любую кнопку в QApplication.
  5. Он обрабатывает signal.CTRL_BREAK_EVENT и завершает работу.

Я бы, конечно, предпочел, чтобы шаг 5 происходил на шаге 3.

Что случилось? Как мне «обновить» QApplication или виртуально нажать кнопку, когда она запускается в подпроцессе? Я подозреваю, что основной цикл событий QApplication каким-то образом находится в режиме ожидания... до тех пор, пока с приложением не взаимодействуют. (?)

server.py

app = None

def start_app():
    global app

    app = subprocess.Popen("python app.py")

def exit_app():
    global app

    p = app.poll()
    if p==None:
        print("Subprocess is alive") # debug
    app.send_signal(signal.CTRL_BREAK_EVENT)

app.py

import sys, signal
from runner import mainWindow

from PyQt5.QtWidgets import QApplication

app = None
mw = None

def exit_signal_handler(signal, frame):
    global app, mw

    print("Terminate signal received")
    app.quit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    signal.signal(signal.SIGBREAK, exit_signal_handler)

    mw = mainWindow.MainWindow() # this is the Qt window starting
    mw.actionExit.triggered.connect(app.quit)

    sys.exit("Runner exit with code: " + str(app.exec()))

person niCk cAMel    schedule 08.02.2018    source источник
comment
Можешь показать как ты connect() сигналил.. и где?   -  person Mohammad Kanan    schedule 08.02.2018
comment
@MohammadKanan Подробно описано здесь: stackoverflow.com/q/47306805/2923755. Если вы видите там что-то важное, я могу отредактировать вопрос   -  person niCk cAMel    schedule 08.02.2018
comment
Не очень хорошо знаком с Py. однако я понимаю, что когда вы запускаете подпроцесс Qapp, он запускает свой (блокирующий) цикл событий (?). Итак, ваш сигнал блокируется, и я не могу понять, почему нажатие произвольной кнопки завершает или разблокирует этот цикл событий!   -  person Mohammad Kanan    schedule 08.02.2018
comment
Я спросил, где вы подключаете свой сигнал/слот, потому что это может быть связано, если connect() выполняется внутри подпроцесса Qapp, тогда он должен работать   -  person Mohammad Kanan    schedule 08.02.2018
comment
@MohammadKanan Итак, здесь нет connect(), сигнал перехватывается exit_signal_handler(signal, frame) в app.py по ссылке, которую я предоставил   -  person niCk cAMel    schedule 08.02.2018
comment
idownvotedbecau.se/nocode, idownvotedbecau.se/nomcve, idownvotedbecau.se/nodebugging   -  person Murphy    schedule 09.02.2018
comment
@Мерфи умница. ihaveaddedco.de/sohelp   -  person niCk cAMel    schedule 09.02.2018
comment
Я не знаю, обрезал ли ваш пример несколько вещей, но я заметил, что приложение является локальной переменной в server.py, ваш пример не является минимальный воспроизводимый пример, его невозможно проверить, так как он неполный   -  person eyllanesc    schedule 09.02.2018
comment
@eyllanesc . Да, сильно обрезанный. Я отредактировал сейчас, чтобы включить больше кода   -  person niCk cAMel    schedule 09.02.2018
comment
Это все еще не минимально воспроизводимый пример. server.py ничего не делает при запуске в моей системе (конечно, отсутствует какой-либо стартовый код), а app.py отсутствует модуль runner.   -  person Murphy    schedule 09.02.2018
comment
@Murphy Я понимаю вашу точку зрения, но если кто-то хочет проголосовать против, потому что не все правила буквально соблюдаются, тогда вам придется проголосовать против большинства вопросов на SO. Это не для оправдания моей ошибки, это просто факт. Кроме того, поскольку я подозреваю, что что-то происходит в основном цикле событий QApplication, который каким-то образом приостановлен и возобновляется только при взаимодействии, я полагаю, что кто-то с достаточными знаниями обнаружит проблему, не имея доступа ко всему рассматриваемому коду.   -  person niCk cAMel    schedule 09.02.2018
comment
Вы не читали предоставленные ссылки, не так ли? Вы тратите время людей.   -  person Murphy    schedule 09.02.2018
comment
@Мерфи, а ты не читал, что я сказал. Вы знаете, вы не обязаны пересматривать и комментировать. Вы проголосовали против, предоставили ссылки.. Я имею в виду, что вы закончили. Спасибо за старания, но не возвращайтесь.   -  person niCk cAMel    schedule 09.02.2018
comment
может ли QApp работать в потоке? Я предполагаю, что он заблокирован системным вызовом, и сигнал в Windows не может сломать блокировку системного вызова.   -  person georgexsh    schedule 11.02.2018


Ответы (1)


Добавление Qtimer() в app.py по причинам опроса, кажется, помогает. Любые отправленные сигналы будут обрабатываться каждую секунду, когда pollMe() вызывается Qtimer.

import sys, signal
from runner import mainWindow
from PyQt5 import QtCore           #<---- NEW
from PyQt5.QtWidgets import QApplication

app = None
mw = None

def pollMe():                      # <--- NEW
    timerPoll.start(1000)

def exit_signal_handler(signal, frame):
    global app, mw

    print("Terminate signal received")
    app.quit()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    signal.signal(signal.SIGBREAK, exit_signal_handler)

    timerPoll = QtCore.QTimer()        #<---- NEW
    timerPoll.timeout.connect(pollMe)
    timerPoll.start(1000)

    mw = mainWindow.MainWindow() # this is the Qt window starting
    mw.actionExit.triggered.connect(app.quit)

    sys.exit("Runner exit with code: " + str(app.exec()))
person niCk cAMel    schedule 10.02.2018