Qt: Connecting signals and slots - c++

I have a MainWindow that contains a custom widget with a QTextEdit in it.
I would like to create a signal/slot between the MainWindow and the QTextEdit.
In MainWindow I have:
QObject::connect(ui->Header,
SIGNAL(ui->Header->getTextWidget()->textChanged()),
this, // this : MainWindow
SLOT(headerUpdated())); // Function of MainWindow
But this does not work. Is it even possible to create such signal/slot combination?

why bother - let Qt do all the magic :) Just name your slot (in the mainWindow) like that:
void on_<object name>_<signal name>(<signal parameters>);
And you're done. More info here: http://doc.qt.io/qt-5/qmetaobject.html#connectSlotsByName
important: "object name" part means name of the object - not variable name. If you design your window in QtDesigner it should be set (in ui.setupUi method). if not - set it manually (by calling setObjectName
Just watch out for number of arguments in your slot. Here's what I do: I simply copy the signal prototype (from from header or the doc - eg: http://doc.qt.io/qt-5/qabstractitemmodel.html#dataChanged - watch out again for the weird whitespace between "::" and method name [some kind of an unbreakable-zerowidth-space] - only present when copying from v5.x doc), and prepend it with on_objectName_. That guarantees, that your slot will be ok to connect it to the signal

Related

C++ Qt: is it possible to create a sort of template slot?

I'm new to Qt and not a C++ expert so please bear with me with this one.
I'm working on an application that has 12 different QPushButtons, but all of them perform very similar actions: they grab some value from a map and then use it to set the style for that button:
void MainWindow::on_btn01_clicked(){
QString img=images["btn01"];
ui->btn01->setStyleSheet("#btn01{ background-image: url(://" + img + ") }");
}
For each one of the 12 buttons I have to create a slot that only differs in the button being used. So it looks a bit weird to create 12 functions that are almost identical.
Is there a better way to do this?
Generally, there are several approaches I've seen used:
The preferred method: lambda expressions.
If you're using modern C++ (C++11 or newer), you can use a lambda function to get the exact effect you described.
I'd expect the resulting code to look something like this:
foreach( QPushButton * button : buttons ) {
connect( button, &QPushButton::clicked, [button, &images]() {
button->setStyleSheet( QString( "{ background-image: url(://%1) }" )
.arg( images[button->objectName()] ) );
});
}
See "Qt Slots and C++11 lambda" for more guidance on how to write lambda functions with Qt.
A dirtier way: QObject::sender().
Qt lets you use QObject::sender() within a slot to get a pointer to the object that invoked it. This has been a widely used approach for many years, but there are limitations, as described in the Qt documentation:
Warning: As mentioned above, the return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
See "How to get sender widget with a signal/slot mechanism?" for more information.
Obsolete code: QSignalMapper.
There's a QSignalMapper class that will let you associate a signal with a bit of data, like a string, to then connect to a slot that uses this parameter. This used to exist as a convenience class in Qt but is being phased out because the lambda methodology makes it pointless.
If you need to update code that uses QSignalMapper to remove it, this tutorial is a reasonable starting point.
You can try one more simple method, that is set the QPushButton's object name respectively, and check the Object name in your slot and use that string. This saves you a lot of code.
Ex:
QPushButton 1 object name is set as button->setObjectName("btn01"); and respectively you can set the other names of the buttons and in your slot you could do some thing like this
void MainWindow::on_button_clicked(){
QPushButton* btn=qobject_cast<QPushButton*>(sender());
QString name=btn->objectName();
QString img=images[name]; btn->setStyleSheet("#" + name + "{ background-image: url(://" + img + ");
}
and then connect all your QPushButtons to this slot

Refer to the Sender Object in Qt

I'm having some trouble, I'm fairly new to Qt and C++ and was testing the waters so to say. Ill try to describe my problem as follows. I have a LineEdit QLineEdit and this edit has a connection which looks like this:
connect(my_lineedit, SIGNAL (textEdited(QString)),this, SLOT (handleEdits()));
The handleEdits() method gets called and does the following:
Disconnect the previous Signal from my_lineedit
Create a new QLineEdit which gets a new signal and calls handleAddedEdits()
Adds the newely created Edit to my layout.
The stated above works fine Im just telling you this so you get the picture.
Now in the new method which I called handleAddedEdits() I want kinda the same procedure to happen again.
Disconnect the Signal which calls handleAddedEdits() from the Edit which invoked this method in the first place.
Create a fresh QLineEdit
Add this to my layout.
The problem is: in the first case my_lineedit is declared in my class so I can freely refer to it and and remove the signal as I wish. In the second case I have a QLineEdit which was created dynamically in the handleEdits() method and is the "Sender". My Question is, how can I refer to the "Sender Object" ro remove the Signal from the dynamically created edit?
You need to use QObject::sender() method in your receiver's slot:
For cases where you may require information on the sender of the
signal, Qt provides the QObject::sender() function, which returns a
pointer to the object that sent the signal.
handleAddedEdits()
{
QObject* obj = sender();
disconnect( obj, SIGNAL(textEdited(QString)), 0, 0 );
//...
}

Transfer Data Between Two Children Using Qt Signals and Slots (C++)

In Qt C++, I have a parent object MainWindow. MainWindow has (among others) 2 member objects: vector, and Serial.
Some relevant members of GUI:
QPushButton pushButton;
int itemNumber;
Relevant members of Serial:
void send(int number)
When GUI's member pushButton is clicked, I want to pass GUI's member 'pushButton' as the argument to the function Serial::send(int number). I see one option of doing something like
connect(GUI,SIGNAL(clicked()),this,SLOT(customSlot()));
in my MainWindow function. However, then I don't know which item in my vector it came from, so I don't know which itemNumber to grab (they're all different).
I also thought maybe I'd do it in the GUI class, but that doesn't have access to the Serial::send(int number) method. I don't want a Serial object in each GUI, because it just won't work that way at this point.
How can I pass information from the child object GUI up to the parent object MainWindow from a signal?
Thanks!
Use QObject::sender() function inside a slot to get the object witch sent a signal.
Of course, you need some appropriate cast method:
void someSlot() {
QPushButton *sender = qobject_cast<QPushButton *>(sender());
...
}

How to tell when a QPushButton is clicked in a QButtonGroup

In my project, I have 40 QPushButtons all put into a QButtonGroup like this:
QButtonGroup* group = new QButtonGroup(this);
group->addButton(ui->slot_0);
group->addButton(ui->slot_1);
//...
group->addButton(ui->slot_38);
group->addButton(ui->slot_39);
Each button is a QPushButton that I made checkable. That way only one button can be checked at a time. All works great, but how can I "make a slot" when one of the buttons becomes checked? I don't want to have 40 different slots, one for each button all to end up doing essentially the same thing. Is there any way I can just use the QButtonGroup I put them in?
As Jamin and Nikos stated: you should create your own slot to handle the signal emitted by QButtonGroup. It could be something like this:
In the header file:
public slots:
void buttonWasClicked(int);
In the *.cpp file:
void MainWindow::buttonWasClicked(int buttonID)
{
cout << "You have clicked button: " << buttonID << endl;
}
And in the code responsible for creation of the MainWindow (i.e. in constructor but not necessairly) there should be this line:
connect(group, SIGNAL(buttonClicked(int)), this, SLOT(buttonWasClicked(int)));
Be aware that since Qt5 the connect syntax has changed. The syntax I used here is from Qt4. It still works but is deprecated now (for more information please refer to New Signal Slot Syntax in Qt 5). Moreover I would suggest going through QButtonGroup class reference as there are other available signals which could suit your needs better than the one I've chosen.
BR
The documentation for QButtonGroup shows a QButtonGroup::buttonClicked() signal - have you already tried that one?
The signal comes in two variants - one that gives the QPushButton as a parameter (as a QAbstractButton), and one that gives the ID of the button in the group.
You can use connect() to setup signal and slot connections in your C++ code.
Sometime during the initialization of your window's class (perhaps in the constructor), call this:
connect(myButtonGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(theSlotThatYouWrite(QAbstractButton*));
Where myButtonGroup is probably this->ui->nameOfTheButtonGroup, and theSlotThatYouWrite is a function that you write in your own code, that belongs to your window's class, that returns void and takes a signal QAbstractButton* as a parameter (since that's what this specific signal gives as an argument).
Make sure theSlotThatYouWrite is under the label "private slots:" or "public slots:" in your class's interface.
Here's a screenshot of actual usage of some signals and slots in my own code.
Signals and Slots is something very important to learn, but can be bit of a hill to climb when first trying to understand it!

Qt doesn't find QStackedWidgets' slot setCurrentWidget

I am writing a wizard-style application in Qt that uses a QStackedWidget to organize the individual pages of the wizard. Now I want to switch between the pages, which should be possible using the function setCurrentWidget(...):
I have a simple main class that instantiates a QWidget audioconfig. Then, it adds this QWidget to a QStackedWidget pageStack using pageStack.addWidget(&audioconfig);.
Later, I want to connect a certain signal from a different QWidget hub to setCurrentWidget(...) of the QStackedWidget in order to switch the page. However, my compiler remarks that
0Object::connect: No such slot QStackedWidget::setCurrentWidget(audioconfig) in /Users/paperflyer/Development/App/main.cpp:41`
There are two things I don't get here:
there clearly is such a function. You can look it up in the class definition of QStackedWidget. What is going on here?
Why is the first character of the compiler output a '0', while my source code clearly and correctly shows it as 'Q'?
Here is the whole code:
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
QStackedWidget pageStack;
CHub hub; // inherits from CWidget
CAudioConfig audioconfig; // ditto
pageStack.addWidget(&hub);
pageStack.addWidget(&audioconfig);
// connect() is a custom signal of hub
QObject::connect(&hub, SIGNAL(configure()), &pageStack, SLOT(setCurrentWidget(&audioconfig)));
pageStack.setGeometry(100,100,700,500);
pageStack.show();
return app.exec();
}
As always, thank you so much for your help!
QObject::connect(&hub, SIGNAL(configure()), &pageStack, SLOT(setCurrentWidget(&audioconfig)));
When you connect a signal to a signal/slot, you connect a signature. The actual parameters are passed when emitting the signal. The above should probably be setCurrentWidget(QWidget*), but even so it won't work, because the signature for the signal must match the one of the slot.
Note: I think that if the signal has more parameters than the slot it will still work, provided that the first parameters are the same.
Your connect line is wrong. It should be:
// connect() is a custom signal of hub
QObject::connect(
&hub, SIGNAL(configure()),
&pageStack, SLOT(setCurrentWidget(QWidget *))); // <- change here
You connect based on the prototype of the slot and/or signal.