Qt: Use functors as sender in connect(...) - c++

I am new to Qt and I wonder how to connect a functor to a slot properly.
This is basically what I tried:
std::function<void ()> sender_function = std::bind(SenderClass::senderFunction, sender);
...
connect(sender, &sender_function, this, &ThisClass::SomeFunction);
However, it does not work. Can someone point me in the right direction?
Thanks and best regards,
Alex
Edit:
Use case is the following. I have a set of ~50 parameters fed by sensors in a fixed frequency. To plot the data individually, I have a signal for every parameter which is called when an update arrives. These signals I store in a vector in a structured way, so I don’t need to perform lookups for every parameter (updates can come with 100-1000 Hz).
Now my idea was, that plots can dynamically connect to the parameter signals, by performing a look up once on connection (parameter name -> signal as std::function).
Edit 2:
Because there were further questions, here some code examples. I hope this makes it clearer. The signals for parameter updates look like this:
signals:
void DataController::port000(double timestamp, Parameter_t p);
Port000 is of course an example, I have 50 more like that, so that every parameter can be individually sent through my program for plotting etc. Next I created a vector of my signals:
using PortUpdateFunc = std::function<void (double, Parameter_t)>;
QVector<PortUpdateFunc> _port_update_functions;
_port_update_functions[0] = std::bind(&DataController::port000, this, ph::_1, ph::_2);
This allows me to easily just call _port_update_functions[30](stamp, parameter) and it will send the parameter that I linked with that port on its way. This is the sender side. Now on the slot side I have something like this:
switch(port_id)
{
case 0: QObject::connect(sender, &DataController::port000, this, &SomeSlotFunction); break;
case 1: QObject::connect(sender, &DataController::port001, this, &SomeSlotFunction); break;
}
While this works perfectly fine, I have to explicitly put all the ports in my switch-case handle. And if I have 50 parameters thats 50 cases with port000 to port049, which is a bit of type work. What I thought of doing was something like this:
DataController::PortUpdateFunc port_functor = _port_update_functions[port_id];
QObject::connect(sender, &port_functor, this, &SomeSlotFunction);
So I could replace the port000, port001, ... case-handle by just getting the functor from the initial _port_update_functions vector with the appropriate port_id. But Qt doesn't like that idea.

If you are using 001, 002 variable/method names, most likely you are doing something wrong. Also, it is better that a Plot class does not know about specific ports and does not deal with the selection and connection / disconnection of signals.
For the example you wrote, you can easily use universal signals' signature like this:
void DataController::portData(int number, double timestamp, Parameter_t p);
or just
void DataController::portData(QVariant var);
or use interface:
struct IParam
{
...
virtual QVector<QPointF> toVector() const = 0;
}
struct ConcreteParamName : public IParam
{
double timestamp;
Parameter_t p;
...
QVector<QPointF> toVector() const override
{
...
}
}
And then emit portData(1, timestamp, p);
or emit portData(QVariant::fromValue(param));
or
emit portData(sharedPointerToParam);
...
void SomeController::portDataSlot(QSharedPointer<IParam> param)
{
// decide what to draw here:
if(thePortNeedToDraw)
{
QVector<QPointF> curve = param->toVector();
plot->drawCurve(curve);
}
}
// or decide what to receive here:
void SomeController::switchSender(int number, bool enabled)
{
// without boilerplate switch-case
if(enabled)
{
QObject::connect(senders[number], &DataController::portData, this, &SomeController::portDataSlot);
}
else
{
QObject::disconnect(senders[number], &DataController::portData, 0, 0);
}
}

This is not possible. The signal argument is either a string or a PointerToMemberFunction. Functors can only be used as target. See https://doc.qt.io/qt-5/qobject.html#connect-5.

Related

Qt/C++ Elegant way for comparison based signal dispatching

