I am trying to propagate Q_GADGET as a Q_PROPERTY into QML, change it there and pass it back into C++.
I have class that derives from Q_OBJECT, which has the Q_GADGET class as a member.
class Foo : public QObject
{
Q_OBJECT
Q_PROPERTY(QGadgetClass bar READ bar WRITE setBar NOTIFY barChanged)
public:
...
QGadgetClass bar() const { return bar_; }
void setBar(const QGadgetClass &bar) { bar_ = bar; emit barChanged(); }
...
signals:
void barChanged();
private:
QGadgetClass bar_;
}
The Q_GADGET class looks like this:
class QGadgetClass
{
Q_GADGET
Q_PROPERTY(AnotherQGadgetClass test READ test WRITE setTest)
... // there are also properties ID & name
public:
...
// QGadgetClass getMyself() const { return *this; } // function explained later
AnotherQGadgetClass test() const { return test; }
void setTest(const AnotherQGadgetClass &test) { test_ = test; }
...
private:
AnotherQGadgetClass test_;
}
Q_DECLARE_METATYPE(QGadgetClass)
I am trying to access Q_GADGET from QML classic way like accessing a Q_OBJECT, but the setters are not called. If I get AnotherQGadgetClass via getter and change it's properties, the setters are called and everything works, but for some reason I cannot manipulate the QGadgetClass. My code in QML looks like this:
Item {
property var bar: foo.bar
function changeBar()
{
console.log(bar.name) // works
console.log(bar.id) // works
bar.name = "New name" // the WRITE function of Q_PROPERTY(name ...) is not called
console.log(bar.name) // shows old name
console.log(bar.test) // prints out AnotherQGadgetClass correctly
var temp = bar.test // copies AnotherQGadgetClass correctly
console.log(temp.name) // prints AnotherQGadgetClass's name
temp.name = "New temp name" // setter is called
console.log(temp.name) // prints new name
bar.test = temp // constructor is NOT called
console.log(bar.test) // prints out old AnotherQGadgetClass
// following code works and will be explained bellow this code
var aa = bar.getMyself() // calls the "hackish" method
console.log(aa.name) // prints out name of QGadgetClass
aa.name = "New name" // calls the setter
console.log(aa.name) // prints out new name
}
}
I have done some research already, but found nothing but this page. I have also found some very unpretty solution here and it worked, but I find it very hacky.
Note that every Q_GADGET is declared as metatype via Q_DECLARE_METATYPE(...) & is registered before usage via qRegisterMetaType<...>("...").
Is there any prettier solution to access QGadgetClass directly from QML, without need to call getMyself() method? Why are the Q_GADGET class setters not called?
A Q_GADGET is always treated as a value type in QML: it must be passed by copying. So the object that you manipulate in QML is not the same instance that you created in C++, and property changes aren't visible in the original. Many related issues are linked from https://bugreports.qt.io/browse/QTBUG-82443
Related
I have a simple class that looks like this:
class QNetworkAccessManager;
class FontiDownloader : public QObject
{
Q_OBJECT
public:
FontiDownloader(QNetworkAccessManager* netManager);
void downloadFonti();
private:
QString m_dataLocation;
};
The implementation of downloadFonti() is something like the following:
// the networkrequest is just a wrapper that makes a QNetworkRequest
auto nr = new NetworkRequest(m_netManager, this);
connect(nr, &NetworkRequest::completed, [this](QNetworkReply* reply){
// crash occurs here
QString dataLocation = m_dataLocation;
});
nr->send(QUrl(FONTI_URL), HttpMethod::GET);
When I call my lambda function inside downloadFonti(), the program crashes and I have located the reason to be the line:
QString dataLocation = m_dataLocation;
I can see using the debugger that at the time of calling that line, m_dataLocation is "not accessible". However, I cannot think why this would be the case.
I am using junit and mokito to write unit test of my java program.
public MyClass {
private ClassA a;
public void process(ClassB b) {
if(b.method()) a = ClassA.builder().build();
}
}
Now I have write a MockClassA and MockClassB. But I don't know how to :
Pass a MockClassB instantiation to process function
How to verify whether private variable a is set successfully
Can anybody help?
You can use something like:
#Test
public void shouldDoSomething() {
// given
ClassB mock = Mockito.mock(ClassB.class);
Mockito.when(mock.method()).thenReturn(true);
MyClass classUnderTest = new MyClass();
// when
classUnderTest.process(mock);
// then
// Insert assertions
}
However, if your field is private you are unable to test it properly. You should provide a getter for this field if you want to make some assertions against it.
But remember that internal representation of MyClass should not be tested, only the behavior of it so maybe you want to try different approach
I'm sorry if I don't know the right word for what I'm trying to accomplish.
Basically I have an event handler object which only has a single member. The member is a Stage object.
When the event handler receives an event, I want it to simply use the stage object to call the relevant method. For example:
Event event; //this event is not part of my code, but rather the library I'm using.
Stage s; // my custom class object
EventHandler event_handler; //also my custom class object
event_handler.stage = &s;
if(event == SHUTDOWN) {
event_handler.stage->handle_shutdown();
}
So what I'm trying to accomplish is that, there will be seperate scopes that my program goes into over time, and I want each scope to have access to the event_handler such that they can do something like:
void some_other_scope(EventHandler* eh) {
Stage* some_new_stage = new Stage(...);
eh->stage = some_new_stage;
}
This way, the original event code stays the same, and the event handler will be calling handle_shutdown on a different object than it was originally going to.
So what I want to do is to overload the handle_shutdown method so that there can be different implementations of it. I know how basic overloading works, it can be done by specifying different parameters, but is there any way to have different definitions of the same class method based on the file that the object was created in?
I was hoping to have several files, each with their own some_other_scope() function, and each file can redefine the handle_shutdown method to do different things based on what that file needs.
I'm sure there's a way to do what I want, I just don't know the right words to use.
It seems you want to use polymorphism:
class IStage
{
public:
virtual ~IStage() = default;
virtual void handle_shutdown() = 0;
// ...
};
class Stage1 : public IStage
{
public:
void handle_shutdown() override { /*Implementation1*/ }
// ...
};
class Stage2 : public IStage
{
public:
void handle_shutdown() override { /*Implementation1*/ }
// ...
};
And then
struct EventHandler
{
std::unique_ptr<IStage> stage;
// ...
};
EventHandler event_handler;
event_handler.stage = std::make_unique<Stage1>();
if (event == SHUTDOWN) {
event_handler.stage->handle_shutdown();
}
// Later
event_handler.stage = std::make_unique<Stage2>();
if (event == SHUTDOWN) {
event_handler.stage->handle_shutdown();
}
I am working on a simple app to demonstrate integration of C++ with QML but I have problems. In nutshell I want to create a C++ object in qml on fly and pass it to C++ for processing. Here is my code.
import QtQuick 2.4
import QtQuick.Window 2.2
import test 1.0
Window {
visible: true
MainForm {
anchors.fill: parent
mouseArea.onClicked: {
console.log("clicked")
var student = Qt.createComponent("Student")
student.name = "Hello frome QML";
console.log( student.name ) // good
school.addStudent( student )
}
}
}
Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
QString m_name;
public:
explicit Student(QObject *parent = 0);
~Student();
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
QString name() const
{
return m_name;
}
signals:
void nameChanged(QString arg);
public slots:
void setName(QString arg)
{
if (m_name == arg)
return;
m_name = arg;
emit nameChanged(arg);
}
};
#endif // STUDENT_H
Now when I addStudent() to the school class, there is where there is trouble. The concern .cpp file below.
#include "school.h"
#include <QDebug>
School::School(QObject *parent) : QObject(parent)
{
}
School::~School()
{
}
// why does this not work? it cause compiler error..can't access private members of QObject
//void School::addStudent(Student student)
//{
//// students.append( &student );
//// qDebug() << "added";
//// qDebug() << student.name();// << " was added to school";
//}
void School::addStudent(Student * student)
{
students.append( student );
qDebug() << "added";
qDebug() << student->name();// if this line is there, it breaks the application
}
The questions are also in comments inside the code but the summaries:
Why does addStudent() crashes when I try to access student.name? I can access it though in the qml file after I set it.
Why does my project not compile if I pass Studentby value like seen in the code?
Additional thoughts
It seems like it may have to do with the C++ object getting destroyed by the time C++ function execute. What is the life cycle of C++ object created in QML? When does it gets destroyed? Could the lifetime of the object be an issue here?
Assume that you register the Student type to QML via qmlRegisterType in cpp file.
In your QML, Qt.createComponent("Student") does not create a Student object but a QQmlComponent. Try to set properties other than name and it still works since the object is not a Student. Instead, you should create an object from a pre-defined component via Component.createObject:
MainForm {
id: mainForm
mouseArea.onClicked: {
var student = studentComponent.createObject(mainForm);
student.name = "Hello frome QML";
school.addStudent( student );
}
Component {
id: studentComponent
Student{}
}
}
And everything works fine now.
Back to your code,
//QML
var student = Qt.createComponent("Student")
student.name = "Hello frome QML";
console.log( student.name ) // good
No, it's not good. student.abcdefg = "Hello from QML" works, too. Add console.log(student) and you can see that student is not a Student.
Why does addStudent() crashes when I try to access student.name? I can access it though in the qml file after I set it.
It crashed since the object passed from QML is not a pointer Student. QML engine passes a null pointer to this function. What you accessed in QML is not a Student.
Why does my project not compile if I pass Student by value like seen in the code?
Because Student is an QObject, which is not copyable. Pass by pointer instead.
What is the life cycle of C++ object created in QML? When does it gets destroyed? Could the lifetime of the object be an issue here?
The lifetime is not a issue in your QML since what you created is a component, not an object. When creating Student object in this answer,
var student = studentComponent.createObject(mainForm);
the newly created object sets mainForm as it's parent. The object won't be deleted until mainForm is released. Except you delete it explicitly.
Try moving the declaration of the function QString name() const in the declaration of class Student to before the Q_PROPERTY macro. Or specify "public:" again before the name function. The macro is resetting the access specifier to "private".
I need insert one object in the linked list when i clicked a button
but when i make instantiate the class List this shows me one error
public ref class Boletos : public System::Windows::Forms::Form
{
public:
Boletos(void)
{
Lista *List=new Lista;
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
//*****************Click_event**********************//
...
if (count==4){
Capacidad=Convert::ToInt32(line);
capc=Capacidad;
//sala->set_capacidad(Capacidad);
Sala *sala=new Sala();
List->insertAlFinal(newSala(numSala,HPeli,capc,"",2000,nombrePelicula));//Here the error List undefined
count=0;
}
u are placing your code at the wrong position, its so to say out of scope. Btw. this is not really c++, looks like c# ...
Try something like
Boletos(void)
{
Lista* list = new Lista();
InitializeComponent();
}
What u need is a class member.
public ref class Boletos ...
{
public:
....
void InitializeComponent()
{
m_lista = new Lista();
}
private:
Lista* m_lista;
}
now u can use m_lista in all the classes member functions. What u need to understand is the concept of scope. If u declare and intialize a variable only in the scope of one function this variable is so to say lost after the program leaves the scope of this function. In the case of c++ the dynamich alloaction new Lista() without a matching call to delete would even be a memory leak.