How to finish Qt programm from any place? - c++

My example:
main.cpp:
QApplication a(argc, argv);
MainWindow w;
w.start();
return a.exec();
w.start():
if (cf.exec()){
this->show();
} else {
qDebug()<<"Need exit";
//here should be exit
}
At comment place, I tried to do: qApp->exit() and qApp->quit() and this->close() (but 'this' not shown and of cource close() is not working). How can I finish app from any place of code?
Whole code:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.start();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "CadrForm.h"
#include "TeacherForm.h"
#include "DepartmentForm.h"
#include "CategoriesForm.h"
#include "PostForm.h"
#include "RanksAndDegreesForm.h"
#include "TeachersRankAndDegreeForm.h"
#include "ConnectionForm.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
void start();
~MainWindow();
signals:
void widgetChanged(QWidget*);
private slots:
void on_actionCadr_triggered();
void resetMainLayout(QWidget* w);
void on_actionTeacher_triggered();
void on_actionDepartment_triggered();
void on_actionPost_triggered();
void on_actionCategories_triggered();
void on_actionRanksAndDegrees_triggered();
void on_actionTeachersRD_triggered();
private:
ConnectionForm cf;
CadrForm *cadrForm;
TeacherForm *teacherForm;
DepartmentForm *departmentForm;
CategoriesForm *categoriesForm;
PostForm *postForm;
RanksAndDegreesForm *ranksAndDegreesForm;
TeachersRankAndDegreeForm *teachersRankAndDegreeForm;
QWidget *current;
Ui::MainWindow *ui;
void addWidgetToMainLayout(QWidget *w);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
connect(this, SIGNAL(widgetChanged(QWidget*)), this, SLOT(resetMainLayout(QWidget*)));
ui->setupUi(this);
cadrForm = new CadrForm(this);
teacherForm = new TeacherForm(this);
departmentForm = new DepartmentForm(this);
categoriesForm = new CategoriesForm(this);
postForm = new PostForm(this);
ranksAndDegreesForm = new RanksAndDegreesForm(this);
teachersRankAndDegreeForm = new TeachersRankAndDegreeForm(this);
addWidgetToMainLayout(cadrForm);
addWidgetToMainLayout(teacherForm);
addWidgetToMainLayout(departmentForm);
addWidgetToMainLayout(categoriesForm);
addWidgetToMainLayout(postForm);
addWidgetToMainLayout(ranksAndDegreesForm);
addWidgetToMainLayout(teachersRankAndDegreeForm);
}
void MainWindow::start()
{
if (cf.exec()){
this->show();
} else {
qDebug()<<"Need exit";
qApp->quit();
qDebug()<<"still working";
}
}
void MainWindow::addWidgetToMainLayout(QWidget *w)
{
ui->mainLayout->insertWidget(0, w);
ui->mainLayout->itemAt(0)->widget()->hide();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resetMainLayout(QWidget *w)
{
int index;
if (current)
{
index = ui->mainLayout->indexOf(current);
ui->mainLayout->itemAt(index)->widget()->hide();
}
index = ui->mainLayout->indexOf(w);
if (index != -1) ui->mainLayout->itemAt(index)->widget()->show();
else {
addWidgetToMainLayout(w);
resetMainLayout(w);
}
current = w;
setWindowTitle(current->windowTitle());
}
void MainWindow::on_actionCadr_triggered()
{
emit widgetChanged(cadrForm);
}
void MainWindow::on_actionTeacher_triggered()
{
emit widgetChanged(teacherForm);
}
void MainWindow::on_actionDepartment_triggered()
{
emit widgetChanged(departmentForm);
}
void MainWindow::on_actionPost_triggered()
{
emit widgetChanged(postForm);
}
void MainWindow::on_actionCategories_triggered()
{
emit widgetChanged(categoriesForm);
}
void MainWindow::on_actionRanksAndDegrees_triggered()
{
emit widgetChanged(ranksAndDegreesForm);
}
void MainWindow::on_actionTeachersRD_triggered()
{
emit widgetChanged(teachersRankAndDegreeForm);
}
And ConnectionForm - it's just a QDialog with some GUI and without any additional code.

It looks like the problem is you're not allowed to call QApplication::quit() or QApplication::exit() until the QApplication event loop has actually started. The event loop gets started by QApplication::exec(), so you're calling quit()/exit() too soon for it to have an effect.
You can fix this either by moving the quit()/exit() call so that it's in the event loop (e.g. by moving your MainWindow::start() code to the QMainWindow::showEvent() slot), or by changing your MainWindow::start() to return a value, inspect that value in main, and exit (without calling QApplication::exec()`) if it's a value that indicates your process should exit early.

Since you start the dialog event loop "early" - which is blocking -, you do not get to the event loop of the application.
If this is an intentional design, you better call exit(3) and remove the application event loop.
If you want to have the application event loop running, then you will need to make sure that it runs before you get to the point of your dialog execution.
The quick fix would be to start a single shot QTimer right just before the application event loop is started and that would trigger your "start" method call.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.start();
QTimer::singleShot(200, w, SLOT(start()));
return a.exec();
}
and change the start to a slot, respectively.
In the long run, you may wish to consider a button and so on for bringing your dialog up, however.

