Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

A subtle issue with QLabel



  • Hi all,

    I'm going to design a login UI when a button clicked on the parent. There's also a label on it which shows a picture when login succeeds. It should work but not in practice. Please also review my code if it's not very good. Thanks.

    LogDialog.h:

    #ifndef LOGDIALOG_H
    #define LOGDIALOG_H
    
    #include <QDialog>
    #include "userandpass.h"
    
    class QLabel;
    class QPushButton;
    
    class LogDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        LogDialog(QWidget *parent = nullptr);
        void on_UsrPas_okBtn(const bool);
    
    private slots:
        void on_loginBtn();
    
    private:
        QLabel* label = nullptr;
        QPushButton* login = nullptr;
    };
    #endif // LOGDIALOG_H
    
    

    LogDialog.cpp:

    #include "logdialog.h"
    
    #include <QLabel>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QMessageBox>
    
    LogDialog::LogDialog(QWidget *parent)
        : QDialog(parent)
    {
        login = new QPushButton(tr("Login"));
    
        label = new QLabel(tr("Not Logged In"));
        label->setAlignment(Qt::AlignCenter);
    
        auto mainLayout = new QVBoxLayout;
        mainLayout->addStretch();
        mainLayout->addWidget(label);
        mainLayout->addStretch();
        mainLayout->addWidget(login);
    
        setLayout(mainLayout);
    
        connect(login, &QPushButton::clicked, this, &LogDialog::on_loginBtn);
    }
    
    void LogDialog::on_loginBtn()
    {
        UserAndPass* log = new UserAndPass(this);
        log->exec();
        delete log;
    }
    
    void LogDialog::on_UsrPas_okBtn(const bool m)
    {
        if(m){
            label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
            login->setText("Welcome");
            login->setEnabled(false);
        }
        else {
            QMessageBox::critical(this, "Wrong Info", "You've entered wrong username and/or"
                                                      "password.\n Try again!");
            accept();
        }
    }
    

    UserAndPass.h:

    #ifndef USERANDPASS_H
    #define USERANDPASS_H
    
    #include "logdialog.h"
    #include <QDialog>
    
    class QLineEdit;
    class QDialogButtonBox;
    
    class UserAndPass : public QDialog
    {
        Q_OBJECT;
    
    public:
        UserAndPass(QWidget *parent = nullptr);
    
    private slots:
        void on_Okbtn();
        void on_Cancelbtn();
    
    private:
        QLineEdit* usrLine = nullptr;
        QLineEdit* passLine = nullptr;
        QDialogButtonBox* btnBox = nullptr;
    
        const QString user = "user";
        const QString pass = "pass";
    };
    
    #endif // USERANDPASS_H
    

    UserAndPass.cpp:

    #include "userandpass.h"
    
    #include <QDialogButtonBox>
    #include <QFormLayout>
    #include <QLineEdit>
    #include <QVBoxLayout>
    
    UserAndPass::UserAndPass(QWidget *parent)
    : QDialog(parent)
    {
        usrLine = new QLineEdit;
        passLine = new QLineEdit;
        passLine->setEchoMode(QLineEdit::Password);
    
        btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    
        auto form = new QFormLayout;
        form->addRow(tr("Username"), usrLine);
        form->addRow(tr("Password"), passLine);
    
        auto mainLayout = new QVBoxLayout;
        mainLayout->addLayout(form);
        mainLayout->addStretch();
        mainLayout->addWidget(btnBox);
    
        setLayout(mainLayout);
    
        connect(btnBox, &QDialogButtonBox::accepted, this, &UserAndPass::on_Okbtn);
        connect(btnBox, &QDialogButtonBox::rejected, this, &UserAndPass::on_Cancelbtn);
    }
    
    void UserAndPass::on_Okbtn()
    {
        LogDialog ld;
    
        if(user == usrLine->text() && pass == passLine->text())
            ld.on_UsrPas_okBtn(true);
        else
            ld.on_UsrPas_okBtn(false);
    
        accept();
    }
    
    void UserAndPass::on_Cancelbtn()
    {
        reject();
    }
    

    The problem is with void LogDialog::on_UsrPas_okBtn(const bool m). While m is true but these:

    label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
    login->setText("Welcome");
    login->setEnabled(false);
    

    won't work!



  • @mrjj

    Hi
    You could do it with signals & slot
    UserAndPass dialog1;
    LogDialog ld;

    Hi :)
    The problem is with the number of instances. We have one for the parent (in main.cpp) and one for the child (inLogDialog.cpp).

    I modified the code this way, and it works now as expected. But I still don't like it very much and hope there's a nicer way especially using the connections or an API.

    LogDialog.h:

    #ifndef LOGDIALOG_H
    #define LOGDIALOG_H
    
    #include <QDialog>
    #include "userandpass.h"
    
    class QLabel;
    class QPushButton;
    
    class LogDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        LogDialog(QWidget *parent = nullptr);
    
    private slots:
        void on_loginBtn();
    
    private:
        QLabel* label = nullptr;
        QPushButton* login = nullptr;
    };
    #endif // LOGDIALOG_H
    

    LogDialog.cpp:

    #include "logdialog.h"
    
    #include <QLabel>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QMessageBox>
    
    LogDialog::LogDialog(QWidget *parent)
        : QDialog(parent)
    {
        login = new QPushButton(tr("Login"));
        
        label = new QLabel(tr("Not Logged In"));
        label->setAlignment(Qt::AlignCenter);
        
        auto mainLayout = new QVBoxLayout;
        mainLayout->addStretch();
        mainLayout->addWidget(label);
        mainLayout->addStretch();
        mainLayout->addWidget(login);
        
        setLayout(mainLayout);
        
        connect(login, &QPushButton::clicked, this, &LogDialog::on_loginBtn);
    }
    
    void LogDialog::on_loginBtn()
    {
        UserAndPass* log = new UserAndPass(this);
        log->exec();
        
        if(log->getOkBtnCld() && log->getMatch()) {
            label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
            login->setText("Welcome");
            login->setEnabled(false);
        }
        else if(log->getOkBtnCld() && !log->getMatch())
            QMessageBox::critical(this, "Wrong Info", "You've entered wrong username and/or"
                                                      "password.\n Try again!");
        delete log;
    }
    

    UserAndPass.h:

    #ifndef USERANDPASS_H
    #define USERANDPASS_H
    
    #include "logdialog.h"
    #include <QDialog>
    
    class QLineEdit;
    class QDialogButtonBox;
    
    class UserAndPass : public QDialog
    {
        Q_OBJECT;
    
    public:
        UserAndPass(QWidget *parent = nullptr);
    
        bool getMatch() const;
        void setMatch(bool value);
    
        bool getOkBtnCld() const;
        void setOkBtnCld(bool value);
    
    private slots:
        void on_Okbtn();
        void on_Cancelbtn();
    
    private:
        QLineEdit* usrLine = nullptr;
        QLineEdit* passLine = nullptr;
        QDialogButtonBox* btnBox = nullptr;
        
        const QString user = "user";
        const QString pass = "pass";
    
        bool match = false;
        bool okBtnCld = false;
    };
    
    #endif // USERANDPASS_H
    

    UserAndPass.cpp:

    #include "userandpass.h"
    
    #include <QDialogButtonBox>
    #include <QFormLayout>
    #include <QLineEdit>
    #include <QVBoxLayout>
    
    UserAndPass::UserAndPass(QWidget *parent)
        : QDialog(parent)
    {
        usrLine = new QLineEdit;
        passLine = new QLineEdit;
        passLine->setEchoMode(QLineEdit::Password);
        
        btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
        
        auto form = new QFormLayout;
        form->addRow(tr("Username"), usrLine);
        form->addRow(tr("Password"), passLine);
        
        auto mainLayout = new QVBoxLayout;
        mainLayout->addLayout(form);
        mainLayout->addStretch();
        mainLayout->addWidget(btnBox);
        
        setLayout(mainLayout);
        
        connect(btnBox, &QDialogButtonBox::accepted, this, &UserAndPass::on_Okbtn);
        connect(btnBox, &QDialogButtonBox::rejected, this, &UserAndPass::reject);
    }
    
    void UserAndPass::on_Okbtn()
    {
        setOkBtnCld(true);
        if(user == usrLine->text() && pass == passLine->text())
            setMatch(true);
        accept();
    }
    
    bool UserAndPass::getOkBtnCld() const
    {
        return okBtnCld;
    }
    
    void UserAndPass::setOkBtnCld(bool value)
    {
        okBtnCld = value;
    }
    
    bool UserAndPass::getMatch() const
    {
        return match;
    }
    
    void UserAndPass::setMatch(bool value)
    {
        match = value;
    }
    
    


  • @tomy

    void UserAndPass::on_Okbtn()
    {
        LogDialog ld;
    
        if(user == usrLine->text() && pass == passLine->text())
            ld.on_UsrPas_okBtn(true);
        else
            ld.on_UsrPas_okBtn(false);
    
        accept();
    }
    

    This creates a local LogDialog, then exits taking it with it. The stuff you do in LogDialog::on_UsrPas_okBtn() won't be seen. I don't know what you're trying to do here, just think through the logic.


  • Qt Champions 2019

    @tomy said in A subtle issue with QLabel:

    LogDialog ld;

    C basics - you're creating a new, local instance and using this instead the previous instantiated one.



  • @JonB @Christian-Ehrlicher

    I guess I got the bug; two different objects.

    What I'm trying to do is to call the function LogDialog::on_UsrPas_okBtn() from the function void UserAndPass::on_Okbtn() when the OK button is clicked. That is, somehow to be able to connect the two objects of two different classes (one the child of the other). I'm sure there's a pretty easy way for that. I could do the stuff:

    label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
    login->setText("Welcome");
    login->setEnabled(false);
    

    in the void LogDialog::on_loginBtn(). But I want to do them when the button OK is clicked not at any circumstances. Is it clear what I'm trying to say, please?


  • Lifetime Qt Champion

    Hi
    You could do it with signals & slot

    (pseudo code ish)

    UserAndPass dialog1;
    LogDialog ld;

    connect ( &dialog1, &UserAndPass ::YourNewSignal, &ld, LogDialog::on_UsrPas_okBtn)
    ld.exec();

    Note that YourNewSignal must take bool as on_UsrPas_okBtn does.

    Then in void UserAndPass::on_Okbtn()
    {

    if(user == usrLine->text() && pass == passLine->text())
        emit YourNewSignal(true);
    else
        emit YourNewSignal(false);
    
    accept();
    

    }



  • @mrjj

    Hi
    You could do it with signals & slot
    UserAndPass dialog1;
    LogDialog ld;

    Hi :)
    The problem is with the number of instances. We have one for the parent (in main.cpp) and one for the child (inLogDialog.cpp).

    I modified the code this way, and it works now as expected. But I still don't like it very much and hope there's a nicer way especially using the connections or an API.

    LogDialog.h:

    #ifndef LOGDIALOG_H
    #define LOGDIALOG_H
    
    #include <QDialog>
    #include "userandpass.h"
    
    class QLabel;
    class QPushButton;
    
    class LogDialog : public QDialog
    {
        Q_OBJECT
    
    public:
        LogDialog(QWidget *parent = nullptr);
    
    private slots:
        void on_loginBtn();
    
    private:
        QLabel* label = nullptr;
        QPushButton* login = nullptr;
    };
    #endif // LOGDIALOG_H
    

    LogDialog.cpp:

    #include "logdialog.h"
    
    #include <QLabel>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QMessageBox>
    
    LogDialog::LogDialog(QWidget *parent)
        : QDialog(parent)
    {
        login = new QPushButton(tr("Login"));
        
        label = new QLabel(tr("Not Logged In"));
        label->setAlignment(Qt::AlignCenter);
        
        auto mainLayout = new QVBoxLayout;
        mainLayout->addStretch();
        mainLayout->addWidget(label);
        mainLayout->addStretch();
        mainLayout->addWidget(login);
        
        setLayout(mainLayout);
        
        connect(login, &QPushButton::clicked, this, &LogDialog::on_loginBtn);
    }
    
    void LogDialog::on_loginBtn()
    {
        UserAndPass* log = new UserAndPass(this);
        log->exec();
        
        if(log->getOkBtnCld() && log->getMatch()) {
            label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
            login->setText("Welcome");
            login->setEnabled(false);
        }
        else if(log->getOkBtnCld() && !log->getMatch())
            QMessageBox::critical(this, "Wrong Info", "You've entered wrong username and/or"
                                                      "password.\n Try again!");
        delete log;
    }
    

    UserAndPass.h:

    #ifndef USERANDPASS_H
    #define USERANDPASS_H
    
    #include "logdialog.h"
    #include <QDialog>
    
    class QLineEdit;
    class QDialogButtonBox;
    
    class UserAndPass : public QDialog
    {
        Q_OBJECT;
    
    public:
        UserAndPass(QWidget *parent = nullptr);
    
        bool getMatch() const;
        void setMatch(bool value);
    
        bool getOkBtnCld() const;
        void setOkBtnCld(bool value);
    
    private slots:
        void on_Okbtn();
        void on_Cancelbtn();
    
    private:
        QLineEdit* usrLine = nullptr;
        QLineEdit* passLine = nullptr;
        QDialogButtonBox* btnBox = nullptr;
        
        const QString user = "user";
        const QString pass = "pass";
    
        bool match = false;
        bool okBtnCld = false;
    };
    
    #endif // USERANDPASS_H
    

    UserAndPass.cpp:

    #include "userandpass.h"
    
    #include <QDialogButtonBox>
    #include <QFormLayout>
    #include <QLineEdit>
    #include <QVBoxLayout>
    
    UserAndPass::UserAndPass(QWidget *parent)
        : QDialog(parent)
    {
        usrLine = new QLineEdit;
        passLine = new QLineEdit;
        passLine->setEchoMode(QLineEdit::Password);
        
        btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
        
        auto form = new QFormLayout;
        form->addRow(tr("Username"), usrLine);
        form->addRow(tr("Password"), passLine);
        
        auto mainLayout = new QVBoxLayout;
        mainLayout->addLayout(form);
        mainLayout->addStretch();
        mainLayout->addWidget(btnBox);
        
        setLayout(mainLayout);
        
        connect(btnBox, &QDialogButtonBox::accepted, this, &UserAndPass::on_Okbtn);
        connect(btnBox, &QDialogButtonBox::rejected, this, &UserAndPass::reject);
    }
    
    void UserAndPass::on_Okbtn()
    {
        setOkBtnCld(true);
        if(user == usrLine->text() && pass == passLine->text())
            setMatch(true);
        accept();
    }
    
    bool UserAndPass::getOkBtnCld() const
    {
        return okBtnCld;
    }
    
    void UserAndPass::setOkBtnCld(bool value)
    {
        okBtnCld = value;
    }
    
    bool UserAndPass::getMatch() const
    {
        return match;
    }
    
    void UserAndPass::setMatch(bool value)
    {
        match = value;
    }
    
    

  • Qt Champions 2019

    @tomy said in A subtle issue with QLabel:

    But I still don't like it very much

    It's exactly like a modal dialog should be used.


  • Lifetime Qt Champion

    hi
    Nothing dirty with nested dialogs
    but why not

    void LogDialog::on_loginBtn()
    {
        UserAndPass log(this);
        log.exec();
        
        if(log.getOkBtnCld() && log.getMatch()) {
            label->setPixmap(QPixmap(":/files/Image/QtTomy.png"));
            login->setText("Welcome");
            login->setEnabled(false);
        }
        else if(log.getOkBtnCld() && !log.getMatch())
            QMessageBox::critical(this, "Wrong Info", "You've entered wrong username and/or"
                                                      "password.\n Try again!");
    
    }
    

    There is no need (or benefit) to new it here
    and we can get rid of
    delete log;
    which we could end up forgetting calling if we add to code later.



  • @mrjj Hi
    Agree, especially due to that fact we are using our object merely inside that function no outside of it. Thanks, applied.

    @Christian-Ehrlicher Does it mean you find the code pretty good, please?


Log in to reply