Завершение программы в середине - PullRequest
2 голосов
/ 17 мая 2011

pythoncom.PumpMessages ()

Насколько я понимаю, эта строка в основном говорит программе ждать вечно.Для моих целей это, кажется, работает.Тем не менее, я хотел бы иметь возможность закончить программу, учитывая правильный стимул.Как можно закончить указанную выше строку или остановить дальнейшую работу программы?

Ответы [ 3 ]

7 голосов
/ 17 мая 2011

В соответствии с этими документами , pythoncom.PumpMessages():

Перекачивает все сообщения для текущего потока до сообщения WM_QUIT.

Таким образом, один из способов остановить сбор сообщений - это отправить сообщение WM_QUIT в очередь сообщений, используя библиотеку ctypes для вызова PostQuitMessage :

ctypes.windll.user32.PostQuitMessage(0)
6 голосов
/ 17 мая 2011

Вот пример выхода из приложения с использованием потока таймера:

import win32api
import win32con
import pythoncom
from threading import Timer

main_thread_id = win32api.GetCurrentThreadId()

def on_timer():
    win32api.PostThreadMessage(main_thread_id, win32con.WM_QUIT, 0, 0);

t = Timer(5.0, on_timer) # Quit after 5 seconds
t.start()

pythoncom.PumpMessages()

PostQuitMessage() будет работать только из основного потока, но опять же основной поток заблокирован , поэтому он сам по себе не очень полезен. Вы можете использовать его, только если подключите свою собственную обработку сообщений к циклу сообщений.

0 голосов
/ 21 октября 2016

Я бы хотел расширить оба ответа на Грегг и Боаз Янив .Обычно вы запускаете код блокировки в отдельном потоке, поэтому вам необходимо отправить WM_QUIT в поток.Вы должны использовать PostQuitMessage , как отметил Грегг, но это работает только в текущей теме.Вы не должны использовать PostThreadMessage для отправки WM_QUIT (не могу вспомнить, где я вижу это в документах).Подробнее об этом вы можете прочитать в обсуждении " Почему существует специальная функция PostQuitMessage? ".Я думаю, что лучше сначала отправить WM_CLOSE в ветку.

# if more hotkeys needs to be supported at the same time this class needs to be rewritten
class HotKey:
    def __init__(self, modifier_key, virtual_key, callback):
        self.hotkey_id = 1
        # shared variable to pass thread id
        self.pid = mpdummy.Value('l', 0)

        # start checking hotkey press in new thread
        self.process_pool = mpdummy.Pool()
        self.process_pool.apply_async(HotKey.register, (self.hotkey_id, self.pid, modifier_key, virtual_key, callback, ))
        self.process_pool.close()

    # bind windows global hotkey
    @staticmethod
    def register(hotkey_id, pid, modifier_key, virtual_key, callback):
        # set thread ID to shared variable
        # Win API could also be used:
        # ctypes.windll.Kernel32.GetCurrentThreadId()
        pid.value = mpdummy.current_process().ident

        # register hotkey with Win API
        logging.getLogger('default').info("Registering hotkey with id " + str(hotkey_id) + " for key " + str(modifier_key) + " " + str(virtual_key))
        if not ctypes.windll.user32.RegisterHotKey(None, hotkey_id, modifier_key, virtual_key):
            logging.getLogger('default').info("Unable to register hotkey with id " + str(hotkey_id))

        msg = ctypes.wintypes.MSG()
        try:
            # wait for a message - it doesn't return until some message arrives
            while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
                # WM_HOTKEY     0x0312
                # https://msdn.microsoft.com/en-us/library/windows/desktop/ms646279(v=vs.85).aspx
                if msg.message == 0x0312:
                    logging.getLogger('default').info("Pressed hotkey with id " + str(hotkey_id))
                    callback()
                # WM_CLOSE
                # https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
                elif msg.message == 0x0010:
                    # quit current thread
                    # WM_QUIT shouldn't be send with PostThreadMessageA therefore we send WM_CLOSE and quit inside thread.
                    # More info at:
                    # https://msdn.microsoft.com/en-us/library/windows/desktop/ms644945(v=vs.85).aspx
                    # https://blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453
                    ctypes.windll.user32.PostQuitMessage(0)
                ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
                ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
        finally:
            logging.getLogger('default').info("Unregistering hotkey for id " + str(hotkey_id))
            ctypes.windll.user32.UnregisterHotKey(None, hotkey_id)

    def unregister(self):
        # send WM_CLOSE signal to thread checking for messages
        # WM_CLOSE      0x0010
        # https://msdn.microsoft.com/en-us/library/windows/desktop/ms632617(v=vs.85).aspx
        ctypes.windll.user32.PostThreadMessageA(self.pid.value, 0x0010, 0, 0)
        # wait for thread to finish
        self.process_pool.join()

Я использую его для RegisterHotKey, но принцип тот же.Этот класс может называться:

# bind global hotkey for "pressing" start/split button
# MOD_ALT       0x0001
# VK_F12        0x7B
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms646309(v=vs.85).aspx
# https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731.aspx
self.hotkey = hotkey.HotKey(0x0001, 0x7B, self.special_key_pressed)

Когда вы хотите прекратить ожидание сообщений, позвоните:

self.hotkey.unregister()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...