Qt and C++: Overwrite or Expand Class - c++

I want to add some properties (like an ID) to a QPushButton. Therefore, I need to expand or overwrite the class Q_WIDGETS_EXPORT QPushButton : public QAbstractButton
How do I do that?
Thanks for the help.

you dont need to extend the class to just put an id in it ... instead make use of the property system.
as specified in the official doc here:
A property can be read and written using the generic functions QObject::property() and QObject::setProperty(), without knowing anything about the owning class except the property's name.
you just have to do:
ui->myButton->setProperty("Id", 123456);
can also be another object e.g a string (or even your own class if you define it to do that)
ui->myButton->setProperty("_name", "123456");
to read the property is the method property() there for you but read the doc because you get a QVariant as return example:
QVariant(int, 123456)

It really depends on the use case. There is no problem (and often the intended way) in inheriting from Qt-(Widget) Classes (correct me, if I am wrong).
So you could do:
class MyQPushButton : public QPushButton
{
Q_OBJECT
public:
MyQPushButton() : QPushButton(...) {}
private:
int ID = -1;
}
Qt has a very good documentation and you can look at the sources to see what to override.
You could also extend a new class with QPushButton, but than you always have to deal with the QPushButton reference in your class, if you want e.g. connect something. In the inherited class you can connect the slots and so on. But for example you could do this:
class MyQPushButton
{
public:
MyQPushButton() {}
const QPushButton& const GetQPushButton() { return pushButton; }
const QPushButton* const GetQPushButtonPtr() { return &pushButton; }
private:
QPushButton pushButton;
int ID = -1;
}
There is no right and wrong. But I would use the inheritance for Qt-classes.

Related

QML/QT How to convert object from C++ to QML?

It took me a while, but eventually I managed to convert a JavaScript/QML POJO to a custom object not derived from QObject.
I think it's easier to understand my issue with a working example. So let's start with this:
struct SomeType { /* Just a plain struct that does not derive from QObject! */ };
SomeType FooFactory::convertQMLToSomeType(const QJSValue& val) {
SomeType result = /*... some kind of conversion takes place here ... */
return result;
}
void FooFactory::registerTypes(QQmlEngine& engine) {
QMetaType::registerConverter<QJSValue, SomeType>(FooFactory::convertQMLToSomeType);
}
What this does is it registers a converter for the transformation of QSValue to SomeType. So now, whenever I do something like this in QML
my_prop = { "foo": "some plain javascript object" };
assuming my_prop is exposed like so in the corresponding C++ class:
Q_PROPERTY(SomeType my_prop MEMBER _myProp);
SomeType _myProp;
// Somewhere else outside the class, this is needed for registering the converter
Q_DECLARE_METATYPE(SomeType);
the string is implicitly converted into a SomeType without the need of doing things manually.
..
Great!
But what about the opposite direction of the conversion? I Need QML to deal with strings, not QVariant(SomeType) objects (QT always uses QVariant wrappers internally to store user defined types when dealing with the meta system).
I already tried registering an inverse converter like this:
QMetaType::registerConverter<SomeType, QJSValue>(FooFactory::convertBackToQML);
or this
QMetaType::registerConverter<QVariant(SomeType), QJSValue>(FooFactory::convertBackToQML);
but none of these approaches work. I believe the second line is quite promising, but I wasn't even able to compile that one due to problems with registering the static meta type.
So, how would I solve this? As a short reminder, I am not able to derive SomeType from QObject, and yes, I am aware that this is the most common way to do these kinds of things.
Does anyone have an idea? Or am I barking up the wrong tree? Many thanks in advance!
This may not be what you want, but it might also be your only option. You can create a QObject wrapper class around your struct. Just create properties for whatever values in the struct you want to expose.
class SomeWrapper : public QObject
{
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)
public:
explicit SomeWrapper(QObject *parent = nullptr) : QObject(parent) {}
QString someData() { return m_struct.someData; }
void setSomeData(QString data)
{
if (data != m_struct.someData)
{
m_struct.someData = data;
emit someDataChanged();
}
}
signals:
void someDataChanged();
private:
SomeType m_struct;
};
If you want to operate with your structure as with a plain JavaScript object, then another option may be using QVariantMap as a type for your property. Then you could define the needed conversions in getter and setter of your property:
class Whichever : public QObject {
Q_OBJECT
Q_PROPERTY(QVariantMap my_prop READ myProp WRITE setMyProp)
QVariantMap myProp() const {
QVariantMap map;
map["some_field"] = _myProp.someField;
// Fill the other fields as needed.
return map;
}
void setMyProp(const QVariantMap& map) {
_myProp.someField = map["some_field"].toString();
// Fill the other _myProp fields as needed.
}
};
Conversions between QVariantMap and the actual JavaScript objects would be handled by QML engine automatically. Nested JavaScript objects should also be possible by nesting the corresponding QVariantMaps.
Of course, this option makes property declaration not so explicit about which type does it correspond to, and perhaps it will require a bit more boilerplate code if you need to declare multiple properties of this type (you can define and use your own macro for that though if needed). But this is probably one of the easiest ways to achieve what you have described.

