Show and hide parent window (QWidget) from child (QDialog)



  • Hi,
    I'm developing a tool for KDE that allows user to toggle between two windows (Qwidget and QDialog)

    When "parentJump" slot is triggered it shows myQdialog window and hides MainWindow . It works good.

    //mainWindow.cpp
    void MainWindow::parentJump(){
    cout << "Jump to qdialog window" <<endl <<flush;
    myQdialog->show(); //myQdialog = new mySetupDialog()
    this->hide();
    }

    When I'm trying to jump back to mainWindow it doesn't work. I tried to do it by invokeMethod and simply use parent->show

    //mySetupDialog.cpp
    void mySetupDialog::jump(){
    cout << "jumping to main window" << endl ;
    // parent->show(); // doesn't work
    // QMetaObject::invokeMethod(parent,"show"); // doesn't work
    this->hide();
    }

    Can you please tell me how is the right way to implement it?

    Thanks,
    Yossi.



  • Hi,
    The parent pointer is a QObject pointer, not a Widget!! So do a qobject_cast to change it into a QWidget pointer and use the show.
    That might do the trick!



  • Hi Jeroen,

    Thanks for your fast response.

    parent is already Qwidget pointer

    mySetupDialog::mySetupDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::mySetupDialog)
    {
    ...
    }

    Anyhow, I tried your suggestion and it wont work

    ((QWidget*)parent)->show();
    ERROR: invalid use of member (did you forget the ‘&’ ?)



  • Hi Jossi,

    I solved my problem with the signals and slots like this:

    in child.h
    signals:
    void Want2Close();

    in child.cpp
    void child::on_btnClose_clicked()
    {
    this->close();
    emit Want2Close();
    }

    in parent.cpp on a QpushButton

    child *child1 = new child;
    connect(child1,&child::Want2Close,this,&MainWindow::show);
    this->hide();
    child1->show();

  • Moderators

    @Yossi said:

    ((QWidget*)parent)->show();
    ERROR: invalid use of member (did you forget the ‘&’ ?)

    parent() is a function, so you need to give it a parameter list, even if it's empty: (QWidget*)parent()->show().

    But you don't have to do that at all. There are also parentWidget() and window() methods that give you your widget's parent widget and your widget's top level widget respectively. Just remember to check if what they return is not null before you try to call anything on it.



  • @Jumetor

    I tried it and I got the following errors:
    error: cannot call member function ‘void child::Want2Close()’ without object
    error: lvalue required as unary ‘&’ operand

    Any idea why?

    Thanks.


  • Moderators

    Want2Close() is not a static memberfunction so you cant call it on a class name like that. You need to call it on an instance of your class, e.g. something like child1->Want2Close(), but you need to post the code that actually errors out for us to help.

    Btw. Please surround code blocks with ```. It will make it a lot easier for us to read here.





  • My guess is your pointer to your "parent" is not your mainwindow for some reason.

    Try putting in something like this:

    void mySetupDialog::jump()
    {
       QObject *p = this;
       do 
       {
          p = p->parent();
       } while (p->parent() != NULL);
    
       QMainWindow *mw = qobject_cast<QMainWindow *>(p);
       if (!mw)
       {
          // couldnt find main window
       }
       else
       {
          mw->show();
          hide();
       }
    }
    

    Now if that works, I would figure out why mw != parent to prevent further issues. Once you figure that out you can ditch this loop method.

    This also assumes QMainWIndow is your top level widget, which it should be. If it's not, add pointer cast testing with qobject_cast into your loop till you find your main window.


  • Moderators

    OMG, guys, you're complicating this beyond reason.

    @Jumetor You're basically reinventing the wheel - a dialog. Also, you're leaking memory (Form instance).
    @ambershark Loops and casts are total overkill. All you need is window()->show(), but even that is unnecessary here.

    The child shouldn't even know about its parent and it's not its role to show or hide it. "Sniffing" for a parent of concrete type is just evil. What if top most class changes one day?

    Here's a simple example (I ommited layouts and such for simplicity):

    #include <QApplication>
    #include <QMainWindow>
    #include <QDialog>
    #include <QPushButton>
    
    class Form : public QDialog {
    public:
        Form() {
            auto closeBtn = new QPushButton("Close", this);
            connect(closeBtn, &QPushButton::clicked, this, &Form::accept);
        }
    };
    
    class MainWindow : public QMainWindow {
    public:
        MainWindow() {
            auto openBtn = new QPushButton("Open child", this);
            connect(openBtn, &QPushButton::clicked, this, &MainWindow::showDialog);
        }
        void showDialog() {
            hide();
            Form form;
            form.exec();
            show();
        }
    };
    
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    


  • Hi @Chris-Kawa ,

    Thank you for your example. I do not know. I use every time a QWidget for my forms.
    In my example, I can avoid the memory leak?


  • Moderators

    @Jumetor You can set a Qt::WA_DeleteOnClose attribute on your form using setAttribute(). This would delete the Form instance when it is closed. But the code widow->show() in the Form will not show the main window. It will show the top most widget containing the caller. In other words it'll just show itself. The form really shouldn't try to show the main window. The main window should show the dialog and wait for it to close then show up again, like in my example. The dependencies are much smaller this way, as only one class knows about another and not both referring to each other.

    Btw. If you never used QDialog I suggest you start doing so. That's what it's there for.



  • @Chris-Kawa I didn't give him that loop for production reasons. I gave it to him to check to see why his parent widget wasn't matching the main window (assuming it wasn't). If you read my whole post you would see I told him to "ditch this loop method".

    This was just to help him figure out what was going on not to leave in for actual usage in a program.

    And if the parent changed some day then the if (!mw) would catch that. Assuming he left this code in which again I recommended against. :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.