Qt pass variables between forms - c++

I want to pass a string from a form that is opened by the first form to the first form.
I am new to C++.
Here is my code.
Form1.h // main form
#include "dialog.h"
namespace Ui {
class Form1;
}
class Form1 : public QMainWindow
{
Q_OBJECT
public:
explicit Form1(QWidget *parent = 0);
~Form1();
void refresh(QString str_local);
private slots:
void on_pushButton_clicked();
private:
Ui::Form1 *ui;
Dialog *dialog1;
};
// form1.cpp
void Form1::on_pushButton_clicked()
{
dialog1= new Dialog; //Create new form with other class
dialog1->show();
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local))); //Connect when is emit signal cambia in the child form and pass the string to local function
}
void Form1::refresh(QString str_local)
{
qDebug() << "Back to main" << str_local;
ui->label->setText(str_local);
}
// dialog.h the second form that should pass the value to main form
...
class Dialog : public QDialog
{
Q_OBJECT
signals:
void change(QString s);
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog *ui;
};
// dialog.cpp
...
void Dialog::on_pushButton_clicked()
{
QString name;
name = ui->lineEdit->text();
emit change(name);
this->close();
}
I get the error:
No such signal Dialog::change(str_remote) in ../Format/form1.cpp:22 .

You have some strange code in here:
QObject::connect(dialog1, SIGNAL(change(str_remote)), this, SLOT(refresh(str_local)));
Since your class already inherits QObject indirectly, you can simply drop the scope specifier.
You probably aim for using the new compilation-time syntax signal-slot mechanism.
You have not marked your slot as slot in the header file.
You are trying to use the old signal/slot syntax with variable names for the signal and slot as opposed to the types.
Your signal is not using the good practice of const T& (i.e. constant reference).
You are specifying this explicitly, whereas it can be dropped. This is just admittedly personal taste.
You do not follow the Qt signal/slot naming convention, e.g. your signal is a verb rather adjective. It is also too generic, rather than "fooChanged" as the good practice goes.
There are other issues in your code as well, but this time I only focused on that one line. I would use this line with modern Qt and C++ programming principles in mind:
connect(dialog1, &Dialog::changed, (=)[const auto &myString] {
ui->label->setText(myString);
});
However, since this requires CONFIG += c++14, if your compiler does not support that (e.g. VS2010), you can go for this:
connect(dialog1, SIGNAL(change(const QString&)), this, SLOT(refresh(const QString&)));

Related

Monitoring file integrity

I would like to write a simple application that tells me when a file has been modified.
Does the <QFileSystemWatcher> class only monitor changes when the program is running?
If so, are there any other classes that I can use for file integrity monitoring?
You could run md5sum, etc. with QProcess initially and then for the changed signals and compare.
The alternative is to read all the file in or mmap and create your hash with QCryptoGraphicHash.
Either way, you would do this initially and then in the signal handlers, a.k.a. slots once the connection is properly made in your QObject subclass.
#include <QObject>
#include <QFileSystemWatcher>
class MyClass : public QObject
{
Q_OBJECT
public:
explicit MyClass(QObject *parent = Q_NULLPTR)
: QObject(parent)
{
// ...
connect(m_fileSystemWatcher, SIGNAL(fileChanged(const QString&)), SLOT(checkIntegrity(const QString&)));
// ...
}
public slots:
void checkIntegrity(const QString &path)
{
// 1a. Use QProcess with an application like md5sum/sha1sum
// OR
// 1b. Use QFile with readAll() QCryptoGraphicsHash
// 2. Compare with the previous
// 3. Set the current to the new
}
private:
QFileSystemWatcher m_fileSystemWatcher;
};
Disclaimer: This is obviously not in any way tested, whatsoever, but I hope it demonstrates the concept.

No matching signal for QAction, no "go to slot" menu entry

I have problem with actually running QActions created with QtCreator. To run e.g. actionSystemSettings, I've added slot to MainWindows so it looks like this:
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_menuWork_actionSystemSettings();
private:
Ui::MainWindow *ui;
};
And this:
void MainWindow::on_menuWork_actionSystemSettings() {
qDebug() << "Yay!";
}
It prompts:
QMetaObject::connectSlotsByName: No matching signal for
on_menuWork_actionSystemSettings()
I guess it's some dumb mistake and I just forgot about something but reading documentation gives me nothing. I have no "go to slot" menu entry which should auto-create some template... at least Visual Studio for C# did that.
When you're defining slots the correct way is:
on_<widget_name>_<signal>
for instance if you have to name your slot
private slots:
on_actionSystemSettings_triggered();
See QtAutoConnect
According to the documentation for QMetaObject::connectSlotsByName():
Searches recursively for all child objects of the given object, and
connects matching signals from them to slots of object that follow the
following form:
void on_object-name_signal-name(signal-parameters);
So, I think your slot should have the following signature:
void MainWindow::on_actionSystemSettings_triggered()
{
//
}

