How to access a struct from another another C++ class? - c++

Hello I have a struct in a TreeItem class:
// TreeItem.h
class TreeItem
{
public:
struct TreePair
{
QString sa_key;
QVariant sa_value;
};
//... blabla
}
I would like access that struct TreePair from another class TreeModel , which has class TreeItem already formarded in its header:
// TreeModel.h
class TreeItem;
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
//..
}
// TreeModel.cpp
TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QVector<TreePair> rootData; // TreePair was not declared in this scope
}
My strcut was not declared in this scope?? In every class it was already automatically set like
#ifndef _TREEITEM_H
#define _TREEITEM_H
#endif

Since TreePair is nested inside TreeItem, it needs to be
QVector<TreeItem::TreePair> rootData;

Related

trying to access QList of struct members in qml

I need to know how to acess the members of struct from qlist in qml.
Currently i can acess only the members of struct in qml and i am also able to acess simple qlist i.e. Qlist made of qString.
But the problem starts when i try to acess the members of struct embedded in qlist.
I have created a struct (MyStruct) in c++ and can acscess it in Qml. I can also acess QList ( which is QStrinList).
But problem comes when i am trying to access QList. it gives me the error
qrc:/OrderBar.qml:26: TypeError: Cannot read property 'name1' of undefined
the Codes are
QML
Text{
//text: myModel2.mystr.name1 // this works
text: myModel2.lstr[0].name1
y: sensor.width + 5
font.family: "Helvetica"
font.pointSize: 10
anchors.horizontalCenter: parent.horizontalCenter
}
C++
test.h
#ifndef TEST_H
#define TEST_H
#include <QObject>
struct MyStruct {
Q_GADGET
// Q_OBJECT
int m_val;
public:
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
Q_DECLARE_METATYPE(MyStruct);
class test : public QObject
{
Q_OBJECT
Q_PROPERTY(MyStruct mystr READ getMyStruct
WRITE setMyStruct NOTIFY myStructChanged)
Q_PROPERTY(QList<MyStruct> lstr READ getLstr
WRITE setLstr NOTIFY lstrChanged)
public:
explicit test(QObject *parent = nullptr);
MyStruct strObj;
MyStruct getMyStruct() const
{
return strObj;
}
void setMyStruct(MyStruct val)
{
strObj = val;
emit myStructChanged();
}
QList<MyStruct> strList;
QList<MyStruct> getLstr() const
{
return strList;
}
void setLstr(QList<MyStruct> val)
{
strList = val;
emit lstrChanged();
}
signals:
void myStructChanged();
void lstrChanged();
public slots:
};
#endif // TEST_H
test.cpp
#include "test.h"
test::test(QObject *parent) : QObject(parent)
{
MyStruct l_value;
l_value.m_name1 = "b1";
l_value.m_name2 = "b2";
setMyStruct(l_value);
QList<MyStruct> l_strList;
l_strList.append(l_value);
setLstr(l_strList);
}
The codes are absolutely right. I found out that this is a bug in Qt older version. I tested the codes with QT 5.14 and it fully works.

Exposing to QML the serial port names from C++

I'm trying to expose the QSerialPort.available() through an Q_INVOKABLE QStringList availablePorts() function from a class I expose directly to QML in my main class.
Main:
qmlRegisterType<SerialPortManager>("com.MyApp.qml", 1, 0, "SerialPortManager");
SerialPortManager
class SerialPortManager : public QObject
{
Q_OBJECT
public slots:
Q_INVOKABLE virtual QStringList availablePorts() {
QList<QSerialPortInfo> portsAvailable = QSerialPortInfo::availablePorts();
QStringList names_PortsAvailable;
for(QSerialPortInfo portInfo : portsAvailable) {
names_PortsAvailable.append(portInfo.portName());
}
return names_PortsAvailable;
}
Which is not valid for a model type in QML because it raises Unable to assign QStringList to QQmlListModel* error.
QML
ComboBox {
model: serial.availablePorts()
}
SerialPortManager {
id: serial
}
So how do I get around this?
One solution is to return a QVariant as recommended by the docs, for this we use QVariant::fromValue()
#ifndef SERIALPORTMANAGER_H
#define SERIALPORTMANAGER_H
#include <QObject>
#include <QSerialPortInfo>
#include <QVariant>
class SerialPortManager : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE static QVariant availablePorts() {
QList<QSerialPortInfo> portsAvailable = QSerialPortInfo::availablePorts();
QStringList names_PortsAvailable;
for(const QSerialPortInfo& portInfo : portsAvailable) {
names_PortsAvailable<<portInfo.portName();
}
return QVariant::fromValue(names_PortsAvailable);
}
};
#endif // SERIALPORTMANAGER_H

Object members not retrieved from a Qt dll

I try to get a QObject-subclassed object from a Qt shared library to a Qt application dynamically.
I have tried to apply a previous answer about this subject : QLibrary - import a class
Here is my common interface tabappinterface.h:
#ifndef TABAPP_H
#define TABAPP_H
#include <QObject>
#include <QWidget>
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface()
{
}
QWidget *app;
QString title;
};
#endif // TABAPP_H
My class dll-side mytabapp.h:
#ifndef MYTAB_H
#define MYTAB_H
#include "tabapp_global.h"
#include "tabappinterface.h"
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
QWidget *app;
QString title;
};
extern "C" MYTABSHARED_EXPORT TabAppInterface *getTabApp();
and its implementation mytabapp.cpp:
#include "mytabapp.h"
MyTabApp::MyTabApp()
{
app = new AppWidget();
title = QStringLiteral("My Tab App");
}
MyTabApp::~MyTabApp()
{
}
TabAppInterface *getTabApp()
{
return new MyTabApp();
}
My app-side implementation:
void ContainerMainWindow::loadLibraries()
{
QLibrary myLib("mytabapp.dll");
if(myLib.isLoaded())
{
qDebug() << "Loaded!";
}
typedef TabAppInterface *(*tabAppGetProt)();
auto tabAppGetter = (tabAppGetProt) myLib.resolve("getTabApp");
if(tabAppGetter)
{
auto *tabApp = tabAppGetter(); // not null
qDebug() << tabApp->title; // print empty string
qDebug() << (QWidget *)(tabApp->app); // SEGFAULT
}
}
As stated in comment in the last lines, the object members are not retrieved although tabApp is not null.
Any idea?
Thanks!
You're accessing the base class variables (fields) title and app, which nobody ever initialized. These variables aren't virtual at all, so those in the derived class just hide those in the base class. As a solution, you can declare them as protected in the base class and encapsulate them in getters and setters.
This way, your base class is like:
class TabAppInterface : public QObject
{
Q_OBJECT
public:
virtual ~TabAppInterface(){}
QWidget *getApp() const { return app; }
void setApp(QWidget *value) { app = value; }
QString getTitle() const { return title; }
void setTitle(const QString &value) { title = value; }
protected:
QWidget *app;
QString title;
};
and the derived class is just like:
class MYTABSHARED_EXPORT MyTabApp: public TabAppInterface
{
public:
MyTabApp();
virtual ~MyTabApp();
};
You can still directly access the variables inside the derived class (i.e. initialize them in constructor) and through the getters/setters methods from outside:
auto *tabApp = tabAppGetter();
qDebug() << tabApp->getTitle();
qDebug() << tabApp->getApp();

