Qt show modal dialog (.ui) on menu item click - c++

I want to make a simple 'About' modal dialog, called from Help->About application menu. I've created a modal dialog window with QT Creator (.ui file).
What code should be in menu 'About' slot?
Now I have this code, but it shows up a new modal dialog (not based on my about.ui):
void MainWindow::on_actionAbout_triggered()
{
about = new QDialog(0,0);
about->show();
}
Thanks!

You need to setup the dialog with the UI you from your .ui file. The Qt uic compiler generates a header file from your .ui file which you need to include in your code. Assumed that your .ui file is called about.ui, and the Dialog is named About, then uiccreates the file ui_about.h, containing a class Ui_About. There are different approaches to setup your UI, at simplest you can do
#include "ui_about.h"
...
void MainWindow::on_actionAbout_triggered()
{
about = new QDialog(0,0);
Ui_About aboutUi;
aboutUi.setupUi(about);
about->show();
}
A better approach is to use inheritance, since it encapsulates your dialogs better, so that you can implement any functionality specific to the particular dialog within the sub class:
AboutDialog.h:
#include <QDialog>
#include "ui_about.h"
class AboutDialog : public QDialog, public Ui::About {
Q_OBJECT
public:
AboutDialog( QWidget * parent = 0);
};
AboutDialog.cpp:
AboutDialog::AboutDialog( QWidget * parent) : QDialog(parent) {
setupUi(this);
// perform additional setup here ...
}
Usage:
#include "AboutDialog.h"
...
void MainWindow::on_actionAbout_triggered() {
about = new AboutDialog(this);
about->show();
}
In any case, the important code is to call the setupUi() method.
BTW: Your dialog in the code above is non-modal. To show a modal dialog, either set the windowModality flag of your dialog to Qt::ApplicationModal or use exec() instead of show().

For modal dialogs, you should use exec() method of QDialogs.
about = new QDialog(0, 0);
// The method does not return until user closes it.
about->exec();
// In this point, the dialog is closed.
Docs say:
The most common way to display a modal dialog is to call its exec() function. When the user closes the dialog, exec() will provide a useful return value.
Alternative way: You don't need a modal dialog. Let the dialog show modeless and connect its accepted() and rejected() signals to appropriate slots. Then you can put all your code in the accept slot instead of putting them right after show(). So, using this way, you wouldn't actually need a modal dialog.

Related

Create a window of custom class type in Qt

This is my first question here, so I'm trying to not sound stupid!
EXPLANATION:
I have a main window in Qt that has a button to create (sub-?) windows within the main window. This can be done as many times as the user wants, and each sub-window displays the same set of properties/items. I figured writing a class to hold all these properties would be a smart way to go about it (this would inherit the main window class), as each instance of the child window would automatically get the properties. I am using a slot to create each instance.
QUESTION:
Besides the desired properties, what do I add to the child window class to let Qt know that if I create an object of that type it should open a window?
For example, say I have implemented all the child window properties in a header file that looks something like this:
#include <QObject>
#include <QDialog> //Not sure about this
class ChildWindow : public ParentWindow
{
Q_OBJECT
public:
ChildWindow(QObject* parent);
~ChildWindow();
//Remaining properties like QSpinBox, Radio buttons etc
}
how then would I implement my slot? Like this?
void Parent::Slot()
{
ChildWindow* window;
window = new ChildWindow(this);
window->show()
}
My problem is that I don't see any code that indicates that window is a separate window. I can see that it is of type ChildWindow, but does just including QDialog give it the show() functionality?
EDIT:
I realise the first suggestion would be try and see if this works, but in the unlikely scenario that it works I wouldn't have learnt anything and I still wouldn't know why it worked, and if it didn't I would be back here asking this same question. I hope you guys understand.
EDIT 2:
error C2039: 'show' : is not a member of 'ChildWindow'
So I am guessing including QDialog did not do the trick
EDIT 3:
If I add this to the ChildWindow constructor
QDialog* child;
child = new QDialog;
child->show()
Do I have to do the same in the slot definition as well?

Display the input of QLineEdit in a different window and or dialog?

