Is there a way to effectively update CAN data in QML? - c++

Currently I am receiving CAN data in real time using socketcan API in main.cpp file.
I am constantly updating the data frame of CAN in one variable in main.cpp.
I want to express the gauge in real time by passing the variable containing the CAN data frame in main.cpp to the QML animation gauge.
I need to detect the change of the variable containing CAN data in QML in real time. I wonder if there is an effective way.
I tried to share data with QML using emit.
However, the function written by emit inside device-> connect (device, & QCanBusDevice :: framesReceived, [device] () {...} does not work.
When using it, I get the error
'this' cannot be implicitly captured in this context.
I looked up the error, but did not find the answer.
if (QCanBus::instance()->plugins().contains(QStringLiteral("socketcan"))) {
qWarning() << "plugin available";
}
QString errorString;
QCanBusDevice *device = QCanBus::instance()->createDevice(
QStringLiteral("socketcan"), QStringLiteral("vcan0"), &errorString);
if (!device) {
qWarning() << errorString;
} else {
device->connectDevice();
std::cout << "connected vcan0" << std::endl;
device->connect(device, &QCanBusDevice::framesReceived, [device]() {
QCanBusFrame frame = device->readFrame();
QString testV = frame.toString();
QString qvSpeed = frame.payload();
std::string text = testV.toUtf8().constData();
std::string vSpeed = qvSpeed.toUtf8().constData();
//At that point the vVal values ​​are being updated in real time.
//I want to pass the updated vVal to qml gui in real time.
int vVal = static_cast<int>(frame.payload()[0]);
//emit sendMessage(vVal); // 'this' cannot be implicitly captured in this context error.
std::cout << text << std::endl;
});
}
As of now, main.cpp can't send the data and QML can't solve the error.
Inside device-> connect, emit sendMessage (vVal); will cause "'this' cannot be implicitly captured in this context" error.
I'm wondering if there is a good way to implement animation by expressing QML GUI data in real time.

Your capture clause only captures device. You need to also explicitly capture this:
device->connect(device, &QCanBusDevice::framesReceived, [this,device]{ /*...*/ });
BTW, note that there's no need to specify the () for a no-args lambda expression.

Related

I want to get the names of my spinboxes in Qt

How can I pull the names of my spinBoxes? I tried looking at a lot of the documentation, however, I couldn't find anything that would show the names of each of the child spinBoxes. I've tried changing the result to a string. However, I just get a Hex or Long Int, of the address I’d imagine, returned instead.
QList<QSpinBox*> spinBoxes= findChildren<QSpinBox*>();
//create the QSignalMapper object
QSignalMapper* signalMapper= new QSignalMapper(this);
//loop through your spinboxes list
QSpinBox* spinBox;
foreach(spinBox, spinBoxes){
//setup mapping for each spin box
connect(spinBox, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
signalMapper->setMapping(spinBox, spinBox);
}
//connect the unified mapped(QWidget*) signal to your spinboxWrite slot
connect(signalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(spinboxWrite(QWidget*)));
.
.
.
void GuiTest::SpinBoxChanged(QWidget* wSp){
QSpinBox* sp= (QSpinBox*)wSp; //now sp is a pointer to the QSpinBox that emitted the valueChanged signal
int value = sp->value(); //and value is its value after the change
//do whatever you want to do with them here. . .
qDebug() << value << "SpinBoxChanged";
}
void GuiTest::spinboxWrite(QWidget* e){
SpinBoxChanged(e);
QString* value = (QString*)e;
qDebug() << e << value << " SpinBoxWrite";
}
Please note qDebug() << e as this is where I'm having trouble getting some information about the spinboxes
The name you are trying to retrieve is the objectName property, which every QObject and QObject-derived class has. Call objectName() to retrieve this value.
You can also use this with the QObject::findChild() function.
This should get what you want:
void GuiTest::spinboxWrite(QWidget* e){
SpinBoxChanged(e);
qDebug() << e->objectName() << " SpinBoxWrite";
And will output:
"norm_spinBox_10" SpinBoxWrite
Note
This line is dangerous:
QSpinBox* sp= (QSpinBox*)wSp;
Use qobject_cast instead of C-style casts.
There is no direct way to get the name of a variable as a string.
However, you can use a QMap<QSpinBox*, QString> to map each spin-box to its name.
In the constructor you have to assign these manually:
map[ui->spinBox] = "spinBox";
map[ui->spinBoxWithStrangeName] = "spinBoxWithStrangeName";
Then you can simply get the strings using:
QString name = map[ui->spinBox];
Just give them names in the designer file and then use that name to retrieve them in the C++ code.
QSpinBox* mySpinner = findChild<QSpinBox*>("myGivenName");

Qt c++ Increasing integer with pushButton to label

I'm trying to make a simple "Cookie Clicker" game and I'm having trouble with this. When I press the button I want the label to print out "You have mined (VALUE) FSCoins" but the label won't update for some reason. Console shows no errors :(
Here's my code:
mainwindow.cpp
void MainWindow::on_pushButton_clicked(int num, int numplus)
{
num = numplus + 1;
QString qstr = QString::number(numplus);
ui->label->setText("You have mined " + qstr + " FSCoins");
}
Any help would be appreciated, I've only started working with Qt yesterday and I'm "Sort of" getting the hang of it.
num = numplus + 1;
What is the point of this line? num is a local variable that is never used. Did you mean to pass it by reference?
You need to connect a SIGNAL to a SLOT, but that function you wrote there does not seem like a SLOT. Somewhere in your code there shall be something like this in your header file:
class ...
{
// ...
private slots:
void onPushButtonClicked();
};
and in your source file:
// For example in the constructor.
connect( ui->PushButton, SIGNAL( clicked() ), this, SLOT( onPushButtonClicked() ) );
// The implementation of your SLOT.
Class::onPushButtonClicked()
{
// Your implementation.
updateLabel( /* Your arguments */ );
}
The SLOT function cannot have more arguments than the SIGNAL, so in this case your SLOT cannot have any.
And something else. I prefer this version of creating a QString:
QString( "You have mined %1 coins" ).arg( value );
I think it's more readable.
So the point is that that you need store that integers somewhere. Maybe in your class as a member variable.

How to disable next button in QWizard

What I'm trying to do
I am trying to create a subclass of QWizardPage that looks somewhat like this,but has a slight tweak. I want to disable the next button when a counter variable is more than 0. (It can't be 0 from the get-go due to some functionality that requires it to go x..x-1...0).
What I've tried
Reimplement isComplete() and emit completeChanged() in the constructor
bool DemoWizardPage::isComplete()
{
return ! (counter > 0); //Also tried just return false;
}
Reimplement initializePage and disable the next button from there
void DemoWizardPage::initializePage()
{
qDebug() << "QWizardPage:: initialize page";
if (!this->isComplete())
{
qDebug() << "try to turn off next button";
wizard()->button(QWizard::NextButton)->setDisabled(true);
qDebug() << "next button enabled? "
<< wizard()->button(QWizard::NextButton)->isEnabled();
}
}
Results so far
From stepping through the code I can see that the next button is disabled when the page loads. But then it is enabled again due to these 2 lines in QWizardPrivate (taken from qwizard.cpp)
bool complete = page && page->isComplete();
btn.next->setEnabled(canContinue && complete);
I am quite baffled as to why isComplete() is returning true here. I mean, I set my counter to be 2 at the beginning and I never decrease it. (And yes, I do emit a completeChanged() whenever I set the counter).
Any ideas?
QWizard automatically manages the state of Next button based on the QWizardPage::isComplete(), you should not implement that functionality yourself in initializePage(). The reason your isComplete() is not being called is that it doesn't actually overwrite QWizardPage::isComplete const from QWizardPage. Declare your function const and it will properly overwrite the original function.

(Qt C++) Send int value from dialog to MainWindow?

I am quite new to C++ and Qt. I've gotten pretty far on my current project, but I've been putting off this one part. I have a pushbutton that opens a new dialog like this:
void MainWindow::on_fillAll_clicked()
{
int yo;
BlockSelect bSelect;
bSelect.setModal(true);
bSelect.exec();
if( bSelect.exec() == QDialog::Accepted )
{
//Get stuff here?
//I want to fill yo with the spinbox value
yo = bSelect.stuff();
return;
}
qDebug() << yo;
}
This works fine. In the dialog I have a spin box. I want to send that value inputted to the spin box to my main window when the user clicks OK.
I have been trying to get "int yo;" to have that value from the spinbox but everything I try just gets an error.
I added this to my BlockSelect public class:
int stuff();
And I made this function in my blockselect.cpp:
int BlockSelect::stuff()
{
qDebug() << "The function was called";
return ui->yolo->value();
}
But qDebug never shows anything???
So how can I fill yo from the main window with yolo from the dialog?
Sorry if I didn't explain this well :( I'm still learning.
Thanks for your time :)
First of all, there is no need to call exec() twice, just use it once within the if statement.
To answer your question, you still have the bSelect dialog object (and I'm assuming BlockSelect is a class you define?), so make an accessor function inside it to retrieve the values you want.
if( bSelect.exec() == QDialog::Accepted )
{
//Get stuff here?
//I want to fill yo with the spinbox value
yo = bSelect.stuff();
return;
}
EDIT:
Your BlockSelect class needs to contain an accessor function, this means a function that returns a value.
int stuff() { return ui->yolo->value();}
What I'm doing here is retrieving the spinbox's value (assuming it is named 'yolo') and returning it as a result of calling the 'stuff' function.

Get target of cascades TouchEvent not working

I'm having problems trying to reach for the target of the Touch Event from BB10 cascades API. I have several containers, one below the other, and each one of them have the same Touch signal and slot assigned. Everything is being dynamically loaded from C++. So, in order to catch each touch event, I need to know which container triggered the event. I've read that I just need to use the TARGET property from the TouchEvent, but is not working and I dont know why. So I'm asking for help
Here's my code:
for (int i = 0; i < 10; i++) {
QmlDocument *qml = QmlDocument::create("asset:///customComponents/TableRow.qml").parent(this);
Container *passivesRow = qml->createRootObject<Container>();
passivesRow->setProperty("labelTextOne", "Hello_" + i);
bool res = QObject::connect(passivesRow,
SIGNAL(touch(bb::cascades::TouchEvent*)), this,
SLOT(handleAccountTouch(bb::cascades::TouchEvent*)));
Q_ASSERT(res);
Q_UNUSED(res);
myCurrentPageContainer->add(passivesScroll);
}
void PosicionConsolidada::handleAccountTouch(bb::cascades::TouchEvent* event) {
if (event->touchType() == TouchType::Up) {
qDebug() << "event catched";
VisualNode *p = event->target();
qDebug() << "object p: " << p->property("labelTextOne"); //Print nothing
}
}
Everything else is working just fine. My list of Containers is being created fine with their respective texts. When I click one of them, the event is being catched successfuly. I also tried to cast the VisualNode object to Container and it didn't work either. Please help!.
I would advice you an alternate approach which I used before. You can set objectName of control like this:
passiveRow->setObjectName("Hello_" + i");
QObject::connect(passiveRow, SIGNAL(touch(bb::cascades::TouchEvent*)), this,
SLOT(handleAccountTouch(bb::cascades::TouchEvent*)));
& in SLOT using it you can know which control emitted the signal:
if (event->touchType() == TouchType::Up) {
qDebug() << "object: " << QObject::sender()->objectName();
}
Here, sender() returns the control which emitted the signal.
In the API reference, there is no onTouch signal for the container.
On the contrary of other element like CustomControl
I do not know how your signal was successfully connected to your slot, but I guess that it was propagated from another component inside the container. So the target may be a Label or something else inside it.