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.
Related
I would like to understand a simple piece of code I came across. It is a connection between an object of the interface and two signals.
The code is:
connect( ui->checkbox_legEnabled,
SIGNAL( stateChanged( int ) ), SIGNAL( edited() ) );
What is the meaning of this line of code?
Thanks,
Sara
With Qt signals and slots, you can directly connect one signal to another signal (or non-signal member function), without having a slot in between. See connection function invoked here is this overload of QObject::connect.
This line of code hence means, whenever the object ui->checkbox_legEnabled (presumably some kind of QCheckbox) emits the stateChanged signal (that has an int parameter passed along), directly emit another signal (or ordinary member function) edited (without parameters).
Short answer is you can connect a signal to another signal and that means that the second signal will also emit whenever the first signal is emitted, read more about signals and slots in the documentation here, also check out the new way to call connect (with function pointers)
Now in your case what it does it's basically allows you to keep the ui private, but in the same time forward the signals you want to the outside of your object, by allowing other objects to connect to the signal(s) you provide in the interface.
Incomplete usage example (based on your code, i named the class that contains your code MyWidget): the main-window (or whoever) that has access to your widget can be notified whenever something changes inside, by connecting to the edited signal:
void MainWindow::createMyWidget()
{
m_myWidget = new MyWidget(this);
connect(m_myWidget, &MyWidget::edited, this, &MainWindow::myWidgetWasEdited));
}
This way whenever something changes inside MyWidget the MainWindow can be notified about the edit and it can take the necessary actions inside the myWidgetWasEdited slot.
This can be expanded, if needed, to provide an signal for each particular "edit" instead of a single generic edited signal (but this depends on your needs).
I am using Qt5.
I have a very simple dialog class that inherits from QDialog.
I have a class that uses this dialog, and also a QFileDialog:
NameDlg m_name_dlg;
QFileDialog m_file_dlg;
This class also has some slots to handle dialog closing:
private slots:
void on_dlgName_accepted();
void on_FileDlgClosed(int result);
In the constructor I do some connecting:
QObject::connect(&m_file_dlg, SIGNAL(finished(int)),
this, SLOT(on_FileDlgClosed(int)));
QObject::connect(&m_name_dlg, SIGNAL(accepted()),
this, SLOT(on_dlgName_accepted()));
The first call to connect is fine, but the second call generates the output:
QMetaObject::connectSlotsByName: No matching signal for on_dlgName_accepted()
Curiously, my slot is correctly called when the name dialog is accepted!
The documentation (and header file) for QDialog says:
Signals
void accepted()
So it isn't a parameter mismatch.
As I said above, the signal is correctly called so my code all works fine, I just would really really like to understand why I get this warning (as an educational exercise) and also get rid of it (for peace of mind).
I cannot post full code, but I do believe there should be enough for anyone to understand the problem.
Things I have tried:
Using finished() instead.
Casting &m_name_dialog to a QDialog *.
Changing the signal to QDialog::accepted().
Thanks in advance.
In some part of your code you are using the method connectSlotsByName, if you have created a design (.ui) this usually calls it since compiling generates a file ui_somefile.h, and this file is used.
According to the docs:
void QMetaObject::connectSlotsByName(QObject *object)
Searches recursively for all child objects of the given object, and
connects matching signals from them to slots of object that follow the
following form:
void on_<object name>_<signal name>(<signal parameters>);
From the above it is observed that this method will try to connect the slots that have that format, and in your case the second slot fulfills it, when trying to connect it looks for the objects and signals but in your case it does not find it since the object does not exist dlgName and generates the warning you see.
This method is created by the .ui file because through the design you can create slots by right clicking on the widget and selecting go to slot, choosing the signal and finally creating the slot.
Note:
If you are going to create your own slot, avoid using the underscores as this could cause you problems because Qt would try to connect it and if the objects do not exist it will send you several warnings.
As far as the GUI designer, I understand how certain signals affect certain slots and invoke code. Other than that method, I am unsure about how to invoke a slot from a signal.
Take this example:
void QFileDialog::directoryEntered ( const QString & directory ) [signal]
This is a signal. When the directory is entered, I want this to populate a widget QColumnView with the contents of the directory.
How does a non widget signal invoke a slot of a UI widget.
I assume you use connect but the example provided uses two separate objects.
Signals and slots are features of QObject. It works well even for non-GUI code.
Connecting a signal to a slot is always done through the connect function:
connect(myDialog, SIGNAL(directoryEntered(QString)),
this, SLOT(updateColumn(QString)));
here assuming that you have updateColumn() slot in your main object handling the actual UI update of that QColumnView.
I am unable to find a proper simulation for ItemClicked() SIGNAL for QTreeWidget.
Is there a way to simulate it so that ItemClicked Signal is generated ?
e.g: we can emit ItemClicked in a derived class of QTreeWidget but cannot (as a QT rule) outside of it.
You can't use the emit call for class A to emit class B's signals. But note that the documentation for signals and slots says:
"You can connect as many signals as you want to a single slot, and a signal can be connected to as many slots as you need. It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)"
So you can work around this by declaring a signal in class A of the same signature as the one you want class B to emit, and connecting the signals together:
connect(
myclass, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
treewidget, SIGNAL(itemClicked(QTreeWidgetItem*, int))
);
Then emit itemClicked from myclass. If I'm not mistaken, it will work for this case...and fire the treewidget's itemClicked signal for you.
If I want to make a connection in Qt as follows:
QObject::connect(quitButton, SIGNAL(clicked()), &myapp, SLOT(quit());
What does &myapp refer to here? Why should it be used?
Thanks.
In this case what you get is that whenever the quitButton sends the signal clicked it will be sent to the slot quit in myapp. If the names mean what I think this is probably a button to, well..., quit your app.
Notice there are different versions of connect. It's hard to get the context from a single line of code, but anyway you might wanna check qApp which already represents your application.
EDIT: From another post from you I noticed you asked a trivial question about pointers. So if this is more about what the &character means, it takes the address of your object. This is pure C++ (nothing specific to Qt).
What does &myapp refer to here? Why should it be used?
This is the object that will handle the signal (The & takes the objects address (ie. the underlying code uses pointers).
QObject::connect(quitButton, SIGNAL(clicked()), &myapp, SLOT(quit());
Translation:
When the signal clicked is activated on the object quitButton
Call the slot quit on the object myapp.
What this means:
A signal is just a method that is called by the object when certain internal state changes. In this case the object will call signal when the user interfaced element is clicked on by the mouse.
The signal method will then call all (slot) methods that have been registered. So in this case when you click on the button signal() is called this in turn will call the quit() method on the object 'myapp`.
Given the way QT examples are normally done. myapp is an application object and the quit() method will cause the main thread to exit from the call to exec().