How to close the qt application when setQuitOnLastWindowClosed(false) - qt

I wish to create a project including 3 windows: mainWindow, childWindow1, childWindow2, and only one window should show at a time. And I can switch between these windows.
So I have three tasks:
I place two buttons in the mainWindow and want to use them to make one of the child windows showing and the main window hiding.
And when I close the child window, I wish to show the main window.
When I close the main window, terminate the whole application.
I first had a problem:
If I close the child window, the application exit.
So I use the qApp.setQuitOnLastWindowClosed(false), and I got task 2 done.
But another problem occured:
If I close the main window, the program is still running.
Last problem:
How to show the child window in the task bar? It looks wired to run a program which can't be found in the taskbar.
I search everywhere I could, any help would be really appreciated!
main.cpp:
int main()
{
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
MainWindow mainWindow;
mainWindow.show();
return a.exec();
}
mainWindow.cpp:
void mainWindow::button1Clicked()
{
this->hide();
childWindow1 = new ChildWindow1(this);
connect(childWindow1, &QMainWindow::destroyed, this, &QMainWindow::show);
childWindow1->setWindowModality(Qt::WindowModal);
childWindow1->show();
}
childWindow1.cpp
ChildWindow1::ChildWindow1(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
}

To achieve this you need to do the following:
In your main.cpp:
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(false);
MainWindow w;
QObject::connect(&w, &MainWindow::exited, &a, &QApplication::quit);
w.show();
return a.exec();
exited signal would be used to exit the application after closing the main window.
In your MainWindow you should reimplement closeEvent like this:
void MainWindow::closeEvent(QCloseEvent *event)
{
QMainWindow::closeEvent(event);
emit exited();
}
Don't forget to add exited() to MainWindow signals section;
Finally, code for creating new windows should be the following:
child1 = new ChildWindow;
child1->setAttribute(Qt::WA_DeleteOnClose);
connect(child1, &QObject::destroyed, this, &QWidget::show);
child1->show();
hide();
Note that I don't pass this as a parent for a ChildWindow, this allows it to appear in the task bar.
So, creating a new ChildWindow will hide the main window, closing the ChildWindow will delete it automatically (that's another reason why you don't need to pass parent to ChildWindow constructor) and closing MainWindow will close the whole application thanks to our exited signal.

Related

How to connect a signal in Qdialog to a slot in QMainwindow

I work with QT Creator 4.9.1 and i've made a gui with the designer. I have a MainWindow with a stackedWidget and round about 60 pages, inside my mainwindow i have a button, with the onButton_clicked signal i open a dialog(show picture) to insert a number to set the page the user want to see inside the mainwindow.
My Problem is that the SIGNAL comes from the Dialog with the name on_pushButton_Enter_clicked and my SLOT is inside my mainwindow with the name setCurrentIndex(). I,ve read the post's: "How to Connect Signal from MainWindow to Slot in Dialog" and "Qt connect mainwindow and dialog using signal and slot".
But that doesn't help me because my dialog doesn't know about my mainwindow and i don't know how i can connect them.
Signal:
Dialognummer_eingeben.h
...
signals:
void enterButtonPressed();
...
void Dialognummer_eingeben::on_pushButton_Enter_clicked()
{
QString text = ui->lineEdit_Dialognummer->text();
ui->lineEdit_Dialognummer->setText("");
this->reject();
emit enterButtonPressed();
}
Slot:
Terminal::Terminal(QWidget *parent) : QMainWindow(parent), ui(new Ui::Terminal)
{
ui->setupUi(this);
QObject::connect(&dialog, SIGNAL(enterButtonPressed()), this, SLOT(setCurrentIndex()));
}
void Terminal::setCurrentIndex()
{
int num = dianr.getNum();
QString strNum = QString::number(num);
switch(num)
{
....
}
}
Edit: 1. Add signal and slot code
2. Make some changes inside the code
inside my mainwindow i have a button, with the onButton_clicked signal i open a dialog(show picture) to insert a number to set the page the user want to see inside the mainwindow.
You have to additionally add a signal in your dialog class which should be emitted once enter button was pressed, using on_pushButton_Enter_clicked as a function is not enough. Add a signal in the dialog class, like "enterButtonPressed()" and emit it in the function on_pushButton_Enter_clicked.
Inside the mainwindow (at some point where the dialog is created) add this line:
connect(dialog, SIGNAL(enterButtonPressed()), this, SLOT(SlotNameWhichShouldGetCalled()));
EDIT: Even if the above solution should work, a better solution came to my mind.
You generally should use the QDialog::accepted signal to connect to (see https://doc.qt.io/archives/qt-4.8/qdialog.html#accept).
Concrete steps:
In on_pushButton_Enter_clicked() at the bottom of the code add accept() instead of this-reject() (I assume you want the dialog to be closed succesful and not as rejected?)
Connect to the QDialog::accepted() signal by adding
QObject::connect(&dialog, SIGNAL(accepted()), this, SLOT(setCurrentIndex()));
Additionally ensure that you have no error in the connect(...) function. If the signal/slot is not found or is not matching you should see something in your application output in Qt Creator

Qt How to update GUI in the loop

I need to update screen to show how button is moving.
Here is my code:
void mouseReleaseEvent(QMouseEvent *event){
double b=(button->x()*event->y())/(button->x()-1);
double k=(button->y()-b)/button->x();
int time=0;
fnl=false;
if(event->button()==Qt::LeftButton)
{
while(!fnl)
{
int mX=button->x()-1;
int mY=k*(button->x()-1)+b;
button->setText(QString::number(b));
button->move(mX,mY);
QThread::sleep(1);
//here I need to update screen and show button
}
}
}
But it does not update GUI. It simply plays inside the loop.
Never use QThread::sleep() in the GUI thread, It will block the GUI thread from doing anything. Instead, You can use QTimer to schedule something to run at a later point in time. Also, Your slots/functions should be as short and optimized as possible in order to return control to the event loop and be able to handle other events that may happen.
You may want to have a look at this question for a similar problem.
The same technique can be applied here to solve the problem by replacing your while loop with a slot and a QTimer whose interval is set to 0. But Qt can do all that job using the animation framework, Here is an example of a button that gets moved when clicked:
#include <QtWidgets>
int main(int argc, char* argv[]){
QApplication a(argc, argv);
//create and show button
QPushButton button("Animated Button");
button.move(QPoint(100, 100));
button.show();
//create property animator object that works on the position of the button
QPropertyAnimation animation(&button, "pos");
//set duration for the animation process to 500ms
animation.setDuration(500);
//when the button is clicked. . .
QObject::connect(&button, &QPushButton::clicked, [&]{
//set the starting point of the animation to the current position
animation.setStartValue(button.pos());
//set the ending point to (250, 250)
animation.setEndValue(QPoint(250, 250));
//start animation
animation.start();
});
return a.exec();
}
Qt also provides many examples for using the animation framework. . .
A timer is the best option. If you want to use brute force you can call
qApp->processEvents();
inside your loop. Ugly but gets the job done.

Get event or notification when user click in taskbar/dock icon in Qt application

I'm developing an application in osx, windows, linux
I want to make feature like skype. when user click close windows, application not exit but hidden. When user click appicon on dock or taskbar, my mainwindow will re-open again.
How do I get a notification or filter events to known when user click on app icon?
First, you need to prevent your application window from closing when you hit the "close window" button. Assuming, that you use QMainWindow:
class MainWindow : public QMainWindow
{
// .. constructors, etc.
// ..
protected:
void closeEvent(QCloseEvent *)
{
// Do not close, but hide the window.
hide();
}
};
Qt has the dedicated class to handle the task bar icons - QSystemTrayIcon. So, the simple application would look like:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mw;
QSystemTrayIcon tray; // needs an icon.
// Show the main window when user activates the tray icon.
QObject::connect(&tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
&mw, SLOT(show()));
tray.show();
return app.exec();
}
This should be helpful:
void setQuitOnLastWindowClosed(bool quit)