Forward declaration in Qt project

I'm trying to use Qt with C++. I'd use QT for programming in Python before.
my simple test doesn't work. This is my tour.h file:
#ifndef TOUR_H
#define TOUR_H
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QTableView>
class TourTable;
class Tour : public QMainWindow
{
Q_OBJECT
public:
Tour();
/*protected:
void closeEvent(QCloseEvent *event);
private slots:
void newCompetitor();
void remCompetitor();
void finalReport();
void openPage();
void savePage();
void reloadTitle();*/
private:
TourTable _table;
};
class QStandardItem;
class QStandardItemModel;
class TourTable : public QTableView
{
Q_OBJECT
public:
TourTable();
/* bool isChanged();
QString windowName();
void finalReport();
void newCompetitor();
void remCompetitor();
bool savePage();
void setChanged(bool value);
void openPage();
protected:
void itemChanged(QStandardItem item);
private:*/
// bool _secondBetter(p1, p2);
Tour _parent;
// QStandardItemModel _model;
// bool _saved;
// bool _changed;
};
#endif
I'd commented almost everything in this code to isolate the problem, but I still don't know what is causing this. Is my first trying in C++.
The error message is:
tour.h:28:12: error: field ‘_table’ has incomplete type ‘TourTable’
TourTable _table;
^~~~~~
tour.h:7:7: note: forward declaration of ‘class TourTable’
class TourTable;
Can someone help me to solve that?
Forward declaration in C++ allows to reference a type before its definition. Problem here is that in your code:
class TourTable;
class Tour : public QMainWindow
{
// ...
TourTable _table;
};
You're not only referencing the type TourTable, you're instantiating it with TourTable _table;. This requires a complete definition of TourTable.
A solution could be to define TourTable before Tour, as follows:
class TourTable : public QTableView
{
// ...
Tour _parent;
}
class Tour : public QMainWindow
{
// ...
TourTable _table;
};
But that just moves the problem since you're instantiating Tour in TourTable.
Depending on the complete design, the solution may be to use pointers. Something like that:
class TourTable;
class Tour : public QMainWindow
{
Tour();
// forward declaration of the constructor,
// see below for the definition
TourTable* _table;
// no complete definition of TourTable at this stage,
// only a forward declaration:
// we can only declare a pointer
};
class TourTable : public QTableView
{
TourTable(Tour* parent):
QTableView(parent),
_parent(parent)
{
}
Tour* _parent;
}
Tour::Tour() // definition of Tour's constructor
{
_table = new TourTable(this);
// TourTable has been defined : we can instantiate it here
}
To be clear, this error is coming from your compiler -- not from qmake -- and is a limitation of the language. But it can be easily overcome by creating a class that defines a parent/child behavior and making any classes where you want that behavior to inherit from the base class, as Qt's QObject does.
Both QMainWindow and QTableView inherit from QObject, so if you make use of QObject's parent/child system this design may be redundant. To find the parent from the child call parent(), and to find the children from the parent you can call children().