Change label text from another class using Qt signals and slots

I'm trying to change text of a class Label from another class. I have class MainWindow, which contains Label.
I also have a Bot class from which I wanna change the value of label.
I'm trying to create signal and slots but I have no idea where to start.
I created signal and slots like so:
//in mainwindow.h
signals:
void changeTextSignal();
private slots:
void changeText();
//in mainwindow.cpp
void MainWindow::changeText(){
this->label->setText("FooBar");
}
But I have no idea how to connect a signal to be able to change Label's text from another class.
Read up on Qt signal-slot mechanism. If I understand you correctly, you are trying to signal from Bot to MainWindow that the Label text needs to change. Here's how you do it...
//bot.h
class Bot
{
Q_OBJECT;
//other stuff here
signals:
void textChanged(QString);
public:
void someFunctionThatChangesText(const QString& newtext)
{
emit textChanged(newtext);
}
}
//mainwindow.cpp
MainWindow::MainWindow
{
//do other stuff
this->label = new QLabel("Original Text");
mybot = new Bot; //mybot is a Bot* member of MainWindow in this example
connect(mybot, SIGNAL(textChanged(QString)), this->label, SLOT(setText(QString)));
}
void MainWindow::hello()
{
mybot->someFunctionThatChangesText("Hello World!");
}

Create a custom slot in C++, Qt5

in python we write custom slots quite easily by passing in the function to be called when a signal is generated.
While in C++ connect function requires us to pass the address of the slot function or so i figured. How do i do that. I tried using this but did'nt work.
Python code::
class imviu(QtGui.QWidget):
def __init__(self):
super(imvui,self).__init__()
self.btn=QtGui.QPushButton('Browse')
btn.clicked.connect(self.openimg)
def openimg(self):
#do something
C++ code::
class imviu: public QWidget
{
public:
imviu(QWidget *parent=0);
QPushButton *btn=new QPushButton("Browse");
void openimg(void);
};
imviu::imviu(QWidget *parent)
:QWidget(parent)
{
connect(btn, SIGNAL(clicked()),this,SLOT(openimg()));//this does'nt work:QObject::connect: No such slot QWidget::openimg()
}
void imviu::openimg()
{
//do something
}
In order to use signals and slots, you need to have the Q_OBJECT macro in your class as well as identifying which functions should be the signals and the slots. Have a look at the documentation for a more in-depth explanation.
After this, you need to set up the project file so that MOC can generate the necessary code.
Your class definition should look like this:
class imviu: public QWidget
{
Q_OBJECT
public:
imviu(QWidget *parent=0);
public slots:
void openimg();
private:
QPushButton *btn;
};

Transfer data between forms in Qt

