2013-07-30 43 views
19

Làm thế nào để khai báo tín hiệu Qt trong lớp trừu tượng/giao diện khi lớp thực hiện đã bị loại khỏi QObject/QWidget?Khai báo tín hiệu trừu tượng trong lớp giao diện

class IEmitSomething 
{ 
    public: 
    // this should be the signal known to others 
    virtual void someThingHappened() = 0; 
} 

class ImplementEmitterOfSomething : public QWidget, public IEmitSomething 
{ 
    // signal implementation should be generated here 
    signals: void someThingHappended(); 
} 
+0

Bạn có thể chỉ viết 'signal: void someThingHappened();'. Nó không cần thiết Thực hiện tín hiệu. – Ruu

+0

Tôi biết tín hiệu được tạo ra trong quá trình thực hiện nhưng làm cách nào mà người quan sát biết đây là tín hiệu (qt) nếu chỉ có giao diện được biết? – Beachwalker

+0

@Beachwalker Tôi đã thay thế từ khóa được bảo vệ bằng các tín hiệu trong câu trả lời của mình. Nó sẽ di chuyển câu hỏi của bạn. –

Trả lời

37

Như tôi đã phát hiện ra trong những ngày cuối cùng ... cách Qt để làm điều này là như thế này:

class IEmitSomething 
{ 
    public: 
    virtual ~IEmitSomething(){} // do not forget this 

    signals: // <- ignored by moc and only serves as documentation aid 
      // The code will work exactly the same if signals: is absent. 
    virtual void someThingHappened() = 0; 
} 

Q_DECLARE_INTERFACE(IEmitSomething, "IEmitSomething") // define this out of namespace scope 

class ImplementEmitterOfSomething : public QWidget, public IEmitSomething 
{ 
    Q_OBJECT 
    Q_INTERFACES(IEmitSomething) 

    signals: 
     void someThingHappended(); 
} 

Bây giờ bạn có thể kết nối với những tín hiệu giao diện.

Nếu bạn không có quyền truy cập đến việc thực hiện khi kết nối với tín hiệu câu lệnh kết nối của bạn sẽ đòi hỏi một diễn viên năng động để QObject:

IEmitSomething* es = ... // your implementation class 

connect(dynamic_cast<QObject*>(es), SIGNAL(someThingHappended()), ...); 

... và theo cách này bạn không bắt buộc để lộ lớp triển khai cho người đăng ký và khách hàng. Yeah !!!

+0

Bạn đã đọc về điều này ở đâu? –

+0

Thời gian trôi qua ... Tôi không nhớ tham chiếu nhưng nếu bạn có từ khóa Q_INTERFACES và Q_DECLARE_INTERFACE thì bạn có thể google cho điều đó. Vấn đề tại thời điểm bài viết của tôi là tôi không biết họ. Bạn có thể đọc nội dung nào đó tại đây http://doc.qt.io/qt-5/qtplugin.html#Q_DECLARE_INTERFACE và duyệt qua các thông tin về giao diện đó. – Beachwalker

+0

Bất kỳ ý tưởng nào tại sao ảo void someThingHappended(); kết quả trong một cảnh báo trình biên dịch, xem tại đây: http://stackoverflow.com/questions/28614607/virtual-override-for-signal-signals-cannot-be-declared-virtual –

14

Trong Qt, "tín hiệu" là synonim cho "được bảo vệ". Nhưng nó giúp MOC tạo ra mã cần thiết. Vì vậy, nếu bạn yêu cầu giao diện với một số tín hiệu - bạn nên khai báo chúng như là các phương thức trừu tượng được bảo vệ ảo. Tất cả mã cần thiết sẽ được tạo bởi MOC - bạn có thể thấy chi tiết, rằng "phát ra somesignal" sẽ được thay thế bằng cuộc gọi ảo của phương thức được bảo vệ có cùng tên. Lưu ý rằng phần thân của phương thức aslo được tạo bởi Qt.

CẬP NHẬT: Mã mẫu:

MyInterfaces.h

#pragma once 

struct MyInterface1 
{ 
signals: 
    virtual void event1() = 0; 
}; 

