Closing a QDialog from another class



  • Hello everyone, I'm developing a desktop application in Qt 4.7.4 using QtCreator (Window 7, 64 bit).
    I'm trying to implement a sort of front controller to centralize the requests derived from the windows, so I created a class called frontcontroller, with frontcontroller.h and frontcontroller.cpp files.

    Everything seems to work, but... I have a QDialog window, created with QtCreator, that i want to open and close through frontcontroller.

    So, this is the frontcontroller class code:

    frontcontroller.h
    @
    #ifndef FRONTCONTROLLER_H
    #define FRONTCONTROLLER_H

    #include <QPointer>

    #include "win1.h"
    #include "win2.h"

    class Frontcontroller
    {
    public:
    Frontcontroller();
    //Application
    void StartApplication();

        //Windows
        void openWIN1();
        void closeWIN1();
    
    private:
        QPointer<W1> MW;
        QPointer<W2> secondW;
    

    };

    #endif // FRONTCONTROLLER_H
    @

    frontcontroller.cpp
    @
    #include <QMessageBox>

    #include "frontcontroller.h"

    Frontcontroller :: Frontcontroller()
    {

    }

    void Frontcontroller :: StartApplication()
    {
    MW = new WIN1();
    MW->showMaximized();
    }

    void Frontcontroller :: openInsertArticleWin()
    {
    seconW = new W2(); //This is a QDialog
    seconW->setAttribute( Qt::WA_DeleteOnClose, true );
    seconW->exec();
    }

    void Frontcontroller :: closeInsertArticleWin()
    {
    seconW->close();
    }

    void Frontcontroller :: resetDataForInsertArticle()
    {
    //TODO
    }
    @

    My problem: when i close the QDialog (secondW, excuse me for var names) through the FC, the whole program crashes exiting with code -1073741819 (Access Violation, right?) and I can not understand what is wrong.
    Can someone help me?
    Thanks a lot, bye bye



  • You must not access GUI elements from threads other than the GUI thread. So the first thread will live in this loop:

    @
    void Frontcontroller :: openInsertArticleWin()
    {
    seconW = new W2(); //This is a QDialog
    seconW->setAttribute( Qt::WA_DeleteOnClose, true );
    seconW->exec(); <---- here
    }
    @

    and the second thread will close the window with

    @
    void Frontcontroller :: closeInsertArticleWin()
    {
    seconW->close();
    }
    @

    right?



  • You can use QThread:currentThreadId() to qDebug() the current thread ID in each class method to figure out what thread is currently running.

    Simply add:

    @
    #include <QDebug>
    ...
    qDebug() << currentThreadId();
    ...
    @

    and see if the output was same or not, then proceed with other questions.



  • [quote author="franku" date="1345213377"]You must not access GUI elements from threads other than the GUI thread. So the first thread will live in this loop:

    @
    void Frontcontroller :: openInsertArticleWin()
    {
    seconW = new W2(); //This is a QDialog
    seconW->setAttribute( Qt::WA_DeleteOnClose, true );
    seconW->exec(); <---- here
    }
    @

    and the second thread will close the window with

    @
    void Frontcontroller :: closeInsertArticleWin()
    {
    seconW->close();
    }
    @

    right?
    [/quote]

    Thnaks for your reply franku, I don't fully understand your answer when you say: "You must not access GUI elements from threads other than the GUI thread"... I have tried the show() instrucrtion instad of exec(), but it is the same.
    So i tried you suggestion, and the thread seems to be the same, here is the output
    @
    A moment before running exec();
    0x14c8
    When i try to close the window via FC
    0x14c8
    @

    So I have tried to debug the secondW variable, and...
    @
    A moment before
    secondW(0x7b16e8, name = "secondW")
    When closing via FC
    QObject(0x0)
    @

    I have to think that the pointer "secondW" is not instantiated when i close the QDialog?



  • Hi, sorry. I mean:

    @
    void Frontcontroller :: openInsertArticleWin()
    {
    qDebug() << "Exec-Thread" << QThread::currentThreadId();

        seconW = new W2();  //This is a QDialog
        seconW->setAttribute( Qt::WA_DeleteOnClose, true );
        seconW->exec&#40;&#41;; 
    }
    

    @

    and

    @
    void Frontcontroller :: closeInsertArticleWin()
    {
    qDebug() << "Close-Thread" << QThread::currentThreadId();

        seconW->close();
    }
    

    @

    Exec-Thread and Close-Thread must not be different. If they are, you have to use some event-queue to do it. If you figure out the IDs, we can try to find a solution.



  • Thank you again franku.
    Here is the debug output:

    @
    Exec-Thread: 0xc60
    Close-Thread 0xc60
    @

    So the open and close threads seems to be the same


  • Moderators

    franku: I'm not sure how threads enter the picture. I'm not sure that this is a multithreaded situation at all... the exec() call was a QDialog::exec(), not a QThread::exec(), as I understand it.


  • Moderators

    Is the dialog modal? (I assume so, since you're using exec() to open it, instead of show().) If so, have you tried calling accept() or reject() instead of close() to close it? I'm not sure off the top of my head how calling close() on a running modal dialog works, as there may be pending events in its event loop, etc. Also, if there's a DeleteOnClose situation, are you sure that the variable isn't still being referenced somewhere else?

    Can you get a working backtrace from the debugger when it crashes?



  • Hi mlong, no, the Dialog is not modal, but i have tried to it to modal and call show() instead of exec(), I have tried to call show() without setModal(), nothing change.
    Yes, I have tried to call accept() and reject instead of close() (my first attempt, actually), nothing and nothing.
    What seems suspicious is that when closing the Dialog, debugging of the poniter returns a QObject (0x0)



  • If it is returning a QObject(0x0) you are get a Null pointer exception. Somewhere along the way it is losing reference to your pointer, though from the code you have given I would not be sure where at.



  • bq. I’m not sure how threads enter the picture.

    Well, some thread must execute the exec() method of the Dialog. In most cases I think this is done by the thread that runs the gui. But I did not know if QMatt uses another thread than the guithread to close() the window. So I wanted to be sure before we think about other possibilities.

    bq. ...if there’s a DeleteOnClose situation, ...

    In that case you could use dialog->setAttribute(Qt::WA_DeleteOnClose, false) to improve that the object isnt't deleted after finishing the event loop. Afterwards you have to delete it manually (for a quick test just don't delete it).

    But as mlogn and webmaster. mentioned above, what does the debugger say?

    QMatt, did you run the code step by step to see what is going on? You may want to create some breakpoints in each method and see what happens, especially when the object is deleted.



  • Hi guys and thanks a lot for your patience with me...
    Trying to start debugging (Debug -> Start Debugging), I receive this message:
    @
    The inferior stopped because it received a signal from the Operating System.
    Signal name: SIGSEGV
    Signal meaning: Segmentation fault
    @

    And a disassembler appears with an ASM code with a right arrow @ line n. 8
    How (and if) I can print a Stack Trace or someting similar?



  • Ok so... probably the night brings counsel, or maybe I am stupid...
    When I call exec() on secondW, I need to use the Frontcontroller in this window, so I do
    @
    Frontconrtoller fc;
    ...
    ...
    ...
    void insertArticleWin :: on_cancelButton_clicked() { fc.closeWIN2(); }
    @

    but this is a new instance of Frontcontroller, a different object, right? So the pointer to secondW is set to NULL... and so I just made this change

    @
    Frontconrtoller fc;
    ...
    ...
    ...
    void insertArticleWin :: on_cancelButton_clicked() { fc.secondW = this; fc.closeInsertArticleWin(); }
    @

    And now all seems to work... do you think what I am doing is theoretically wrong?



  • You are creating modal dialog and trying to use it like a modeless one. exec blocks until the dialog is closed and then returns. So in a true modal environment, your closeInsertArticleWin() function couldn't be called until after the dialog is closed. It sounds like to me that you should be working with a modeless dialog (QDialog::show) instead of QDialog::exec and set your qobject parenting. I don't think you want deleteOnClose. Modeless dialog should be constructed upon app start shown and hidden by controller and deleted on app shutdown.

    you should check seconW before using it. That is what qpointer is for. i.e. @if (seconW)
    seconW->close();@

    If you can, post something we can easily build.


Log in to reply
 

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