The idiomatic way of queuing a method call until the event loop gets a chance to run is:
QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
Thus, your main would become:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
return a.exec();
}

Related

change theme with radio button Qwidget in Qt C++

I want to change my application Theme with QRadioButton in the QWidget application.
can anyone help me?
I have a Setting class that has some settings and one of them is changing the theme between dark and light.
it is a C++ app with OpenGL.
void Settings::on_DarkTheme_clicked()
{
}
void Settings::on_lightTheme_clicked()
{
}
what should I have to write in these 2 methods?
I used .qss file like this
int main(int argc, char *argv[])
{
QSurfaceFormat fmt;
fmt.setVersion(3,3);
fmt.setProfile(QSurfaceFormat::CoreProfile);
fmt.setSamples(8);
fmt.setOption(QSurfaceFormat::StereoBuffers);
fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
QSurfaceFormat::setDefaultFormat(fmt);
loadSettings();
App app(argc, argv);
QFile stylesheetFile("./Combinear.qss");
stylesheetFile.open(QFile::ReadOnly);
QString stylesheet = QLatin1String(stylesheetFile.readAll());
app.setStyleSheet(stylesheet);
MainWindow w;
w.show();
const auto returnValue = app.exec();
App::setFinished();
return returnValue;
}
but it didn't Work and I'm confused
First of all, I add a radioButton in my mainwindow.ui .
this is my mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow: public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void changedDark();
void changedLight();
private slots:
void on_radioButton_clicked(bool checked);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
and my mainwindow.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_radioButton_clicked(bool checked)
{
if (checked)
{
ui->radioButton->setText("Dark");
emit changedDark();
}
else
{
ui->radioButton->setText("Light");
emit changedLight();
}
}
and my main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QObject::connect(&w, &MainWindow::changedDark, &a, [&]
{
/**
* Load the application style
*/
QFile dark_styleFile(":/theme/themes/MaterialDark.qss");
dark_styleFile.open(QFile::ReadOnly);
/**
* Apply the loaded stylesheet
*/
QString style(dark_styleFile.readAll());
a.setStyleSheet(style);
});
QObject::connect(&w, &MainWindow::changedLight, &a, [&]
{
/**
* Load the application style
*/
QFile light_styleFile(":/theme/themes/Ubuntu.qss");
light_styleFile.open(QFile::ReadOnly);
/**
* Apply the loaded stylesheet
*/
QString style(light_styleFile.readAll());
a.setStyleSheet(style);
});
return a.exec();
}
This is my result:
you can clone it from this repo:
https://github.com/parisa-hr/qt-theme-example

Switching two mainwindows

