Dialog QDialog layout manager

Poor knowledge in UI, screenshot demonstration

I'll write this down

6Dialog QDialog _ 

6.1 Basic concepts

Dialog boxes are an integral part of GUI programs. Many functional components that cannot or are not suitable to be placed in the main window must be set in the dialog box. A dialog box is usually a top-level window that appears at the top of the program and is used to implement short-term tasks or simple user interaction.

Qt uses the QDialog class to implement dialog boxes. Just like the main window, we usually design a class to inherit QDialog. QDialog (and its subclasses, and all classes of Qt::Dialog type) have additional explanations for their parent pointers: if parent is NULL, the dialog box will act as a top-level window, otherwise it will act as a parent component. Child dialog box (at this time, its default position is the center of the parent). The difference between top-level windows and non-top-level windows is that top-level windows will have their own location on the taskbar, while non-top-level windows will share the location of their parent components.

Dialog boxes are divided into modal dialog boxes and non-modal dialog boxes.

  1. A modal dialog box blocks input from other windows in the same application.

Modal dialog boxes are common, such as the "Open File" function. You can try opening a file in Notepad. When the Open File dialog box appears, we cannot operate on the window parts other than this dialog box.

  1. The opposite is a non-modal dialog box, such as the find dialog box. We can continue to edit the contents of the notepad while the find dialog box is displayed.

6.2 Standard dialog box

The so-called standard dialog boxes are a series of dialog boxes built into Qt to simplify development. In fact, there are many dialog boxes that are common, such as opening files, setting colors, printing settings, etc. These dialog boxes are almost identical in all programs, so there is no need to implement such a dialog box in each program.

Qt's built-in dialog boxes are roughly divided into the following categories:

  1. QColorDialog: Select color;
  2. QFileDialog: Select a file or directory;
  3. QFontDialog: Select font;
  4. QInputDialog: Allows the user to enter a value and returns its value;
  5. QMessageBox: Modal dialog box, used to display information, ask questions, etc.;
  6. QPageSetupDialog: Provides paper-related options for the printer;
  7. QPrintDialog: Printer configuration;
  8. QPrintPreviewDialog: print preview;
  9. QProgressDialog: Displays the operation process.

6.3 Custom message box

Qt supports modal and modeless dialog boxes.

Modal and non-modal implementation:

  1. Using QDialog::exec() to implement application-level modal dialog boxes
  2. Use QDialog::open() to implement window-level modal dialog boxes
  3. Use QDialog::show() to implement a modeless dialog box.
modal dialog
  1. Qt has two levels of modal dialogs:
    1. Application level modals

When this modal dialog box appears, the user must first interact with the dialog box until the dialog box is closed, and then can access other windows in the program.

    1. Window level modal

This modal only blocks the window associated with the dialog box, but still allows the user to interact with other windows in the program. Window-level modals are especially suitable for multi-window mode.

The general default is application-level modality.

In the example below, we call exec() to display the dialog box, so this is a modal dialog box. When a dialog box appears, we cannot have any interaction with the main window until we close the dialog box.

     QDialog dialog;

     dialog.setWindowTitle(tr("Hello, dialog!"));

dialog.exec();

Modeless dialog box

Next we try to change exec() to show() to see the non-modal dialog box:

     QDialog dialog(this);

     dialog.setWindowTitle(tr("Hello, dialog!"));

      dialog.show();

Did it backfire? The dialog box flashed by! This is because the show() function does not block the current thread, the dialog box is displayed, and then the function returns immediately and the code continues execution. Note that the dialog is built on the stack, the show() function returns, the MainWindow::open() function ends, and the dialog is destructed beyond the scope, so the dialog box disappears. Once we know the reason, we can easily change it. We change the dialog to be created on the heap. Of course, this problem disappears:

    QDialog *dialog = new QDialog;

    dialog->setWindowTitle(tr("Hello, dialog!"));

    dialog->show();