I have a school project where I am using Qt to drive my GUI interface. I need to know the best way or the easiest way to transfer a vector of class objects between the different .cpp files for the different forms. I was thinking of including the .h files and making a setPointer and getPointer that points to the vector, but is there a better way?
Thanks for the help
Let's assume that, you are using two forms. formA and formB.
Create a signal and slot in forma.cpp
public slots:
void receiveData(QVectorobjects);
signals:
void sendData(QVector);
Do the same for formb.cpp.
Now connect formA and formB like this.
connect(formA, SIGNAL(sendData(QVector<MyClass>)), formB, SLOT((receiveData(QVector<MyClass>)));
connect(formA, SIGNAL(receiveData(QVector<MyClass>)), formB, SLOT((MyClass(QVector<MyClass>)));
Now formA will share data (set of objects) when you write emit sendData(QVector() << objA << objB); and formB will catch it!
Enjoy the magic of signal and slot. :)
You should use custom signals and slots.
Your main window can connect signal and slot between each form.
In this way, you forms are independent of each other (i.e. doesn't need a pointer).
First of all, Qt container classes are implicitly shared, that means you can pass them by value, and only a shallow copy will occur. If you attempt to modify the container, then a new copy will be created. So there is no need to use pointers in that particular case.
Then, use signals and slot to do the actual data transfer - the common pattern is for the parent widget to manage its child widgets, and it is that parent class that the actual passing of data usually takes place.
The best way to transfer data between Qt-classes is to use signal/slot system.
Pay an attention, that if you want to transfer data with type differ from standard C++ and Qt, you should register it's type with qRegisterMetaType
Depending upon your usage, there can be at least two ways.
First is to create a public variable in your class (form) to which you can assign the current value of the vector (pointer) so that you can access it in that class.
Another option is to create a singleton class in the application and store the vector pointer inside that class. This will allow access to this class throughout the application.
Based on your requirement, if you want the vector to stay alive for the application life, you should opt the second option, otherwise opt the first option.
What about extern keyword? But Qt's signal slot is safe.
Use QVector or QList or any number of Qt's container classes. You can pass an iterator to your forms, or a reference (QList::operator[]) to the form so that you're not copying the data.
If you want to pass the whole vector, pass it as a reference. For example:
//pass the whole vector as for read-write
void doStuffOnMany(QList<MyClass>& listref) {} //declaration
...
QList<MyClass> mylist; //usage
doStuffOnMany(mylist);
//read-only
void doStuffOnMany(const QList<MyClass>& listref) {}
//pass one portion of the vector for read-write
void doStuffOnOne(MyClass& classref) {} //declaration
...
QList<MyClass> mylist; //usage
doStuffOnOne(mylist[0]);
Also, the Qt container classes are implicitly shared, so you don't even necessarily have to pass a reference to the vector if you need good performance.
I ended up using the extern keyword. I looked in to custom signals and slots and I think that it would be the better way to go, but given time and the fact that this is for school I went with the fast and dirty way for now.
Here is a simple explanation:
Take two forms:
Dialog windows
Dashboard and Sensor
on Dashboard:
#ifndef DASHBOARD_H
#define DASHBOARD_H
#include "sensor.h"
#include <QDialog>
namespace Ui {
class dashboard;
}
class dashboard : public QDialog
{
Q_OBJECT
public:
explicit dashboard(QWidget *parent = 0);
QTimer *timer;
~dashboard();
public slots:
void MyTimerSlot();
private slots:
void on_pushButton_clicked();
private:
Ui::dashboard *ui;
double mTotal;
sensor *snsr;
};
#include "dashboard.h"
#include "ui_dashboard.h"
#include <QDebug>
#include <QTimer>
#include <QMessageBox>
dashboard::dashboard(QWidget *parent) :
QDialog(parent),
ui(new Ui::dashboard)
{
ui->setupUi(this);
this->setWindowTitle(QString("dashboard"));
// create a timer
timer = new QTimer(this);
// setup signal and slot
connect(timer, SIGNAL(timeout()),
this, SLOT(MyTimerSlot()));
timer->stop();
mTotal = 0;
snsr = new sensor(this);
// msecx
}
dashboard::~dashboard()
{
delete ui;
}
void dashboard::on_pushButton_clicked()
{
snsr->show();
}
void dashboard::MyTimerSlot()
{
mTotal += 1;
snsr->setValue(mTotal);
ui->sensorlabel->setText(QString::number(mTotal));
}
Now on Sensor: sensor.h
#ifndef SENSOR_H
#define SENSOR_H
#include <QTimer>
#include <QDialog>
namespace Ui {
class sensor;
}
class sensor : public QDialog
{
Q_OBJECT
public:
explicit sensor(QWidget *parent = 0);
~sensor();
public slots:
void setValue(double value);
signals:
void changeLabel();
void valueChanged(double newValue);
private:
Ui::sensor *ui;
double mTotal;
};
#endif // SENSOR_H
sensor.cpp
#include "sensor.h"
#include "ui_sensor.h"
#include "dashboard.h"
sensor::sensor(QWidget *parent) :
QDialog(parent),
ui(new Ui::sensor)
{
ui->setupUi(this);
this->setWindowTitle(QString("sensor"));
connect(this, SIGNAL(valueChanged(double)), this, SLOT(changeLabel()));
}
void sensor::changeLabel()
{
ui->sensorlabel->setText(QString::number(mTotal));
}
void sensor::setValue(double value)
{
if (value != mTotal) {
mTotal = value;
emit changeLabel();
}
}
sensor::~sensor()
{
delete ui;
}