Whenever the application window is minimized or maximized i want to link that signal with a function.
This is the code.
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w(model ); // This is QWidget
w.show();
QObject::connect(&w, &QWindow::windowStateChanged, [&](Qt::WindowState state) {
});
// how will i define the QObject::connect
return application.exec();
}
What would be the parameters for the QObject::connect function ?
You cannot use the connect function to connect to different slots based on the given value. You can however simply call the functions based on the value by checking the value in your lambda.
At least, you could if you had the signal. However, your connect suggests that w is - or inherits - a QWindow. You can obviously only connect to signals your class provides. As your Renderer is a QWidget, you have to check that class.
The documentation of QWidget tells us, that there is no windowStateChanged signal, but it states:
When the window state changes, the widget receives a changeEvent() of type QEvent::WindowStateChange.
So therefor we can create our own signal and connect to that. This can look similar to the following working example:
#ifndef RENDERER_H
#define RENDERER_H
#include <QWidget>
#include <QEvent>
class Renderer : public QWidget {
Q_OBJECT
signals:
void stateChanged(bool isMaximized);
protected:
void changeEvent(QEvent *e)
{
if(e->type() == QEvent::WindowStateChange) {
emit stateChanged(windowState() & ~Qt::WindowMaximized);
}
QWidget::changeEvent(e);
}
};
#endif // RENDERER_H
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w; // This is QWidget
w.show();
QObject::connect(&w, &Renderer::stateChanged, [&](bool maximized) {
qDebug() << "Maximized?" << maximized;
});
return application.exec();
}
I was able to solve by using QApplication::focusWindow()
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
Renderer w; // This is QWidget
w.show();
QObject::connect(QApplication::focusWindow(), &Renderer::stateChanged, [&](bool maximized) {
qDebug() << "Maximized?" << maximized;
});
return application.exec();
}
Related
It is very straightforward to connect to QMenu::triggered or QMenu::hovered signals by calling QObject::connect and pass the appropriate QAction.
However, I do not know how to use QMenu::aboutToHide signal, as there is no action passed to that signal.
How to use QMenu::aboutToHide and QMenu::aboutToShow signals or those are just virtual functions that can be overridden?
The signals in the world of Qt are not functions, never invoke them. The signals notify that something has happened with the QObject and send information if necessary.
In the case of triggered and hovered it is necessary to send the QAction because several QActions in a QMenu, then the developer thought that it is necessary to know with which QAction was interacting. On the other hand with aboutToShow and aboutToHide the signal does not send anything because it wants to notify is that if the QMenu was shown or hidden, respectively. Is there any need to know that QMenu was shown or hidden if he did it ? no, because the sender did it, I do not use other properties that we do not have at hand.
Example of use:
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QMenu *foo_menu = w.menuBar()->addMenu("Foo Menu");
for(const QString & name: {"action1", "action2", "action3"}){
foo_menu->addAction(name);
}
QObject::connect(foo_menu, &QMenu::aboutToShow, [](){
qDebug()<<"aboutToShow";
});
QObject::connect(foo_menu, &QMenu::aboutToHide, [](){
qDebug()<<"aboutToHide";
});
QObject::connect(foo_menu, &QMenu::triggered, [](QAction *action){
qDebug()<< "triggered: " <<action->text();
});
QObject::connect(foo_menu, &QMenu::hovered, [](QAction *action){
qDebug()<< "hovered: " <<action->text();
});
w.show();
return a.exec();
}
And what happens if you have several QMenu that connect to the same slot? How do I know QMenu was shown or hidden?
The solution is to use sender() which is a method that belongs to the QObject class that returns the object that emitted the signal, in this case the QMenu.
Example:
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QDebug>
class MainWindow: public QMainWindow{
public:
MainWindow(QWidget *parent=nullptr):
QMainWindow(parent)
{
for(const QString & name_of_menubar: {"bar1", "bar2", "bar3"}){
QMenu *menu = menuBar()->addMenu(name_of_menubar);
connect(menu, &QMenu::aboutToShow, this, &MainWindow::on_aboutToShow);
connect(menu, &QMenu::aboutToHide, this, &MainWindow::on_aboutToHide);
for(const QString & name: {"action1", "action2", "action3"}){
menu->addAction(name);
}
}
}
private slots:
void on_aboutToShow(){
if(QMenu *menu = qobject_cast<QMenu *>(sender()))
qDebug()<<"aboutToShow" << menu->title();
}
void on_aboutToHide(){
if(QMenu *menu = qobject_cast<QMenu *>(sender()))
qDebug()<<"aboutToHide" << menu->title();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I have this piece of code. I need to catch the event when my program is about to close, but I cant make that the slot gets called.
QtSingleCoreApplication app(argc, argv);
if(app.isRunning()){
return 0;
}else{
MyClass mainClass;
QObject::connect(&app, SIGNAL(aboutToQuit()),
&mainClass, SLOT(aboutToQuit()));
return app.exec();
}
QtSingleCoreApplication inherits from QCoreApplication
Instead of making MyClass a separate QObject class, why don't you inherit it directly from QtSingleCoreApplication. That way, you can catch the signal before the whole signal/slot mechanism is shut down.
class MyApplication : public QtSingleCoreApplication {
Q_OBJECT
public:
MyApplication(int argc, char **argv) : QtSingleCoreApplication(argc, argv) {
connect(this, &QCoreApplication::aboutToQuit, this, &MyApplication::cleanupApplication);
}
public slots:
void cleanupApplication();
};
void MyApplication::cleanupApplication(){
// do something important
}
void main(int argc, char **argv){
MyApplication app(argc, argv);
return app.isRunning() ? 0 : app.exec();
}
I've created a Qt Quick 2.5 app and connected signals and slots to my C++ module,
I only can send signals from C++ and activate QML slots, but I can't receive QML signals on Qt side.
Here is main.cpp:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
AlfredApp(engine.rootObjects().first());
return app.exec();
}
here is my QML code which holds the signal:
MouseArea {
id: mainButtonMouseArea
objectName: "mainButtonMouseArea"
anchors.fill: parent
signal signalClicked()
onClicked: {
console.log("clicked")
signalClicked()
}
}
I always get the console message from QML when I click on the MouseArea.
Here is my c++ constructor:
AlfredApp::AlfredApp(QObject* viewRootObject, QObject* parent)
: QObject(parent), d(new Private)
{
d->viewRootObject = viewRootObject;
d->viewMainButton = viewRootObject->findChild<QObject*>("mainButton");
d->viewMainButtonIcon = viewRootObject->findChild<QObject*>("mainButtonIcon");
d->viewMainButtonMouseArea = viewRootObject->findChild<QObject*>("mainButtonMouseArea");
// Signals/Slots connection
connect(d->viewMainButtonMouseArea, SIGNAL(signalClicked()),
this, SLOT(mainButtonClicked()));
connect(this, SIGNAL(signalListening()),
d->viewMainButtonIcon, SLOT(listening()));
connect(this, SIGNAL(signalProcessing()),
d->viewMainButtonIcon, SLOT(processing()));
}
Here is my slot that never gets called:
void AlfredApp::mainButtonClicked()
{
qDebug() << "Main Button Clicked";
}
BTW, are there some qml code examples that have slots/function that respond normally to C++ signals
Just for testing, could you connect the signal and the slot in main.cpp?
Something like this:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
QObject *rootObj = engine.rootObjects().first();
QObject *item = rootObj->findChild<QObject*>("mainButtonMouseArea");
AlfredApp alfredapp(rootObj);
QObject::connect(item, SIGNAL(signalClicked()),
&alfredapp, SLOT(mainButtonClicked()));
return app.exec();
}
This should work. If not, try the idea suggested by #hyde.
Here you have the sample code.
I have following main.cpp:
#include <QtQml>
#include <QApplication>
#include <QQmlApplicationEngine>
#include "database/uepeoplemodel.h"
#include "core/uestatus.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now, inside main.cpp I create two objects from classes:
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
and I connect signal from UePeopleModel to slot in ueApplicationStatus:
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
The problem is when uePeopleModel is created, the signal is emmited inside constructor:
UePeopleModel::UePeopleModel(QObject* parent)
: QSqlQueryModel(parent),
QQuickImageProvider(QQmlImageProviderBase::Image,
QQmlImageProviderBase::ForceAsynchronousImageLoading)
{
if(!QSqlDatabase::connectionNames().contains(UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE,
Qt::CaseInsensitive))
{
this->ueSetDatabase(QSqlDatabase::addDatabase(UePosDatabase::DATABASE_DRIVER,
UePosDatabase::UeDatabaseConnectionNames::DATABASE_CONNECTION_NAME_PEOPLE));
} // if
this->ueDatabase().setHostName(/*this->uePosSettings()->ueDbHostname()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_HOSTNAME);
this->ueDatabase().setDatabaseName(/*this->uePosSettings()->ueDbName()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_NAME);
this->ueDatabase().setUserName(/*this->uePosSettings()->ueDbUser()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_USERNAME);
this->ueDatabase().setPassword(/*this->uePosSettings()->ueDbPassword()*/UePosDatabase::UeDatabaseConnectionParameters::DATABASE_PASSWORD);
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
/*
if(this->lastError().isValid())
qDebug() << this->lastError();
*/
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
// qDebug() << this->ueDatabase().lastError();
}
// qDebug() << this->ueDatabase().connectionNames();
} // default constructor
before connect is issued and therfore ueApplicationStatus object does not catch is with slot. Does anyone has idea how to get rid of this situation?
You shouldn't use the constructor to open the connection with the database.
Use the constructor only to instantiate other classes, initialize variables, allocate memory and so on.
In your case, your constructor should be used to initialize the database, but you could create another method with:
if(this->ueDatabase().open())
{
emit this->ueSignalDatabaseConnectionChanged(CONNECTED);
this->setQuery(UePosDatabase::UeSqlQueries::UeTablePeople::SQL_QUERY_GET_ALL_PEOPLE,
this->ueDatabase());
}
else
{
emit this->ueSignalDatabaseConnectionChanged(NOT_CONNECTED);
}
This method would be called after the connect you have in your main.cpp.
I've solved the problem by adding method void ueConnectToDatabase() and moved the content of constructor into it and redefined main.cpp as:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
UeStatus* ueApplicationStatus=new UeStatus(qApp);
UePeopleModel* uePeopleModel=new UePeopleModel(qApp);
QObject::connect(uePeopleModel,
SIGNAL(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)),
ueApplicationStatus,
SLOT(ueSignalDatabaseConnectionChanged(UeTypeDatabaseConnectionStatus)));
uePeopleModel->ueConnectToDatabase();
engine.rootContext()->setContextProperty("uePeopleModel",
uePeopleModel);
engine.rootContext()->setContextProperty("ueApplicationStatus",
ueApplicationStatus);
engine.addImageProvider(QLatin1String("uePeopleModel"),
uePeopleModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
Now the object is created, signal and slot connected and AFTER this the connection to database occurs.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDialog dlg;
dlg.exec();
return a.exec();
}
That's all my code, but when I close the window, The process isn't exit, it seems that drop in the loop a.exec().
Generally speaking, calling any exec is a bad idea, other than QCoreApplication::exec() or QDrag::exec(). The presence of exec() and waitForXxx() methods is an enticing trap for the unwary. Those methods are "easy" to use, but that ease comes at a price of hard to track bugs. Don't use them.
You should simply show the dialog:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMessageBox msg;
msg.setText("Hello");
msg.addButton(QMessageBox::Close);
msg.show();
return a.exec();
}
If you wish to wait for the dialog to be accepted or rejected, you should use the dialog's clickedButton slot. QMessageBox has a long-standing bug that makes the accepted and rejected signals useless :(
// https://github.com/KubaO/stackoverflown/tree/master/questions/messagebox-show-25545652
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
#include <functional>
[...]
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
auto onClick = [&msg]() {
auto role = msg.buttonRole(msg.clickedButton());
if (role == QMessageBox::NoRole)
QApplication::quit();
if (role == QMessageBox::YesRole) {
auto label = new QLabel("I'm running");
label->setAttribute(Qt::WA_DeleteOnClose);
label->show();
}
};
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
QObject::connect(&msg, &QMessageBox::buttonClicked, onClick);
#else
QObject::connect(&msg, SIGNAL(buttonClicked(QAbstractButton*)),
new FunctorSlot{onClick, &msg}, SLOT(call()));
#endif
msg.show();
return app.exec();
}
#include "main.moc"
For Qt 4, you need the following helper:
// Qt 4 only
struct FunctorSlot : public QObject {
Q_OBJECT
public:
std::function<void()> callable;
template <typename Fun>
FunctorSlot(Fun && fun, QObject * parent = {}) :
QObject{parent}, callable{std::forward<Fun>(fun)} {}
Q_SLOT void call() {
callable();
}
};
Possible solution:
QApplication a(argc, argv);
QDialog dlg;
QTimer::singleShot( &dlg, 0, SLOT(exec()) );
return a.exec();
It will work well. First - application event loop will be started. Then dialog event loop will be executed. After closing of dialog, both dialog and application loop will be finished. Application loop will be terminated automatically (by default), when last window is closed.
But, as noted by #thuga - there are no reason to call exec(). It is enough to call show() method.