C++ Qt program design issue - c++

In C++ Qt there is a class QWidget
class A inherits QWidget and adds some features
class B inherits A and adds some features
class C inherits B and adds some features, C must be of type QWidget and should do all things done by B
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.

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};
...
}
};

Related

How can I pass a QEvent to an object owned by the receiver?

How can an event received by a class through the QObject::event() function be passed to one of its data members, which would then handle the event?
For example, if I have
class A
{
B b;
public:
event(QEvent *);
//other members and functions
};
and
class B
{
public:
event(QEvent *);
//other members
};
Suppose I send the event from another function, an event filter to an object of A using postEvent(), from what I understand, the event() function of A receives the event. Is there a way to pass on the event to a member of A, B instead, which will then handle the event?
Use QCoreApplication::sendEvent:
class B : public QObject
{
public:
bool event(QEvent *);
};
class A : public QObject
{
// Correct
B b{this};
// Wrong
B bad;
public:
bool event(QEvent * ev) override {
if (ev->type() == my_event_type) {
// Correct
return QCoreApplication::sendEvent(&b, ev);
// Wrong
return b.event(&ev);
}
return QObject::event(ev);
}
};
In C++98, without uniform initialization, you'd have to use initializer lists instead:
class A : public QObject
{
B b;
public:
A(QObject * parent = 0) : QObject(this), b(this) {}
bool event(QEvent * ev) { /*...*/ };
};
Pitfalls to Avoid
The parentage of B is critical in ensuring that it lives in the same thread as A. Users of A are free to move it to any thread - that's the contract of QObject (breaking it is a bad idea). When they do, sendEvent turns into undefined behavior unless B is in the same thread. The canonical way to ensure that related objects follow thread changes it to parent them to the object they should track.
Don't invoke QObject::event() directly: it's only meant to be invoked by Qt. Calling it directly would bypass the event filters and cause B not to behave like a QObject. Part of QObjects contract is that event filters (at various levels) can modify its functionality. Invoking event() directly would break LSP for all of B's users! : they'd be using a QObject, but it'd not act like a QObject would anymore.

Virtual method misconception in C++

I am not experienced in OOP. I am developing an application using C++ and Qt. I have implemented 2 classes, base one and the one that inherits from it. Then I have added virtual methods for both and everything worked. But then I realized that I don't think it should... Here is the example:
This is my base class :
namespace Ui {
class CGenericProject;
}
class CGenericProject : public QDialog
{
Q_OBJECT
public:
explicit CGenericProject(QWidget *parent = 0);
~CGenericProject();
EMeasures_t type();
private:
Ui::CGenericProject *ui;
virtual void initPlot();
protected:
QCustomPlot* customPlot;
QVector<double> m_x;
QVector<double> m_y;
EMeasures_t m_type;
};
It has a virtual method called initPlot and it looks like this:
void CGenericProject::initPlot()
{
customPlot = ui->workPlot;
customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes );
customPlot->setFocusPolicy(Qt::ClickFocus);
customPlot->xAxis->setAutoTickStep(false);
customPlot->yAxis->setAutoTickStep(false);
customPlot->xAxis->setTickStep(100);
customPlot->yAxis->setTickStep(100);
customPlot->xAxis->setRange(0, 1000);
customPlot->yAxis->setRange(0, 1000);
}
And then i have a class that derives it:
class CEisProject : public CGenericProject
{
public:
CEisProject();
~CEisProject();
private:
virtual void initPlot();
void exampleEisMethod();
};
its initPlot is here:
void CEisProject::initPlot()
{
// give the axes some labels:
customPlot->xAxis->setLabel("Re [Ohm]");
customPlot->yAxis->setLabel("- Im [Ohm]");
customPlot->replot();
}
This is how i create the object:
CGenericProject* test = new CEisProject();
Now, when the initPlot() method is called, first the initPlot() from base class CGenericProject is called and then initPlot() from CEisProject is called. I wanted this functionality, where I can predefine some stuff in generic class and then add specific stuff in the childs.
But when I think of it, shouldn't initPlot() be calles exclusevily? I mean, shouldn't the method be called from base class or child class, instead of both, one after another? I have noticed this after reading this answer.
Constructors:
CGenericProject::CGenericProject(QWidget *parent) :
QDialog(parent),
ui(new Ui::CGenericProject)
{
ui->setupUi(this);
initPlot();
m_x.clear();
m_y.clear();
}
CEisProject::CEisProject()
{
m_type = EMeasures_t::eEIS;
initPlot();
}
You did not show the definition of the constructors, just their declaration. But I'm pretty sure the constructor definitions contain the answer to your question.
You may not be aware that the derived class constructor calls the base class constructor before directing virtual functions to the derived class. So a virtual function called in the base class construction (of an object which will soon be derived class) gets the base class definition of that virtual function.
Also, your constructor should be like:
// File .h
CEisProject(QWidget *parent = 0);
// File .cpp
CEisProject::CEisProject(QWidget *parent) : CGenericProject(parent)
{
...
}
or you won't be able to parent your derived widgets.

Access QList<T> from qml