I am new to QT GUI programming.
I am trying to test switching two mainwindows continously by using show and hide.
I have created a simple code in main.cpp
main(){
QApplication a(argc , argv)
Mainwinodw1 *window1 = new Mainwindow1();
Mainwinodw1 *window2 = new Mainwindow2();
for (;;)
{
window1->show();
delay();
window1->hide();
window2->show();
delay();
window2->hide();
}
return a.exec();
}
The test can display the windows only one time , but duirng the second iteration they dont show and hide.
Can somebody help to fix this.
Try to use Qt timers instead of hardcoded delay function.
main.cpp file:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Mainwindow1 *window1 = new Mainwindow1();
Mainwindow2 *window2 = new Mainwindow2();
WindowSwitcher ws(window1, window2, 2000);
window1->show();
return a.exec();
}
WindowSwitcher source code:
#include "windowswitcher.h"
#include <QTimer>
WindowSwitcher::WindowSwitcher(QMainWindow *w1, QMainWindow *w2, int delay) : QObject(), window1(w1), window2(w2)
{
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(switchWindow()));
timer->start(delay);
}
void WindowSwitcher::switchWindow()
{
if (window1->isVisible())
{
window1->hide();
window2->show();
}
else
{
window1->show();
window2->hide();
}
}
WindowSwitcher header file:
#include <QObject>
#include <QMainWindow>
class WindowSwitcher : public QObject
{
Q_OBJECT
public:
explicit WindowSwitcher(QMainWindow *w1, QMainWindow *w2, int delay);
private:
QMainWindow *window1;
QMainWindow *window2;
public slots:
void switchWindow();
};

how to force Qt mainWindow to wait for some changes

I am designing UI for my opencv application and I'm new in Qt.
I have a QString in my Qt code that is a licence plate. and it can be change when a car arrive to our camera, but we don't know when it change.
and when car arrive we need to show it's plate on a QTableView on MainWindow.
how can I handle it in Qt?
I make my code simple here:
mainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
.
.
.
public slots:
void set_plate(QString p);
signals:
void plate_changed(QString newPlate);
private:
Ui::MainWindow *ui;
QString plate;
};
mainWindow.cpp
void MainWindow::set_plate(QString newPlate)
{
if(plate != newPlate){
plate = newPlate;
emit plate_changed(newPlate);
}
}
MainWindow::MainWindow(QString p, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
plate(p)
{
.
.
.
QTableWidgetItem* item2;
item2 = new QTableWidgetItem(plate);
ui->table->setItem(table->rowCount() - 1, 0, item2);
}
main.cpp
int main(int argc, char *argv[])
{
QString plate;
.
.
.
//some changes on plate
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
return a.exec();
}
thanks
When you detect a car, send a signal to your instance. Connect your emitted signal to your slot and that's all.
https://wiki.qt.io/Qt_for_Beginners#Creating_custom_signals_and_slots
Let's begin with a paraphrase of the code for main that you've posted
void someChangesOnPlate(QString &);
int main(int argc, char *argv[])
{
QString plate;
someChangesOnPlate(plate);
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
return a.exec();
}
It seems that someChangesOnPlate would be a plate detection code that runs continuously in a loop, taking images from the camera, detecting plates, and extracting the plate numbers.
The main mistake in your approach is: while the plate detection code is running, the application window isn't shown yet - the code after someChangesOnPlate hasn't executed yet! The execution is within someChangesOnPlate, after all.
What you need to do, instead, is to run someChangesOnPlate in a separate thread, and to have that thread invoke the main window's newPlate method in a thread-safe fashion. Given C++11, this is a very straightforward change:
void someChangesOnPlate(MainWindow *);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w(plate);
w.show();
std::thread thread(someChangesOnPlate, &w);
int rc = a.exec();
thread.join(); // wait for the thread to finish
return rc;
}
Within the someChangesOnPlate code, the thread-safe call to newPlate is done as follows:
void someChangesOnPlate(MainWindow * w) {
while (...) {
// process camera images
...
QString plate = ....;
...
QMetaObject::invoke(w, "newPlate", Qt::QueuedConnection, Q_ARG(QString, plate));
...
}
}
Finally, I understand that you want a new item to be added to the table whenever a new plate is indicated. Here's how to do it:
class MainWindow : public QMainWindow {
Q_OBJECT
Ui::MainWindow ui; // no need for it to be a pointer
QString m_lastPlate;
public:
MainWindow(QWidget * parent = 0) : QMainWindow(parent) {
ui.setupUi(this);
}
Q_SLOT void newPlate(const QString & plate) {
if (plate == m_lastPlate) return;
m_lastPlate = plate;
auto item = new QTableWidgetItem(plate);
ui->table->setItem(table->rowCount() - 1, 0, item);
}
}