I am working on a project where I receive a message via UDP and based on that message I am emitting different signals and all of them have the same parameters.
The structure is like this:
if(command_type == COMMAND_TYPE_MOVE)
{
emit sigMoveForward(data);
}
else if(command_type == COMMAND_TYPE_STOP)
{
emit sigStopMove(data);
}
This gets really tedious to programm and maintain when getting past like 10 commands. Is there a way to do this better?
I thought of creating a QMap and doing a lookup on it and emiting the signal I am getting. Is this possible in Qt to have a pointer to the function and omit it this way?
There is no difference between
emit sigMoveForward(data);
and
sigMoveForward(data);
So, you can create QMap with pointers to signals or beter plain array if commands are continuous. It has quite tricky syntax, though.
void (Your_class::*signals[COMMAND_COUNT])(your_data_type) ;
...
signals[COMMAND_TYPE_MOVE] = &Your_class::moveForward;
signals[COMMAND_TYPE_STOP] = &Your_class::stopMove;
....
And emit it like that:
(this->*signals[command_type])(data);
If all signals contain the same data, you could send a unique signal containing 2 parameters (the command_type + the data) and then check the command_type in the receiving slot
//...
emit sigCommand(command_type, data)
//...
void MyClass::commandReceived(CommandType command_type, QVariant data) {
if(command_type == COMMAND_TYPE_MOVE)
{
moveForward(data);
}
else if(command_type == COMMAND_TYPE_STOP)
{
stopMove(data);
}
//...
}

Can I simplify the following code for qt?

I need to simplify validations on qlineedit, which invokes a function that returns a capital letter when I'm typing. I have this:
void dg_cliente::on_lineEdit_4_textChanged(const QString &arg1)
{
Cls_Validaciones *Valido = new Cls_Validaciones;
ui->lineEdit_4->setText(Valido->Validar_Mayuscula(arg1));
}
The code is the very similar for lineEdit5, lineEdit6, lineEdit7, etc., which is redundant. Is there a better way to do this that removes the redundancy?
I interpret your question as:
How can I recognize which widget is an actual signal sender?
By calling sender() function in your slot.
void DlgClient::onLineEditTextChanged(const QString &arg1)
{
QLineEdit* pLineEditSender = qobject_cast<QLineEdit*>( sender() );
if (pLineEditSender) // also verify that is required type of sender
{
// FYI: setText also signals textChanged
// make sure the code is not looping here
// so bool m_forcedSetText initially set false
if ( ! m_forcedSetText)
{
m_forcedSetText = true;
pLineEditSender->setText( myTransform(arg1) );
}
else
m_forcedSetText = false;
}
}
P.S. Maybe the other type of solution as suggested in comments is better? But the answer is explicit to what you ask. The info on sender() does warn that the OOP principle of modularity is violated etc. while in certain cases the function is still useful.

Unable to add slot and connect it to a button

I gathered a code of an application called calendar from the base of examples of the Qt Framework. I am trying to learn from it and add there some functionality. The problem right now that I've got is that I want to implement two function to the two button that I created ( one for increase counting of the days and the second for decrease ).
The code that I added to the function for increasing the days is:
void MainWindow::forward(int *click_forward)
{
click_forward++;
}
and the code added to the function for decreasing the days:
void MainWindow::backwards(int *click_backwards)
{
click_backwards--;
}
In the constructor I defined a variable named click which of the int
type, and I sent this variable to the both function by reference:
forward(&click);
backward(&click);
In the header file, in the public slosts area these both functions are
defined as:
void forward(int *click_forward);
void backwards(int *click_backwards);
I also implemented two SIGNAL-SLOT connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward(int
&click)));
QObject::connect(beforebtn, SIGNAL(clicked()), this,
SLOT(backwards(int &clickt)));
But for some reasons when I compile the project I receive an information that:
QObject::connect: No such slot MainWindow::forward(int &click)
QObject::connect: No such slot MainWindow::backwards(int &clickt)
I wanted to use pointers in these two functions, just to work on the original variable itself not on the copy.
Could I please ask you to point me out what I am doing wrong.
Thank you,
The problem is that your signal and slot(s) have different signatures: signal has no arguments, but slot has an argument of pointer type. Besides, even if your signals connections would work, the execution of such code wouldn't do anything useful (at least) as you modify the temporary defined variables click_backwards etc.
I would solve this in the following way:
Define the class member variables and slots:
class MainWindow
{
[..]
private slots:
void forward();
void backwards();
private:
int click_forward;
int click_backwards;
}
Define slots:
void MainWindow::forward()
{
click_forward++;
}
void MainWindow::backwards()
{
click_backwards--;
}
And finally establish connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward()));
QObject::connect(beforebtn, SIGNAL(clicked()), this, SLOT(backwards()));
if you do your signals and slots like this, then you get a compiler error instead of a run time error, which i personally find very helpful since it will just tell you that they wont connect because of incompatible signals/slots
QObject::connect(nextbtn, &QPushButton::clicked, this, &MainWindow::forward);
By the way, you're not increasing the value of the integer, you're increasing the pointer.
That's a bug waiting to happen.