Can't declare Q_ENUM from an enum defined in another class

This documentation states
If you want to register an enum that is declared in another class, the enum must be fully qualified with the name of the class defining it. In addition, the class defining the enum has to inherit QObject as well as declare the enum using Q_ENUMS().
However I can't make this work, in the following example.
Class A:
#ifndef CLASSA_H
#define CLASSA_H
#include <classb.h>
class ClassA : public QObject
{
Q_OBJECT
Q_ENUMS(ClassB::TestEnum)
public:
explicit ClassA(QObject *parent = 0) : QObject(parent)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
}
};
#endif // CLASSA_H
ClassB:
#ifndef CLASSB_H
#define CLASSB_H
#include <QDebug>
#include <QMetaEnum>
#include <QObject>
class ClassB : public QObject
{
Q_OBJECT
Q_ENUMS(TestEnum)
public:
enum TestEnum { A, B, C };
explicit ClassB(QObject *parent = 0) : QObject(parent)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
}
};
#endif // CLASSB_H
main:
#include <classa.h>
#include <classb.h>
int main()
{
ClassA objectA;
ClassB objectB;
}
Expected output:
1
1
Actual Output:
0
1
Here is a summary of a little research:
Information stated in the documentation about registration of a enum declared in another class looks outdated.
Q_ENUMS(Class::EnumName doesn't create a new enumerator, and useless.
When you declare a new Q_PROPERTY in ClassA you should use full form of the enum ClassB::EnumName.
As soon as EnumName is registered in ClassB it doesn't need to be registered any more.
A property created using a enumerator from another class works correctly.
class ClassA : public QObject
{
public:
Q_OBJECT
Q_PROPERTY(ClassB::TestEnum test READ test)
public:
explicit ClassA(QObject *parent = 0)
{
const QMetaObject *metaObj = this->metaObject();
qDebug() << metaObj->enumeratorCount();
QMetaProperty property = metaObj->property(metaObj->indexOfProperty("test"));
if (property.isEnumType())
{
const QMetaEnum& enumerator = property.enumerator();
qDebug() << enumerator.name();
for (int i = 0 ; i < enumerator.keyCount(); i++)
{
qDebug() << QLatin1String(enumerator.key(i)) << enumerator.value(i);
}
}
}
ClassB::TestEnum test() const
{
return ClassB::A;
}
};
Output:
0
TestEnum
"A" 0
"B" 1
"C" 2