I'm using the next line in order to display the position of the slider on the label.
connect(slider, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));
It works fine.
However, I don't really understand how is this value being transferred.
How does the parameter of the valueChanged function pass to the setNum function ?
When you call connect you specify a signature of a signal and of a slot (or another signal).
Qt uses these signatures to store an "internal link" between 2 methods.
When a signal method is called (for example, with emit valueChanged(5)) Qt looks for a corresponding slot method in the list of "links".
Then Qt calls a slot method passing arguments from the first signal method.
Read this article thoroughly. It's really awesome.
Every time the signal is triggered, it gives the int to the slot function. It's like if you (the slot) go and see you neighbor to give him eggs and then he do whatever he wants with it.
You can see this excellent doc about how Qt Signals and Slots works
Related
I have an application with many windows (QWidgets).
I didn't save a list of open windows, though, so everytime I want to close a window, I have to retrieve it.
Particularly, each of these windows is called here SubWindow.
Every SubWindow class contains a layout with a MultiEditor *sEditors, which has a menu with an action that closes the current window.
Every SubWindow is created within the MainWindow.
I have two plans.
1) destroying the SubWindow from within itself, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
this, closeWindow()));
or
2) destroying the SubWindow from within the MainWindow class, by adding in the SubWindow constructor
connect(sEditors, SIGNAL(closeWindow()),
main, SLOT(closeWindow(this)));
About 1), I don't understand how I can close and destroy a QWidget from within itself (delete this; didn't seem to work, but I can try again).
About 2) my SLOT(closeWindow(this)) doesn't seem to be triggered, so I am wondering if I can pass "this" as an argument.
Ad 1) You can use QObject::deleteLater(). This will destroy the object in the next event loop cycle, and is specifically create for situations like this
Ad 2) You cannot pass actual arguments as parameters in signal-slot connections.
You can however find out who has emitted the signal by using the sender() function in the slot. In your case, that would be the sEditors object.
Other options:
3) You can use a QSignalMapper to map signals from your editors to the Subwindows.
4) (Using Qt5 / C++11) You can use a lambda connection in your Subwindows:
connect(sEditors, SIGNAL(closeWindow()), [this] () {this->closeWindow();});
Can I pass this to a Qt slot?
A slot is a non-static method, so it already has access to this. The this you refer to is the third argument to QObject::connect. In Qt 4 syntax, you're free to omit the third argument - it defaults to this. In Qt 5 syntax, you must be explicit about it, though.
I don't understand how I can close and destroy a QWidget from within itself
To delete any QObject from within itself, use QObject::deleteLater(). Recall that a QWidget is-a QObject in terms of LSP.
my SLOT(closeWindow(this)) doesn't seem to be triggered
There's no such slot (give us a link to its documentation: you can't), and your slot signature is also invalid because the only things within the parentheses in the slot signature can be types, and this is not a type: SLOT(slotName(TYPE_LIST_HERE)), e.g. SLOT(mySlot(int,QString)).
To close a widget, use its close() slot:
connect(sEditors, SIGNAL(closeWindow()), this, SLOT(close());
Yet, by using Qt 4 connect syntax, you're leaving coding mistakes to be detected at runtime - and then if you don't pay attention to the debug output at runtime, you'll miss it. It's thus much better to use the new (Qt 5) connect syntax, and let the compiler detect errors for you:
connect(sEditors, &MultiEditor::closeWindow, this, &QWidget::close);
Alas, there's no need to tightly couple the object that sends closeWindow to SubWindow - at least not within the SubWindow::SubWindow(). Instead, you can connect at the place where you create the editor.
To delete a widget when it gets closed, simply set the Qt::WA_DeleteOnClose attribute on it and let Qt do it for you. No need to explicitly call deleteLater etc.
You might factor all of it into a factory method:
template <class T> T* SubWindow::makeEditor() {
auto sub = new T{this};
sub->setAttribute(Qt::WA_DeleteOnClose);
connect(sEditor, &MultiEditor::closeWindow, sub, &QWidget::close);
return sub;
}
MainWindow::MainWindow(/*...*/) : /*...*/ {
makeEditor<EditorType1>();
makeEditor<EditorType2>();
/*...*/
}
I have a problem with slots and signals. I created buttons and connected them to the clicked() slot. Then i decided to connect signals and slots manually and since then when I click the button it calls its function twice.
connect(ui->okButton, SIGNAL(clicked()), this, SLOT(on_okButton_clicked()));
void settingswindow::on_okButton_clicked()
{
qDebug() << "ok clicked";
this->close();
}
I was looking for the answer on google, but all i found was this: Where is the generated code of qt signals slots editor but my *.ui file looks like this: pastebin to the code. As you can see there's only one line with and nothing more. I can't find where the information about signals and slots is saved. Rebuild and clean options won't help.
This is not a bug in Qt. If you look at the generated code for your ui_*.h file, you'll notice that the last statement executed in the setupUi() function is a call to QMetaObject::connectSlotsByName().
Since your slot already conforms to the naming convention that this function is looking for, your slot is automatically connected to the signal.
By manually connecting the signal to the slot, in your settingswindow class, you effectively duplicate the connection.
As #Devopia mentioned, this is a documented feature.
I'm a beginner in Qt and trying to understand the SIGNAL and SLOT macros. When I'm learning to use the connect method to bind the signal and slot, I found the tutorials on Qt's official reference page uses:
connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))
However, this also works very well:
connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
So what exactly do the macros SIGNAL and SLOT do? Do they just look for the signal in the class the object belongs to and return the address of it?
Then why do most programmers use these macros instead of using &Obj1::signal since the latter appears to be simpler and you don't need to change the code if the parameters of the signal function change?
The use of the SIGNAL and SLOT macros used to be the only way to make connections, before Qt 5. The connection is made at runtime and require signal and slots to be marked in the header. For example:
Class MyClass : public QObject
{
Q_OBJECT
signals:
void Signal();
slots:
void ASlotFunction();
};
To avoid repetition, the way in which it works is described in the QT 4 documentation.
The signal and slot mechanism is part of the C++ extensions that are provided by Qt and make use of the Meta Object Compiler (moc).
This explains why signals and slots use the moc.
The second connect method is much improved as the functions specified can be checked at the time of compilation, not runtime. In addition, by using the address of a function, you can refer to any class function, not just those in the section marked slots:
The documentation was updated for Qt 5.
In addition, there's a good blog post about the Qt 4 connect workings here and Qt 5 here.
Addition to the first answer.
what exactly did the macro SIGNAL and SLOT do
Almost nothing. Look at the qobjectdefs.h:
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
It just adds 1 or 2. It means that next code is valid and works as expected:
QObject *obj = new QObject;
connect(obj,"2objectNameChanged(QString)",this,"1show()");//suppose this is a pointer to a QDialog subclass
obj->setObjectName("newNAme");
why do most programmers use these macros instead of using like
&Obj1::signal
Because these macros work not only in Qt5.
Because with these macros there is no complexity with overloaded
signals (it can make your code very dirty and it is really not a simple thing)
Because with new syntax you sometimes need to use specific
disconnects
More details here.
To complete TheDarkKnight's answer, it is an excellent practice to refactor legacy code that is using the old Qt 4 SIGNAL and SLOT macros to Qt 5's new syntax using function address.
Suddenly, connection error will appear at compile time instead of at runtime! It's very easy to make a Qt 4 connection error as any spelling mistake will result in such an error. Plus, the name of the function must be the fully qualified name, i.e preceded with the full namespace if any.
Another benefit is the ability to use a lambda for the slot function, which can reduce need of a named function if the slot body is trivial.
These macros just convert their parameters to signal/slot-specific strings. The Differences between String-Based and Functor-Based Connections can be found in the docs. In short:
String-based:
Type checking is done at Run-time
Can connect signals to slots which have more arguments than the signal (using default parameters)
Can connect C++ functions to QML functions
Functor-based:
Type checking is done at Compile-time
Can perform implicit type conversions
Can connect signals to lambda expressions
Qt4.8.5
QObject::connect(button,SIGNAL(clicked()),label,SLOT(setText("dd"));
The Qt Creator tell me It's wrong . What's the problem ?
That you can't pass arguments in a connect() statement. You need a "trampoline" slot that sets the text of your label (or, in Qt 5, you might choose to use a lambda).
For instance, by using a subclass:
class MyLabel : public QLabel {
Q_OBJECT
public slots:
void setTextToFoo() { setText("foo"); }
};
// ...
connect(button,SIGNAL(clicked()),label,SLOT(setTextToFoo());
It depends what exactly you are trying to achieve, to be honest, the example code you provided is not very functional, is "dd" a particular static value you are using, or potentially some other string? Where does it come from, is it in the scope of the called, or is it sent by the caller, which is the usual practice when sending arguments to slots.
Either way, in order to make a connect statement the first requirement is for the arguments to match, clicked() has no arguments while setText() has one, so there is a mismatch. As of how to resolve that mismatch, the easiest way is to use simple wrappers, although you can use a QSignalMapper and as of Qt5, lambdas and std::bind.
For starters, you cannot specify the actual argument instance in the connect statement, even with arguments on both sides you only need to specify the types to help resolve overloads (it is terrible with the new connection syntax in Qt5), and not any actual identifiers or literals.
In case of the more usual scenario, where the data is send to the slot by the caller, the identifier or literal is specified in the emit signal(value) statement. Since you don't have clicked(const QString &) you need a wrapper slot that you connect to clicked() and emit with the value in that wrapper slot, or subclass the button and add your own overload of clicked(QString).
In case the value is in the scope of the called, then subclassing doesn't make much sense, all you need is the wrapper slot in the scope of the called object.
If you want more, you will have to use Qt 5, whose syntax is significantly more powerful.
If the question is whats wrong, just remember the parameter number must be the same for the Signal and the Slot. Asking a collegue and according the Peppe, setText(QString) wait for One parameter and the Clicked() is empty...A custom slot is to call the setText() method indirectly.
You can look that : http://qt-project.org/doc/qt-4.8/widgets-calculator.html
It uses the QWidget, an important part of Qt interfaces beside QML.
I ran into a problem that I need to keep the mapped source signal's parameters. So far I only found examples to map signals without any parameter.
For example, the clicked() signal:
signalMapper = new QSignalMapper(this);
signalMapper->setMapping(taxFileButton, QString("taxfile.txt"));
connect(taxFileButton, SIGNAL(clicked()),
signalMapper, SLOT (map()));
connect(signalMapper, SIGNAL(mapped(QString)),
this, SLOT(readFile(QString)));
However, I would need to map some signal with its own parameters, for example the clicked(bool) signal, then the SLOT need to have two arguments doStuff(bool,QString):
connect(taxFileButton, SIGNAL(clicked(bool)),
signalMapper, SLOT (map()));
connect(signalMapper, SIGNAL(mapped(QString)),
this, SLOT(doStuff(bool,QString)));
However, it does not work like this? Is there any work around?
Thanks!
QSignalMapper does not provide functionality to pass signal parameters.
see documentation:
This class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal.
There are the ways to solve that:
If Qt4 is used then I'd suggest to implement your own signal mapper which supports parameters what you need.
QSignalMapper implementation would be good example to start.
But if Qt5 is used then you can do exactly what you need without usage QSignalMapper at all. Just connect signal to lambda:
connect(taxFileButton, &TaxFileButton::clicked, [this](bool arg) {
doStuff(arg, "taxfile.txt");
} );
I assume taxFileButton is instance of TaxFileButton class.
If C++11 lambda is not suitable for some reason then tr1::bind could be used to bind this and "taxfile.txt" values.
Please note such connection will not be disconnected automatically when this object is destroyed.
More details are here.