2009-06-26 47 views
29

của Qt Tôi đang xây dựng ứng dụng khách Qt cho trò chơi chiến lược 4X khách/máy chủ nguồn mở Thousand Parsec. Đây là dự án Google Summer of Code. Tuy nhiên, tôi bị mắc kẹt ở một ngõ cụt. Về cơ bản, client giao tiếp với máy chủ thông qua một lớp giao thức C++ tạo điều kiện cho giao tiếp client/server. Tài liệu của giao thức có sẵn here.Kết hợp vòng lặp sự kiện bên ngoài với số

Bây giờ vấn đề của tôi là giao thức yêu cầu bạn tạo một lớp con của lớp EventLoop ảo (link) trong ứng dụng khách của bạn. Có một ví dụ về SimpleEventLoop được sử dụng cho các máy khách bàn điều khiển trên cùng một liên kết. Tôi đang gặp khó khăn trong việc tìm ra cách tôi có thể thiết kế lớp con vòng lặp sự kiện của riêng mình để xử lý các sự kiện của giao thức trong khi gắn vào ứng dụng Qt cùng một lúc. Nghiên cứu của tôi đã dẫn tôi tin rằng QAbstractEventDispatcher là lớp Qt tôi muốn sử dụng nhưng tài liệu có vẻ khá mỏng và tôi không chắc chắn làm thế nào tôi sẽ đi về việc này.

Có ai khác có kinh nghiệm liên kết các vòng sự kiện bên ngoài với ứng dụng Qt không? Tôi cũng đã tìm thấy trang này example trên trang Qt nhưng nó không thực sự hữu ích - hoặc ít nhất tôi không thực sự hiểu nó.

Cảm ơn!

Trả lời

30

Tôi đã không làm quá nhiều phát triển Qt thời gian gần đây, nhưng nếu tôi nhớ chính xác, bạn có thể gọi QApplication::processEvents() trong vòng lặp sự kiện riêng của bạn (thay vì bắt đầu vòng lặp chính Qt qua QApplication::exec())

Edit: tôi đã sử dụng cơ hội của một buổi sáng chủ nhật chậm để kiểm tra lái xe/tìm hiểu một cái gì đó về PyQt (ràng buộc Python cho Qt) và cobbled với nhau một mã chứng minh khái niệm dưới đây. Thay thế cuộc gọi đến QApplication::exec() bằng vòng lặp sự kiện tùy chỉnh dựa trên QApplication::processEvents()có vẻ như để hoạt động.

Tôi cũng đã xem nhanh simpleeventloop.cpptpclient-cpptext main.cpp. Từ vẻ ngoài của nó, nó shoud được tốt để chỉ cần thêm QApplication::processEvents() một nơi nào đó trong vòng lặp chính của SimpleEventLoop::runEventLoop(). Để thêm nó vào vòng lặp chính, tôi có lẽ sẽ thay thế tv khoảng cho select() chức năng trong lines 106 through 117 với

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

và thay đổi chữ ký trong line 89 để void SimpleEventLoop::runEventLoop(QApplication *app). Sẽ tốt hơn nếu bạn thêm công cụ Qt thông thường vào việc triển khai ứng dụng khách của mình (thay thế là tpclient-cpptext main.cpp)

Dường như một bản hack. Tôi có lẽ sẽ bắt đầu với một cái gì đó như thế này để bắt đầu. Tôi nghĩ rằng ý tưởng của bạn về gói TPSocket và bộ đếm thời gian trong các khái niệm tương ứng của Qt để chuyển tiếp chúng bằng QAbstractEventDispatcher đến QEventLoop là giải pháp lâu dài tốt hơn. Sau đó, nó sẽ đủ để runEventLoop() của bạn chỉ cần gọi QApplication::exec(). Nhưng tôi chưa bao giờ sử dụng QAbstractEventDispatcher trước đây, vì vậy hãy lấy ý kiến ​​của tôi cho những gì họ đang có.

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

Trong khi mục tiêu của tôi là sử dụng AbstractEventDispatcher để tích hợp đúng vòng lặp sự kiện, tôi chỉ là quá nhiều người mới bắt đầu tại Qt để kéo nhanh. Tôi đang cố gắng để làm điều này ở bên trong khi chỉ nhận được một giải pháp làm việc tại chỗ. Tôi đang cố gắng để hack lớp SimpleEventLoop để nó có thể trả lại trạng thái "đang chạy" của nó, sau đó có thể kiểm tra từ ứng dụng chính bằng câu lệnh trong khi tương tự như ví dụ của bạn. Tôi sẽ cho bạn biết nó hoạt động ra sao. Điều tôi lo lắng là nếu và làm thế nào các cuộc gọi lại tín hiệu Boost sẽ được xử lý đúng từ bên trong ứng dụng Qt. – mhilmi

+0

@Gimpyfuzznut: thêm một mẫu hack cho simpleeventloop.cpp. Hack được đề xuất của bạn có nhiều khả năng phức tạp hơn, vì việc triển khai SimpleEventLoop :: runEventLoop() hiện tại thực hiện vòng lặp sự kiện chuẩn (xem ví dụ: http://stackoverflow.com/questions/658403/how-would-you-implement-a- cơ bản-sự kiện-loop/658495 # 658495 cho một lời giải thích), và do đó không bao giờ trả về trừ khi một tín hiệu hoặc hẹn giờ gọi SimpleEventLoop :: endEventLoop() như là một phần của vòng lặp sự kiện đang chạy. – stephan

2

Tôi có thể mã các vòng sự kiện thành các chuỗi riêng biệt. Bạn có thể xử lý các sự kiện từ thư viện trong một lớp và tạo ra các tín hiệu sau đó sẽ được xử lý bởi Eventloop Qt chính bất cứ khi nào bạn muốn (gọi QApplication :: processEvents() nếu cần trong các hoạt động dài). Bí quyết duy nhất cho điều này là đảm bảo rằng vòng lặp sự kiện bên ngoài của bạn là Q_OBJECT để nó biết cách phát ra các tín hiệu mà bạn quan tâm.

Có các vấn đề khác về chủ đề, chẳng hạn như vẽ không bao giờ (bao giờ) trong một chủ đề không phải là luồng QT chính.

+8

"bây giờ bạn có hai vấn đề" :-) – Kos

1

Các tài liệu Qt nói:

Để làm cho ứng dụng của bạn hoạt động xử lý nhàn rỗi (ví dụ: thực hiện một chức năng đặc biệt bất cứ khi nào không có sự kiện đang xem xét), sử dụng một QTimer với 0 timeout.

Không phải là một giải pháp khá hay.

Các vấn đề liên quan