I need to create a signal/slot connection in Qt (old syntax). In order to do that, I need to create a class. In that class, some members must be declared. Those members are: a variable doverka which is a QString and text which is a QTextEdit widget. The question is: how on earth do I declare them? Pardon me for the stupid question but I am new to classes. For me, declaring those is not that simple. I have already declared a member function and created a connection, but as the doverka and the text have not yet been declared, nothing works, naturally.
class MyObject : public QObject
{
Q_OBJECT
public: /*how should I declare 'text' and 'doverka' here??? */
public slots:
void onClicked() {
text.setText(doverka);
}
};
QObject::connect(
&btn_t,
SIGNAL(clicked()),
this,
SLOT(onClicked()));
Related
I wanted to declare a QGraphicsView which has a previously declared member as an argument of the constructor, but the compiler interprets it as a function.
(Code for reference)
class Widnow : public QMainWindow
{
Q_OBJECT
// constructors, member functions, etc...
private:
Ui::Widnow *ui;
QTimer timer01;
QGraphicsScene gaem;
QGraphicsView wiev(&gaem); //this gets interpreted as a function
}
Trying to call the constructor as QGraphicsView wiev = QGraphicsView(&gaem); also causes an error, as the copy constructor has been deleted... Is there a way to declare this member without errors?
The C++ compiler thinks that it is a method declaration where "wiev" as method that returns an instance of QGraphicsView. Use this way
class Widnow : public QMainWindow
{
private:
QGraphicsScene gaem;
QGraphicsView wiev; //this gets interpreted as a function
public:
Widnow() : wiev(&gaem)
{}
};
my Qt/QML program uses classes declared in C++ to structure information in QML and pass it as a bundle to C++ functions.
The structs are derived from QObject as required by QML. Example:
class ResultStorageOptionsStruct : public QObject {
Q_OBJECT
public:
explicit ResultStorageOptionsStruct(QObject * parent = nullptr) : QObject(parent) {}
~ResultStorageOptionsStruct() = default;
ResultStorageOptionsStruct(const ResultStorageOptionsStruct& blob) {
}
bool folderValid;
QString folderURL;
Q_PROPERTY(bool folderValid MEMBER folderValid)
Q_PROPERTY(QString folderURL MEMBER folderURL)
};
Q_DECLARE_METATYPE(ResultStorageOptionsStruct);
Using this method, passing information from QML to C++ works without a problem, but handling of that information on the C++ side is very bothersome due to the fact that you cannot copy/assign the class(derived of QObject).
I would like to copy/serialize/deserialize my classes for easy handling once they are on the c++ side. I do not need the features QObject gives me once we are on the c++ side as those classes are just containers for the information.
Is there some kind of trick or data structure to make this happen?
You can serialize and deserialize to a QIODevice, but this would be for file storage. To me, it sounds more like you want a QObject wrapper around a plain C++ object.
I would create a C++ class with the data that you need. Then create a QObject derived class with a (weak) reference to the C++ class that you wrap the original class in when passing it to QML.
class MyData
{
public:
int x;
};
class MyDataWrapped : QObject
{
Q_OBJECT
public:
MyDataWrapped(MyData *obj) : md(obj) {}
void x() const { return md->x; }
Q_PROPERTY(...)
private:
MyData *md; // You might want to make this a weak pointer
};
What is potentially tricky is if the data is changed from QML or C++, while the wrapper lives. How can QML tell that a property is changed if you change it from C++, and the other way around. Here, QObject and signals and slots come in handy. However, if the data is read-only while shared, I guess you should be fine.
Yesterday I was asked to recreate a regular QT form using QML (which was my first attempt ever using QLM). Everything was going well until I tried using c++ methods in the QML. This is obviously not the original code, but the scenario looks something like this:
I have a super class deriving from QObject, with some properties, methods and even virtual methods:
class SuperClass : public QObject {
Q_OBJECT
Q_PROPERTY(QString someProperty READ someProperty WRITE setSomeProperty)
protected:
QString m_someProperty;
public:
QString someProperty(void){return m_someProperty;} //get method
void setSomeProperty(QString newValue){m_someProperty = newValue;} //set method
Q_INVOKABLE virtual QString printSomething(void) = 0;
}
And then I have a class deriving from the SuperClass (like a specialization) with some more specific properties and methods and of course the virtual methods implementations and stuff:
class DerivedClass : public SuperClass {
Q_PROPERTY(QString someSpecificProperty READ someSpecificProperty WRITE setSomeSpecificProperty)
private:
QString m_someSpecificProperty;
public:
QString specificProperty(void){return m_someSpecificProperty;} //get method
void someSpecificProperty(QString newValue){m_someSpecificProperty = newValue;} //set method
QString printSomething(void){return QString("Something!");} //SuperClass virtual method
Q_INVOKABLE QString printSomethingSpecific(void){return QString("Something Specific!");}
}
OK, this is it! Now assuming that DerivedClass is instantiated and added to the QML context properly under the name of "DrvClass" for example and that I have some QML control like a TextField which has a 'text:' property:
text: DrvClass.someProperty
using MasterClass' properties, it works just fine.
text: DrvClass.printSomething()
even using virtual methods from MasterClass' which are implemented in the derived class works fine. but...
text: DrvClass.someSpecificProperty
doesn't work and I get something like "Unable to assign [undefined] to QString"
text: DrvClass.printSomethingSpecific()
also doesn't work! "TypeError: Property 'printSomethingSpecific' of object SuperClass() is not a function" And the weird part is that it says that it's not a function from the SuperClass, being the instantiated class the Derived one!
I've looked for similar errors, but most of the time is from people who just forgot to include the Q_OBJECT macro... Mine's there for sure!
It seems that QML doesn't like much classes deriving from other classes that derive from QObjects :-/ Probably something to do with the meta-object compiler who only looks for invokable methods where it finds the Q_OBJECT macro and not on it's subclasses!
So what you guys think the solution for this might be?
I could just add the Q_OBJECT macro to the DerivedClasses instead of the SuperClass, but I really need the SuperClass to be a QObject because of signals and stuff! So is there some other macro I have to add to the DerivedClass for the moc to 'see' it?
Or is this just the fruit of inexperience and I'm doing a dumb mistake somewhere?
DerivedClass is missing Q_OBJECT macro (it is not inherited!).
Then simply run qmake again on your project & compile: it should work.
For ex. I got:
"wrapper.h"
class wrapper : public QWidget
{
Q_OBJECT
public:
Wrapped_class m_class;
private:
QTimer* m_timer;
}
"Wrapped_class.h"
class Wrapped_class
{
public:
Wrapped_class();
public slots:
f(); // slot which is called when m_timer send signal timeout()
}
"Wrapped_class.cpp"
Wrapped_class::Wrapped_class()
{
QOBject::connect(wrapper::m_timer, SIGNAL(timeout()), this, SLOT( f()))
}
I get error that wrapper::m_timer in not accessible
You need a pointer or reference to the class to access it's non static members. Pass a pointer to the wrapped class when it's being wrapped
add something like this to your Wrapped_class:
void Wrapped_class::setWrapper(wrapper *w)
{
m_wrapper = w;
}
and call this function when the object is being wrapped. Initialize m_rapper to nullptr in constructor
Depending on your intent and the design of your system, you can choose:
Pass a pointer or reference of "wrapper" class to "wrapped" class. Be ware, you have to define wrapper class as a friend in order to access private member.
Write a member function of "wrapper" class to deal with the interaction between two classes. (This does not really conform to your restriction, but it is a design alternative.)
m_timer is not a static member so you cant access it like that. In Wrapped_class.cpp you need the instance of wrapped class to use it
Besides the problem with wrapper::m_timer not being static, it is also private which means that Wrapped_class can't access it. You need to make Wrapped_class a friend of wrapper for it to access private members.
I am trying to implement a QToolBar subclass, which has its items specified by a model, instead of added individually. This means a selection of functions to add/remove items (toolbar buttons), such as addAction shouldn't be publicly accessible.
What is the best way to inherit from this object, but make a selection of functions private?
My current best idea is to do like this:
class ToolbarView : public QToolBar
{
Q_OBJECT
public:
explicit ToolbarView(QWidget *parent = 0);
signals:
public slots:
private:
void addAction (QAction *action) {Q_UNUSED(action)};
QAction* addAction (const QString &text) {return QToolBar::addAction(text) ;}
...
QAction* addSeparator() {QToolBar::addSeparator();}
... [list of about 10 of these]
};
So, redefining all the functions that should not be public, as private.
Is this a good idea, or are there better methods?
As long as you inherit publicly from QToolBar, you make it possible for a client code to treat your object as such and call for example the addAction member function. If you want to ensure that these functions are inaccessible, you'll have do this the other way :
Inherit privately from QToolBar
Publicly expose the functions you wish to expose (for example with using declarations)
If you want to stick with your initial solutions and inherit publicly from QToolbar :
Be aware that it doesn't guarantee base class functions won't be called
You should consider using using declarations to change the accessibility of the base class functions instead of hiding them
Maybe you could think of this
class ToolbarView : private QToolBar
{
//...
}
In such case, all of accessible QToolBar will be with private access in your ToolbarView .
You are publically inheriting from QToolbar. How about changing that to private inheritance. That, is the class definition should begin as
class ToolbarView : private QToolBar
{
// good only if you want to
// make "most" of the public members of QToolBar private in ToolbarView
}