2009-06-26 3 views
29

오픈 소스 클라이언트/서버 4X 전략 게임 Thousand Parsec을위한 Qt 클라이언트를 구축 중입니다. Google Summer of Code 프로젝트입니다. 그러나 나는 막 다른 골목에 갇혀있다. 기본적으로 클라이언트는 클라이언트/서버 통신을 용이하게하는 C++ 프로토콜 계층을 통해 서버와 인터페이스합니다. 프로토콜의 설명서는 here입니다.외부 이벤트 루프와 Qt의 짝짓기하기

이제 내 문제는 프로토콜에서 클라이언트에 가상 EventLoop 클래스 (link)의 하위 클래스를 만들어야한다는 것입니다. 같은 링크에있는 콘솔 클라이언트에 사용되는 SimpleEventLoop 예제가 있습니다. 동시에 Qt 애플리케이션에 연결하는 동안 프로토콜의 이벤트를 처리하는 자체 이벤트 루프 하위 클래스를 어떻게 디자인 할 수 있는지 파악하는 데 어려움이 있습니다. 내 연구는 내가 QAbstractEventDispatcher이 내가 사용하고 싶어하는 Qt 클래스라고 믿게 만들었지 만 설명서가 꽤 슬림하게 보입니다. 어떻게하는지에 대해 정확히 알지 못합니다.

누구나 외부 이벤트 루프를 Qt 애플리케이션과 연결 한 경험이 있습니까? 또한 Qt 페이지에서 example을 찾았지만 그다지 도움이되지 못했습니다. 아니면 적어도 이해하지 못했습니다.

감사합니다.

답변

30

나는 최근에 너무 많은 Qt를 개발을 완료하지 않은,하지만 난 제대로 기억한다면, 당신은

편집 (대신 QApplication::exec()을 통해 Qt의 메인 루프를 시작하는) 자신의 이벤트 루프 내에서 QApplication::processEvents()를 호출 할 수 I 느린 일요일 아침에 PyQt (Qt 용 Python 바인딩)을 테스트하고/배우고 아래에 개념 증명 (proof-of-concept) 코드를 결합했습니다. QApplication::exec()에 대한 호출을 QApplication::processEvents()을 기반으로하는 사용자 지정 이벤트 루프로 바꾸면이 작동합니다.

나는 또한 simpleeventloop.cpptpclient-cpptext main.cpp을 빨리 보았습니다. 그것의 모양에서, QApplication::processEvents() 어딘가에 SimpleEventLoop::runEventLoop()의 어딘가에 추가하는 것은 좋을 것이다. 메인 루프에 추가하기 위해, 나는 아마

tv.tv_sec = 0; 
tv.tv_usec = 10000; // run processEvents() every 0.01 seconds 
app->processEvents(); 

lines 106 through 117select() 기능에 대한 tv 간격을 교체하고 void SimpleEventLoop::runEventLoop(QApplication *app)line 89의 서명을 변경합니다. 클라이언트 구현에 일반적인 Qt를 추가하는 것이 좋습니다 (tpclient-cpptext main.cpp 대체)

해킹처럼 보입니다. 아마도 시작하기 위해 이와 같은 것으로 시작할 것입니다. 제 생각에 TPSocket을 포장하고 QAbstractEventDispatcherQEventLoop으로 전달하기 위해 Qt의 각 개념 내에 타이머를 넣는 것이 더 나은 장기적인 해결책이라고 생각합니다. 그러면 runEventLoop()QApplication::exec()으로 전화하기 만하면됩니다. 그러나 전에는 QAbstractEventDispatcher을 사용한 적이 없으므로 내 의견을 들어보십시오.

import sys 
import time 

from PyQt4 import QtGui 
from PyQt4 import QtCore 

# Global variable used as a quick and dirty way to notify my 
# main event loop that the MainWindow has been exited 
APP_RUNNING = False 

