C ++:为事件处理程序创建一个匿名类

时间:2015-09-18 09:14:18

标签: java c++ qt polymorphism anonymous-types

免责声明:此说明包含许多Qt细节。他们没有必要回答这个问题,我只是想给你背景。

我需要对libevent的{​​{1}}做出反应。 不幸的是,这不是一个信号,这就是我需要继承focusInEvent的原因。由于这是我需要的唯一更改,我想使用匿名子类

像这样:

QTextEdit

这是我用Java编写的代码,它不是用c ++编译的。 以下所有代码都位于自定义QTextEdit的构造函数中。 myTextEdit =new QTextEdit(){ void focusInEvent(){ //code here } }; 包含在此小部件中,应在其构造函数中初始化。

奇怪的是这段代码编译:

QWidget

但没用,因为我无法将QTextEdit的实例分配给指向class MyTextEdit:protected QTextEdit{ void focusInEvent(); }; auto myTextEdit=new MyTextEdit(); 的指针。不知何故,多态性失败了。这段代码没有编译:

myTextEdit*

编译错误是:

  

/home/lars/ProgrammierPraktikum/moleculator/implementation/Moleculator/gui_elements/editor.cpp:40:   错误:' QTextEdit'是一个无法进入的基地   '编辑器编辑器::(STD :: shared_ptr的):: MyTextEdit'        QTextEdit * myTextEdit = new MyTextEdit();

实际问题:

如何创建与其超类的指针兼容的匿名子类?

2 个答案:

答案 0 :(得分:1)

您的子类化尝试

class MyTextEdit:protected QTextEdit{
        void focusInEvent();
    };
QTextEdit* myTextEdit=new MyTextEdit();

几乎可以。

仅仅因为该方法受到保护并不意味着您应该继承受保护。

  • 受保护的方法说:这不是我的界面的一部分。除了我,没有人应该能够称之为。我将自己称呼(作为事件处理的一部分)。该方法可以在子类中重写。
  • 继承受保护的说:没有人应该知道这个继承,它是一个实现细节,可能对扩展我的类有用。

您需要常规的公共继承。

class MyTextEdit:public QTextEdit{
        void focusInEvent();
    };
QTextEdit* myTextEdit=new MyTextEdit();

现在你说MyTextEdit是QTextEdit的替代品。 您可能希望添加构造函数以将父窗口小部件提供给MyTextEdit。

在c ++中没有类似java的匿名内部类。

答案 1 :(得分:1)

根本不需要子类化。您可以使用可以应用于任何对象上的任何事件类型的帮助程序类将事件转换为信号。 EventSignaler充当一个或多个对象的事件过滤器。当匹配事件到达给定对象时,它会发出eventSignal

class EventSignaler : public QObject {
   Q_OBJECT
   QMap<QObject*, QSet<int>> m_watch;
   bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
      auto it = m_watch.find(obj);
      if (it != m_watch.end() && it.value().contains(ev->type()))
         emit eventSignal(EventWrapper(obj, ev));
      return false;
   }
public:
   EventSignaler(QObject * parent = 0) : QObject(parent) {}
   void watch(QObject * object, QEvent::Type type) {
      auto it = m_watch.find(object);
      if (it == m_watch.end()) {
         it = m_watch.insert(object, QSet<int>() << type);
         object->installEventFilter(this);
         connect(object, &QObject::destroyed, this, [this, object]{
            m_watch.remove(object);
         });
      } else
         it.value().insert(type);
   }
   void unWatch(QObject * object, QEvent::Type type) {
      auto it = m_watch.find(object);
      if (it == m_watch.end()) return;
      it.value().remove(type);
      if (it.value().isEmpty()) m_watch.erase(it);
   }
   Q_SIGNAL void eventSignal(const EventWrapper &);
};

EventWrapper是一个辅助类,用于表示事件的类型并安全地携带指向事件的指针。复制课程时,例如当它通过排队的连接传递时,原始事件将不再存在,因此包装器将事件指针清零。这是必要的,因为事件通常是不可复制的。

// https://github.com/KubaO/stackoverflown/tree/master/questions/event-signaler-32648234
#include <QtWidgets>

struct EventWrapper {
   QPointer<QObject> target;
   QEvent::Type type { QEvent::None };
   QEvent * event { nullptr };
public:
   EventWrapper() {}
   EventWrapper(QObject * target, QEvent * event) :
      target(target), type(event->type()), event(event) {}
   EventWrapper(const EventWrapper & o) : target(o.target), type(o.type) {}
   EventWrapper(EventWrapper && o) :
      target(o.target), type(o.type), event(o.event) { o.event = nullptr; }
   EventWrapper & operator=(const EventWrapper & o) {
      target = o.target;
      type = o.type;
      event = nullptr;
      return *this;
   }
};
Q_DECLARE_METATYPE(EventWrapper)

最后,我们可以通过标签和行编辑在一个小例子上演示所有这些。只要单击标签,行编辑中的文本就会复制到标签上。

int main(int argc, char ** argv) {
   QApplication app(argc, argv);
   EventSignaler signaler;
   QWidget w;
   QVBoxLayout layout(&w);
   QLabel label("text");
   QLineEdit edit;
   layout.addWidget(&label);
   layout.addWidget(&edit);
   signaler.watch(&label, QEvent::MouseButtonPress);
   QObject::connect(&signaler, &EventSignaler::eventSignal,
                    [&label, &edit]{ label.setText(edit.text()); });
   w.show();
   return app.exec();
}

#include "main.moc"