Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Qt Academy Launch in California!

    Best way to make 2 differents subclasses communicate

    General and Desktop
    3
    16
    3631
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      Max13 last edited by

      Hello !

      I'm subclassing QMainWindow as MainWindow and QWidget as ConnectionWidget which have to be a central widget. I want my centralWidgets being able to change the QStatusBar from MainWindow easily, what is the best way to do it ?

      Here is what I thought about: I've added to MainWindow a slot (MainWindow::showMessage(...), which calls MainWindow->statusBar()->showMessage(...)) which will be called by the central widgets (here: ConnectionWidget). It seems a little ugly, because I HAVE to store the parent in ConnectionWidget which MUST be a MainWindow, and I've been told to use delegates instead.

      So here is my question: Is my approach a good way, are delegates better for this, or should I reimplement "setCentralWidget" to connect the children signals instead of doing it IN the children, or any other?

      Thank you for your help.

      -- EDIT --
      I can't connect my ConnectionWidget directly to MainWindow->statusBar() because when a message timeouts, I show the last permanent message, which is stored in MainWindow.

      We all have started by asking questions. Then after some time, we can begin answering them.

      1 Reply Last reply Reply Quote 0
      • SGaist
        SGaist Lifetime Qt Champion last edited by

        Hi,

        Why not have your ConnectionWidget emit a signal with a QString parameter and connect it to the QMainWindow statusbar slot showMessage() ?

        MainWindow.cpp
        @
        ConnectionWidget *connectionWidget = new ConnectionWidget;
        connect(connectionWidget, SIGNAL(messageToShow(QString)), statusBar(), SLOT(showMessage(QString)));@

        Hope it helps

        EDIT:forgot showMessage QString parameter

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply Reply Quote 0
        • M
          Max13 last edited by

          [quote author="SGaist" date="1365676850"]Hi,
          Why not have your ConnectionWidget emit a signal with a QString parameter and connect it to the QMainWindow statusbar slot showMessage() ?
          [/quote]

          Actually, this is what I did first. The thing is I want to handle general status like "Ready" and temporary status like "Field can't be empty", and when the temporary is cleared, I show back the last message. I have a QString attribute to store it in the MainWindow. If I connect directly the parent's statusBar, I have to implement the "last message" system in the children which is not logical for me.

          Thank you anyway.

          We all have started by asking questions. Then after some time, we can begin answering them.

          1 Reply Last reply Reply Quote 0
          • SGaist
            SGaist Lifetime Qt Champion last edited by

            Field empty error should be shown directly besides your mandatory input, it would be clearer for the user.

            As for managing temporary/constant message, if your temporary message are "time based" you can use showMessage(myString, myTimeoutValue). If it's a bit more complex you can either make a QStatusBar subclass and handle that there, make an object that is a "man in the middle" that handles that, or use your MainWindow for that purpose.

            Hope it helps

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply Reply Quote 0
            • M
              Max13 last edited by

              This is the point, I want to know if there is a "common" or "classic" pattern for this sort of interactions.

              Currently, here is what I have:
              @// ConnectionWidget.hpp
              signals:
              void changeStatus(QString message, int timeout);@

              @// ConnectionWidget.cpp
              connect(this, SIGNAL(changeStatus(QString, int)),
              this->m_parent->statusBar(), SLOT(showMessage(QString, int)));
              emit this->changeStatus("Ready", 0);@

              @ // MainWindow.cpp
              if (timeout)
              this->m_oldStatusMessage = this->statusBar()->currentMessage();
              else
              this->m_oldStatusMessage.clear();
              this->statusBar()->showMessage(message, timeout);@

              The thing here is that the children have to connect themselves to the parent status bar, my question is more "is it a good way to do it" instead for example, make the parent listen to the children signals ? The correct way to make this. Parent listen child(ren), Children connect to parent, delegate, ...?

              Thank you for your answers.

              We all have started by asking questions. Then after some time, we can begin answering them.

              1 Reply Last reply Reply Quote 0
              • SGaist
                SGaist Lifetime Qt Champion last edited by

                Make these connections in MainWindow.

                ConnectionWidget should not care of where the signal is going. On the other hand MainWindow knows what to do with this signal so it's his job to do the connection.

                This keeps your classes decoupled.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                1 Reply Last reply Reply Quote 0
                • M
                  Max13 last edited by

                  Here we are. If the MainWindow makes the connection itself, it means it has to know the type of the child.

                  As the "childs" are subclasses of QWidget, do I have to subclass QWidget to add the signals ? Then force MainWindow to only accept "MyOwnWidget *" by overloading "setCentralWidget" ?

                  I ask this because if I don't do this (which complicates my code) I don't know how to listen for the "setCentralWidget" to avoid trying to connect to empty centralWidget.

                  Thank you :)

                  We all have started by asking questions. Then after some time, we can begin answering them.

                  1 Reply Last reply Reply Quote 0
                  • B
                    b1gsnak3 last edited by

                    well... didn't you say that connectionwidget is your subclass of QWidget, which is your centralWidget? If you trully are worried about this, you could check to see if QMainWindow::centralWidget() != 0, because "documentation":http://qt-project.org/doc/qt-4.8/qmainwindow.html#centralWidget says that it will return 0 when no widget has been set

                    1 Reply Last reply Reply Quote 0
                    • M
                      Max13 last edited by

                      [quote author="b1gsnak3" date="1365687201"]well... didn't you say that connectionwidget is your subclass of QWidget, which is your centralWidget?[/quote]
                      Hey, you're focused, I like it =P

                      Yes I did, my ConnectionWidget is a subclass of QWidget, it's intended to be a central widget but not the only one. That's why I'm stuck here. I have to find a way to let children handle the message easily.

                      Thanks anyway.

                      We all have started by asking questions. Then after some time, we can begin answering them.

                      1 Reply Last reply Reply Quote 0
                      • B
                        b1gsnak3 last edited by

                        Ok. But be careful because setting a new central widget will delete the old one. As to your problem, please, if you can, explain again to me because I can't understand from bits and pieces xD

                        1 Reply Last reply Reply Quote 0
                        • SGaist
                          SGaist Lifetime Qt Champion last edited by

                          If you have multiple widgets that will go as "central widget", you might be interested by QStackedWidget. Have all your widgets in the stack and show the right widget at the right time.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          1 Reply Last reply Reply Quote 0
                          • M
                            Max13 last edited by

                            [quote author="b1gsnak3" date="1366008052"]Ok. But be careful because setting a new central widget will delete the old one.[/quote]

                            Yup, thanks. I always @delete this->centralWidget();@


                            [quote author="SGaist" date="1366010452"]you might be interested by QStackedWidget.[/quote]
                            Unfortunately, I forgot about it and did something ugly, but really efficient for my case.

                            I re-explain for b1gsnak3: I want a simple and easy system to change my centralWidget and listen to the child "changeStatus" to route it to statusBar()->showMessage(). I did it my way at the beginning (connection in children, bad), but someone (Objective-C dev) told me about the delegates but I wanted C++ dev advices.

                            Here is what I did:

                            I've created my own "AbstractWidget" which has a pure virtual slot (nextWidgetAction()), which what the children have to call when they've done their job (Database connection for example).

                            "nextWidgetAction()" must actually create a new widget, which is the next widget the parent have to show in its centralWidget, and emit the signal "widgetJobFinished(AbstractWidget *newWidget)".

                            The parent is listening to widgetJobFinished() and call setCentralWidget with the parameter.

                            I've overloaded "setCentralWidget()" in my MainWindow to take only "AbstractWidget *", to be able to pass it any of my subclassed widgets.

                            In "setCentralWidget(AbstractWidget *)", I delete "this->m_centralWidget;" (which is my subclassed current widget).

                            Then I call "QMainWindow::setCentralWidget(newWidget);" to set my new centralWidget, store it in my MainWindow and listen to the newWidget's slot "widgetJobFinished(AbstractWidget *)".

                            It's not really nice to do that way, but to combine a system where the MainWindow can't know in advance which "type" of widget it has to show when and change the statusBar() correctly, the best way for me was to initialize IN the children the following widget (for i.e.: "welcomeWidget" inits "databaseConnection" which inits "queryWidget") and obviously the widgets can't show backwards (the old are deleted) and there is no need.

                            What do you think about that ?

                            We all have started by asking questions. Then after some time, we can begin answering them.

                            1 Reply Last reply Reply Quote 0
                            • SGaist
                              SGaist Lifetime Qt Champion last edited by

                              Isn't that some sort of QWizard you are writing ?

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              1 Reply Last reply Reply Quote 0
                              • M
                                Max13 last edited by

                                [quote author="SGaist" date="1366014252"]Isn't that some sort of QWizard you are writing ?[/quote]
                                Hum... Now you mention it, yes it is :/
                                But I don't need the ability to go backward, but except that, it could be a QWizard.

                                We all have started by asking questions. Then after some time, we can begin answering them.

                                1 Reply Last reply Reply Quote 0
                                • B
                                  b1gsnak3 last edited by

                                  1st. For your setCentralWidget I would do it like:

                                  @
                                  if(this->centralWidget() != 0) delete this->centralWidget();
                                  @

                                  2nd. You could've used just one class, with an Enum of properties (which you set when you instantiate the properties) that would be your different types of action your widget needs to do and according to those properties create your widgets and call different methods (or use different constructors for each type of widget). And you would've had one big class instead of multiple ones.

                                  1 Reply Last reply Reply Quote 0
                                  • M
                                    Max13 last edited by

                                    1. I think you can delete multiple times "NULL" but not an already deleted pointer. So checking if NULL won't guaranty me to delete an allocated space. Anyway, I have the habits to do like this EVERY TIME, to be safe, and to be able to delete it again and again if I try to delete a pointer passed by a parent for example:
                                      @ptr = new ...;
                                      delete ptr;
                                      ptr = NULL;@

                                    2. I could do like that, but I wanted my MainWindow completely unaware of the children, as a QMainWindow would. So it means, every time I want a new widget, I just have to create it in the previous child and pass it in the SIGNAL. Then I don't need to modify the MainWindow class, and I will have multiple children because anyway, these children will have their own job and so their own class. Isn't it ?

                                    We all have started by asking questions. Then after some time, we can begin answering them.

                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post