编译代码中的“Reparent”类

时间:2012-05-31 11:26:02

标签: c++ qt multiple-inheritance

以下案例: 假设有一个二进制库,它定义了类“Base”,以及它的许多子类(“Derivative1”,“Derivative2”等)。

我想在我自己的代码中扩展这些子类,但是因为我的扩展对于所有子类是相同的,因为它们只处理Base的部分,所以将每个Derivative类子类化并一遍又一遍地添加相同的代码将是繁琐的。试。

我的第一个想法是简单地编写一个类模板,它可以为我工作,但因为我正在处理的库是Qt,QObject挫败了我。 我的第二个想法是使用宏来生成每个类结构,但这也被moc阻止了。

标题中的“reparent”是因为我想从Base派生并创建BaseExtended,然后以某种方式告诉编译器将每个Derivative重新显示给这个扩展类。有没有办法例如在“BaseExtended”虚拟中声明“Base”,然后只写

class Derivative1Extended : public Derivative1, public BaseExtended {}

并将BaseExtended中的虚拟Base指向Derivative1中的Base,从而基本上“挤压”Base和Derivative1之间的扩展?

(顺便说一句,我试图尽可能保持上面的通用,但我实际上正在尝试为每个QWidget衍生物添加“focusIn”和“focusOut”信号,而无需反复编写相同的代码再次为我使用的每个QWidget子类

编辑: 作为参考,这是我当前的实现:

// qwidgetfs.h
class QLineEditFS : public QLineEdit
{
    Q_OBJECT

private:
    void focusInEvent(QFocusEvent *);
    void focusOutEvent(QFocusEvent *);

public:
    QLineEditFS(QWidget *parent = 0);
signals:
    void focusReceived(QWidgetFS::InputType);
    void focusLost();
};

// qwidgetfs.cpp
QLineEditFS::QLineEditFS(QWidget *parent /*= 0*/)
    : QLineEdit(parent)
{}

void QLineEditFS::focusInEvent(QFocusEvent *e)
{
    QLineEdit::focusInEvent(e);
    emit focusReceived(QWidgetFS::InputText);
}

void QLineEditFS::focusOutEvent(QFocusEvent *e)
{
    QLineEdit::focusOutEvent(e);
    emit focusLost();
}

这对于QSpinBoxFS,QComboBoxFS,QCheckBoxFS等重复... 相反,我想在公共类QWidgetFS中定义此逻辑,然后将其“注入”到从QWidget派生的其他类中

2 个答案:

答案 0 :(得分:3)

我不确定如果不修改Qt并重新编译它,你真的能够做你的建议。

也许要做你想做的事,你可以使用安装在你想要处理焦点事件的对象上的事件过滤器吗?

小测试应用程序:

头:

class FocusEventFilter : public QObject
{
    Q_OBJECT
public:
    FocusEventFilter(QObject* parent)
        : QObject(parent)
    {}

Q_SIGNALS:
    void focusIn(QWidget* obj, QFocusEvent* e);
    void focusOut(QWidget* obj, QFocusEvent* e);

protected:
    bool eventFilter(QObject *obj, QEvent *e);
};

class testfocus : public QMainWindow
{
    Q_OBJECT

public:
    testfocus(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~testfocus();

public Q_SLOTS:
    void onFocusIn(QWidget*, QFocusEvent*);
    void onFocusOut(QWidget*, QFocusEvent*);

private:
    Ui::testfocusClass ui;
};

实施

#include <QFocusEvent>
#include "testfocus.h"

bool FocusEventFilter::eventFilter(QObject *obj, QEvent *e)
{
    if (e->type() == QEvent::FocusIn) {
        bool r = QObject::eventFilter(obj, e);
        QFocusEvent *focus = static_cast<QFocusEvent*>(e);
        QWidget* w = qobject_cast<QWidget*>(obj);
        if (w) {
            emit focusIn(w, focus);
        }
        return r;
    } 
    else if (e->type() == QEvent::FocusOut) {
        bool r = QObject::eventFilter(obj, e);
        QFocusEvent *focus = static_cast<QFocusEvent*>(e);
        QWidget* w = qobject_cast<QWidget*>(obj);
        if (w) {
            emit focusOut(w, focus);
        }
        return r;
    } 
    else {
        // standard event processing
        return QObject::eventFilter(obj, e);
    }
}


testfocus::testfocus(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    ui.setupUi(this);

    FocusEventFilter* filter = new FocusEventFilter(this);

    ui.lineEdit->installEventFilter(filter);
    ui.lineEdit_2->installEventFilter(filter);

    connect(filter, SIGNAL(focusIn(QWidget*, QFocusEvent*)), this, SLOT(onFocusIn(QWidget*, QFocusEvent*)));
    connect(filter, SIGNAL(focusOut(QWidget*, QFocusEvent*)), this, SLOT(onFocusOut(QWidget*, QFocusEvent*)));
}

testfocus::~testfocus()
{

}

void testfocus::onFocusIn(QWidget* obj, QFocusEvent*)
{
    obj->setStyleSheet("background-color:#aaaaff;");

}

void testfocus::onFocusOut(QWidget* obj, QFocusEvent*)
{
    obj->setStyleSheet("background-color:#ffaaaa;");
}

当然,YMMV。每个对象总是可以有一个单独的过滤器。此方法意味着您可以避免从所有内容派生。效率不高但应该有效。

您可以在事件过滤器本身中执行您想要的操作,而不是使用信号/插槽。

答案 1 :(得分:1)

我过去用模板做过这样的事情。问题是你不能使用信号。

我在没有编译器的情况下输入它,所以请善待:):

template<typename T>
class FSWidget: public T
{
public:
    FSWidget()
    {
        _delegate = NULL;
    }

    setDelegate(FSDelegate *delegate)
    {
        _delegate = delegate;
    }

protected:
    virtual void focusInEvent(QFocusEvent *e)
    {
        T::focusInEvent(e);
        if (_delegate) {
            _delegate->focusInEvent(this);
        }
    }

    virtual void focusOutEvent(QFocusEvent *e)
    {
        T::focusOutEvent(e);
        if (_delegate) {
            _delegate->focusOutEvent(this);
        }

    }

private:
    FSDelegate *_delegate;
};

所以,优点是当你需要使用它时,你基本上可以创建一个这样的类:

FSWidget<QLineEdit *> lineEdit = new FSWidget<QLineEdit *>;
lineEdit->setDelegate(delegate);

你可以放入你想要的任何东西而不是QLineEdit,它会起作用。

然后FSDelegate可能只是一个接口,你可以混合到需要对信息采取行动的任何类。它可能是其中之一:

class FSDelegate
{
public:
    virtual void focusInEvent(QWidget *w) = 0;
    virtual void focusOutEvent(QWidget *w) = 0;
};

如果你总是在focusInEvent和focusOutEvents上做同样的事情,你可以实现这些函数并创建一个真正的Mixin类。

希望这可以避免一些代码重复。