Error passing custom Object from QtScript to C++ - c++

I have written a custom class which is available in QtScript through a Prototype. Also another global class is available which should be used to print the custom class generated in QtScript.
This is my custom class (very simple ;) ):
class Message
{
public:
int source;
int target;
};
This is the prototype I am using:
class MessagePrototype : public QObject, public QScriptable
{
Q_OBJECT
Q_PROPERTY(int source READ getSource WRITE setSource)
Q_PROPERTY(int target READ getTarget WRITE setTarget)
public:
void setSource(const int source);
int getSource() const;
void setTarget(const int target);
int getTarget() const;
};
The setter / getter are only changing / printing the corresponding Message object through a qscriptvalue_cast(QScriptable::thisObject());
Now my script looks like this:
var test = new Message;
test.source = 5;
print(test.source);
GlobalObject.sendMessage(test);
So, the script compiles fine and the print() command does what it should, it prints 5. But the problem is the sendMessage function of my GlobalObject:
void MessageAnalysis::sendMessage(Message msg)
{
qDebug() << "[Message]" << msg.source << msg.target;
}
This piece of code always prints: "[Message] 0 0".
MessageAnalysis is registered as "GlobalObject" for QtScript. Also I have registered Message and Message* as Metatypes and the constructor, prototype and everything else. This seems to work.
Does anyone knows why the values have been changed in QtScript but are not accessible from my C++ function? Or what I am doing wrong?

Ok. After several attempts I fixed it.
I changed the sendMessage function to accept a QScriptValue instead of a Message as parameter. Now I can get the properties out of it without problems.
Seems to work fine now :)

Related

Initializing a new nested class from outer class function

I'm currently learning nested classes in C++ while building a project and I currently inside setupBLE() I need to pass one of the nested classes but to init that new class I need to pass to its constructor the outer class so it can access its variables and functions but I'm not exactly sure how to pass to the constructor the pointer of the class that's trying to create it.
It's a bit confusing so I hope the code helps with it.
Like in python we have self but in C++ as far as I know we don't have that so I was wondering what should I pass to the constructor.
Code (PillDispenser.h):
class PillDispenser {
public:
explicit PillDispenser(BLEAddress deviceAddress);
private:
BLEAddress _device_address;
BLEAdvertisedDevice _device;
bool _connected;
// Device properties
std::string _device_name;
// Callbacks
static void notifyCallBack();
class AdvertisedDeviceCallBack : public BLEAdvertisedDeviceCallbacks {
PillDispenser &_outer;
explicit AdvertisedDeviceCallBack(PillDispenser &outer) : _outer(outer){};
void onResult(BLEAdvertisedDevice advertisedDevice) override;
};
}
Code (PillDispenser.cpp):
void PillDispenser::setupBLE() {
BLEScan *scanner = BLEDevice::getScan();
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack());
scanner->setInterval(SCAN_INTERVAL);
scanner->setWindow(SCAN_WINDOW);
scanner->setActiveScan(true);
scanner->start(SCAN_DURATION);
}
Issue:
This line is trying to use the default constructor which does not exist
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack());
instead you should use the explicit constructor you defined
scanner->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallBack(*this));
note that this (in this context) has type PillDispenser* so you have to dereference with * to get a PillDispenser&

How to mock a class within a function that I'm trying to test?

