2017-12-18 120 views
0

除了QWidget之外,還有另外一個類是否擁有兩者的所有通用函數?像QEdit ...Qt初學者:QLineEdit和QTextEdit的基類

作爲一個例子,我想引用剪切(),複製()和粘貼(),但它看起來像我必須動態鑄造QWidget。有沒有其他方法?

+0

你的問題不清楚,解釋自己更好。 – eyllanesc

+0

動態投射你的問題是什麼? (在Qt中你應該使用'qobject_cast') –

回答

1

QWidget之外沒有別的辦法。原因是QLineEdit直接從QWidget繼承。您可以看到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