[英]Using a macro to create QObject derived classes
我試圖簡化(即擺脫樣板代碼的負擔)創建QObject
包裝器類, QObject
轉發其他QObject
派生類的屬性訪問。
首先,我只是嘗試使用一種屬性:
// Sy_test.h - The wrapped class
class Sy_test : public QObject
{
Q_OBJECT
Q_PROPERTY( bool prop READ getProp WRITE setProp NOTIFY propChanged )
public:
Sy_test( QObject* parent = nullptr ) :
QObject{ parent },
prop_{ false } {}
bool getProp() const { return prop_; }
public slots:
void setProp( bool value )
{
if ( value != prop_ ) {
prop_ = value;
emit propChanged( prop_ );
}
}
signals:
void propChanged( bool value );
private:
bool prop_;
};
// Sy_proxy.h - The wrapper generator
#define SY_PROXYPROPERTY( Type, Name, Getter, Setter, Notifier )\
private:\
Q_PROPERTY( Type Name READ Getter WRITE Setter NOTIFY Notifier )\
\
public:\
Type Getter() const { return target_->Getter(); }\
\
public slots:\
void Setter( Type value ) { target_->Setter( value ); }\
\
signals:\
void Notifier( Type value );\
\
private:\
void setConnection()\
{\
connect( target_, &std::remove_pointer< decltype( target_ ) >::type::Notifier,\
this, &std::remove_pointer< decltype( this ) >::type::Notifier );\
}
#define SY_PROXY( ProxyName, TargetType, Prop1 )\
class ProxyName : public QObject\
{\
Q_OBJECT \
Prop1 \
\
public:\
ProxyName( TargetType* target ) :\
target_{ target }\
{\
setConnection();\
}\
\
virtual ~ProxyName() {}\
\
private:\
TargetType* target_;\
};
// This should create a Sy_test wrapper class called Sy_testProxy
SY_PROXY( Sy_testProxy,
Sy_test,
SY_PROXYPROPERTY( bool, prop, getProp, setProp, propChanged ) )
因此, SY_PROXY
宏應創建一個名為Sy_testProxy
的類,該類攜帶Sy_test::prop
屬性的副本以及僅轉發請求/信號的實現。
而且幾乎可以做到。 查看后預處理器的輸出(我使用g ++,所以使用.ii文件),我可以看到Sy_testProxy
類已構建,並且其形式與Sy_test
類相同。 但是,我得到一個錯誤:
../CppTest/Sy_proxy.h:47: Error: NOTIFY signal 'propChanged' of property 'prop' does not exist in class Sy_testProxy.
make: *** [moc_Sy_proxy.cpp] Error 1
這樣看來, moc
無法解析我的宏魔術。 盡管我不確定SY_PROXY
宏在哪里存在(錯誤來自名為Sy_testProxy
的類),並且SY_PROXYPROPERTY
必須有效(因為moc
必須從中讀取Q_PROPERTY
宏)。 誰能看到我哪里出問題了?
記錄一下:我討厭像其他所有人一樣的宏,但是由於moc
對模板和QObject
虛擬繼承的厭惡,我不得不使用它們。 之所以觸發此調查,是因為我有一個在單獨的線程中執行大量計算的實例的集合,但是它們驅動QML表示形式。 但是QML不允許連接/屬性綁定到主線程之外的對象,因此我被迫創建駐留在主線程中的代理對象。 如果有人有更好的主意,我將非常歡迎他們!
moc
不太喜歡宏。 它可以在一定程度上擴展它們,但是當它們變得復雜¹時會失敗。
您可以嘗試將signals:
替換為public:
²(即,手動擴展signals
宏),並通過將Q_SIGNAL
放在函數聲明的前面,告訴您希望該函數成為信號。
更換
signals:\
void Notifier( Type value );\
與
public:\
Q_SIGNAL void Notifier( Type value );\
¹:關於復雜的定義...我不知道什么時候失敗,但是過去我遇到了一些不同的問題。 根據我的經驗,當宏主體包含另一個宏時,moc會出現問題,例如您的示例中的signals
。 但這只是一個猜測-也許moc失敗的那種宏是另外一回事。
²:在Qt 5之前,它曾經是protected
。
除了雜亂無章的moc
,您的包裝也不是線程安全的。 沒有從正確的線程調用屬性getter。 所以我看不到包裝的任何地方。 您最好直接從QML中使用包裝的類,而不是包裝器。
為了線程安全,包裝程序應緩存已包裝屬性的值,以便始終從本地副本進行讀取。
到那時,您還可以編寫一個完全動態的包裝器,該包裝器線程安全地轉發包裝對象中的所有屬性。 使用元對象系統,您可以即時生成所有內容-屬性值的副本,等等。就屬性而言,您可以復制整個二進制描述符,就像包裝器假裝具有相同的屬性一樣。
有一段很棒的代碼,您可以在Google上搜索qmltricks,它提供了所需的一切作為一個好的開始。
您只需要一個標題。 有擴展空間以支持只讀屬性或自定義getter / setters ..但我建議您看看。 我現在找不到原始頁面,在上一屆Qt峰會上看到一個演講,您可能可以在qt網站上查看動手材料。
在github上的鏈接下面,有幾個可用的版本。
https://github.com/Cavewhere/lib-qt-qml-tricks/blob/master/include/QQmlHelpers
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.