2

次の場合:クラス「Base」とその多くのサブクラス(「Derivative1」、「Derivative2」など)を定義するバイナリライブラリがあるとします。

これらのサブクラスを自分のコードで拡張したいのですが、私の拡張はBaseの一部のみを処理するため、すべてのサブクラスで同じであるため、すべてのDerivativeクラスをサブクラス化し、同じコードを何度も追加するのは面倒です。

私の最初のアイデアは、私のために作業を行うクラステンプレートを作成することでしたが、私が扱っているライブラリはQtであるため、QObjectは私を失敗させました。私の2番目のアイデアは、マクロを使用して各クラス構造を生成することでしたが、これもmocによって阻止されました。

タイトルの「親」は、Baseから派生してBaseExtendedを作成し、コンパイラにこの拡張クラスのすべての派生を再親にするように指示したためです。たとえば、「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 に答える