How to pass a QAction to a Qt slot from a QMenu - c++

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

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 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 externally call a signal in Qt?

I know how to call a signal from inside the class where the signal is located: by using emit. But what if I want to call it externally, from the parent object?
The reason why I want to do is is because a given QPushButton is connected to a slot which picks the button that called it by using sender(). Now I want the same functionallity of that slot to be called but not after a manual click in the button, but from within the code itself. Normally I would just programatically call for the slot, but because of the usage of sender(), that way is invalid: calling the slot directly will not give it the id of the button.
So how could I "externally" ask for the object for it to emit one of its signals? That is, how can I make my QPushButton emit its clicked() signal from within the code, not by clicking the button with the mouse?
You cannot emit signal directly from the parent object.
Only the class that defines a signal and its subclasses can emit the signal. (http://qt-project.org/doc/qt-4.8/signalsandslots.html#signals)
You can define a method in your QPushButton emitClicked() where you emit the signal. Then you call emitClicked() on instance of your QPushButton from the code.
The Qt headers contain this interesting line (in qobjectdefs.h):
#define emit
Which means that presence or absence of the emit keyword has no effect on the code, it's only there to make it more obvious to the human reader that you are emitting a signal. That is to say:
emit clicked();
is exactly the same (as far as the C++ compiler is concerned) as
clicked();
Given that, if you want your button to emit its clicked() signal, it's just a matter of doing this:
myButton->clicked();
(although if you wanted to be clever about it, this would work equally well):
emit myButton->clicked();
Seems that Qt Test module is just for this case.
Check out this tutorial on simulating GUI events.
Basically you use QTest::​mouseClick and pass pointer to your push button.

connect() seems to prefix signal with wrong namespace

I'm trying to use signals and slots to pass information to the GUI thread from another thread, as I can't modify a pixmap from any other thread. I'm encountering a runtime error:
Object::connect: No such signal QThread::image_change(std::string) in visualiser.cpp:33
Judging from this, though I may be wrong, it looks like the signal is being searched for in the wrong namespace, as it is actually defined in Visualiser::image_change().
My code is as follows:
Visualiser.cpp:
QFutureWatcher<void> watcher;
connect(watcher.thread(), SIGNAL(image_change(std::string)), QCoreApplication::instance()->thread(), SLOT(update_image(std::string)), Qt::QueuedConnection);
QFuture<void> update_thread = QtConcurrent::run(this, &Visualiser::update_state);
watcher.setFuture(update_thread);
...
emit(image_change(imageSrc));
...
void Visualiser::update_image(std::string src)
{
QImage image;
image.load(src.c_str());
ui->visualContainer->setPixmap(QPixmap::fromImage(image));
}
visualiser.h:
signals:
void image_change(std::string src);
public slots:
void update_image(std::string src);
Don't pass thread pointers into connect - pass pointers to the sender and receiver of the event (like this). Because you're giving it QThread pointers instead, Qt is looking for those signals and slots in QThread, where they don't exist. If you give it Visualizer pointers instead, Qt will look for those functions in Visualizer, where they really are, and everything will work.
Hope that helps!
The source and the target of the connection are the same object, this, so the connect call should be:
connect(this, SIGNAL(image_change(std::string)), this, SLOT(update_image(std::string)));
Since the signal will be emitted from another thread than the one the Visualizer has an affinity with (see QObject::moveToThread()), the connection with the slot will automatically be queued, and the slot will be executed by the correct thread.
But for queued connection to work, Qt has to store temporarily the parameter until it can actually call the slot, which is done by converting it to QVariant, storing it somewhere, and then reconverting it to the actual type when the receiving thread is ready to execute the slot.
So you need to register std::string to Qt's metatype system with Q_DECLARE_METATYPE or change the signal and slot parameter type to one that is already registered to (like QString or QByteArray).

qt slots currying

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