Subclassing QString to add more functionality? - c++

Trying to add functionality to QString but get build errors ?? And if I am missing things??
#ifndef CSTRING_H
#define CSTRING_H
#include <QString>
#include <QStringList>
#include <QObject>
class CString : public QString, public QObject
{
Q_OBJECT
public:
explicit CString(QObject *parent = 0);
QStringList Find(QString qstrSearch);//all occurances
signals:
public slots:
};
#endif // CSTRING_H
#include "cstring.h"
CString::CString(QObject *parent) :
QString(parent) //ERROR IS POINTING TO HERE
{
}
QStringList Find(QString qstrSearch)//all occurances
{//indexOf, contains
QStringList qstrList;
return qstrList;
}

Don't derive classes form QString since it wasn't designed with polymorphy in mind (note that it has no virtual methods, in particular no virtual destructors) If you want to provide new utility functions, just use free functions - you may want to put them in a namespace:
namespace CString {
QStringList find(const QString &search);
}

QString(parent) Qstring does not have a constructor taking a QObject-parent as parameter. Therefor the compiler tries to cast your QObject to closest Matching constructor, which probably would be QString ( QChar ch )

You should use composition instead of inheritance here, because QString is not designed for subclassing. You can get a lot of troubles if you will subclass it.
Do something like this:
class CString : public QObject //if you're really need this class to be QObject, that's not always a good idea
{
Q_OBJECT
public:
explicit CString(QObject *parent = 0) :
QObject(parent),
mString() //QString have no constructors with parameter QObject*...
{
}
private:
QString mString;
}
Of course, implementation should be in cpp file, it's just a short example

Related

How to pass container with custom objects from C++ to QML?

