2011-04-30 30 views
46

Boost.Signals cho phép various strategies sử dụng giá trị trả về của các vị trí để tạo thành giá trị trả về của tín hiệu. Ví dụ. thêm chúng, tạo thành một vector trong số chúng hoặc trả lại cái cuối cùng.Tín hiệu Qt có thể trả về một giá trị không?

Sự khôn ngoan (thể hiện trong tài liệu Qt [EDIT: cũng như một số câu trả lời cho câu hỏi này ]) là không có điều đó là có thể với tín hiệu Qt.

Tuy nhiên, khi tôi chạy moc vào định nghĩa lớp sau đây:

class Object : public QObject { 
    Q_OBJECT 
public: 
    explicit Object(QObject * parent=0) 
     : QObject(parent) {} 

public Q_SLOTS: 
    void voidSlot(); 
    int intSlot(); 

Q_SIGNALS: 
    void voidSignal(); 
    int intSignal(); 
}; 

Không chỉ không Mộc phàn nàn về các tín hiệu với kiểu trả về không có hiệu lực, nó có vẻ tích cực thực hiện nó trong ví dụ một cách để phép một giá trị trả về để vượt qua:

// SIGNAL 1 
int Object::intSignal() 
{ 
    int _t0; 
    void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) }; 
    QMetaObject::activate(this, &staticMetaObject, 1, _a); 
    return _t0; 
} 

vì vậy: theo các tài liệu, điều này là không thể. Vậy moc đang làm gì ở đây?

Slots can have return values, vì vậy chúng tôi có thể kết nối một vị trí với giá trị trả về tín hiệu với giá trị trả lại ngay bây giờ không? Có thể là có thể, sau khi tất cả? Nếu vậy, nó có hữu ích không?

CHỈNH SỬA: Tôi không yêu cầu giải pháp, vì vậy, vui lòng không cung cấp bất kỳ giải pháp nào.

CHỈNH SỬA: Điều này rõ ràng không hữu ích ở chế độ Qt::QueuedConnection (không phải là QPrintPreviewWidget API, mặc dù vẫn tồn tại và hữu ích). Nhưng những gì về Qt::DirectConnectionQt::BlockingQueuedConnection (hoặc Qt::AutoConnection, khi nó giải quyết để Qt::DirectConnection).

Trả lời

33

OK. Vì vậy, tôi đã nghiên cứu thêm một chút. Dường như điều này là có thể. Tôi có thể phát ra tín hiệu và nhận giá trị từ khe mà tín hiệu được kết nối. Nhưng, vấn đề là nó chỉ trả lại giá trị trả trước từ các khe kết nối nhiều:

Dưới đây là một định nghĩa lớp đơn giản (main.cpp):

#include <QObject> 
#include <QDebug> 

class TestClass : public QObject 
{ 
    Q_OBJECT 
public: 
    TestClass(); 

Q_SIGNALS: 
    QString testSignal(); 

public Q_SLOTS: 
    QString testSlot1() { 
     return QLatin1String("testSlot1"); 
    } 
    QString testSlot2() { 
     return QLatin1String("testSlot2"); 
    } 
}; 

TestClass::TestClass() { 
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1())); 
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2())); 

    QString a = emit testSignal(); 
    qDebug() << a; 
} 

int main() { 
    TestClass a; 
} 

#include "main.moc" 

Khi chạy chính, nó xây dựng một trong những lớp học thử nghiệm . Constructor nối hai khe với tín hiệu testSignal và sau đó phát ra tín hiệu. Nó nắm bắt giá trị trả về từ (các) vị trí được gọi.

Thật không may, bạn chỉ nhận được giá trị trả lại cuối cùng. Nếu bạn đánh giá mã ở trên, bạn sẽ nhận được: "testSlot2", giá trị trả lại cuối cùng từ các vị trí được kết nối của tín hiệu.

Đây là lý do. Tín hiệu Qt là một giao diện cú pháp sugared với mẫu báo hiệu. Slots là người nhận tín hiệu. Trong một mối quan hệ tín hiệu-khe kết nối trực tiếp, bạn có thể nghĩ về nó tương tự như (pseudo-code):

foreach slot in connectedSlotsForSignal(signal): 
    value = invoke slot with parameters from signal 
return value 

Rõ ràng là moc làm nhiều hơn một chút để giúp đỡ trong quá trình này (kiểm tra kiểu thô sơ, vv), nhưng điều này giúp vẽ hình ảnh.

+2

cảm ơn bạn đã thực sự cố gắng :) Tôi đã chỉnh sửa mã của bạn trở nên đơn giản và ngắn hơn. Tuy nhiên, câu hỏi vẫn đứng vững: nếu nó hoạt động (với "ngữ nghĩa cuối cùng"), tại sao các tài liệu nói nó không? –

+0

