2017-12-18 22 views
0

QWidgetのほかに、両方の汎用関数を保持するクラスがありますか? QEditのようなもの...Qt初心者:QLineEditとQTextEditの基本クラス

例として、私はcut()、copy()、paste()を参照したいと思いますが、QWidgetを動的キャストしなければならないようです。他の方法はありますか?

+0

あなたの質問は、より良い自分自身を説明し、不明です。 – eyllanesc

+0

ダイナミックキャストの問題は何ですか? (Qtでは 'qobject_cast'を使うべきです) –

答えて

1

QWidget以外の方法はありません。理由は、QLineEditQWidgetから直接継承されているためです。あなたはQtクラスの完全な階層を見ることができますhere

+0

ありがとうございます。しかし、なぜ私は彼らがこのようにしたのか疑問に思いますか?これらのcut()、copy()、paste()、canPaste()関数などは、それらを継承できる基底クラスに設定することができます。 – Igor

+0

@Igorここでは推測しかできません。これらの関数はQtアーキテクトにとってあまり重要ではないようです。彼らはQFrameベースクラスについてもっと考えていました。 – demonplus

+0

'QWidget'は' QObject'であり、それはイントロスペクションのために生のC++タイプよりも少し強力です: –

1

これは、通常、悪い設計の兆候です。 Qtには一般的にインターフェイスクラスがほとんどありません。通常は名前の末尾にAbstractという単語があり、非抽象基本クラスを持つため実際には純粋なインターフェイスではありません。 QObject。したがって、パターンに従う必要はなく、編集操作をインタフェースに抽象化する必要はありません。

これを克服するためのいくつかのアプローチがあります。

  1. は、当該方法は、メタオブジェクトシステムによって知られているという事実を活用。 invokeMethodは、という名前のという名前の署名ではありません。

    bool cut(QWidget * w) { 
        return QMetaObject::invokeMethod(w, "cut"); 
    } 
    bool copy(QWidget * w) { 
        return QMetaObject::invokeMethod(w, "copy"); 
    } 
    //... 
    

    上記のような自立機能は、編集操作をサポートする任意のウィジェットで使用できます。

  2. 上記のように、コストを繰り返し支払うのではなく、メソッドルックアップをキャッシュします。 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); 
    } 
    //... 
    
  3. ウィジェットタイプに特化したインターフェイスを定義して実装します。このアプローチの唯一の利点は、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); 
    } 
    
+0

ありがとうございました。ありがとうございました。 – Igor