I know something about C++ but I'm pretty new to QML.
I want to pass multiple custom C++ objects in a container to QML but I am having trouble doing so.
The code provided is narrowed down to the basics.
I can communicate from and to QML in a single object which I register with setContextProperty, this works fine. But if I try to do so with a QHash, then I get an error:
‘QVariant::QVariant(void*)’ is private within this context‘
Maybe you can help me out or give me a direction?
Thanks a bunch.
Update:
Thanks derM, here is my try at it:
I have added: Q_DECLARE_METATYPE(MyData); at the end of the header file. I have changed the container to a QVariantMap.
If I try: QVariant qvtest1(test1);
I get the error:
no matching function for call to ‘QVariant::QVariant(MyData&)’
However this works:
QVariant qvtest1, qvtest2;
qvtest1.setValue(test1);
qvtest2.setValue(test2);
But again I get an error with: setContextProperty("mymap", &mymap);
error:
calling a private constructor of class 'QVariant'
Code is adjusted accordingly.
Update 2
Thanks eyllanesc, your approach is working!
However I now get confronted with related issues in QML.
It seems that I can not acces all the QMap functions from QML.
For example:
var test_data = mymap["three"] // works fine
var test_data2 = mymap.find("two").value() // results in: Property 'find' of object [object Object] is not a function
Same problem:
var tmp1 = mydata_qml_object // object was created before
mymap["four"] = tmp1 // works fine
mymap.insert("four", tmp1) // Property 'insert' of object [object Object] is not a function
I am using Qt 5.11.1
Is this a bug or am I missing something?
C++ code
mydata.hpp:
#ifndef MYDATA_HPP
#define MYDATA_HPP
#include <QObject>
#include <QString>
class MyData : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ get_name WRITE set_name NOTIFY nameChanged)
public:
explicit MyData(QObject *parent = nullptr);
MyData(QString name);
MyData(const MyData &other);
MyData(MyData &&other) = delete;
MyData &operator=(const MyData &other);
MyData operator=(MyData &&other) = delete;
~MyData() override = default;
signals:
void nameChanged();
public slots:
void set_name(const QString &name);
QString get_name();
private:
QString _name;
};
Q_DECLARE_METATYPE(MyData);
#endif // MYDATA_HPP
mydata.cpp:
#include "mydata.hpp"
MyData::MyData(QObject *parent)
: QObject(parent)
{
}
MyData::MyData(QString name)
: _name(name)
{
}
MyData::MyData(const MyData &other)
{
_name = other._name;
}
MyData &MyData::operator=(const MyData &other)
{
if (this != &other)
{
_name = other._name;
return *this;
}
}
void MyData::set_name(const QString &name)
{
_name = name;
}
QString MyData::get_name()
{
return _name;
}
main.cpp:
#include <mydata.hpp>
#include <QGuiApplication>
#include <QMap>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQmlContext>
#include <QQuickView>
#include <iostream>
int main(int argc, char *argv[])
{
MyData test1("Hi");
MyData test2("Hello");
QMap<QString, QVariant> mymap; // QVariantMap
QVariant qvtest1(test1); // error: no matching function for call to ‘QVariant::QVariant(MyData&)’
//working:
QVariant qvtest1, qvtest2;
qvtest1.setValue(test1);
qvtest2.setValue(test2);
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
auto *engine = new QQmlEngine;
QQuickView view;
QQmlContext *ctxt = view.rootContext();
// this is working:
qmlRegisterType<MyData>("MyData", 1, 0, "MyData");
engine->rootContext()->setContextProperty("test1", &test1);
// this produces an error: calling a private constructor of class 'QVariant'
engine->rootContext()->setContextProperty("mymap", &mymap);
QQmlComponent component(engine, QUrl("qrc:/main.qml"));
QQmlEngine::setObjectOwnership(engine, QQmlEngine::CppOwnership);
QObject *object = component.create();
return app.exec();
}
According to the docs, the classes that inherit from QObject can not have a copy constructor or assignment operator:
No Copy Constructor or Assignment Operator
QObject has neither a copy constructor nor an assignment operator.
This is by design. Actually, they are declared, but in a private
section with the macro Q_DISABLE_COPY(). In fact, all Qt classes
derived from QObject (direct or indirect) use this macro to declare
their copy constructor and assignment operator to be private. The
reasoning is found in the discussion on Identity vs Value on the Qt
Object Model page.
The main consequence is that you should use pointers to QObject (or to
your QObject subclass) where you might otherwise be tempted to use
your QObject subclass as a value. For example, without a copy
constructor, you can't use a subclass of QObject as the value to be
stored in one of the container classes. You must store pointers.
On the other hand, if you want a class that inherits from QObject to support the QMetaType to use it as QVariant, you must pass it to the pointer because, as noted, the QObjects do not have a copy constructor, but the pointers are copyable.
//mydata.h
#ifndef MYDATA_H
#define MYDATA_H
#include <QObject>
class MyData : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ get_name WRITE set_name NOTIFY nameChanged)
public:
explicit MyData(QObject *parent = nullptr);
MyData(const QString & name);
~MyData() override = default;
signals:
void nameChanged();
public slots:
void set_name(const QString &name);
QString get_name();
private:
QString _name;
};
Q_DECLARE_METATYPE(MyData*)
#endif // MYDATA_H
//mydata.cpp
#include "mydata.h"
MyData::MyData(QObject *parent) : QObject(parent)
{}
MyData::MyData(const QString & name)
: _name(name){}
void MyData::set_name(const QString &name)
{
if(_name == name) return;
_name = name;
emit nameChanged();
}
QString MyData::get_name()
{return _name;}
You point out that setValue works, have you bought that it works ?, besides this method is used for the types that do not support QVariant so they will probably accept any type of data, what must be done is to pass the pointer:
MyData test1("Hi");
MyData test2("Hello");
QMap<QString, QVariant> mymap;
QVariant qvtest1 = QVariant::fromValue(&test1);
QVariant qvtest_1, qvtest_2;
qvtest_1.setValue(&test1);
qvtest_2.setValue(&test2);
On the other hand is setContextProperty, this accepts a QVariant or a pointer to QObject, and in your first case you pass QObject, the correct thing is to pass the pointer, in the second case you pass a QVariant so there are no problems as it can be copied.
engine->rootContext()->setContextProperty("test1", &test1);
engine->rootContext()->setContextProperty("mymap", mymap);
In conclusion you must pass an object copyable to setContextProperty.
qmlRegisterType only records that a type can be transmitted through the signals, but this does not guarantee that it works, this is a necessary condition but not enough since it is not copyable, so you must use MyData*.

inheritance in Qt won't allow me to reference?

