2012-12-29 38 views
14

Trước tiên tôi muốn đề cập rằng sau đây đã làm việc tốt với Qt 5.0.0 beta 1 (có thể là beta 2 và RC nữa, không biết), nhưng không thành công trong Qt Phiên bản phát hành cuối cùng 5.0.0. Tôi chỉ muốn tham khảo các kết quả được thấy trong phiên bản phát hành cuối cùng Qt 5.0.0. Vì vậy, hầu hết có lẽ điều này có liên quan đến những thay đổi gần đây trong Qt5. Về phía C++, tôi có một tập hợp các lớp (có nguồn gốc từ QObject) trong một không gian tên (được kích hoạt tùy ý với cờ trình biên dịch; các lớp nằm trong một thư viện riêng biệt và thư viện để lại cách sử dụng vùng tên như một tùy chọn để người dùng thư viện). Một lớp học, ở đây Game, có thể trông như thế này (trích đoạn):Sử dụng C++ - slot trong QML trả về kiểu trong không gian tên

OAE_BEGIN_NAMESPACE 

// forward-declarations: 
class Player; // Player is just another class in the same library 

class Game : public QObject 
{ 
    Q_OBJECT 

public: 
    explicit Game(...); 

public slots: 
    Player *player() const; // <-- the quesion is about such slots 
}; 

OAE_END_NAMESPACE 

Các macro OAE_BEGIN/END_NAMESPACE mở rộng cho một trong hai namespace OAE_NAMESPACE { ... } hoặc không có gì, trong cùng một cách Qt hiện nó trong <qglobal.h>, chỉ cần "QT" thay thế với "OAE" trong tên macro:

#ifndef OAE_NAMESPACE 

# define OAE_PREPEND_NAMESPACE(name) ::name 
# define OAE_USE_NAMESPACE 
# define OAE_BEGIN_NAMESPACE 
# define OAE_END_NAMESPACE 
# define OAE_BEGIN_INCLUDE_NAMESPACE 
# define OAE_END_INCLUDE_NAMESPACE 
# define OAE_BEGIN_MOC_NAMESPACE 
# define OAE_END_MOC_NAMESPACE 
# define OAE_FORWARD_DECLARE_CLASS(name) class name; 
# define OAE_FORWARD_DECLARE_STRUCT(name) struct name; 
# define OAE_MANGLE_NAMESPACE(name) name 

#else /* user namespace */ 

# define OAE_PREPEND_NAMESPACE(name) ::OAE_NAMESPACE::name 
# define OAE_USE_NAMESPACE using namespace ::OAE_NAMESPACE; 
# define OAE_BEGIN_NAMESPACE namespace OAE_NAMESPACE { 
# define OAE_END_NAMESPACE } 
# define OAE_BEGIN_INCLUDE_NAMESPACE } 
# define OAE_END_INCLUDE_NAMESPACE namespace OAE_NAMESPACE { 
# define OAE_BEGIN_MOC_NAMESPACE OAE_USE_NAMESPACE 
# define OAE_END_MOC_NAMESPACE 
# define OAE_FORWARD_DECLARE_CLASS(name) \ 
    OAE_BEGIN_NAMESPACE class name; OAE_END_NAMESPACE \ 
    using OAE_PREPEND_NAMESPACE(name); 

# define OAE_FORWARD_DECLARE_STRUCT(name) \ 
    OAE_BEGIN_NAMESPACE struct name; OAE_END_NAMESPACE \ 
    using OAE_PREPEND_NAMESPACE(name); 

# define OAE_MANGLE_NAMESPACE0(x) x 
# define OAE_MANGLE_NAMESPACE1(a, b) a##_##b 
# define OAE_MANGLE_NAMESPACE2(a, b) OAE_MANGLE_NAMESPACE1(a,b) 
# define OAE_MANGLE_NAMESPACE(name) OAE_MANGLE_NAMESPACE2(\ 
     OAE_MANGLE_NAMESPACE0(name), OAE_MANGLE_NAMESPACE0(OAE_NAMESPACE)) 

namespace OAE_NAMESPACE {} 

# ifndef OAE_BOOTSTRAPPED 
# ifndef OAE_NO_USING_NAMESPACE 
    /* 
    This expands to a "using OAE_NAMESPACE" also in _header files_. 
    It is the only way the feature can be used without too much 
    pain, but if people _really_ do not want it they can add 
    DEFINES += OAE_NO_USING_NAMESPACE to their .pro files. 
    */ 
    OAE_USE_NAMESPACE 
# endif 
# endif 

#endif /* user namespace */ 

trong phần tiếp theo, khi nói "tạo điều kiện cho các không gian tên", ý tôi là tôi tuyên bố vĩ mô OAE_NAMESPACE, trong trường hợp này với giá trị oae.

Trong số những trường hợp khác, tôi truy cập các phiên bản của lớp này và lớp Player khi được trả về bởi player() từ trong QML cho giao diện người dùng của ứng dụng của tôi. Đối với điều này, tôi đăng ký các lớp học như sau:

qmlRegisterType<Game>(); 
qmlRegisterType<Player>(); 

tôi cung cấp các QML Frontend một con trỏ đến một thể hiện của một Game, gọi theGame trong QML:

view.engine()->rootContext()->setContextProperty("theGame", 
     QVariant::fromValue<Game*>(game)); 

Trong QML, tôi sử dụng như bình thường.Một ví dụ nhỏ nên in địa chỉ con trỏ của player():