Update QMainWindow Parent elements from child

I have two QMainWindows (A and B) defined, and B is initialized from A. In other words, B is the child of A.
I need to update the elements of A based on the user input in B, so what is the way to update elements in the parent window from child window because apparently we can't update elements across windows.
A simple example such as setting a label in A based on input in B would be great.
Thanks in advance.
Use signals and slots to do this, connect them before you instantiate either of the QMainWindows.
Usually I initialize all my windows from within my main class, so that I can set up the signals and slots.
//----- MORE INFO HERE ----//
When you create a new QWindow project, you get a mainwindow.cpp class, what you need to do is create a childWindow.cpp class which looks the same, then your main function looks like this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
ChildWindow child;
connect(&w, SIGNAL(labelChanged),
&child, SLOT(updateLabelChange));
w.show();
return a.exec();
}
Then, you can use signals and slots to control them. The important thing to remember is that you should write a new class for each window, so your child window should have its own class. Hope that helps.

Select text of QLineEdit on focus

I have created a dialog using QtDesigner. There is a QLineEdit object in the dialog with some default content. When the dialog initializes and the focus goes to the QLineEdit, I want the default content to be auto selected, so once the user start writing, the previous content will be overwritten.
EDIT:
In constructor:
dialog->accept();
and
connect( dialog, SIGNAL(accepted()), QlineObj, SLOT( selectAll() ) );
This is an older question, but nevertheless, I ended up here searching for a solution this exact problem. It can be solved in the following way:
Create a class derived from QLineEdit and override the focusInEvent in the header:
void focusInEvent(QFocusEvent *event) override;
Then implement it like so:
void MyLineEdit::focusInEvent(QFocusEvent *event)
{
// First let the base class process the event
QLineEdit::focusInEvent(event);
// Then select the text by a single shot timer, so that everything will
// be processed before (calling selectAll() directly won't work)
QTimer::singleShot(0, this, &QLineEdit::selectAll);
}
Just in case anybody else wonders how this can be done ;-)
Call
lineEdit->selectAll();
after you set the default text. (In the dialog constructor, perhaps.)
There is a simpler method to get almost the same behaviour, which is to set the default content using setPlaceholderText() instead of setText(). This will show the default content grayed out and as soon as the QLineEdit gains focus, it will disappear.
You can use QApplication::focusChanged along with QTimer::singleShot to select all the text on a changed focus.
Normally your QApplication is declared in main, so use QObject::connect there, eg:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
My_Main_Window w();
QObject::connect(&a, SIGNAL(focusChanged(QWidget*, QWidget*)),
&w, SLOT(my_focus_changed_slot(QWidget*, QWidget*)));
w.show();
return a.exec();
}
Remember to make the public slot in the My_Main_Window class:
public slots:
void my_focus_changed_slot(QWidget*, QWidget*);
Then in your definition of my_focus_changed_slot, check if the second QWidget* (which points to the newly focused widget) is the same as the QLineEdit you wish to select all of, and do so using QTimer::singleShot so that the event loop gets called, then the QLineEdit has the selectAll slot called immediately after, eg
void My_Main_Window::focus_changed(QWidget*, QWidget* new_widget) {
if (new_widget == my_lineedit) {
QTimer::singleShot(0, my_lineedit, &QLineEdit::selectAll);
}
}
where my_lineedit is a pointer to a QLineEdit and is part of the My_Main_Window class.

Resources