I am writing a small QT gui application where there is a QLineEdit in my mainwindow.ui and I want to display the entered text in a separate dialog and or window when a button is pressed.
Now, I have stored the input in a variable, and I am also able to show this string on a label within this same mainwindow,
void MainWindow::on_GoButton_clicked()
{
QString mytext = ui->lineEdit_1->text();
ui->label_1->setText(mytext);
}
Now, I want to open a popup dialog (can be a window also), for example SecDialog;
SecDialog secdialog;
secdialog.setModal(true);
secdialog.exec();
and display the text of mainwindow->mytext string variable in a label of the SecDialog. How can I do that ??? I know it is a basic level question, but I think it will help clear lot of my doubts reagrding moving values of variables in between forms and classes.
Situation
So this is your situation:
From your code, the dialog is a modal dialog:
SecDialog secdialog;
//secdialog.setModal(true); // It's not needed since you already called exec(), and the
// dialog will be automatically set to be modal just like what
// document says in Chernobyl's answer
secdialog.exec();
Solution
To make the dialog display the text from the Window,
the concept is to pass the information(text) from the Window
to the dialog, and use a setter function from the dialog to display it.
Like Floris Velleman's answer, he passed the mytext string (by reference) to a customized dialog constructor and called the setter theStringInThisClass(myString) at once.
The implementation detail of this function is complemented by Chernobyl's answer (use the name setLabelText instead):
void SecDialog::setLabelText(QString str)
{
ui->label->setText(str); // this "ui" is the UI namespace of the dialog itself.
// If you create the dialog by designer, it's from dialog.ui
// Do not confuse with the ui from mainwindow.ui
}
Chernobyl suggested another way which calls the setter in the slot function and it bypasses the need of defining another constructor, but basically the concept is the same:
void MainWindow::on_GoButton_clicked()
{
QString mytext = ui->lineEdit_1->text();
ui->label_1->setText(mytext);
SecDialog secdialog;
secdialog.setLabelText(myText); // display the text in dialog
secdialog.exec();
}
Comment
I try to illustrate the concept as clear as possible, because from my previous experience on your question, you just "copy & paste" codes from answers and took them as your final solution, which is not right. So I hope this summary could help you understand the concept and then you may write your own code.
This task can be easy done with getter/setter method or with signal and slot, but setter is more suitable here. In SecDialog header:
public:
void setLabelText(QString str);
//in cpp
void SecDialog::setLabelText(QString str)
{
ui->label->setText(str);//it is label dialog
}
Usage:
secDialog.setLabelText(myText);
Also line where you set modal to true is not necessary because
This property holds whether show() should pop up the dialog as modal
or modeless. 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.
Assuming SecDialog is a custom class with an interface file as well you might want to pass it as a constructor argument or pass it by using another function.
So in the SecDialog constructor you could have something like:
SecDialog::SecDialog(QWidget* parent, const QString& myString)
: QDialog(parent),
theStringInThisClass(myString)
{}
And then you could call it like:
SecDialog secdialog(this, mytext);

How to properly clean-up a QWidget / manage a set of windows?

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.

Qt doesn't display child widget