struct MyInterface2 
{ 
signals: 
    virtual void event2() = 0; 
}; 

MyImpl.h

#ifndef MYIMPL_H 
#define MYIMPL_H 

#include <QObject> 
#include "MyInterfaces.h" 

class MyImpl 
    : public QObject 
    , public MyInterface1 
    , public MyInterface2 
{ 
    Q_OBJECT 

public: 
    MyImpl(QObject *parent); 
    ~MyImpl(); 

    void doWork(); 

signals: 
    void event1(); 
    void event2(); 
}; 

class MyListner 
    : public QObject 
{ 
    Q_OBJECT 

public: 
    MyListner(QObject *parent); 
    ~MyListner(); 

public slots: 
    void on1(); 
    void on2(); 
}; 

#endif // MYIMPL_H 

MyImpl.cpp

#include "MyImpl.h" 
#include <QDebug> 

MyImpl::MyImpl(QObject *parent) 
    : QObject(parent) 
{} 

MyImpl::~MyImpl() 
{} 

void MyImpl::doWork() 
{ 
    emit event1(); 
    emit event2(); 
} 

MyListner::MyListner(QObject *parent) 
{} 

MyListner::~MyListner() 
{} 

void MyListner::on1() 
{ 
    qDebug() << "on1"; 
} 

void MyListner::on2() 
{ 
    qDebug() << "on2"; 
} 

main.cpp

#include <QCoreApplication> 
#include "MyImpl.h" 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    MyImpl *invoker = new MyImpl(NULL); 
    MyListner *listner = new MyListner(NULL); 

    MyInterface1 *i1 = invoker; 
    MyInterface2 *i2 = invoker; 

    // i1, i2 - not QObjects, but we are sure, that they will be. 
    QObject::connect(dynamic_cast< QObject * >(i1), SIGNAL(event1()), listner, SLOT(on1())); 
    QObject::connect(dynamic_cast< QObject * >(i2), SIGNAL(event2()), listner, SLOT(on2())); 

    invoker->doWork(); 

    return a.exec(); 
} 
+0

thx, thêm ảo, tôi bỏ lỡ nó chỉ trong mẫu này – Beachwalker

+0

nếu bạn chắc chắn rằng i1 là một QObject, sau đó dynamic_cast là không cần thiết. static_cast hoạt động tốt trong trường hợp này. –

+2

@FernandoPelliccioni no, bạn hoàn toàn sai. Bởi vì giao diện không thừa kế 'QObject'. Chỉ 'reinterpret_cast' có thể được sử dụng, nhưng nó không hoạt động - bởi vì có sự thừa kế nhân. –

3

Có hai vấn đề với tuyên bố tín hiệu như các phương pháp trừu tượng trong giao diện:

  1. Một tín hiệu là một tín hiệu từ quan điểm Qt của chỉ khi thực hiện một cách đặc biệt - cụ thể là, khi thực hiện được tạo ra bởi moc và được bao gồm trong siêu dữ liệu cho đối tượng.

  2. Thường là thiết kế kém để phát ra tín hiệu trực tiếp từ bên ngoài của đối tượng.

Như một hệ quả tất yếu, vì giao diện là trừu tượng, bạn không thực sự cần phải khai báo tín hiệu của nó ở tất cả - nó phục vụ mục đích nào khác hơn là cung cấp tư liệu mục đích, vì:

  1. Nếu một tín hiệu được thực hiện trong một lớp có nguồn gốc từ giao diện, bạn có thể sử dụng hệ thống metaobject để xác minh sự hiện diện của nó.

  2. Bạn không phải trực tiếp gọi các phương thức tín hiệu này.

  3. Sau khi bạn tự động truyền giao diện không đối tượng đến QObject, việc triển khai không bắt nguồn từ giao diện là không quan trọng nữa.

Những lý do hợp lệ duy nhất còn lại để làm thể dục dụng cụ như vậy sẽ được:

  1. Coax doxygen hoặc phát tài liệu khác vào cung cấp tài liệu cho mã của bạn.

  2. Buộc lớp bê tông phải triển khai phương thức có cùng tên. Điều này không tất nhiên đảm bảo rằng đó là một tín hiệu thực tế.

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