2

以下案例:假设有一个二进制库定义了“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 派生的其他类中

4

2 回答 2

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。每个对象总是可以有一个单独的过滤器。这种方法意味着您可以避免从所有事物中派生。效率不高,但应该可以。

您可以在事件过滤器本身中做您想做的事情,而不是使用信号/槽。

于 2012-05-31T12:15:13.317 回答
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 类。

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

于 2012-05-31T16:08:55.457 回答