So I I have an h file and a cpp file in a Qt project. I have to declare some qstrings inside my header file and I would like to reference them in my cpp file but I don't seem to be able to access it, can someone explain why or the correct way to do it?
#ifndef PROFILE_H
#define PROFILE_H
#include <QMainWindow>
#include "login.h"
#include "searchnote.h"
#include "note.h"
#include <QDebug>
namespace Ui {
class Profile;
}
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
#endif // PROFILE_H
#include "profile.h"
#include "ui_profile.h"
Profile::Profile(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Profile)
{
ui->setupUi(this);
}
Profile::~Profile()
{
delete ui;
}
void Profile::on_actionAdd_Note_triggered()
{
SearchNote openSearch; //will send us the searchNote gui
openSearch.setModal(true);
openSearch.exec();
}
void myNoteListAdd(QString newName){
myNoteList.add(); //the cpp file doesnt recognize this object
}
myNoteListAdd is a stand-alone function, myNoteList is a private data member of Profile class.
Only member functions (often also called methods) of the same class can access these private data members
It may be the case that you intend myNoteListAdd to be a member function of Profile, i.e.
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
private slots:
void on_actionAdd_Note_triggered();
**void myNoteListAdd(QString newName);**
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
Note myNoteList;
};
And implement as:
void Profile::myNoteListAdd(QString newName){
myNoteList.add(newName); // assuming you want to add newName to myNoteList
}
Otherwise, you need some form of accessing the member myNoteList, either by making it public or having a getter member. In either case you need an instance of a Profile to work with, i.e.:
class Profile : public QMainWindow
{
Q_OBJECT
public:
explicit Profile(QWidget *parent = 0);
~Profile();
//either this:
Note myPublicNoteList;
// or this
Note getNoteList() { return myNoteList; }
private slots:
void on_actionAdd_Note_triggered();
private:
Ui::Profile *ui;
private:
QString name;
QString major;
QString school;
};
then in your .cpp
void myNoteListAdd(QString newName)
{
Profile p = new Profile(); // or some other mechanism to get a Profile
//then either
p.myPublicNoteList.add(newName);
// or
p->getNoteList().add(newName);
}

Qt abstract class as interface