I am trying to test a function like below within Provider.cpp,
SomeType::Data Provider::getData()
{
const Param param();
SomeType wanted_data = SomeType::Data(Creator{}(param));
return wanted_data;
}
But that Creator creation in getData() makes testing this function difficult.
FYI, Provider.h is like
class Provider {
public:
SomeType::Data getData();
// constructor/destructor
Provider(System& system);
~Provider();
private:
System& m_system;
};
While Creator has the following in Creator.h
class Creator {
public:
//operator function overload?
virtual SomeType::Data operator()(Param param) {
SomeType::Data data = ...;//create data
return data;
}
// constructor/destructor
Creator();
virtual ~Creator(){};
};
I looked up for hours, and it seems like mocking a creation of an object within a function seems not possible. If I still wanna test this function and create an the DataCreator object whenever I call getData(), how can I get it done? (if it's possible...)
I read on google saying something like you can use pointer or reference in the constructor in such case, but I am not sure what it means... :'(

Anonymous inner class in C++ (Java-style listener)

My C/C++ skills are a bit rusty, and I've mostly been working in Java for the past few years. Now I just started playing around with Arduino, and made a simple button class. I want to add an event listener, so I did something like this:
class MyButton{
public:
MyButton(byte pin);
bool isPressed();
bool wasToggled();
bool wasPressed();
void eventLoop();
inline void setListener(MyButtonListener* listener) { _listener = listener; }
private:
byte _pin;
boolean _lastToggledState = false;
MyButtonListener* _listener;
};
class MyButtonListener{
public:
virtual void onPressed() = 0;
private:
};
The eventLoop() method (which is intended to be called from the Arduino loop() function ), invokes the onPressed() method in the listener class:
void MyButton::eventLoop(){
if( wasPressed() && _listener ){
_listener->onPressed();
}
}
So far, things are okay. But I can't figure out how to actually assign and use the listener in the main Arduino file. Coming from Java, I'm used to just doing something like
myBtn.setListener( new MyButtonListener(){
void onPressed(){
Serial.println("Pressed");
toggleLed(); // toggleLed() is a method in the main Arduino file
}
});
I got it to work in a very convoluted way, by declaring a new class which takes the toggleLed() method as an argument (because it can't be accessed from within the new class otherwise):
class BtnListener : public MyButtonListener{
public:
BtnListener(void* toggleFunction) : _toggleFunction(toggleFunction){ };
private:
void (*_toggleFunction)();
void onPressed(){
Serial.println("Pressed");
_toggleFunction();
};
};
myBtn.setListener( new BtnListener(toggleLed) );
Surely there must be a more convenient way of doing something like this in C++? It's doable (but ugly) with one listener - I can't even imagine the horror of having 10 buttons which all need different listener implementations...
In your case, one or the simplest methods would be to store the listener as a std::function<void()> and don't have an actual class to model the buttonlistener at all (you can still have that if you really want to encapsulate that, but it's not neccesary). Then use a lambda function to the setListener call, something like this:
myBtn.setListener( [this]{
Serial.println("Pressed");
toggleLed(); // toggleLed() is a method in the main Arduino file
});
Since the Arduino IDE by default doesn't seem to include <functional.h>, I wasn't able to use the answer using std::function<void()>. However, after some experimenting I realized there was an easier way, which also has the benefit of being able to model the listener.
The listener class simply contains function pointers to each listener callback function, and a constructor that takes an argument for each callback. Then it's very convenient to just create a new instance of the listener class and pass each callback as a lambda.
class MyButton{
public:
inline void setListener(MyButtonListener* listener) { _listener = listener; }
private:
MyButtonListener* _listener;
}
class MyButtonListener{
public:
MyButtonListener(void* onPressed, void* onToggled) : onPressed(onPressed), onToggled(onToggled) {};
void (*onPressed)();
void (*onToggled)();
};
void MyButton::eventLoop(){
if( _listener ){
if( wasPressed() ){
_listener->onPressed();
}
if( wasToggled() ){
_listener->onToggled();
}
}
}
myBtn.setListener(
new MyButtonListener(
// onPressed
[](){
Serial.println("Pressed");
toggleLed();
},
// onToggled
[](){
Serial.println("Toggled");
}
)
);
Not sure if there are any drawbacks with this solution, but it works, is readable and is fit for use on Arduino.

Understanding Exposing Attributes of C++ Types to QML

I wanted to write a pretty simple code which looks for a string and then outputs the variable assigned to it.
I wanted to learn more about the communication between C++ and QML. So I thought of using a hash map in C++ and then use those functions in QML to list out the result.
I had lot of errors so I basically tried everything to make it work and now my code works. But can someone help me in understanding what I have done.
I have few doubts
I was not able to access my functions loadItemList() and findcubby() but as soon as I included the Q_OBJECT Macro it started working why ?
I have seen in some codes online that they often use something like explicit Itemlist(QObject *parent = 0); why and what does this mean?
I have defined my Hash map as public variable which I know is not good, can someone show me how would I go about for a private hash map.
Here is my header file
#ifndef ITEMLIST_H
#define ITEMLIST_H
#include <QObject>
#include <QHash>
class Itemlist : public QObject
{
Q_OBJECT
public:
Itemlist();
Q_INVOKABLE int find_cubby(QString);
QHash<QString, int> my_itemlist;
};
Here is cpp file
#include "itemlist.h"
Itemlist::Itemlist()
{
my_itemlist["aaaa"]=1;
my_itemlist["bb"]=1;
my_itemlist["cc"]=1;
my_itemlist["dd"]=1;
my_itemlist["ee"]=2;
my_itemlist["ff"]=2;
my_itemlist["gg"]=3;
my_itemlist["hh"]=3;
my_itemlist["ii"]=3;
}
int Itemlist::find_cubby(QString Name)
{
if(my_itemlist.contains(Name))
{
return my_itemlist.value(Name);
}
else
{
return 4;
}
}
Q_OBJECT is necessary as it serves as a marker for the moc code generator to create runtime introspection data for the class. Features such as properties or Q_INVOKABLE depend on that mechanism.
explicit is a C++ key word that marks a constructor as not available for implicit type conversions. Generally, constructors that can be called with a single argument can be used by the compiler to convert between the argument type and the class of that constructor.
E.g.
class Foo
{
public:
Foo(int i) {}
};
void doSomething(Foo f) {}
doSomething(5);
The compiler has an integer, 5, and needs a Foo object. There is a constructor for Foo that takes an int, so it can use it for an automatic type conversion.
explicit Foo(int i) {} removes that option, so the compiler will exit with an error, saying that it can't find a doSomething(int) function.
Use a private: section in your class just like you currently do with public:

C++ Calling a getter method when it is not ready

I'm working on a project and it works but it is really messy so I am trying to clean it up by moving things around.
Here is a short version of the class containing the getter method
Link::Link
{
jsonUrl = QUrl("www.example.json");
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(downloadFinished(QNetworkReply*)));
QNetworkRequest request(jsonUrl);
nam->get(request)
}
void Link::downloadFinished(QNetworkReply *reply)
{
jsonArray = reply->readAll();
jsonStuff();
}
void Link::jsonStuff()
{
//does a bunch of json stuff then gets a string
string = map["url"].toString();
}
QString Link::getString()
{
return string;
}
Here is a short version of the class that calls the getter in the constructor
Header
class Commands
{
private:
Link link;
}
Source inside the constructor
Commands::Commands()
{
addCommand("!test", link.getString());
}
The problem is when I try to do it like this, I think the Commands constructor runs first and the string from the Link class is not ready yet so the string that comes out of link.getString() is empty. Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands? Not sure if this matters but most of my code is written in Qt
I hope you guys can understand what I'm trying to ask. My terminology is really poor.
Edit: Added more to my Link class
When the constructor of Commands (in this case Commands()) is called firstly it creates all variables(they are unintialized) in Commands class. That being said link is created via Link(). What you might want to do is to use jsonStuff() in the Link() constructor (it creates all member variables as well as), NOTE THAT it creates variables in this case it creates string with base costructor - it creates empty string.) Try following to fill the string:
Link() {
jsonStuff(); // string will be set
}
Or you can initialize it via initialization section:
Link() : string("Text") { }
Also you might want to return reference to string from getString() function. Reference means it doesn't create additional copy and it returns string which is stored in Link, so you can change string in a function where getString() is called. Also if it is read only you should use const reference.
Is there a way to wait until the Link class finishes doing it's stuff and fills up the string before calling link.getString() inside the constructor of Commands?
Certainly. The Link class must be a QObject that emits a signal when it has changed its properties - presumably based on the replies it got to its network request.
class Link : public QObject {
Q_OBJECT
Q_PROPERTY(QString string READ string WRITE setString NOTIFY stringChanged)
QString m_string;
public:
void jsonStuff() {
...
connect(reply, &QNetworkReply::finished, this, [this]{
...
setString(map["url"].toString());
});
}
void setString(const QString &s) {
if (m_string == s) return;
m_string = s;
emit stringChanged(m_string);
}
QString string() const { return m_string; }
Q_SIGNAL void stringChanged(const QString &);
};
You can then add the command when the link is ready:
Commands::Commands()
{
connect(&link, &Link::stringChanged, this, [this](const QString &string){
if (!string.isEmpty()) addCommand("!test", string);
});
}