c++qtmodal-dialogqdialognon-modal

Custom modeless dialog not showing


I have to convert a modal dialog to a modeless one.

I made some changes already by referring to the Qt Documentation. I basically created two signals to detect if the dialog is accepted or rejected, and connected them using connect().

I tried to show the widget using the show(), but the widget is not showing.

What is the mistake I am making?

#ifndef INDENTOPTIONS_H
#define INDENTOPTIONS_H

#include <QDialog>

namespace Ui {
class indentOptions;
}

class indentOptions : public QDialog
{
    Q_OBJECT

public:
    explicit indentOptions(QWidget *parent = nullptr, int * left = nullptr, int * right = nullptr);
    ~indentOptions();
signals:
    void dialogAccepted();
    void dialogRejected();

protected:
    void closeEvent(QCloseEvent* event) override;

private slots:
    void on_buttonBox_accepted();

    void on_buttonBox_rejected();

private:
    Ui::indentOptions *ui;
    int * left;
    int * right;

};

#endif // INDENTOPTIONS_H

indentoptions.cpp

#include "indentoptions.h"
#include "ui_indentoptions.h"

indentOptions::indentOptions(QWidget *parent, int* left, int* right) :
    QDialog(parent),
    ui(new Ui::indentOptions)
{
    ui->setupUi(this);
    this->left = left;
    this->right = right;
    setWindowTitle("Set Indentation");
    setWindowModality(Qt::WindowModality::NonModal);
}

indentOptions::~indentOptions()
{
    delete ui;
}

void indentOptions::closeEvent(QCloseEvent* event)
{

    emit dialogRejected();// Set check_b to true when the dialog is closed
    QDialog::closeEvent(event);
}

void indentOptions::on_buttonBox_accepted()
{

    int l = ui->textEdit_left->toPlainText().toInt();
    int r = ui->textEdit_right->toPlainText().toInt();
    if(l==0 && r==0){
        emit dialogRejected();
        return;
    }

    *left = l;
    *right = r;
    emit dialogAccepted();
}

void indentOptions::on_buttonBox_rejected()
{
    emit dialogRejected();
    this->close();
}

mainwindow.cpp

void MainWindow::on_actionIndentation_Options_triggered()
{
    int left = 0, right = 0;
    indentOptions i(this, &left, &right);
    i.show();

    connect(&i, &indentOptions::dialogAccepted, this, [this, &left, &right](){
        if(left + right <= 14){
            on_actionIncrease_Indent_triggered(left, right);
        }
    });
}

Solution

  • You created dialog on the stack, so it's deleted after on_actionIndentation_Options_triggered exits. You also captured pointers to local variables inside lambda function, which will be invalid after on_actionIndentation_Options_triggered exits (undefined behaviour at the time lambda will be called).

    Create memeber variables and getter functtions for left and right inside indentOptions and allocate dialog on the heap.

    void MainWindow::on_actionIndentation_Options_triggered()
    {
        indentOptions* i = new indentOptions(this);
        i->show();
        connect(i, &indentOptions::dialogAccepted, this, [=](){
            int left = i->left();
            int right = i->right();
            if(left + right <= 14) {
                on_actionIncrease_Indent_triggered(left, right);
            }
            i->deleteLater();
        });
    }
    

    Dialogs are usually allocated on the stack because QDialog::exec() blocks function until dialog is accepted, so it can only work for modal dialogs.