In Qt, find out that all windows are closed, when QApplication::processEvents() is used?

There is a QApplication::lastWindowClosed() signal. The Qt docs say:
This signal is emitted from QApplication::exec()
when the last visible primary window [...] is closed.
However, I used QApplication::processEvents() instead of QApplication::exec() in a loop. See this minimal example. (save as qapp.h, it must end on .h, and run qmake -project && qmake && make)
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QMainWindow>
int exitprogram = 0;
class MyMainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void request_exit() {
qDebug() << "exit requested";
exitprogram = 1;
}
};
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyMainWindow w;
QObject::connect(&app, SIGNAL(lastWindowClosed()),
&w, SLOT(request_exit()));
w.show();
while(!exitprogram)
{
app.processEvents(QEventLoop::AllEvents, 20);
}
}
Is there still a good way to find out, or to even get a signal, if the last such window is being closed?
Whatever reason you have for using processEvents in place of exec is wrong. The two are not equivalent. exec() will, for example, process the deferred deletion events, while processEvents will not. As you've just found out, the lastWindowClosed signal is not emitted either. This should be telling you right there that you're doing it wrong.
The idiomatic Qt way of doing something each time the event loop goes for another iteration, is to use a zero-timeout timer. Those are virtual timers that do not use operating system resources, they are an internal Qt construct.
The example below illustrates the following:
Use of a zero-timeout timer within a QObject.
Use of the State Machine Framework to manage the state of the application. We have three states:
sWindows is the state when the application windows are still shown. The application is set not to quit on the last window being closed.
sSetup is the state reached when the last of the windows was closed. In this state we ask our Object to send its notification signal with the number of times it executed the zero-timeout timer. This will set the proper count in the message label (C++11 code) or in the count label (legacy code). The state machine automatically transitions to the following state.
sMessage is the state when the message labels are shown, and the application is set to quit upon the last window being closed.
The use of a state machine leads to declarative code: you tell the state machine how to behave, without implementing all of the behavior. You only have to implement the behaviors that are specific to your application and not already provided by Qt. The objects that the state machine manages can be very much decoupled, and the code that declares the behavior of the machine is cohesive - it can be all in one function, instead of being spread around. This is considered to be good software design.
Do note that the zero-timeout timer is very diligent: it will force your handler code to execute constantly whenever the event loop is empty. This will force 100% CPU consumption on the core where the GUI thread happens to be executing. If you have nothing to do, you should stop() the timer.
Qt 5 C++11 Code
// https://github.com/KubaO/stackoverflown/tree/master/questions/close-process-19343325
#include <QtWidgets>
int main(int argc, char** argv)
{
QApplication app{argc, argv};
QLabel widget{"Close me :)"};
QLabel message{"Last window was closed"};
int counter = 0;
auto worker = [&]{
counter++;
};
QTimer workerTimer;
QObject::connect(&workerTimer, &QTimer::timeout, worker);
workerTimer.start(0);
QStateMachine machine;
QState sWindows{&machine};
QState sSetup {&machine};
QState sMessage{&machine};
sWindows.assignProperty(qApp, "quitOnLastWindowClosed", false);
sWindows.addTransition(qApp, &QGuiApplication::lastWindowClosed, &sSetup);
QObject::connect(&sSetup, &QState::entered, [&]{
workerTimer.stop();
message.setText(QString("Last window was closed. Count was %1.").arg(counter));
});
sSetup.addTransition(&sMessage);
sMessage.assignProperty(&message, "visible", true);
sMessage.assignProperty(qApp, "quitOnLastWindowClosed", true);
machine.setInitialState(&sWindows);
machine.start();
widget.show();
return app.exec();
}
Qt 4/5 C++11 Code
#include <QApplication>
#include <QLabel>
#include <QStateMachine>
#include <QBasicTimer>
class Object : public QObject {
Q_OBJECT
QBasicTimer m_timer;
int m_counter = 0;
protected:
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId())
m_counter ++;
}
public:
Object(QObject * parent = 0) : QObject{parent} {
m_timer.start(0, this);
}
Q_SLOT void stop() const {
m_timer.stop();
emit countedTo(m_counter);
}
Q_SIGNAL void countedTo(int) const;
};
int main(int argc, char** argv)
{
QApplication app{argc, argv};
Object object;
QLabel widget{"Close me :)"};
QLabel message{"Last window was closed"};
QLabel count;
QStateMachine machine;
QState sWindows{&machine};
QState sSetup{&machine};
QState sMessage{&machine};
sWindows.assignProperty(qApp, "quitOnLastWindowClosed", false);
sWindows.addTransition(qApp, "lastWindowClosed()", &sSetup);
object.connect(&sSetup, SIGNAL(entered()), SLOT(stop()));
count.connect(&object, SIGNAL(countedTo(int)), SLOT(setNum(int)));
sSetup.addTransition(&sMessage);
sMessage.assignProperty(&message, "visible", true);
sMessage.assignProperty(&count, "visible", true);
sMessage.assignProperty(qApp, "quitOnLastWindowClosed", true);
machine.setInitialState(&sWindows);
machine.start();
widget.show();
return app.exec();
}
#include "main.moc"
I modified your code and now it works. I override closeEvent
==> test.cpp <==
#include "windows.hpp"
int exitprogram = 0;
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyMainWindow w;
w.show();
while(!exitprogram)
{
app.processEvents(QEventLoop::AllEvents, 20);
}
}
==> test.pro <==
TEMPLATE = app
TARGET = test
QT += widgets
INCLUDEPATH += .
HEADERS += windows.hpp
# Input
SOURCES += test.cpp
==> windows.hpp <==
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QMainWindow>
#include <QCloseEvent>
extern int exitprogram;
class MyMainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void closeEvent(QCloseEvent *event) override {
exitprogram = 1;
event->accept();
}
};

Possible to make QDialog shake in OSx

Since Qt is using Cocoa under OSX, is it possible to make a modal QDialog to shake if the user enters the wrong password for example? Im not able to find anything about it but it would be really nice to implement on mac.
Thanks!
I'm not aware of a built-in way to do it, but you could implement the shaking yourself, like this:
header.h
#include <QtGui>
class ShakyDialog : public QDialog
{
Q_OBJECT
public slots:
void shake()
{
static int numTimesCalled = 0;
numTimesCalled++;
if (numTimesCalled == 9) {
numTimesCalled = 0;
return;
}
vacillate();
QTimer::singleShot(40, this, SLOT(shake()));
}
private:
void vacillate()
{
QPoint offset(10, 0);
move(((shakeSwitch) ? pos() + offset : pos() - offset));
shakeSwitch = !shakeSwitch;
}
bool shakeSwitch;
};
main.cpp
#include "header.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
ShakyDialog dialog;
QHBoxLayout layout(&dialog);
QPushButton button("Push me.");
layout.addWidget(&button);
QObject::connect(&button, SIGNAL(clicked()), &dialog, SLOT(shake()));
dialog.show();
return app.exec();
}