Create a custom slot in C++, Qt5 - c++

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;
};

Related

C++ QT Call C++ function in QJSEngine

I'm trying to call a function which is implemented in C++ to call in a JS function, which gets evaluated with the QT QJSEngine.
So far I have tried this
class Person : public QObject {
Q_OBJECT
public:
Q_INVOKABLE cppFunction(int a);
};
My function evuation looks like this
QJSValue formulaFunction = jsEngine->evaluate("(function(" + functionArgList.join(",") + "){ " + formula + "})");
In formula I have a call to cppFunction and functionArgList provides the arguments, these work fine, I have checked them.
So, but somehow it doesn't get called, I don't get an error too. Am I missing something or should it work this way?
So, after some research I got it running.
class MyObject : public QObject{
Q_OBJECT
public:
Q_INVOKABLE MyObject() {}
Q_INVOKABLE bool hasChannel(int id);
};
QJSEngine engine;
QJSValue injectedObject;
injectedObject= engine.newQMetaObject(&MyObject::staticMetaObject);
engine.globalObject().setProperty("MyObject", injectedObject);
So, here I'm creating a new class which is inheriting from QObject.
The class has two methods, every method I want to invoke in the QJSEngine has to provide the Q_INVOKABLE Label in front of the method declaration.
An example JS code run by the engine would look like this
let myObject = new MyObject();
myObject.hasChannel(1234);
I don't know if the injected prefix is appropriate, but I couldn't think of a better one

Connect slots from another class not working in Qt

I have this class in button.h:
class Buttons : public QObject
{
Q_OBJECT
public:
Buttons();
QVector<QPushButton*> buttons;
public slots:
void getBtnInfo();
};
and in mainwindow.cpp, I connect like this:
Buttons mButtons;
for(int i = 0; i < mButtons.buttons.size(); i++) {
mButtons.buttons[i] = new QPushButton(mCentralWidget);
...
connect(mButtons.buttons[i], SIGNAL(clicked(bool)), &mButtons, SLOT(getBtnInfo()));
}
It runs without any errors; but the getBtnInfo() slot seems like not do anything. Because I tried simply just debug in this slot, not working.
But if I declare getBtnInfo() slot in mainwindow.h and connect like this:
connect(mButtons.buttons[i], SIGNAL(clicked(bool)), this, SLOT(getBtnInfo()));
then it works.
I wonder why? And how do I solve the problem above?
Thanks.
If a variable is created in a function it only exists in that function, then it will not be accessible, and that is what I think is happening, I recommend you to make mButtons a member of the class.
*.h
private:
Buttons mButtons;

Qt pass variables between forms

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&)));

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()
{
//
}

Qt: Creating a QDoubleSlider

I want to connect a QDoubleSpinBox with a QSlider like this:
QObject::connect(ui->myDoubleSpinBox, SIGNAL(valueChanged(double)),
ui->mySlider, SLOT(setValue(double)));
QObject::connect(ui->mySlider, SIGNAL(valueChanged(double)),
ui->myDoubleSpinBox, SLOT(setValue(double)));
This won't work, for a QSlider only handles int values. So I think i need to add a custom slot to QSlider.
I thought about creating a new class derived from QSlider and then implementing the slot, like this:
QDoubleSlider.hpp
#ifndef QDOUBLESLIDER_H
#define QDOUBLESLIDER_H
#include <QSlider>
class QDoubleSlider : public QSlider
{
Q_OBJECT
public:
explicit QDoubleSlider(QObject *parent = 0);
signals:
public slots:
void setValue(double givenValue);
};
#endif // QDOUBLESLIDER_H
QDoubleSlider.cpp
#include "qdoubleslider.h"
QDoubleSlider::QDoubleSlider(QObject *parent) :
QSlider(parent)
{
}
void QDoubleSlider::setValue(double givenValue)
{
// code
}
Now I have two problems:
The compiler complains about an invalid conversion from QObject* to QWidget* in the constructor.
I don't know how setValue works and thus I don't even know how to implement that slot.
Any ideas?
parent needs to be a QWidget*, just as the error states
Slots work like regular member functions. You should probably store an exact double as a member and set the underlying slider to the appropriate integer equivalent. Remember to only send valueChanged signals if the value really changes.
Furthermore you should probably inherit from QWidget instead and have a QSlider as a child, as you do not want users of your class to change the integer range of your internal slider.
just simply replace your QObject to QWidget, because QSlider constructor is
QSlider ( QWidget * parent = 0 )
you'd better have a new slot named setDoubleValue(double givenValue) and connect to this slot. in this slot, it is simple. like
void QDoubleSlider::setDoubleValue(double givenValue)
{
setValue(static_cast<int>(givenValue));
}