QWidget
のほかに、両方の汎用関数を保持するクラスがありますか? QEditのようなもの...Qt初心者:QLineEditとQTextEditの基本クラス
例として、私はcut()、copy()、paste()を参照したいと思いますが、QWidget
を動的キャストしなければならないようです。他の方法はありますか?
QWidget
のほかに、両方の汎用関数を保持するクラスがありますか? QEditのようなもの...Qt初心者:QLineEditとQTextEditの基本クラス
例として、私はcut()、copy()、paste()を参照したいと思いますが、QWidget
を動的キャストしなければならないようです。他の方法はありますか?
QWidget
以外の方法はありません。理由は、QLineEdit
がQWidget
から直接継承されているためです。あなたはQtクラスの完全な階層を見ることができますhere
これは、通常、悪い設計の兆候です。 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'を使うべきです) –