Rectangle { 
    width: 100; height: 100 
    Component.onCompleted: console.log(theGame.player()) 
} 

tôi nhận được kết quả như sau, tùy thuộc vào việc tôi đặt một OAE_NAMESPACE hay không (bằng cách này: Tôi sử dụng các thiết lập tương tự cho cả hai thư viện và các ứng dụng sử dụng nó):

  • Khi vô hiệu hóa không gian tên, mọi thứ hoạt động như mong đợi và QML in cho tôi những con trỏ:

    Player(0x10b4ae0) 
    
  • Khi cho phép namespace (và using nó trong C++ sử dụng thư viện, vì vậy tôi không thay đổi mã ở tất cả), QML không hiểu được kiểu trả về của Game::player():

    Error: Unknown method return type: Player* 
    
  • Khi thay đổi kiểu trả của Game::player() để oae::Player*, mọi thứ hoạt động tốt nữa:

    oae::Player(0x10b4ae0) 
    

Kết luận của tôi cho đến nay là moc không xem xét không gian tên tôi đặt quanh lớp. đoán đầu tiên của tôi là: Này, moc không biết rằng tôi xác định không gian tên khi gọi g++, đó là những gì tôi làm trong file .pro:

DEFINES += OAE_NAMESPACE=oae 

Tuy nhiên, khi thay đổi kiểu trả về để OAE_NAMESPACE::Player*, nó vẫn hoạt động, vì vậy moc không biết về macro OAE_NAMESPACE, nhưng nó không mở rộng các macro OAE_BEGIN/END_NAMESPACE hoặc nó không phân tích cú pháp các không gian tên nữa.

moc sản xuất sau "stringdata" cho Player * Game::player() const mà containes kiểu trả về của phương pháp:

  • Khi vô hiệu hóa không gian tên và sử dụng các kiểu trả về Player*:

    "player\0Player*\0" 
    
  • Khi cho phép không gian tên và sử dụng kiểu trả về Player*:

    "player\0Player*\0" 
    
  • Khi cho phép namespace và sử dụng các kiểu trả về OAE_NAMESPACE::Player*:

    "player\0oae::Player*\0" 
    

Ở phía bên kia, moc prepends tên lớp như được trả về bởi QMetaObject::className() với namespace nếu đã bật.

Kết luận của tôi bây giờ là tôi thể khắc phục điều này bằng cách viết OAE_NAMESPACE::ClassName thay vì ClassName bất cứ khi nào sử dụng các loại trong chữ ký của phương pháp meta QObject. (Vâng, có macro tốt hơn OAE_PREPEND_NAMESPACE). Bởi vì điều này sẽ trông khủng khiếp trong mã, và với tôi nó thậm chí có vẻ sai bởi vì phương pháp đã có trong không gian tên, là có một giải pháp tốt hơn?

Bây giờ cũng có OAE_BEGIN/END_MOC_NAMESPACE (tương tự như QT_BEGIN/END_MOC_NAMESPACE), như vậy có lẽ tôi cần những bất cứ nơi nào? Tôi không biết chúng được sử dụng ở đâu trong Qt, vì vậy tôi nên sử dụng chúng trong thư viện của tôi, vì tôi muốn sử dụng tính năng không gian tên tùy chọn giống như Qt.

+0

Tôi sẽ thêm một số thông tin về mã moc được tạo ra (ví dụ: chữ ký của vị trí được phân tích cú pháp). – leemes

+1

Việc sử dụng qmlRegisterType <> với tên miền đủ điều kiện không gian tên có thay đổi gì không? – mlvljr

+0

@mlvjr Cảm ơn gợi ý của bạn, nhưng tôi đã thử điều này. Trên thực tế, điều này không nên thay đổi bất cứ điều gì, vì đó là một specifier kiểu C++ nhưng đây là cách 'moc' phân tích cú pháp tập tin header. Nó không phát hiện rằng 'Player' trong không gian tên thực sự tham chiếu đến lớp' oae :: Player' khi được sử dụng bên ngoài vùng tên. Ngoài ra tôi tin rằng hành vi này khác nhau trong Qt 5.0.0 alpha và beta1. – leemes

Trả lời

8

Đã thực sự hoạt động trong 5.0.0a chưa?

Tôi duyệt qua mã nguồn Qt 5.0.0 và xem phương thức được phân tích cú pháp, đặc biệt là kiểu trả về (fyi, 5.0.0 \ qtbase \ src \ tools \ moc \ moc.cpp: L160) và không có vùng tên kiểm tra (không phải trên các đối số, vì vậy player(Player* p) sẽ không hoạt động). Trong khi đó, nó được thực hiện cho def lớp (5.0.0 \ qtbase \ src \ tools \ moc \ moc.cpp: L620 & L635)

Tôi nghĩ rằng "chúng ta" có thể gọi đây là một lỗi (hoặc giám sát)

+0

Cảm ơn bạn đã nỗ lực. Tôi sẽ kiểm tra lại vào ngày mai. Tất nhiên, sai lầm có thể là về phía tôi, tôi không muốn loại trừ khả năng này;) – leemes

+0

Vâng, có vẻ như * không * để làm việc trong Qt 5.0.0 beta1, quá. Tôi vừa thử lại nó. Lạ thật là tôi nhớ nó đã hoạt động. Cảm ơn bạn đã dành thời gian tìm kiếm nội dung này trong mã moc và chúc mừng các điểm thưởng của bạn! – leemes

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