Sumit
Sumit

Reputation: 1525

C++ Qt program design issue

In C++ Qt there is a class QWidget

For some reason C is not behaving as expected, I have to rewrite class C. I can not modify code up to class B creation.

How can I solve this problem? Any design pattern, or anything else?

If I try to inherit QWidget and B, a multiple inheritance, there will be two QWidget which leads to problem (QObject - moc does not allow it).

If I inherit from QWidget and pass object of B to C's constructor, whatever operation B performs applies to another QWidget coming through B, which is not desired, all features provided by B should apply to my C's QWidget.

Upvotes: 0

Views: 140

Answers (1)

Suppose there is a temperature sensor, when that gets disconnected from machine, class B draws a content blocker image on the whole area of QWidget that it owns, I can monitor sensor connect /disconnect and suppose C's fun. OnDisconnect() gets called, I will call B::OnDisconnect(), B will draw blocker image on its own QWidget, not on the one which is owned by C.

This has everything to do with C++'s rather inflexible method implementation inheritance when compared e.g. to the Common LISP Object System.

Since B's obscuration is always meant to be on top of B's contents, what you effectively need is for B to provide an overlay that draws on top of its contents, even if paintEvent is overriden in derived classes.

See this answer for a simple example, or another answer for an overlay with blur graphical effect.

This is fairly easy to accomplish by having B add an optional overlay widget to itself.

Example:

class OverlayWidget; // from https://stackoverflow.com/a/19367454/1329652    

class ObscureOverlay : public OverlayWidget
{
public:
  ObscureOverlay(QWidget * parent = {}) : OverlayWidget{parent} {}
protected:
  void paintEvent(QPaintEvent *) override {
    QPainter p{this};
    p.fillRect(rect(), {Qt::black});
  }
};

class A : public QWidget {
  ...
protected:
  void paintEvent(QPaintEvent *) override { ... }
};

class B : public A {
  ...
  ObscureOverlay m_obscure{this};
public:
  B() {
    m_obscure.hide();
  }
  Q_SLOT void OnDisconnect() {
    m_obscure.show();
    ...
  }
};

class C : public B {
  ...
protected:
  void paintEvent(QPaintEvent * event) override {
    B::paintEvent(event);
    ...
  }
};

If you don't have the source code to B, you can add the overlay to C, replicating original B's functionality when obscured. All of Qt's slots are effectively virtual, so if you pass a C to someone expecting B and connecting to its OnDisconnect slot, it will be C's slot that will get invoked.

class C : public B {
  Q_OBJECT
  ...
  ObscureOverlay m_obscure{this};
public:
  explicit C(QWidget * parent = {}) : B{parent} {
    m_obscure.hide();
  }
  Q_SLOT void OnDisconnect() { // slots are effectively virtual
    m_obscure.show();
    B::OnDisconnect();
  }
protected:
  void paintEvent(QPaintEvent * event) override {
    B::paintEvent(event);
    QPainter p{this};
    ...
  }
};

Upvotes: 1

Related Questions