I am working on an IDE written in QT. I need to use the QMainWindow AND the QSyntaxHighLighter classes. However, when compiling it spits out the following error.
cannot declare variable 'w' to be of abstract type 'SquareSDK'
That refers to my main.cpp file.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SquareSDK w;
w.show();
return a.exec();
}
That class is defined in ediot.h
#ifndef EDIOT_H
#define EDIOT_H
#include <QMainWindow>
#include <QFileDialog>
#include <QtCore>
#include <QtGui>
#include <QObject>
#include <QSyntaxHighlighter>
namespace Ui {
class SquareSDK;
}
class SquareSDK : public QMainWindow, private QSyntaxHighlighter
{
Q_OBJECT
public:
explicit SquareSDK(QWidget *parent = 0);
~SquareSDK();
private slots:
void on_actionUndo_triggered();
void on_actionRedo_triggered();
void on_actionCut_triggered();
void on_actionCopy_triggered();
void on_actionPaste_triggered();
void on_actionNew_triggered();
void on_actionOpen_triggered();
void on_actionSave_triggered();
void on_actionSave_As_triggered();
void on_actionRun_in_Default_Web_Browser_triggered();
void on_actionReload_triggered();
void test();
void syntax();
private:
Ui::SquareSDK *ui;
QString mFilename;
QString urlname;
QString urldebug;
QString OS;
QString a;
QString b;
QString error;
QString ext;
QString text;
};
#endif // EDIOT_H
As one or both of base classes have 1 or more pure virtual methods, until you implement them in SquareSDK, SquareSDK is an abstract class (because it literally inherits those pure virtual methods). You can't instantiate an abstract class.
(Although you can use it as a type for pointer or reference. But it can only point to its non-abstract sub-classes, despite pointer-type being of abstract class. But that's not important right now)
I checked out the documentation for QSyntaxHighlighter, and it has 1 pure virtual method.
//this is how it looks like inside QSyntaxHighlighter class
virtual void highlightBlock (const QString& text) = 0;
So implement it in your SquareSDK:
//in .h
void highlightBlock (const QString& text);
//in .cpp
void SquareSDK::highlightBlock (const QString& text)
{
//...yourcode...
}
It's a function for highlighting blocks, and because it's pure virtual, it has absolutely no original behavior defined so you must program it completely on your own. So implement it in a way it highlights a block the way you want it highlighted.
QMainWindow, luckily, contains no pure virtual methods, which cuts you some slack.
EDIT:
Inherit QSyntaxHighlighter as public. highlightBlock is protected, and if base class is inherited as private, it becomes unreachable.
Double QObject inheritance is forbidden in Qt! So you can't do it with QMainWindow and QSyntaxHighlighter. In this case double inheritance is bad in many many other ways!
Use composition not aggregation here!

What is the easiest way to create a inherited class in Qt 5?

I'm a Qt newbie and all I'm trying to do is create a custom QLineEdit class with a few customizations (default alignment and default text). Right now I'm just trying to establish a base class, inheriting only QWidget. This is what I have (very bad code I know):
userText (utxt.h):
#ifndef UTXT_H
#define UTXT_H
#include <QWidget>
#include <QLineEdit>
class utxt : public QWidget
{
Q_OBJECT
public:
explicit utxt(QWidget *parent = 0);
QString text () const;
const QString displayText;
Qt::Alignment alignment;
void setAlignment(Qt::Alignment);
signals:
public slots:
};
#endif // UTXT_H
utxt.cpp:
#include "utxt.h"
utxt::utxt(QWidget *parent) :
QWidget(parent)
{
QString utxt::text()
{
return this->displayText;
}
void utxt::setAlignment(Qt::Alignment align)
{
this->alignment = align;
}
}
I know this is really wrong, and I keep getting "local function definition is illegal" errors on the two functions in utxt.cpp. Can someone please point me in the right direction? I'm just trying to create a custom QLineEdit to promote my other line edits to.
QLineEdit already has the alignment that can be set and also placeholderText.
LE: As I said there is no need to inherit from QLineEdit (or QWidget) for this functionality, but if you really want to do it you can just create your class and code a constructor that takes the parameters you want and call QLineEdit's functionality with that, something like:
//in the header
//... i skipped the include guards and headers
class utxt : public QLineEdit
{
Q_OBJECT
public:
//you can provide default values for all the parameters or hard code it into the calls made from the constructor's definition
utxt(const QString& defaultText = "test text", Qt::Alignment align = Qt::AlignRight, QWidget *parent = 0);
};
//in the cpp
utxt::utxt(const QString& defaultText, Qt::Alignment alignement, QWidget *parent) : QLineEdit(parent)
{
//call setPlaceHolder with a parameter or hard-code the default
setPlaceholderText(defaultText);
//same with the default alignement
setAlignment(alignement);
}

Access UI elements from another class c++

I have a problem with accessing ui elements from another class(with instance). I have a second QMainWindow in my application, I can access in secondWindow.cxx class all ui elements but not in read.cxx class. My code looks like following. Where is my mistake? Thank you for your help.
-------------------------------secondWindow.h------------------------------------
#ifndef __secondWindow_h
#define __secondWindow_h
#include "ui_secondwindow.h"
class secondWindow : public QMainWindow
{
friend class read;
igstkStandardClassBasicTraitsMacro(secondWindow, QMainWindow);
Q_OBJECT
public:
igstkStateMachineMacro();
secondWindow();
virtual ~secondWindow();
void createSignalAndSlots();
public slots:
void secondWindowTest();
protected:
private:
Ui::secondMainWindow m_secondWindowUI;
};
#endif
-------------------------------secondWindow.cxx------------------------------------
#include "secondWindow.moc"
#include "secondWindow.h"
#include "read.h"
secondWindow::secondWindow() :m_StateMachine(this)
{
m_secondWindowUI.setupUi(this);
createSignalAndSlots();
}
void secondWindow::createSignalAndSlots()
{
connect(m_secondWindowUI.pushButton1, SIGNAL(clicked()),this, SLOT(secondWindowTest()));
connect(m_secondWindowUI.pushButton2, SIGNAL(clicked()), read::instance(), SLOT(readTest()));
}
void secondWindow::secondWindowTest()
{
m_secondWindowUI.pushButton1->setEnabled(true); //OK
}
secondWindow::~secondWindow(){}
---------------------------------read.h--------------------------------------
#pragma once
#include "secondWindow.h"
class read : public QObject
{
Q_OBJECT
public:
static read *instance();
read();
virtual ~read() {}
public slots:
void readTest();
protected:
secondWindow *m_readUI;
static read *m_read;
private:
};
---------------------------------read.cxx--------------------------------------
#include <read.moc>
#include "secondWindow.h"
#include "read.h"
read *read::m_read= NULL;
read::read()
{
m_readUI = dynamic_cast<secondWindow*>( QApplication::instance() );
}
read *read::instance()
{
if(m_read == NULL)
m_read = new read();
return m_read;
}
void read::readTest()
{
m_readUI->m_secondWindowUI.qlabelTest->setText("test"); //segmentation fault
}
You are casting a QApplication::instance(), which is a QApplication * deriving from QCoreApplication * deriving from QObject *. That won't work, it's not a secondWindow *, not even a QMainWindow *, not even a QWidget *.
Apart from that, your coding style is rather strange -- in Qt, it's customary to use CamelCase for classes, not thisStuff which usually applies to functions and methods. Including <read.moc> is just wrong. Why is read::m_read static? Finally, the coupling between the two window classes is set up in a strange way (accessing global stuff like QApplication just to get a reference to another window smells ugly code). A much better and more obvious approach is to either wrap all of your windows in a parent object or setting up the dependencies explicitly, perhaps like this:
MainWindow *mainWindow = new MainWindow();
SecondWindow *second = new SecondWindow(mainWindow);
UtilityWindow *utilityWin = new UtilityWindow(second);