If you are careful enough, you should find that there is a problem with the above code: the dialog has a memory leak! dialog uses new to allocate space on the heap, but it has never been deleted. The solution is also very simple: assign the MainWindow pointer to the dialog. Remember the Qt object system we talked about earlier?

However, there is a problem with this: What if our dialog box does not appear in an interface class? Since the parent of QWidget must be a QWidget pointer, this restricts us from passing an ordinary C++ class pointer to the Qt dialog box. In addition, if there are strict restrictions on memory usage, when we use the main window as the parent, if the main window is not closed, the dialog box will not be destroyed, so it will always occupy memory. In this scenario, we can set the WindowAttribute of the dialog:

     QDialog *dialog = new QDialog;

     dialog->setAttribute(Qt::WA_DeleteOnClose);

     dialog->setWindowTitle(tr("Hello, dialog!"));

     dialog->show();

The setAttribute() function automatically destroys the dialog box when the dialog box is closed.

6.4 Message dialog box

QMessageBox is used to display message prompts. We generally use several static functions provided by it:

  1. Shows the About dialog box.

void about(QWidget * parent, const QString & title, const QString & text)

This is the simplest dialog box, its title is title, the content is text, and the parent window is parent. The dialog box has only one OK button.

  1. Displays the About Qt dialog box. This dialog box is used to display information about Qt.

void aboutQt(QWidget * parent, const QString & title = QString()):

  1. Displays a critical error dialog box.

StandardButton critical(QWidget * parent,

const QString & title,

const QString & text,

StandardButtons buttons = Ok,

StandardButton defaultButton = NoButton):

This dialog box will display a red error symbol. We can specify the buttons it displays through the buttons parameter. By default there is only one Ok button, we can use the StandardButtons type to specify multiple buttons.

  1. Similar to QMessageBox::critical(), except that this dialog box provides a normal message icon.

StandardButton information(QWidget * parent,

const QString & title,

const QString & text,

StandardButtons buttons = Ok,

StandardButton defaultButton = NoButton)

  1. Similar to QMessageBox::critical(), except that this dialog box provides a question mark icon and the buttons it displays are "Yes" and "No".

StandardButton question(QWidget * parent,

const QString & title,

const QString & text,

StandardButtons buttons = StandardButtons( Yes | No ),

StandardButton defaultButton = NoButton)

  1. Similar to QMessageBox::critical(), except that this dialog box provides a yellow exclamation point icon.

StandardButton warning(QWidget * parent,

const QString & title,

const QString & text,

StandardButtons buttons = Ok,

StandardButton defaultButton = NoButton)

We can use the following code to demonstrate how to use QMessageBox.

if (QMessageBox::Yes == QMessageBox::question(this,

              tr("Question"), tr("Are you OK?"),

              QMessageBox::Yes | QMessageBox::No,

              QMessageBox::Yes))

{

    QMessageBox::information(this, tr("Hmmm..."),

tr("I'm glad to hear that!"));

}

else

{

    QMessageBox::information(this, tr("Hmmm..."),

tr("I'm sorry!"));

}

We use QMessageBox::question() to ask a question.

  1. The parent window of this dialog box is this.

QMessageBox is a subclass of QDialog, which means that its initial display position will be in the center of the parent window.

  1. The second parameter is the title of the dialog box.
  2. The third parameter is what we want to display.
  3. The fourth parameter is the associated key type, we can use the OR operator (|) to specify the button that the dialog box should appear. For example, we want a Yes and a No.
  4. The last parameter specifies the button selected by default.

This function has a return value that is used to determine which button the user clicked. According to the way we write it, it should be easy to see that this is a modal dialog box, so we can get its return value directly.

The advantage of the static function of the QMessageBox class is that it is easy to use, but the disadvantage is also obvious: it is very inflexible. We can only use a few simple forms. In order to be able to customize the QMessageBox details, we must use the QMessageBox's property setting API. If we want to make a dialog box asking whether to save, we can use the following code:

QMessageBox msgBox;

msgBox.setText(tr("The document has been modified."));

msgBox.setInformativeText(tr("Do you want to save your changes?"));

msgBox.setDetailedText(tr("Differences here..."));

msgBox.setStandardButtons(QMessageBox::Save

                          | QMessageBox::Discard

                          | QMessageBox::Cancel);

msgBox.setDefaultButton(QMessageBox::Save);

int ret = msgBox.exec();

switch (ret)

{

case QMessageBox::Save:

    qDebug() << "Save document!";

    break;

case QMessageBox::Discard:

    qDebug() << "Discard changes!";

    break;

case QMessageBox::Cancel:

    qDebug() << "Close document!";

    break;

}

msgBox is a QMessageBox instance built on the stack. We set its main text information to "The document has been modified." and informativeText is a simple explanatory text that will be displayed in the dialog box. Below we use a detailedText, which is detailed information. When we click the detailed information button, the dialog box can automatically display more information. The dialog box we defined has three buttons: Save, Discard and Cancel. Then we used exec() to make it a modal dialog box, and perform corresponding operations based on its return value.

6.5 Standard file dialog box

QFileDialog, which is the file dialog box. In this section, we will try to write a simple text file editor. We will use QFileDialog to open a text file and save the modified file to the hard disk.

First, we need to create a window with text editing capabilities. Borrowing our previous program code, it should be easy to complete:

openAction = new QAction(QIcon(":/images/file-open"),tr("&Open..."), this);

openAction->setStatusTip(tr("Open an existing file"));

saveAction = new QAction(QIcon(":/images/file-save"), tr("&Save..."), this);

saveAction->setStatusTip(tr("Save a new file"));

QMenu *file = menuBar()->addMenu(tr("&File"));

file->addAction(openAction);

file->addAction(saveAction);

QToolBar *toolBar = addToolBar(tr("&File"));

toolBar->addAction(openAction);

toolBar->addAction(saveAction);

textEdit = new QTextEdit(this);

setCentralWidget(textEdit);

We've added two actions to the menu and toolbar: Open and Save. Next is a QTextEdit class, which is used to display rich text files. That is to say, it is not only used to display text, but also can display pictures, tables, etc. However, we will only use it to display plain text files for now. QMainWindow has a setCentralWidget() function, which can set a component as the center component of the window and place it in the central display area of ​​the window. Obviously, in a text editor, the text editing area is the central component, so we use QTextEdit as this component.

We use the connect() function to add corresponding actions to these two QAction objects:

connect(openAction, &QAction::triggered,

this, &MainWindow::openFile);

connect(saveAction, &QAction::triggered,

this, &MainWindow::saveFile);

The following is the code of the two main functions openFile() and saveFile():

//open a file

void MainWindow::openFile()

{

    QString path = QFileDialog::getOpenFileName(this,

               tr("Open File"), ".", tr("Text Files(*.txt)"));

    if(!path.isEmpty())

{

        QFile file(path);

        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))

{

            QMessageBox::warning(this, tr("Read File"),

                         tr("Cannot open file:\n%1").arg(path));

            return;

        }

        QTextStream in(&file);

        textEdit->setText(in.readAll());

        file.close();

    }

else

{

        QMessageBox::warning(this, tr("Path"),

                             tr("You did not select any file."));

     }

}

//save document

void MainWindow::saveFile()

{

    QString path = QFileDialog::getSaveFileName(this,

               tr("Open File"), ".", tr("Text Files(*.txt)"));

    if(!path.isEmpty())

{

        QFile file(path);

        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))

{

            QMessageBox::warning(this, tr("Write File"),

                         tr("Cannot open file:\n%1").arg(path));

            return;

        }

        QTextStream out(&file);

        out << textEdit->toPlainText();

        file.close();

    }

else

{

        QMessageBox::warning(this, tr("Path"),

                             tr("You did not select any file."));

    }

}