Một câu hỏi hay. Tôi sẽ giả định các tài liệu nói rằng nó không hoạt động bởi vì nó chỉ là một giá trị trả về một phần. Giá trị trả về true của phát xạ tín hiệu * nên * là tổng hợp của tất cả các kết quả dựa trên một số loại trình tổng hợp (như tăng cường). Nhưng, nếu không có, đó là một kết quả một phần và không xác định (đặc biệt là trong bối cảnh của một cuộc gọi tín hiệu đồng thời). Có lẽ có một số khác biệt về trình biên dịch? – jsherer

+1

Hành vi không có giấy tờ có nghĩa là bạn không được đảm bảo rằng ứng dụng vẫn hoạt động, ví dụ: Qt 5.0 :) – Torp

7

Không, chúng không thể.

Boost::signals hoàn toàn khác với những thứ trong Qt. Trước đây cung cấp một cơ chế gọi lại nâng cao, trong khi sau này thực hiện thành ngữ báo hiệu. Trong bối cảnh đa luồng, tín hiệu Qt (cross-threaded) phụ thuộc vào hàng đợi tin nhắn, do đó chúng được gọi một cách không đồng bộ tại một số điểm (không biết đến luồng của trình phát) trong thời gian.

+1

Làm thế nào bạn có thể dựa vào loại kết nối, sẽ xảy ra trong thời gian chạy, trong khi bạn viết mã bằng cách sử dụng chúng? Đây không phải là mẫu, Qt chủ yếu là thư viện thời gian chạy :) – vines

+0

Vì vậy, bạn cũng nghĩ rằng [QPrintPreviewWidget :: paintRequested()] (http://doc.trolltech.com/latest/qprintpreviewwidget.html#paintRequested) là API xấu. Tôi cũng vậy. Tuy nhiên, nó ở đó, và hoạt động. –

+0

Tôi nghĩ đây là câu trả lời đúng cho câu hỏi, vì cơ chế tín hiệu/khe Qt được thiết kế để hoạt động không đồng bộ. –

-1

Bạn có thể thử để workaround này với sau:

  1. Tất cả các khe kết nối của bạn phải lưu kết quả của họ trong một số nơi (container) truy cập từ tín hiệu đối tượng
  2. Khe cắm kết nối cuối cùng nên bằng cách nào đó (chọn tối đa hoặc giá trị cuối cùng) quá trình thu thập các giá trị và vạch trần chỉ có một
  3. Đối tượng phát ra có thể thử truy cập vào kết quả này

Cũng giống như một ý tưởng.

+0

Thật không may bạn không thể biết đó là khe cắm kết nối cuối cùng, bởi vì thư viện sẽ không cho bạn biết và cẩn thận kiểm soát thứ tự kết nối loại thất bại mục đích sử dụng tín hiệu ngay từ đầu. –

+0

Tôi không yêu cầu giải pháp, vui lòng đọc lại câu hỏi của tôi. –

0

Hàm qt_metacall của Qt trả về mã trạng thái nguyên. Bởi vì điều này, tôi tin rằng điều này làm cho một giá trị trả lại thực tế không thể (trừ khi bạn fudge xung quanh với hệ thống đối tượng meta và các tập tin moc sau khi biên dịch trước).

Bạn có, tuy nhiên, có các thông số chức năng bình thường theo ý của bạn. Bạn có thể sửa đổi mã của mình theo cách như vậy để sử dụng các tham số "ngoài" hoạt động như "trả lại" của bạn.

void ClassObj::method(return_type * return_) 
{ 
    ... 

    if(return_) *return_ = ...; 
} 

// somewhere else in the code... 

return_type ret; 
emit this->method(&ret); 
+0

Tôi tin rằng điều này sẽ yêu cầu một kết nối không đồng bộ, trừ khi bạn bằng cách nào đó quản lý để wrangle trong một đối tượng "tương lai" với nhiều tín hiệu hơn. – jsherer

1

Bạn có thể nhận được một giá trị trả về từ Qt signal với đoạn mã sau:

dụ của tôi cho thấy làm thế nào để sử dụng một Qt signal để đọc nội dung của một QLineEdit. Tôi chỉ mở rộng những gì @jordan đã đề xuất:

Có thể sửa đổi mã của bạn theo cách như vậy để sử dụng các tham số "hoạt động" hoạt động như "trả lại" của bạn.

#include <QtCore> 
#include <QtGui> 

class SignalsRet : public QObject 
{ 
    Q_OBJECT 

public: 
    SignalsRet() 
    { 
     connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection); 
     connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection); 
     edit.setText("This is a test"); 
    } 

public slots: 
    QString call() 
    { 
     QString text; 
     emit Get(&text); 
     return text; 
    } 

signals: 
    void Get(QString *value); 
    void GetFromAnotherThread(QString *value); 

private slots: 
    void GetCurrentThread(QString *value) 
    { 
     QThread *thread = QThread::currentThread(); 
     QThread *mainthread = this->thread(); 
     if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living 
      ReadObject(value); 
     else //Signal called from another thread 
      emit GetFromAnotherThread(value); 
    } 

    void ReadObject(QString *value) 
    { 
     QString text = edit.text(); 
     *value = text; 
    } 

private: 
    QLineEdit edit; 

}; 

Để sử dụng, chỉ cần yêu cầu call();.

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