I want to access a QList from qml.
Here is a sample code
class A;
class B : public QObject {
...
Q_INVOKABLE QQmlListProperty<A> read();
...
private:
QList<A*> lst;
}
I'm using context property to access object of class B in qml.
How can I access the list in qml. Any sample code will be helpful.
You will need to Q_DECLARE_METATYPE(A *) to be able to wrap it in a QVariant for use in QML.
But that's just for referring to and passing it around QML.
If you want to use A in QML as in C++, it will have to inherit QObject and implement properties, slots and such.
You can see how to implement the QQmlListProperty here: http://doc.qt.io/qt-5/qtqml-referenceexamples-properties-example.html
Also, if QObject is too heavy for you and impractical to have a lot of them, you can always use a single QObject derived to work as a controller for a non-QObject but still registered as metatype type.
class A {
public:
int a;
};
Q_DECLARE_METATYPE(A *)
class AProxy : public QObject {
Q_OBJECT
public slots:
int a(QVariant aVar) {
return aVar.value<A *>()->a;
}
void setA(QVariant aVar, int v) {
aVar.value<A *>()->a = v;
}
};
This way you don't have the size overhead and limitations of QObject for every object in the list, and can instead use a single controller to access the data, albeit at lower performance. In your case you could use B to act as both container and controller proxy for A.

Add functionality to class and all of it's subclasses

I have 3 classes that inherit from 3 different classes which all inherit from QWidget base class.
For example:
MyMainWindow : public QMainWindow : public QWidget
MyPushButton : public QPushButton : public QWidget
MyTextEdit : public QTextEdit : public QWidget
And I will have more classes like this eventually.
What I'd like to do now, is add a common method to all my classes; this means it should be added to the QWidget base class, but I can't edit it (I'd rather not change the Qt source code for one method).
Is this kind of behaviour possible?
I've already tried using interfaces like so:
class MyTextEdit : public QTextEdit, IMyMethodContainer { ... };
But the problem is, I need to access QObject::connect(sender, signal, this, slot); in IMyMethodContainer, and by this I'm trying to access the MyTextEdit, not the IMyMethodContainer, which is not a subclass of QWidget.
CRTP might help.
template<typename Derived, typename Base>
struct InjectMethod: Base {
static_assert( std::is_base_of< InjectMethod<Derived,Base>, Derived >::value, "CRTP violation" );
Derived* self() { return static_cast<Derived*>(this); }
Derived const* self() const { return static_cast<Derived*>(this); }
void my_method() {
// use self() inside this method to access your Derived state
}
};
Then:
class MyTextEdit: InjectMethod< MyTextEdit, QTextEdit > {
};
class MyPushButton: InjectMethod< MyPushButton, QPushButton > {
};
inside InjectMethod< MyTextEdit, QTextEdit > you have access to a self() pointer that has access to all stuff inside MyTextEdit, and inside InjectMethod< MyPushButton, QPushButton > the same.
You may not need the Derived portion -- possibly having a single template parameter (your base) would be enough, if you only use QWidget functionality.
In Java you can "extend" QWidget and add your custom methods there.
Class MyQWidgetExtension extends QWidget { ... }
Your other classes (QMainWindow, QpushButton, QtextEdit) just extend ("inherit") from that. Is there similar for C++?
Class MyQWidgetExtension : public QWidget { ... }

Common base class in plug-in code

The application defines 3 interfaces to be implemented in a plug-in. Widget is always the base.
// Application code...
class Widget {
virtual void animate() = 0;
};
class BigWidget : public Widget {
};
class SmallWidget : public Widget {
};
Every interface implementation is derived from NiceWidget which provides some plug-in internal common information.
// Plug-in code...
class NiceWidget {
// nice::Thing is only known in plug-in code.
nice::Thing thing();
};
class NiceBigWidget : public NiceWidget, public BigWidget {
void animate() override;
};
class NiceSmallWidget : public NiceWidget, public SmallWidget {
void animate() override;
};
func is called from application code. wid is known to be implemented by this plugin. Thus wid is also a NiceWidget. The goal of func is to call the thing method of it.
// Plugin-in code...
void func(Widget* wid) {
// wid is either NiceBigWidget or NiceSmallWidget.
auto castedBig = dynamic_cast<NiceBigWidget*>(wid);
if (castedBig) {
castedBig->thing().foo();
return;
}
auto castedSmall = dynamic_cast<NiceSmallWidget*>(wid);
if (castedSmall) {
castedSmall->thing().foo();
return;
}
assert(false);
}
But trying to cast wid to every Nice* can become very awful with increasing hierarchy size. Are there better solutions out there?
First: if you know that wid will always be a NiceWidget*, why not say so in func()? And you would not need a cast at all:
void func(NiceWidget* wid)
{
wid->thing().foo(); // Done
}
Even if you can't change the function signature for whatever reason, you would only need one cast:
void func(Widget* wid)
{
NiceWidget* casted = dynamic_cast<NiceWidget*>(wid);
if (casted)
casted->thing().foo();
else
throw std::exception(); // Well, throw the right exception
}
You can assert() instead of throwing an exception, of course, if you think it is better for your purposes.
In any case, you just need a pointer to the class that defines the functions you need to use (in this case, thing()), not to the most derived classes. If you will override the function in derived classes, make it virtual and you are done anyway.
If you know, that every NiceWidget is Widget, you should consider extending NiceWidget from Widget.
class Widget {
virtual void animate() = 0;
};
class BigWidget : public Widget {
};
class SmallWidget : public Widget {
};
class NiceWidget : Widget{
// nice::Thing is only known in plug-in code.
nice::Thing thing();
};
class NiceBigWidget : public NiceWidget, public BigWidget {
void animate() override;
};
class NiceSmallWidget : public NiceWidget, public SmallWidget {
void animate() override;
};
There will be another problem called The diamond problem, and it may be solved using virtual extending
After that it's should be OK to dynamic_cast from Widget to NiceWidget