파이썬을 이용해서 윈도우 메시지펌프를 하는 간단한 예제 코드 입니다
우선 전체 코드를 먼저 본 다음 일부 중요 함수들 설명 이어가겠습니다.
메시지 펌프 코드는 아래 사이트를 참고 했습니다.
import sys import pythoncom from PyQt5.QtWidgets import * import win32event StopEvent = win32event.CreateEvent(None, 0, 0, None) ################################################ # 테스트를 위한 메인 화면 class MyWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Test") self.setGeometry(300, 300, 300, 180) nH = 20 btnStart = QPushButton('strat Pump', self) btnStart.move(20, nH) btnStart.clicked.connect(self.btnStartPump) nH += 50 btnStop = QPushButton('stop Pump', self) btnStop.move(20, nH) btnStop.clicked.connect(self.btnStopPump) nH += 50 btnExit = QPushButton('종료', self) btnExit.move(20, nH) btnExit.clicked.connect(self.btnExit_clicked) nH += 50 def MessagePump(sef, timeout): waitables = [StopEvent] while 1: rc = win32event.MsgWaitForMultipleObjects( waitables, 0, # Wait for all = false, so it waits for anyone timeout, #(or win32event.INFINITE) win32event.QS_ALLEVENTS) # Accepts all input if rc == win32event.WAIT_OBJECT_0: # Our first event listed, the StopEvent, was triggered, so we must exit print('stop event') break elif rc == win32event.WAIT_OBJECT_0 + len(waitables): # A windows message is waiting - take care of it. (Don't ask me # why a WAIT_OBJECT_MSG isn't defined < WAIT_OBJECT_0...!). # This message-serving MUST be done for COM, DDE, and other # Windowsy things to work properly! print('pump') if pythoncom.PumpWaitingMessages(): break # we received a wm_quit message elif rc == win32event.WAIT_TIMEOUT: print('timeout') return pass else: print('exception') raise RuntimeError("unexpected win32wait return value") def btnStartPump(self): self.MessagePump(5000) return def btnStopPump(self): win32event.SetEvent(StopEvent) return def btnExit_clicked(self): exit() return if __name__ == "__main__": app = QApplication(sys.argv) myWindow = MyWindow() myWindow.show() app.exec_()
메시지 펌프를 하는 실제 코드는 아래 함수 입니다.
- MsgWaitForMultipleObjects 라는 윈도우 API 를 이용해서 윈도우 메시지 큐에 메시지가 올 때까지 기다립니다. 파라미터로 이벤트 리스트를 보내게 되는데 윈도우 메시지 말고도 지정한 이벤트 리스트 중 하나라도 시그널이 발생하면 대기를 멈추고 리턴합니다.
- if rc == win32event.WAIT_OBJECT_0: 같은 코드들은 이벤트 리스트 배열에 들어 있는 항목들 만큼 반복해서 어느 이벤트에서 시그널이 발생했는지 확인하는 용도 입니다. 이번 예제에서는 이벤트(StopEvent) 를 하나만 등록했고 그 이벤트가 발생(Signal) 할 경우 처리를 하면 됩니다.
- rc == win32event.WAIT_OBJECT_0 + len(waitables): 실제 윈도우 메시지가 들어온 경우 처리 해야 할 로직으로 여기서는 pythoncom.PumpWaitingMessages() 함수를 호출해서 윈도우 메시지를 가져와 실행하게 됩니다.
- rc == win32event.WAIT_TIMEOUT : 무한대로 기다릴 수도 있지만 특정 시간이 경과 하면 MsgWaitForMultipleObjects 호출이 리턴되도록 할 수 있습니다
def MessagePump(sef, timeout): waitables = [StopEvent] while 1: rc = win32event.MsgWaitForMultipleObjects( waitables, 0, # Wait for all = false, so it waits for anyone timeout, #(or win32event.INFINITE) win32event.QS_ALLEVENTS) # Accepts all input if rc == win32event.WAIT_OBJECT_0: # Our first event listed, the StopEvent, was triggered, so we must exit print('stop event') break elif rc == win32event.WAIT_OBJECT_0 + len(waitables): # A windows message is waiting - take care of it. (Don't ask me # why a WAIT_OBJECT_MSG isn't defined < WAIT_OBJECT_0...!). # This message-serving MUST be done for COM, DDE, and other # Windowsy things to work properly! print('pump') if pythoncom.PumpWaitingMessages(): break # we received a wm_quit message elif rc == win32event.WAIT_TIMEOUT: print('timeout') return pass else: print('exception') raise RuntimeError("unexpected win32wait return value")
메시지 펌프를 시작 시키고 이벤트를 발생 시켜 중단하는 코드는 아래에 있습니다.
- win32event.CreateEvent 를 통해 새로운 이벤트를 생성합니다.
- win32event.SetEvent(StopEvent)로 Signal 을 발생시킵니다.
# 이벤트 생성 StopEvent = win32event.CreateEvent(None, 0, 0, None) # 중략... # 메시지 펌프 시작 def btnStartPump(self): self.MessagePump(5000) return def btnStopPump(self): win32event.SetEvent(StopEvent) return
위 예제 코드를 실행 시켜 보면 start pump 버튼이 눌려진 상태에서 메시지펌핑이 시작 되고, 아직 함수를 빠져나오지 않았는데도 메시지 펌핑에 의해 버튼이 계속 눌려지는 것을 확인할 수 있습니다
PYQT 가 이미 내부적으로 윈도우 메시지 펌핑을 하고 있기 때문에 이렇게 이중으로 메시지 펌핑을 하는 경우 약간의 문제들이 생길 수 있어 조심스럽게 코딩해야 합니다.
'개발 > 파이썬' 카테고리의 다른 글
[파이썬] 함수 호출 CALL BY VALUE/CALL BY REFERENCE (2) | 2019.10.06 |
---|---|
파이썬의 for 루프 (1) | 2019.06.16 |
[CREON PLUS API 활용] BlockRequest 와 Request (362) | 2018.12.11 |
[CREON PLUS API 활용] MACD 매매 시그널 실시간 구하기(5분 차트 이용) (0) | 2018.11.23 |
파이썬 리턴값 편리 기능 (0) | 2018.11.18 |
[파이썬] 파일 다루기(유니코드, 파일 읽기 등) (0) | 2018.10.21 |
댓글