In the openFile() function, we use QFileDialog::getOpenFileName() to get the path of the file that needs to be opened. The prototype of this function is as follows:

QString getOpenFileName(QWidget * parent = 0,

                        const QString & caption = QString(),

                        const QString & dir = QString(),

                        const QString & filter = QString(),

                        QString * selectedFilter = 0,

                        Options options = 0)

Note, however, that all its parameters are optional, so to a certain extent, this function is simple. These six parameters are:

  1. parent: parent window.

Qt's standard dialog box provides static functions for returning a modal dialog box;

  1. caption: dialog box title;
  2. dir: the default directory when the dialog box is opened
    1. "." represents the program running directory
    2. "/" represents the root directory of the current drive letter (specifically the Windows platform; the Linux platform is of course the root directory). This parameter can also be platform-related, such as "C:\\", etc.;
  3. filter: filter.

We can browse many types of files using the file dialog box, but many times we only want to open files of a specific type. For example, a text editor wants to open a text file, and a picture browser wants to open an image file. Filters are used to filter specific suffixes . If we use "Image Files(*.jpg *.png)", only files with the suffix name jpg or png can be displayed. If multiple filters are needed, use ";;" to separate them , such as "JPEG Files(*.jpg);;PNG Files(*.png)";

  1. selectedFilter: the filter selected by default;
  2. options: Some parameter settings of the dialog box

For example, only displaying folders, etc., its value is enum QFileDialog::Option, and each option can be combined using the | operation.

The return value of QFileDialog::getOpenFileName() is the selected file path. We assign it to path. By judging whether the path is empty, you can determine whether the user has selected a file. Only when the user selects a file do we perform the following operations.

QFileDialog::getSaveFileName() used in saveFile() is similar. Using this static function, the local dialog box is directly called on Windows and Mac OS, but on Linux, it is QFileDialog's own simulation. This implies that if you do not use these static functions, but directly use QFileDialog to set it, the resulting dialog box is likely to be inconsistent with the appearance of the system dialog box. This is something to note.

layout manager

The so-called GUI interface, in the final analysis, is the superposition of a bunch of components. We create a window, put buttons on it, and put icons on it, so it becomes an interface. The position of components is particularly important when placing them. We have to specify where to place the component so that the window renders the way we need it to. This involves the mechanism of component positioning.

Qt provides two component positioning mechanisms: absolute positioning and layout positioning.

  1. Absolute positioning is the most primitive positioning method: giving the coordinates and length and width values ​​of this component.

This way, Qt knows where to place the component and how to size it. But one problem caused by this is that if the user changes the window size, such as clicking the maximize button or dragging the edge of the window with the mouse, the absolutely positioned component will not respond in any way. This is also natural, because you don't tell Qt whether and how the component should update itself when the window changes. Or, there's an easier way: disable the user from resizing the window. But this is not always a long-term solution.

  1. Layout positioning: You only need to put the components into a certain layout, and the layout is managed by a dedicated layout manager. When the size or position needs to be adjusted, Qt uses the corresponding layout manager to make adjustments.

Layout positioning perfectly solves the shortcomings of using absolute positioning.

Among the layouts provided by Qt, the following three are our most commonly used:

  1. QHBoxLayout: layout from left to right in the horizontal direction;
  2. QVBoxLayout: layout from top to bottom in the vertical direction;
  3. QGridLayout: layout in a grid, similar to HTML table;

7.1 Layout controls provided by the system

These four layout controls are provided by the system, but they are not very flexible to use, so they will not be introduced in detail here.

7.2 Use widgets for layout

The second layout method is to use the widgets in the control to do the layout. In Containers

The controls in the widget can perform horizontal, vertical, grid layout and other operations, which is relatively flexible.

While re-layout, we need to flexibly use the characteristics of spring to make our layout more beautiful. Below is a login window. Using widgets, we can build the following login interface:

Guess you like

Origin blog.csdn.net/weixin_61847358/article/details/135427492