class SampleMainWindow(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     QtGui.QMainWindow.__init__(self) 
     global APP_RUNNING 
     APP_RUNNING = True 

     # main window 
     self.setGeometry(300, 300, 250, 150) 
     self.setWindowTitle('Test') 
     self.statusBar().showMessage('Ready') 

     # exit action (assumes that the exit icon from 
     # http://upload.wikimedia.org/wikipedia/commons/b/bc/Exit.png 
     # is saved as Exit.png in the same folder as this file) 
     exitAction = QtGui.QAction(QtGui.QIcon('Exit.png') 
            ,'Exit' 
            ,self) 
     exitAction.setShortcut('Ctrl+Q') 
     exitAction.setStatusTip('Exit application') 
     self.connect(exitAction 
        ,QtCore.SIGNAL('triggered()') 
        ,QtCore.SLOT('close()')) 

     # main menu 
     menubar = self.menuBar() 
     fileMenu = menubar.addMenu('&File') 
     fileMenu.addAction(exitAction) 

     # toolbar 
     self.toolbar = self.addToolBar('Exit') 
     self.toolbar.addAction(exitAction) 

     # text editor 
     textEdit = QtGui.QTextEdit() 
     self.setCentralWidget(textEdit) 

     #tool tip 
     textEdit.setToolTip('Enter some text') 
     QtGui.QToolTip.setFont(QtGui.QFont('English', 12)) 

    def closeEvent(self, event): 
     reply = QtGui.QMessageBox.question(self 
              ,'Message' 
              ,"Are you sure?" 
              ,QtGui.QMessageBox.Yes 
              ,QtGui.QMessageBox.No) 

     if reply == QtGui.QMessageBox.Yes: 
      event.accept() 
      global APP_RUNNING 
      APP_RUNNING = False 
     else: 
      event.ignore() 

# main program 
app = QtGui.QApplication(sys.argv) 
testWindow = SampleMainWindow() 
testWindow.show() 
# run custom event loop instead of app.exec_() 
while APP_RUNNING: 
    app.processEvents() 
    # sleep to prevent that my "great" event loop eats 100% cpu 
    time.sleep(0.01) 
+0

내 목표는 이벤트 루프를 제대로 통합하기 위해 AbstractEventDispatcher를 사용하는 것이지만 Qt의 초보자가 너무 빠르다. 그냥 자리에서 작동하는 솔루션을 얻는 동안 측면 에서이 일을하려고합니다. SimpleEventLoop 클래스를 해킹하여 "실행 중"상태를 반환 할 수 있도록 해 주므로 예제와 비슷한 while 문으로 주 앱에서 확인할 수 있습니다. 어떻게 작동하는지 알려 드리겠습니다. 내가 걱정하는 것은 부스트 ​​신호 콜백이 Qt 애플리케이션 내부에서 제대로 처리 될지 여부입니다. – mhilmi

+0

@Gimpyfuzznut : simpleeventloop.cpp에 대한 샘플 해킹을 추가했습니다. SimpleEventLoop :: runEventLoop()의 현재 구현은 표준 이벤트 루프를 구현하기 때문에 제안 된 해킹이 가장 복잡 할 수 있습니다 (예 : http://stackoverflow.com/questions/658403/how-would-you-implementa-a- basic-event-loop/658495 # 658495 설명), 따라서 신호 나 타이머가 SimpleEventLoop :: endEventLoop()을 실행 이벤트 루프의 일부로 호출하지 않으면 절대로 반환하지 않습니다. – stephan

2

이벤트 루프를 별도의 스레드로 코딩 할 것입니다. 클래스의 라이브러리에서 이벤트를 처리하고 필요할 때마다 주 Qt 이벤트 루프에 의해 처리되는 신호를 생성하도록 할 수 있습니다 (긴 작업에서 필요한 경우 QApplication :: processEvents()를 호출하십시오). 이것에 대한 유일한 트릭은 외부 이벤트 루프가 Q_OBJECT인지 확인하여 관심있는 신호를 내보내는 방법을 알고 있어야합니다.

메인 QT 스레드가 아닌 스레드에서 페인팅하지 않는 것과 같은 다른 스레드 문제가 있습니다.

+8

"이제 두 가지 문제가 있습니다.":-) – Kos

1

Qt는 설명서를 말한다 :

이 (보류중인 이벤트가 없을 때마다 즉 특별한 기능을 실행), 응용 프로그램이 유휴 처리를 수행 할 수 있도록 0 시간 제한이있는 QTimer을 사용합니다.

별로 해결책은 아닙니다.