qt slots currying - c++

Is there a way curry qt slot? Maybe there is something similar to curryng?

Although it's not possible directly using Qt, some binding/currying is available through LibQxt. For example and from the docs of QxtBoundFunction:
By far, the most common expected use is to provide a parameter to a slot when the
signal doesn't have offer one. Many developers new to Qt try to write code like this:
\code
connect(button, SIGNAL(clicked()), lineEdit, SLOT(setText("Hello, world")));
\endcode
Experienced Qt developers will immediately spot the flaw here. The typical solution
is to create a short, one-line wrapper slot that invokes the desired function. Some
clever developers may even use QSignalMapper to handle slots that only need one
int or QString parameter.
QxtBoundFunction enables the previous connect statement to be written like this:
\code
connect(button, SIGNAL(clicked()), QxtMetaObject::bind(lineEdit,
SLOT(setText(QString)), Q_ARG(QString, "Hello, world!")));
\code
This accomplishes the same result without having to create a new slot, or worse,
an entire object, just to pass a constant value.
Additionally, through the use of the QXT_BIND macro, parameters from the signal
can be rearranged, skipped, or passed alongside constant arguments provided
with the Q_ARG macro. This can be used to provide stateful callbacks to a
generic function, for example.
Many kinds of functions can be bound. The most common binding applies to
Qt signals and slots, but standard C/C++ functions can be bound as well.
Future development may add the ability to bind to C++ member functions,
and developers can make custom QxtBoundFunction subclasses for even more
flexibility if necessary.
Although I have submitted some patches to LibQxt, I haven't used this directly so your mileage may vary.

Binding arguments is not possible using Qt signal/slots. You'll have to use boost::signals and boost::bind instead to achieve such functionality.

You could use QSignalMapper to bind connect some signals to it and then connect it's own signals to target slots with some parameters attached.
// connect signal to mapper
signalMapper = new QSignalMapper(this);
signalMapper->setMapping(button1, QString("param1"));
signalMapper->setMapping(button2, QString("param2"));
connect(button1, SIGNAL(clicked()), signalMapper, SLOT(map()));
connect(button2, SIGNAL(clicked()), signalMapper, SLOT(map()));
// connect mapper signal to slot
connect(signalMapper, SIGNAL(mapped(const QString &)), this, SLOT(originalSlot(const QString &)));

Of course, now we have Qt 5 and the ability to connect signals to arbitrary callable objects:
connect(sender, &MyClass::mySignal, receiver, std::bind(&OtherClass::mySlot, boundArg));
connect(sender, &MyClass::mySignal, receiver, [=] { receiver->mySlot(boundArg); });

Related

How to get a clicked button id from QButtonGroup in qt 6.4 through signal and slot connection

i am new to qt and what to know how to get the id of the button that is clicked in qt through signal and slot.
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(buttonWasClicked(int)));
This was the earlier syntax to get the id, but qt has declared buttonClicked(int) as obsolete and it no longer allows us use it. is there any new replacement for this code.
Plz forgive if this question was silly, but i don't know much about qt yet.
The QButtonGroup::buttonClicked(int) signal is obsoleted but you can still use QButtonGroup:: buttonClicked(QAbstractButton *). Perhaps use it in conjunction with a lambda and your existing buttonWasClicked slot...
connect(group, &QButtonGroup::buttonClicked,
[this, group](QAbstractButton *button)
{
buttonWasClicked(group->id(button));
});
Alternatively, use the idClicked signal as suggested by #chehrlic...
connect(group, &QButtonGroup::idClicked, this, &MainWindow::buttonWasClicked);
(Assuming MainWindow is the type pointed to by this.)

How to execute QML slot from C++ without a signal?

