I need to raise the click signal of my QPushButton when I press Enter on QSpinBox (actually on every input box), but even if my button is the default button, the following code doesn't work.
#include <QApplication>
#include <QHBoxLayout>
#include <QPushButton>
#include <QSpinBox>
#include <QMessageBox>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QWidget* window = new QWidget();
QSpinBox* spinbox = new QSpinBox();
QPushButton* button = new QPushButton("Ok");
button->setDefault(true);
QObject::connect(button, &QPushButton::clicked, []()
{
QMessageBox::question(nullptr, "Test", "Quit?", QMessageBox::Yes|QMessageBox::No);
});
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(spinbox);
layout->addWidget(button);
window->setLayout(layout);
window->show();
return app.exec();
}
How can I fix it?
You can see in the Qt documentation about QPushButton :
The default button behavior is provided only in dialogs
You are using a QWidget and expect the default button behavior to work. Just use a QDialog instead of QWidget :
QDialog * window = new QDialog();
...
you can use Event
The QObject::installEventFilter() function enables this by setting up
an event filter, causing a nominated filter object to receive the
events for a target object in its QObject::eventFilter() function. An
event filter gets to process events before the target object does,
allowing it to inspect and discard the events as required.
void QObject::installEventFilter ( QObject * filterObj )
Installs an event filter filterObj on this object. For example:
monitoredObj->installEventFilter(filterObj);
An event filter is an object that receives all events that are sent to
this object. The filter can either stop the event or forward it to
this object. The event filter filterObj receives events via its
eventFilter() function. The eventFilter() function must return true if
the event should be filtered, (i.e. stopped); otherwise it must return
false.
Related
I wrote a basic C++ program for simulating the signal and slot process. I made a push button "button", a QVBoxLayout "layout". I added the button in the layout. Everything is fine till now. But when push button is made to connect by signal and slot, there's are two problem/errors.
"no instance of overloaded function "QObject::connect matches the argument list"."
'QObject::connect': none of the 3 overloads could convert all the argument types.
Question:
I am sure that there's something missing, which I am not able to decipher. Here, the push button "button" has to invoke the function "connectFunc". Instead it gives me above two errors. How to make the button invoke the function?
This is my code.
#include "signalsslots.h"
#include <QtWidgets/QApplication>
#include<qpushbutton.h>
#include<qboxlayout.h>
#include<iostream>
using std::cout;
using std::endl;
void connectFunc()
{
cout << endl << "connected " << endl;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton* button = new QPushButton("Press Here");
QAction* bAction = new QAction;
button->addAction(bAction);
QVBoxLayout* layout = new QVBoxLayout;
layout->addWidget(button);
//layout->SetFixedSize(200, 150);
QObject::connect(bAction, SIGNAL(QPushButton::clicked()), &a,(connectFunc()));
QWidget w;
w.setLayout(layout);
w.setWindowTitle("Signal and Slot Example !!!");
w.show();
return a.exec();
}
FYI, I am using VS 2019 for writing Qt widget applications.
The QObject::connect() function that you use, connects a signal (i.e. a method) of an object to a slot (i.e. a method) of another object.
What you are telling QT is to connect the clicked() method of your QAction object, to the connectFunc() of your QApplication object. Both methods do not exist on those objects!
What you probably want is to connect the clicked() method of your QButton button to the free function connectFunc(). Like this:
QObject::connect(button, &QPushButton::clicked, &connectFunc);
Note that this requires QT5. (See Is it possible to connect a signal to a static slot without a receiver instance?)
For example I have 2 widgets and I press button on first widget. I need to delete first widget and create new widget.
How is it possible? I mean some structure for this. I used stackedwidgets, but pages from stackedwidgets located in memory. I need to avoid this.
void Window::on_registrationButton_clicked(){
ui->logWindow->hide();
ui->RegistrWindow->show();
}
As you are going to eliminate the object you can not do it within the same class the object belongs to, you have to do it outside of it, for example in the following code I created a signal that is triggered when the button is pressed, this I have connected it to a lambda function where the new object is created and the object that emits it is eliminated.
class LogWindow: public QWidget{
Q_OBJECT
public:
LogWindow(const QString &text, QWidget *parent=Q_NULLPTR):QWidget(parent){
setLayout(new QVBoxLayout);
btn = new QPushButton(text, this);
layout()->addWidget(btn);
connect(btn, &QPushButton::clicked, this, &LogWindow::customSignal);
}
signals:
void customSignal();
private:
QPushButton *btn;
};
class RegWindow : public QWidget{
[...]
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LogWindow *log= new LogWindow("LogWindow");
RegWindow *reg;
QObject::connect(log, &LogWindow::customSignal, [®, &log](){
reg = new RegWindow("RegWindow");
reg->show();
log->deleteLater();
});
log->show();
return a.exec();
}
#include "main.moc"
The complete example can be found in the following link
I'm reading a book on QT4 and here's an example from the book:
QApplication a(argc, argv);
QWidget window;
QVBoxLayout* mainLayout = new QVBoxLayout(&window);
QLabel* label = new QLabel("0");
QSpinBox* spinBox = new QSpinBox;
QSlider* slider = new QSlider(Qt::Horizontal);
mainLayout->addWidget(label);
mainLayout->addWidget(spinBox);
mainLayout->addWidget(slider);
QObject::connect(spinBox, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));
QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)), label, SLOT(setNum(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
window.show();
As the book and compilation show, changing the value of one of the widgets leads to changing the values of the other elements.
What I don't understand is how it happens. How do we pass that value from one widget to the rest? There's no variable that gets changed by means of one widget and gets passed to the others.
PS Conceptually, I do understand the idea of slots and signals and 'connect'. It's how the value is passed from one widget to the rest is the problem.
A signal is a C++ method with code generated by a utility called moc (meta object compiler). A slot is regular C++ method, with code under your control. A connection is a way of letting the signal know what slots to call. When the signal gets emitted, it really means that you call the machine-generated method that iterates the connection list.
Conceptually, the valueChanged signal implementation looks like this:
void valueChanged(int value) {
for (slot : this->slots)
(slot.object->*slot.method)(value);
}
Thus, when the slider "emits" its signal, it calls each slot with a given value. After the connections are made, you should think of the spinbox's valueChanged signal as doing the following:
void SpinBox::valueChanged(int value) {
// 1st connection
label->setNum(value);
// 2nd connection
slider->setVale(value);
}
There's no "variable" that gets changed because the signal-slot mechanism is, at its core, an easier-to-use way of doing indirect method calls (via method pointers and instance pointers).
In modern code (Qt5/C++11), that example would be (this is complete code):
#include <QtWidgets>
int main(int argc, char** argv) {
QApplication a{argc, argv};
QWidget window;
QVBoxLayout mainLayout{&window};
QLabel label{"0"};
QSpinBox spinBox;
QSlider slider{Qt::Horizontal};
mainLayout.addWidget(&label);
mainLayout.addWidget(&spinBox);
mainLayout.addWidget(&slider);
QObject::connect(&spinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
&label, static_cast<void(QLabel::*)(int)>(&QLabel::setNum));
QObject::connect(&spinBox, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
&slider, static_cast<void(QSlider::*)(int)>(&QSlider::setValue));
QObject::connect(&slider, static_cast<void(QSlider::*)(int)>(&QSlider::valueChanged),
&label, static_cast<void(QLabel::*)(int)>(&QLabel::setNum));
QObject::connect(&slider, &QSlider::valueChanged, &spinBox, &QSpinBox::setValue);
window.show();
return a.exec();
}
I am trying to create a MDI document program. I have a question on creating the subwindow.
This is my mainwindow constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("MDI"));
workspace = new QMdiArea;
setCentralWidget(workspace);
//fileNew();
createActions();
createMenus();
createToolbars();
statusBar()->showMessage(tr("Done"));
enableActions();
}
The interesting point is the fileNew(); function. It is a private slot function actually which I want to invoke when "New File" button is triggered. Here is the private slot fileNew() function:
void MainWindow::fileNew()
{
DocumentWindows* document = new DocumentWindows;
workspace->addSubWindow(document);
}
This function works perfectly when I call from the mainwindow constructor. However, there is a problem when I call it from the createActions(); function which uses a signal-slot mechanism.
Here is my createActions()
void MainWindow::createActions()
{
newAction = new QAction(QIcon(":/Image/NewFile.png"),tr("&New"),this);
newAction->setShortcut(tr("Ctrl+N"));
newAction->setToolTip(tr("Open new document"));
connect(newAction, SIGNAL(triggered(bool)), this, SLOT(fileNew()));
}
No subwindow is created even the SLOT is triggered. Subsequently, I find out that if I add document->show();, everything works well.
void MainWindow::fileNew()
{
DocumentWindows* document = new DocumentWindows;
workspace->addSubWindow(document);
document->show();
}
My question is: Why the show() function is needed in a SLOT but not in the constructor?
PS. DocumentWindows is just a class inherits QTextEdit.
This problem has nothing to do with the class of the widgets one is using. It is unrelated to documents, MDI, or the main window. After you add a child widget to a widget that is already visible, you must explicitly show it. Otherwise, the widget will remain hidden.
All widgets are hidden by default. When you initially show the MainWindow, all of its children are recursively shown too. When you later add a child MDI widget, it remains hidden. When widgets are added to layouts, they are shown by default - but your widget is managed by the MDI area, not by a layout.
This is a minimal test case demonstrating your issue:
// https://github.com/KubaO/stackoverflown/tree/master/questions/widget-show-32534931
#include <QtWidgets>
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QWidget w;
w.setMinimumSize(200, 50);
QLabel visible{"Visible", &w};
w.show();
QLabel invisible{"Invisible", &w};
invisible.move(100, 0);
return app.exec();
}
I'm trying to get to grips with Qt's signal and slots mechanism. I have an app with a QPushButton and a QSpinBox. When I click the button I want the spinbox to change to 20. What signal and slot do I need to set up?
The code below shows the app, the connect function is the one I am having trouble with.
As I understand it the setValue(int) slot of QSpinBox will not work here because the clicked() signal of QPushButton has a different signature, and anyway how would I pass the value 20 to the spinbox? Do I need to write some sort of auxiliary function to act as a slot which calls spinbox->setValue(20)? If so, what form would that take?
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *window = new QWidget;
QSpinBox *spinbox = new QSpinBox;
QPushButton *button = new QPushButton("Set to 20");
spinbox->setRange(0, 100);
// What should I put below?
QObject::connect(button, SIGNAL(clicked()), spinbox, SLOT(???????));
QLayout *layout = new QHBoxLayout;
layout->addWidget(spinbox);
layout->addWidget(button);
window->setLayout(layout);
window->show();
return app.exec();
}
You can either do:
class AuxSignals : public QObject
{
Q_OBJECT
...
signals:
void valueChanged(int);
public slots:
void buttonClicked() { emit valueChanged(20); }
};
...
// On main.cpp
AuxSignals *auxSignals = new AuxSignals;
QObject::connect(button, SIGNAL(clicked()), auxSignal, SLOT(buttonClicked));
QObject::connect(auxSignals, SIGNAL(valueChanged(int)), spinbox, SLOT(setValue(int)));
or
class AuxSignals : public QObject
{
Q_OBJECT
...
QSpinBox *m_spinBox;
public:
AuxSignals(QSpinBox *spinBox) : m_spinBox(spinBox) {}
public slots:
void buttonClicked() { m_spinBox->setValue(20); }
};
...
// On main.cpp
AuxSignals *auxSignals = new AuxSignals(spinBox);
QObject::connect(button, SIGNAL(clicked()), auxSignals, SLOT(buttonClicked()));
I prefer the first option because it doesn't require the AuxSignals class to have a pointer to a specific QWidget.
I think you are looking at a custom SLOT here. A QPushButton::clicked signal will give a boolean (true|false) event. If you catch it using QSpinBox::setValue you won't go very far. The QSpinBox::setValue expects an int and converts the input boolean to 0 or 1 as the case maybe and your spinbox increments by only 1 unit. If you were to write a custom SLOT you can actually set the exact slider value with far more control.