In my Qt Program, there is a menu bar where one of the menu options is Settings. When the user click on the Settings window, it should open a Settings window. The settings window gets opened with a openSettingsWindow() function. This is how I made the Settings menu in the main window:
QMenu settingsMenu("&Settings");
QAction *settings = toolsMenu.addAction("&Settings");
Window::connect(settings,&QAction::triggered,&mainWindow,[&mainWindow](){
openSettingsWindow();
});
menuBar.addMenu(&toolsMenu);
mainWindow is the main window and Window is the class used to create windows which inherits from QWidget. Its constructor takes two arguments: the title of the window and the icon of the window. This is the openSettingsWindow() function:
void openSettingsWindow(){
Window settingsWindow("Settings","icon.png");
settingsWindow.show();
}
The problem is that when I click ont he Settings option in the Settings menu, the Settings window opens as it should, but it closes directly after less than a second. What should I do to keep the Settings window opened?
The local variable settingsWindow gets destructed when your function openSettingsWindow goes out of scope, you need to keep the object valid as long as you want to show your settingsWindow.
one solution would be to allocate the Window object on the heap, and use the Qt::WA_DeleteOnClose to make Qt delete the Window object for you when it is closed, here is how your openSettingsWindow would look like:
void openSettingsWindow(){
Window* settingsWindow = new Window("Settings","icon.png");
settingsWindow->setAttribute(Qt::WA_DeleteOnClose);
settingsWindow->show();
}
You need to return a reference to that Window and keep it until you're no longer using it.
Window *openSettingsWindow() {
Window *settingsWindow = new Window("Settings, "icon.png");
settingsWindow.show();
return settingsWindow;
}
QMenu settingsMenu("&Settings");
QAction *settings = toolsMenu.addAction("&Settings");
Window *settingsWindow = null;
Window::connect(settings,&QAction::triggered,&mainWindow,[&mainWindow, &settingsWindow](){
settingsWindow = openSettingsWindow();
});
menuBar.addMenu(&toolsMenu);
You might want to find a better way of storing the settingsWindow pointer in the main function if you're going to have many possible open windows but this will work.
Remember to call delete() on that pointer when you're done with the settings window (likely on the window close event)
Related
I'm trying to create a C++ Widget Application in QT with multiple windows where you can return to the mainwindow by clicking a Pushbutton.
I'm a complete noobie so I try to follow YouTube tutorial and for opening windows by pushbuttons I watched this one (minute 8:00): https://youtu.be/tP70B-pdTH0
It works when opening secondary windows from the main one but if I try to do the same from a secondary windows to the mainwindow it doesn't. It appears an error "cannot initialize object parameter of type 'Widget' with an expression of type 'MainWindow'"
in the source file I wrote:
void Crediti::on_pushButton_clicked()
{
close();
mainwindow = new MainWindow(this);
mainwindow->show();
}
mainwindow->show(); is the incriminated part
I also included mainwindow in the header of the secondary window and specified the class
MainWindow *mainwindow
in the header so It recognizes mainwindow initially in the source.
I'm doubting if doing this thing is possible at all, and if not so how can I make a pushbutton that, when clicked, can redirect me to the mainwindow?
Please I need this for a school application, thanks
So here you're creating a new main window each time you click on the button. From your description that's not the behaviour you want. I understand you have an application with a main window and other secondary windows and want to bring up the main window when clicking on the button, assuming the main window still exists somewhere and hasn't been deleted.
What I would try is to find the main window when hitting the push button and show / raise it, something along the line of:
#include <QApplication>
#include "MainWindow.h" // Adapt that one to you main window header
// ... some code of your secondary window
void SecondaryWindow::on_pushButton_clicked()
{
for(auto widget : QApplication::topLevelWidgets())
{
// This will return a nullptr if the widget is not the main window
auto mainWindow = dynamic_cast<MainWindow*>(widget);
// skip if not the main window
if(!mainWindow)
continue;
// Show it if hidden
if(mainWindow->isHidden())
mainWindow->show();
// raise it, as in bring it forward, over all other windows
mainWindow->raise();
}
// eventually close the current window if that's what you want
close();
// if you close it and don't need it any more you might also want to delete it
deleteLater();
}
Note that this function won't do anything if the main window has been deleted in the meantime, which might be the case if you closed it and the Qt::WA_DeleteOnClose attribute is set.
Hope that helps.
I am running into the following issue:
Users presses "Ctrl+N" which goes into function MainWindow::newAction()
In MainWindow::newAction(), create a QDialog dlg(centralWidget()) and call dlg.exec()
While dlg is open, users pressed "Ctrl+N" again
The result is that dlg never gets deleted (it will only get deleted once centralWidget() gets deleted).
The call stack is something like this:
MainWindow::newAction ()
...
MainWindow::newAction()
I am wondering how to handle this case. I want all of the local dialog variables from the first call to newAction() to be deleted by the time we go into the function newAction() again.
You also can try something like this:
void MainWindow::newAction() {
const auto dialog = new MyDialog(centralWidget());
// When user will close the dialog it will clear itself from memory
connect(dialog, &QDialog::finished, [dialog]() {
dialog->deleteLater();
});
dialog->exec();
}
However, a good move would be to stop user from summoning more QDialogs than a single one, given that this one is a modal dialog(might be a good idea to keep this dialog pointer as a class member and check is it on screen already before calling exec() on it.
If i understood the question right, you want one dialog to be opened and want to delete it before a new dialog request comes in?
If that's the case you can do following:
In MainWindow.h declare QDialog *dlg = nullptr
In your MainWindow.cpp newAction() function you can do following:
void newAction()
{
if(dlg != nullptr)
{
dlg->close();
dlg->deleteLater();
//or
//dlg->destroy(); // this will immediately free memory
}
dlg = new QDialog(centralWidget());
...
//dlg->exec(); // This will automatically make QDialog modal.
dlg->show(); // This will not make a QDialog modal.
}
I hope this will help. Remember QDialogs when displayed with exec() they automatically behave as Modal window. show() will make it non-modal.
I'm new at Qt. I've created small application and I created second page help.cpp. On MainWindow.cpp I have a button, that switches to help.cpp page.
Function which switches to "help" page:
void MainWindow::on_box1button_clicked()
{
helpwindow = new help(this);
helpwindow->show();
}
This code works properly.
On the "help" page I've got a QButton, which will switch back to mainwindow.cpp. How Can I code that button to actually make this action?
If your intention by "switching" is hiding one window and showing another one, so you can simply pass a reference of the main window to your help window and there when you want to switch back, you can hide/close itself and show the main window.
MainWindow (this code is fine)
helpwindow = new help(this);
helpwindow->show();
HelpWindow
When you want to switch back to the main window, you can do this:
// Hide the HelpWindow itself
// or this->close()
this->hide()
// Show the MainWindow (i.e. the parent window)
QWidget *parent = this->parentWidget();
parent->show();
Since you are creating a new help(this); on mainwindow it is better to close the help window
Use
this->close();
For now I can do:
void MainWindow::on_actionPATH_triggered() {
std::unique_ptr<QDialog> win(new QDialog());
win->exec();
}
Should I use async / run in separate threadto avoid blocking main window or is there way to subscribe to close even and delete / free object there?
You can use just show()
void MainWindow::on_actionPATH_triggered() {
QDialog* win = new QDialog();
//needed connect
win->setAttribute(Qt::WA_DeleteOnClose);//we don't want memory leak
win->show();
}
and use
win->setModal(false);//but it is default option, you don't need to change it
From doc:
By default, this property is false and show() pops up the dialog as
modeless. Setting his property to true is equivalent to setting
QWidget::windowModality to Qt::ApplicationModal. exec() ignores the
value of this property and always pops up the dialog as modal.
Qt::WA_DeleteOnClose will delete your dialog, when user close it.
You can also set parent to dialog:
QDialog* win = new QDialog(this);
In this case win will be delete with your mainWindow.
Info about Qt parent child relationship
And you don't need here separate thread.
Let's say I have 2 windows in my application, and two classes responsible for them:
class MainWindow: public QMainWindow and class SomeDialog: public QWidget.
In my Main Window I have a button. When it is clicked, I need to display the second window. I do it this way:
SomeDialog * dlg = new SomeDialog();
dlg.show();
Now, the user does something in the window, and closes it. At this point I want to get some data from that window, and then, I suppose, I will have to delete dlg. But how do I catch the event of that window being closed?
Or is there another way not to have a memory leak? Maybe It would be better to create an instance of each window on startup, and then just Show()/Hide() them?
How do I manage such a case?
It is advised to use show() / exec() and hide() instead of dynamically creating the dialog every time you want to show it. Also use QDialog instead of QWidget.
In the constructor of your main window create it and hide it
MainWindow::MainWindow()
{
// myDialog is class member. No need to delete it in the destructor
// since Qt will handle its deletion when its parent (MainWindow)
// gets destroyed.
myDialog = new SomeDialog(this);
myDialog->hide();
// connect the accepted signal with a slot that will update values in main window
// when the user presses the Ok button of the dialog
connect (myDialog, SIGNAL(accepted()), this, SLOT(myDialogAccepted()));
// remaining constructor code
}
In the slot connected to the buttons's clicked() event simply show it, and if necessary pass some data to the dialog
void myClickedSlot()
{
myDialog->setData(data);
myDialog->show();
}
void myDialogAccepted()
{
// Get values from the dialog when it closes
}
Subclass from QWidget and reimplement
virtual void QWidget::closeEvent ( QCloseEvent * event )
http://doc.qt.io/qt-4.8/qwidget.html#closeEvent
Also it looks like the widget you want to show is a dialog. So consider using QDialog or it's subclasses. QDialog has useful signals you can connect to:
void accepted ()
void finished ( int result )
void rejected ()
I think you are looking for the Qt::WA_DeleteOnClose window flag: http://doc.qt.io/archives/qt-4.7/qt.html#WidgetAttribute-enum
QDialog *dialog = new QDialog(parent);
dialog->setAttribute(Qt::WA_DeleteOnClose)
// set content, do whatever...
dialog->open();
// safely forget about it, it will be destroyed either when parent is gone or when the user closes it.