How can i access ui files of children of a class. Lets say MainWindow class has twoa child dialog. I want to access LINEEDIT of dialog so that i can take text from there. Similarly how can i access ui files of parent inside child class in QT. Note: I havn't inherited any thing from Parent class.
I have writen the following code, in order to display a dialog but it won't show!
void MainWindow::displaydialog()
{
ItemDialog dialog= new ItemDialog(this);
dialog->show(); // it is not displaying the dialog
}
and how can i access the ui widgets like check whether ListWidget item has been selected or not.
Here is the code of itemdialog,
#include "itemdialog.h"
#include "ui_itemdialog.h"
#include "mainwindow.h"
ItemDialog::ItemDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ItemDialog)
{
ui->setupUi(this);
setWindowTitle("Status Dialog");
setFixedSize(QWidget::sizeHint());
}
ItemDialog::~ItemDialog()
{
delete ui;
}
void ItemDialog::on_pushButton_clicked()
{
MainWindow obj;
obj.okbuttonclicked(ui->lineEdit->text());
}
Please review an example such as this: http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
It explains how to use the ui files that you generate from Qt Designer. You shouldn't really think of them as "ui files" in the sense of accessing them on the widgets in your class. The idea is that you include them, and then use their setupUi() function to apply them to your given class. At that point, everything you created in qt designer, and that is in that ui file, is now a member of your class. They can be accessed via the naming you used in qt designer.
As for why your dialog isn't showing...I don't know because you only included 3 lines of code as an example. Theoretically it should show if Mydialog was properly set up. You could just try changing it to a QDialog to make sure you didn't do anything wrong with your custom class.
It depends what you want that dialog for. Either it's a modal dialog - some kind of a information display or retrival that blocks the function of your program until user reacts, or it's somekind of toolbox or similar, in which case you probably should not use QDialog.
If a modal dialog with a line edits and/or additional features is what you want, you should read up on QDialog in the doc. See the exec() function. Basic usage would go like this:
void MainWindow::displaydialog()
{
ItemDialog *dialog = new ItemDialog();
if (dialog->exec() == someApropriateReturnStatus)
{
QString somevalue = dialog->someValue();
int dialog->someOtherValue();
//do something with the value
}
delete dialog;
}
The point is that the ItemDialog class handles the UI internally and implements the getter functions accordingly, you should not (in most typical cases) access it's UI from outside.
If a simple line edit is all you want, you'd be better off using one of the standard dialogs already implemented in Qt, have a look at the Standard Dialogs Example

QT Creator Main window - how to change the interface for each element from the menu?

I am new to QT Creator. I did create a menu: Login || Open. When login is clicked I would like to see a line edit and a press button. When Open is clicked I would like to see a picture in the window. Can I change the interface of the same window depending on what I click in the menu bar? How can I do that?
I did something similar to this - an app with several major areas, toggled by an icon bar at the top.
I used a QStackWidget to stack the different application areas on top of each other, a set of QActions that I created using the designer, and a QActionGroup to implement the toggling.
When the actions are marked as "checkable" and grouped in a QActionGroup, theQToolBar only lets one be active at the time.
Here's a simplified extract of my code:
// MyApp.h
#include <QMainWindow>
class QAction;
class QActionGroup;
namespace Ui {
class MyApp;
}
class MyApp: public QMainWindow
{
Q_OBJECT
public:
explicit MyApp(QWidget *parent = 0);
~MyApp();
public slots:
void showSection(QAction* a);
private:
Ui::MyApp *ui;
QActionGroup* sections;
};
//MyApp.cpp
#include "structureapp.h"
#include "ui_structureapp.h"
#include <QActionGroup>
MyApp::MyApp(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyApp),
sections(new QActionGroup(this)),
{
ui->setupUi(this);
/* Populate section list */
/* Page indices for the stack widget*/
ui->actionSectionOne-> setData(0);
ui->actionSectionTwo-> setData(1);
ui->actionSectionThree-> setData(2);
sections->addAction(ui->actionSectionOne);
sections->addAction(ui->actionSectionTwo);
sections->addAction(ui->actionSectionThree);
ui->mainToolBar->addSeparator();
connect(sections, SIGNAL(triggered(QAction*)), this, SLOT(showSection(QAction*)));
/* Show the default section */
ui->actionContentSection->trigger();
}
MyApp::~MyApp()
{
delete ui;
}
void MyApp::showSection(QAction *a)
{
ui->mainArea->setCurrentIndex(a->data().toInt());
}
Yes, you can. As I explained earlier, each menu entry is a signal, and that's connected to a slot. With two different menu entries, you have two signals, and you'd connect them to two different slots. So, you could name your first slot onLogin, and the second slot onOpen. (It helps to choose descriptive names, so you'll understand your program when you come back on mondays).
Now, it the slot onLogin, you put the code for login. In the slot onOpen, you put the other code. But do consider what happens if you click the two menu entries one after another. Should that even be possible? If not, you may need another solution. It's quite common to use a QDialog for a login. When a dialog is active, you can't use the menu of the main application, so you can't accidentily hit onOpen when you're busy with the login.