以下案例: 假设有一个二进制库,它定义了类“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派生的其他类中
答案 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类。
希望这可以避免一些代码重复。