I got a QML object in the QObject shape. With ->setProperty(..., ...) I can change properties, but how can I execute slots without signals?
Currently I declare a signal in my C++ class:
signals:
void testSignal();
and signal/slot in QML object:
signal executeTestFunc(); onExecuteTestFunc: {
testAnimation.start();
}
Then I connect these two:
QObject::connect(this, SIGNAL(testSignal()),
QmlObject, SIGNAL(executeTestFunc()));
But this is not clean, as I can see:
De facto this is strange SIGNAL/SIGNAL connection.
I do not want to use SIGNAL/SLOT mechanism, unless I have to, due to performance and long code.
Is there a way to execute QML onExecuteTestFunc(); from QObject directly?
You can create a C++ class that will emit a signal. That signal will be caught in QML. No explicit connection with SIGNAL/SLOT is needed. Example:
C++:
class Presenter : public QObject
{
Q_OBJECT
public:
explicit Presenter()
{
QTimer *timer = new QTimer();
timer->setInterval(500);
connect(timer, &QTimer::timeout,
this, &Presenter::timeout);
timer->start();
}
Q_SIGNAL void timeout();
};
QML:
Window {
...
Presenter {
onTimeout: {
console.log("called from c++")
}
}
}
Result:
qml: called from c++
qml: called from c++
qml: called from c++
qml: called from c++
...
#Thomenson has already given a good answer on how you can connect to a signal from C++ and act on it in QML. His solution works if you can create the C++ from QML, which may not always be the case.
Connections element
There are two other options you might consider. First, if you have an object that was not created from QML but was put into it in some other way (QML context, static object, returned from an invokable...) you may use the Connections element:
Connections {
target: theObjectWithTheSignal
onSignalName: {doSomething();}
}
This is a flexible way to react to signals from object that you did not create in QML, or even objects that were created elsewhere in QML.
Callback using JSValue
If you really insist on avoiding signal/slot (though I don't understand why; Qt and QML are build around it and trying to avoid it is fighting against the framework instead of using its strenghts), there is another way. You can, on the C++ object that is exposed to QML, create a property of type QJSValue. Then, in C++ on setting, check that whatever was set is callable (using QJSValue::isCallable()). Then as the point you wish to trigger whatever you want to execute in your QML, call it using QJSValue::call.
On the QML side, you can simply assign or bind something callable, just like you'd do for a signal handler.
Anti pattern: QMetaObject::invokeMethod
There is another way, which I will only include as a warning against an anti-pattern. You can call into the QML from C++ using Qt's introspection mechanism. You can find an object by it's set objectName and call any (invokable) method on it using QMetaObject::invokeMethod, read and write any property and listen to all signals. That includes calling methods you defined in QML. Using this, you can manipulate your QML from your C++. Don't do this. It leads to inflexible and unmaintainable code.

How to pass a variable from main to signal and slot macros?

Having the hardest time setting up signal and slot macros for variables in main. It is extremely easy to do when the variables are located in classes, but how do you do this when you want to connect a variable in main?
I have two radio buttons in main as follows:
QRadioButton *btn_ledWhite = new QRadioButton;
QRadioButton *btn_ledBlack = new QRadioButton;
I want to pass these buttons to a function that sets their stylesheet. Something like below:
btn_led->setStyleSheet("QRadioButton::indicator::unchecked{background-color:gold;}");
When the user of my application presses btn_start, the white player's LED should light up. Unfortunately, I cannot pass the buttons from main to signal and slot macros. I want something like this:
QObject::connect(btn_start, SIGNAL(clicked()), whiteClock, SLOT(updateLED(btn_ledWhite)));
This is illegal qt syntax, however. Apparently, you cannot pass an argument to a function wrapped in a SLOT macro.
You can do something like:
Counter a, b;
QObject::connect(&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
... but I cannot mix the presentation (GUI) layer, with the business layer (i.e. standard 3-tier architecture model... think MVC). Else I would just stick this button in a class and not worry make this thread.
Does anyone have idea how to connect a variable in main with a signal and slot macro?
You can use a QSignalMapper for this.
You connect your buttons' clicked() signal to the mapper's map() slot, then set the mapping from button to led with the mapper's setMapping function.
Once that's done, connect the mapper's mapped signal to your whiteClock. You might need to adjust your slot function's signature to take a QWidget rather than a QPushButton, but if all you need is to call setStyleSheet, then that's not much of a problem.
This code works. You do need to adjust the function signature as previously mentioned to a QWidget*, instead of a QRadioButton*...but everything else should be the same.
main.cpp
QSignalMapper * signalMapper = new QSignalMapper;
//Start game, start white's clock, turn on white's LED
QObject::connect(btn_start, SIGNAL(clicked()), whiteClock, SLOT(startClock()));
QObject::connect(signalMapper, SIGNAL(mapped(QWidget*)), whiteClock, SLOT(updateLED(QWidget*)));
QObject::connect(btn_start, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(btn_start, btn_ledWhite);
Set the stylesheet in your clock class and you're good to go.

How to pass a QAction to a Qt slot from a QMenu

Iam new in Qt and I have problem how to pass QAction as parameter like this code:
connect(fileToolBarAct, SIGNAL(toggled(bool)), this, SLOT(ToggleBar(fileToolBarAct));
And this my slots function:
void MainWindow::ToggleBar(QAction& what)
{
what.isCheckable();
}
QObject::connect doesn't work like this. You can not pass objects to SIGNAL and SLOT macros. SIGNAL and SLOT macros should take function signatures. In addition the signature of a signal must match the signature of the receiving slot as described in the Qt documentation.
I see that you lack in understanding the signals and slots mechanism and I recommend you read the Qt Signals and Slots documentation for more info. Reading the Qt Signals and Slots documentation will clear everything for you.
onnect(fileToolBarAct, SIGNAL(toggled(bool)), this, SLOT(ToggleBar(bool));
void MainWindow::ToggleBar(bool checked)
{
QAction* action = qobject_cast<QOAction*>(sender());
if (action)
action->setChecked(checked);
}

How to handle signals when a Qt object isn't created through Designer?

Hi I've got a spare moment so decided to look at Qt and how easily I can port my windows applications to Qt.
My only real problem is a couple of controls that will need re-implementing under Qt. I've already handled the basic drawing of the control but my control creates a child scroll bar. The problem is that this scrollbar is created dynamically as part of my new Widget (i.e. m_Scrollbar is a member of the widget). How can I then respond to movement of the scrollbar. Under other circumstances this is easy as I'd just create an on_myscrollbar_sliderMoved function under my protected slots and handle it there. This does however rely on the QScrollBar being called myscrollbar. As I've created the object dynamically (i.e. not through designer) how do I capture this signal?
I'm guessing this is really simple and I'm missing the obvious :)
connect( myScrollbar, SIGNAL( <signal signature>), this, SLOT( <slot signature>));
Call connect after creating the scroll bar (I presume that you need this signal handling immediately after creating the scroll bar).
I assumed myScrollbar is of type QScrollBar* and that the slot is defined as a member in your class.
When myScrollbar is destroyed, the connection is removed (disconnect is called).
See the documentation of QObject::connect and QObject::disconnect methods.
Later edit - to be more concrete, in your code it could be:
myScrollbar = new QScrollBar; // Create the scroll bar
// ... add it to the layout, etc.
// ... and connect the signal to your slot
connect( myScrollbar, SIGNAL( sliderMoved( int)), this, SLOT( handleSliderMoved( int)));
where handleSliderMoved is the slot method of your class.