Binding instance of C++ object to QML object

I'm new to Qt, and have written a basic application which has one class which inherits from QObject and is bound to a QML file.
I now want that class to contain a Vector of objects (let's say from a class Customers), which contains some data, such as a QString for name, etc.
To make life easier I'll create these objects manually in main, and place some text fields in my QML file.
I now want to be able to bind specific objects to specific text fields in the QML file, such that when a value changes, the value in the text field updates.
How can this be done? It looks like QML statically calls methods of the classes it's bound to, instead of on an assigned object.
I feel like QAbstractList may have some use here, but not too sure. Would rather not have to inherit from anything for my Customers class.
EDIT:
I think I may be able to do what I want with a QObjectList-based Model (https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html). I notice it says at the bottom that "There is no way for the view to know that the contents of a QList has changed. If the QList changes, it is necessary to reset the model by calling QQmlContext::setContextProperty() again."
Does this mean that if a value inside DataObject (such as name) changes, the model has to be reset, or only when the Qlist itself changes (i.e. new item added, or item deleted)? If the latter, I would think this should be fairly easy to maintain as I would only need to set the context property whenever anything is added or deleted.
This may be usefull if you want to process raw QObject instance in QML script. You can append properties to Element class and modify them from qml.
class Element : public QObject {
Q_OBJECT
private:
QString type;
QLinkedList<Element*> child;
public:
explicit Element(QString type, QLinkedList<Element*> child);
virtual ~Element();
public:
QLinkedList<Element*> getChild() const;
QString getType() const;
public:
static void printTree(Element* root);
};
this is so simple you need to use NOTIFY
define your properties like this :
Q_PROPERTY (QString name READ name WRITE setName NOTIFY nameChanged)
then you need to define each one like this :
public : QString name() const;
signals :
void nameChanged(QString name);
public slots:
void setName(const QString &name);
private QString _name;
and then you should define body in cpp like this :
QString className::name() const{
return _name;
}
void className::setName(const QString &name){
if(name==_name) return;
_name = name;
Q_EMIT nameChanged(_name);
}
after registering it to QML with qmlRegisterType<ClassName>("com.className",1,0,"className");
simply set name it will notify if it changes for example in a textfield set text to that name property

how to create static QLabel in Qt

Is it possible to create some static QLabels in one class, and other classes can access its QLabels variable and apply changes to the QLabels without creating its object?
I found some answers online like if you want to access one class variables without creating its object in another class, you have to make its data static.
So basically what I am trying to do here is accessing and changing one class variables, for me it is QLabels, in another class without creating its object.
I know how to create static variables, but when comes to declare a staic QLabel, I found it difficult to achieve it.
I think you may just make the label accessible, i.e. expose it as a public member. Say you have a Form class, and a label QLabel in its ui. Add this method to the class:
public:
QLabel * label();
the implementation is just:
QLabel *Form::label()
{
return ui->label;
}
If all you need to expose is the label text property, just add these two accessors methods:
public:
QString labelText();
void setLabelText(QString & text);
in implementation file:
QString Form::labelText()
{
return ui->label->text();
}
void Form::setLabelText(QString &text)
{
ui->label->setText(text);
}
These last strategy fits encapsulation better.
About having it static: what if you have more than one instance of the Form class? Which label is supposed to be pointed to by the static member? If you are 100% sure you will have only one instance of the widget, you can add a static public QLabel * member:
public:
static QLabel * label;
in implementation file, on top:
QLabel *Form::label = 0;
in Form constructor:
ui->setupUi(this);
if(label == 0)
{
label = ui->label;
}
Again, this makes sense if you have one Form instance only. Otherwise, the static pointer will point forever to the label of the widget which was created first (and, dangerously, to nothing when that instance gets destroyed).

Qt access D-Pointer of inherited Class

I am trying to understand how the whole d-pointer thing i working. I got most parts but I am currently facing a problem:
Like the guy here Dpointer inheritance i want to inherit a class using d-pointers (infact it is QProcess).
Since the function to access the d-pointer is private i can not access it with simple inheritance. My idea is to again use the Q_DECLARE_PRIVATE macro to get the function and to access it. Can this work? Before I try out I want some hints since I dont know if this can even work.
(I need this to avoid the whole licensing issues.)
MyProcess.h
#ifndef MYPROCESS_H
#define MYPROCESS_H
class QProcessPrivate;
class MyProcess : public QProcess {
public:
MyProcess(QObject *parent = 0);
protected:
Q_DECLARE_PRIVATE(QProcessPrivate);
};
#endif /* WIDGET_H */
MyProcess.cpp
#include "myprocess.h"
MyProcess::MyProcess(QObject *parent = 0)
: QProcess(parent) {
}
MyProcess::setPid(Q_PID pid) {
Q_D(const QProcess);
d->pid = pid;
}
First of all, let's cover the basics. IANAL, but here it goes:
I presume that you have a closed-source application that wishes to use Qt under terms of LGPL.
Under some interpretations of U.S. law, making your code dependent on Qt's private headers makes it a derived work of Qt, so your code must be available under terms of LGPL (or GPL), unless you have a commercial license.
Your obligation under LGPL is to make it possible for people you distribute your app, to relink it with a version of Qt they compiled from the sources you're obliged to offer to them. This may be dynamic linking done by the OS, or static linking done with a linker utility. It doesn't matter whether you modified Qt or not. They ask, you must give them Qt sources with the exact build scripts you used to build the Qt that you use in your app.
When you depend on private headers, it's impossible for someone to make binary compatible changes to the Qt version you offer and relink it with your code, without things breaking. The private Qt classes can be changed without breaking binary compatibility - that's why they are private. Myself I interpret LGPL as follows: My code is not derived work if it will successfully link and work with any version of Qt that's binary-compatible to the version I offer along with my application. Of course that's within limits of Qt bugs and other changes I made, so it may not be viable for someone to patch this Qt to an older version and expect it to run OK.
So, the only thing you can do to keep your code closed-source is to modify the *public interface of QProcess within Qt proper. Anyone can take this modified version of Qt (that you offer!), make further binary compatible changes to it, and relink with your code. So if you think that not modifying Qt and depending on private headers makes your life easier, you are quite off base.
Generally speaking, you can't inherit from QXyzPrivate since you need to include Qt's private headers. So that's not a good practice, and there's really no good reason to do it. The price you pay is an extra heap allocation when you instantiate the class, so I'd say don't worry about it.
You must start your own private PIMPL class hierarchy. Note how each class that intends to be derived from must offer a constructor taking a reference to an instance of the private class.
// myprocess.h
class MyProcessPrivate;
class MyProcess : public QProcess {
Q_DECLARE_PRIVATE(MyProcess) // No semicolon!
public:
explicit MyProcess(int arg, QObject * parent = 0);
~MyProcess();
protected:
MyProcess(MyProcessPrivate&, int arg, QObject * parent); // Must be present to allow derivation
const QScopedPointer<MyProcessPrivate> d_ptr; // Only in the base class, must be protected!
}
// myprocess_p.h
class MyProcessPrivate {
Q_DECLARE_PUBLIC(MyProcess) // No semicolon!
...
public:
explicit MyProcessPrivate(MyProcess*);
protected:
MyProcess * const q_ptr; // Only in the base class, must be protected!
};
// derivedprocess.h
#include "myprocess.h"
class DerivedProcessPrivate;
class DerivedProcess {
Q_DECLARE_PRIVATE(DerivedProcess) // No semicolon!
public:
explicit DerivedProcess(int arg, QObject * parent = 0);
~DerivedProcess();
}
// derivedprocess_p.h
#include "myprocess_p.h"
class DerivedProcessPrivate : public MyProcessPrivate {
Q_DECLARE_PUBLIC(DerivedProcess) // No semicolon!
//...
public:
explicit DerivedProcessPrivate(DerivedProcess*);
};
// myprocess.cpp
MyProcess::MyProcess(int arg, QObject * parent) :
QProcess(parent),
d_ptr(new MyProcessPrivate(this)) {}
MyProcess::MyProcess(MyProcessPrivate & d, int arg) :
d_ptr(&d) {}
MyProcessPrivate::MyProcessPrivate(MyProcess* parent) :
q_ptr(parent) {}
// derivedprocess.cpp
DerivedProcess::DerivedProcess(int arg, QObject * parent) :
MyProcess(* new DerivedProcessPrivate(this), arg, parent) {}
DerivedProcessPrivate::DerivedProcessPrivate(DerivedProcess* parent) :
MyProcessPrivate(parent) {}
It can be accessed by d_ptr.data().
I want to extend the behaviors of QML without recompiling Qt source code, which need access to d_ptr. Here's how I get the QTextDocument in d_ptr of QDeclarativeTextEdit in an inherit class:
QT_FORWARD_DECLARE_CLASS(QDeclarativeTextEditPrivate)
class MyTextEdit : public QDeclarativeTextEdit
{
...
void aMethod()
{
QDeclarativeTextEditPrivate *d = reinterpret_cast<QDeclarativeTextEditPrivate *>(QDeclarativeItem::d_ptr.data());
QTextDocument *d_doc = d->document;
...
}
};
btw, we can also get d_ptr without inheriting classes.
For example, here's how I get QTextDocument in QDeclaractiveTextEditPrivate without inheritance:
#include <QtGui/QGraphicsItem>
QT_FORWARD_DECLARE_CLASS(QGraphicsItemPrivate)
class DQGraphicsItem : public QGraphicsItem
{
DQGraphicsItem() {}
public:
QGraphicsItemPrivate *d() const { return d_ptr.data(); }
};
inline QGraphicsItemPrivate *d_qgraphicsitem(const QGraphicsItem *q)
{ return static_cast<const DQGraphicsItem *>(q)->d(); }
#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p.h>
#include <qt/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h>
inline QDeclarativeTextEditPrivate *d_qdeclarativetextedit(const QDeclarativeTextEdit *q)
{ return static_cast<QDeclarativeTextEditPrivate *>(d_qgraphicsitem(q)); }
inline QTextDocument *d_qdeclarativetextedit_document(const QDeclarativeTextEdit *q)
{ return d_qdeclarativetextedit(q)->document; }

Change base class of existing derivated class

At the moment I'm writing an application which shows level measurement data into some graphs. Always I have date/time on x-axis and data on th y-axis. I use Qwt for this and modified QwtPlotPicker class to show proper time labels. I did this by derivation and redefining a member function:
class myQwtPlotPicker : public QwtPlotPicker {
Q_OBJECT
public:
explicit myQwtPlotPicker( QWidget* canvas, bool DateScale = false );
explicit myQwtPlotPicker( int xAxis, int yAxis, QWidget* canvas, bool DateScale = false );
explicit myQwtPlotPicker( int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget* canvas, bool DateScale = false );
virtual ~myQwtPlotPicker() {};
protected:
virtual QwtText trackerTextF( const QPointF &position ) const {
... redefinition of the label text ...
}
};
As you can see I also added a new parameter DateScale which turns date labels on or off. This works perfectly, but there is a class QwtPlotZommer which is derivated from QwtPlotPicker:
class QWT_EXPORT QwtPlotZoomer: public QwtPlotPicker { };
Now, the problem is, how do I get the class QwtPlotZommer to derive from myQwtPlotPicker and not from QwtPlotPicker?
Or course I could edit the Qwt sources, but there has to be a proper way of doing this.
I hope there is a proper way to do this. I would be glad, if someone could help me with this.
Try multiple inheritance:
class myQwtPlotZoomer : public QwtPlotZoomer, public QwtPlotPicker { };
There's no way to change class hierarchy at runtime in C++.
I guess that you should reconsider your design - you cannot and should not change the inheritance hierarchy of some library class.
Did you look at some examples to see how the classes you mentioned are intended to be used? Perhaps you should ask a new question to find out how to solve the problem you are actually facing (i.e. how to create a zoomable plot in qwt if I understand you correctly)
You have to overload QwtPlotZoomer reimplementing trackerTextF(). If you also have a use case of a standalone QwtPlotPicker - not being a QwtPlotZoomer - you have to do it twice:
class YourPicker: public QwtPlotPicker ...
class YourZoomer: public QwtPlotZoomer ...
As your implementation is a one-liner I don't see a problem in writing it twice, but if you want to avoid that, you have to put the code to some other class, that is called in both overloaded methods.