除了QWidget
之外,還有另外一個類是否擁有兩者的所有通用函數?像QEdit ...Qt初學者:QLineEdit和QTextEdit的基類
作爲一個例子,我想引用剪切(),複製()和粘貼(),但它看起來像我必須動態鑄造QWidget
。有沒有其他方法?
除了QWidget
之外,還有另外一個類是否擁有兩者的所有通用函數?像QEdit ...Qt初學者:QLineEdit和QTextEdit的基類
作爲一個例子,我想引用剪切(),複製()和粘貼(),但它看起來像我必須動態鑄造QWidget
。有沒有其他方法?
您不必動態地施放任何東西:這通常是設計不好的標誌。 Qt通常只有很少的接口類 - 它們通常在名稱的某個地方有Abstract
這個詞,而且它們不是純粹的接口,因爲它們有非抽象的基類,例如, QObject
。因此沒有可遵循的模式,也不需要將編輯操作抽象爲接口。
有克服這一幾種方法:
槓桿的事實是有問題的方法是由元對象系統知道。請注意,invokeMethod
需要一個方法名稱,而不是簽名。
bool cut(QWidget * w) {
return QMetaObject::invokeMethod(w, "cut");
}
bool copy(QWidget * w) {
return QMetaObject::invokeMethod(w, "copy");
}
//...
您可以在任何支持編輯操作的窗口小部件上使用上述獨立功能,如上所述。
如上所述,但緩存方法查找不會反覆支付其成本。請注意,indexOfMethod
採取方法簽名,不僅僅是它的名字。
static QMetaMethod lookup(QMetaObject * o, const char * signature) {
return o->method(o->indexOfMethod(signature));
}
struct Methods {
QMetaMethod cut, copy;
Methods() {}
explicit Methods(QMetaObject * o) :
cut(lookup(o, "cut()")),
copy(lookup(o, "copy()")) {}
Methods(const Methods &) = default;
};
// Meta class names have unique addresses - they are effectively memoized.
// Dynamic metaobjects are an exception we can safely ignore here.
static QMap<const char *, Methods> map;
static const Methods & lookup(QWidget * w) {
auto o = w->metaObject();
auto it = map.find(o->className());
if (it == map.end())
it = map.insert(o->className(), Methods(o));
return *it;
}
bool cut(QWidget * w) {
lookup(w).cut.invoke(w);
}
bool copy(QWidget * w) {
lookup(w).copy.invoke(w);
}
//...
定義一個接口並提供專用於窗口小部件類型的實現。這種方法的唯一好處是它比QMetaMethod::invoke
快一點。將此代碼用於剪貼板方法是沒有意義的,但對於經常調用的小型方法而言,可能會降低開銷。我建議不要過度設計它,除非基準測試顯示它確實有幫助。以前的方法(上面#2)應該足夠。
// Interface
class IClipboard {
public:
virtual cut(QWidget *) = 0;
virtual copy(QWidget *) = 0;
virtual paste(QWidget *) = 0;
};
class Registry {
// all meta class names have unique addresses - they are effectively memoized
static QMap<const char *, IClipboard*> registry;
public:
static void register(const QMetaObject * o, IClipboard * clipboard) {
auto name = o->className();
auto it = registry.find(name);
if (it == registry.end())
registry.insert(name, clipboard);
else
Q_ASSERT(it->value() == clipboard);
}
static IClipboard * for(QWidget * w) {
auto it = registry.find(w->metaObject()->className());
Q_ASSERT(registry.end() != it);
return it->value();
}
static void unregister(const QMetaObject * o) {
registry.remove(o->className());
}
};
template <class W> class ClipboardWidget : public IClipboard {
Q_DISABLE_COPY(ClipboardWidget)
public:
cut(QWidget * w) override { static_cast<W*>(w)->cut(); }
copy(QWidget * w) override { static_cast<W*>(w)->copy(); }
paste(QWidget * w) override { static_cast<W*>(w)->paste(); }
ClipboardWidget() {
Registry::register(&W::staticMetaObject(), this);
}
~ClipboardWidget() {
Registry::unregister(&W::staticMetaObject());
}
};
// Implementation
QMap<const char *, IClipboard*> Registry::registry;
static ClipboardWidget<QTextEdit> w1;
static ClipboardWidget<QLineEdit> w2;
void yourCode() {
//...
Registry::for(widget)->cut(widget);
}
謝謝你有非常好的建議。 – Igor
你的問題不清楚,解釋自己更好。 – eyllanesc
動態投射你的問題是什麼? (在Qt中你應該使用'qobject_cast') –