Call Qt object method from another std::thread

I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.
I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum

Prevent Firing Signals in Qt

We have a QCheckBox object, when user checks it or removes check we want to call a function so we connect our function to stateChanged ( int state ) signal. On the other hand, according to some condition we also change the state of QCheckBox object inside code, and this causes the unwanted signal.
Is there any way to prevent firing signal under some conditions?
You can use the clicked signal because it is only emitted when the user actually clicked the check box, not when you manually check it using setChecked.
If you just don't want the signal to be emitted at one specific time, you can use QObject::blockSignals like this:
bool oldState = checkBox->blockSignals(true);
checkBox->setChecked(true);
checkBox->blockSignals(oldState);
The downside of this approach is that all signals will be blocked. But I guess that doesn't really matter in case of a QCheckBox.
You can always block signal emission on QObjects using QObject::blockSignals(). Note that to be correct about things, you should remember the old state (returned from the function call), and restore it when you are done.
At my job, we prefer RAII for this sort of thing. A simple class to do so might look like this:
class SignalBlocker
{
public:
SignalBlocker( QObject *obj ) : m_obj( obj ), m_old( obj->blockSignals( true ) )
{
}
~SignalBlocker()
{
m_obj->blockSignals( m_old );
}
private:
QObject *m_obj;
bool m_old;
};
Edit: Starting with Qt 5.3, see QSignalBlocker (h/t to HappyCactus in comments)
While learning Qt, I ran into this problem with a set of interconnected widgets that I wanted to update "atomically". I liked #cjhuitt's solution, but found that it goes even better with a bit of syntactic sugar based on proxy objects. Here's the approach that I used...
First, I defined a class template for a blocker proxy object. Like Caleb's, this blocks the signals on construction, and then restores their previous state on destruction. However, it also overloads the -> operator to return a pointer to the blocked object:
template<class T> class Blocker {
T *blocked;
bool previous;
public:
Blocker(T *blocked)
: blocked(blocked),
previous(blocked->blockSignals(true)) {}
~Blocker() { blocked->blockSignals(previous); }
T *operator->() { return blocked; }
};
Next, I defined a small template function to construct and return a Blocker:
template<class T> inline Blocker<T> whileBlocking(T *blocked) {
return Blocker<T>(blocked);
}
Putting this all together, I'd use it like this:
whileBlocking(checkBox)->setChecked(true);
or
whileBlocking(xyzzySpin)->setValue(50);
This gets me all the benefits of RAII, with automatically paired blocking and restore around the method call, but I don't need to name any wrapper or state flags. It's nice, easy, and pretty darn foolproof.
You can QObject::disconnect to remove the corresponding signal-slot connection and can QObject::connect again once you are done...
In QObject derived classes, you can call blockSignals(bool) to prevent the object from emitting signals. So for example:
void customChangeState(bool checked)
{
blockSignals(true);
ui->checkBox->setCheckState(Qt::Checked);
// other work
blockSignals(false);
}
The above method would change the check state without clicked, stateChanged, or any other signals being emitted.
Qt5.3 introduced the QSignalBlocker class that does exactly what needed in an exception safe way.
if (something) {
const QSignalBlocker blocker(someQObject);
// no signals here
}
Even in QT5, its a bit cumbersome when there are many/several things to block. Here's a multi-object version that is concise to use:
class SignalBlocker
{
public:
SignalBlocker(QObject *obj)
{
insert( QList<QObject*>()<<obj );
}
SignalBlocker(QList<QObject*> objects)
{
insert(objects);
}
void insert(QList<QObject*> objects)
{
for (auto obj : objects)
m_objs.insert(obj, obj->signalsBlocked());
blockAll();
}
void blockAll() {
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals(true);
}
~SignalBlocker()
{
for( auto m_obj : m_objs.keys() )
m_obj->blockSignals( m_objs[m_obj] );
}
private:
QMap<QObject*,bool> m_objs;
};
usage:
void SomeType::myFunction()
{
SignalBlocker tmp( QList<QObject*>()
<< m_paramWidget->radioButton_View0
<< m_paramWidget->radioButton_View1
<< m_paramWidget->radioButton_View2
);
// Do more work, ...
}
When some UI element should not respond to user it is appropriate to disable it. So that user would know that this element is not accepting input.