Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Communicating between Widgets without parent casting
Forum Updated to NodeBB v4.3 + New Features

Communicating between Widgets without parent casting

Scheduled Pinned Locked Moved General and Desktop
23 Posts 3 Posters 11.3k Views 1 Watching
  • 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.
  • A Offline
    A Offline
    andre
    wrote on last edited by
    #10

    No, I think you did not understand whatever you read about volatile. For the work you do with C++, you don't need it either.

    The volatile keyword has a very specific use for the optimization that compilers do on your code in the context of multi threading or working with IO registers. It basically tells the compiler that the memory address the variable is pointing at may get changed by something outside of the current process (or thread), and that the compiler therefore cannot make assumptions about it keeping a certain value.

    For instance:
    @
    int someValue(2);
    volatile int someVolatileValue(42);

    //some code that does not use someValue or someVolatileValue

    if (1 == someValue) {
    // any code here (and the if branch itself) will be optimized out by any half-decent compiler
    }
    if (1 == someVolatileValue) {
    // this code will not be optimized out!
    }
    @

    1 Reply Last reply
    0
    • T Offline
      T Offline
      TheDestroyer
      wrote on last edited by
      #11

      Thank you for your reply.

      That's exactly what I had understood about volatile variables. Let me expain why I think volatile could make this work, and please correct me if I'm wrong:

      What I saw in my program, is that a change in an object cannot be seen by other objects (but only by the debugger), unless some call like signals and slots is done.
      So, when I use volatile, I expect the object to be always taken/modified in the memory, and not in the CPU registers; which means (since memory management in C++ is low-level) that if I use a widget to change some value in the memory, which is under a volatile variable (and which I can see that it's changed in the debugger), I will be able to read this memory address with its new changed value through the other widgets, since the volatile keyword blocked the possibility for it to lie in the CPU registers.

      Does this argument make any sense?

      1 Reply Last reply
      0
      • D Offline
        D Offline
        DerManu
        wrote on last edited by
        #12

        -I strongly disagree with Andre.-
        Signals/Slots is not appropriate for connecting your controlWidget with your rendering mechanism as a replacement for your settings object, for many reasons. First of all, it lacks state, which might become necessary some day (think of queuing settings-changes or saving/loading different presets). It is very cumbersome and error-prone creating all the signals/slots and managing the connections, especially when your simulation grows to more objects that need to see or even interact with the settings. You'd basically have all your setting variables scattered all over the place, connected wildly with signals/slots. A central settings object is the correct way to go. Since I work on numerical physics myself, I can say that the observer pattern is well suited for the task. It's especially easy to extend the simulation to multiple cores (which you'll surely want), even in non-shared memory architectures, by extending the capabilities of the settings object.

        About your problem: Let's make sure we're talking about the same thing here. Andre suspects you expect the change of the pointed-to variable to automatically invoke a method in the rendering class. As he already pointed out, this is not the case.
        I'm not sure you're actually saying that. Your rendering class surely does something continously, i.e. render a frame via a QTimer timeout-slot. In this slot, you check the current settings state and render accordingly. In that setup, you indeed should see the effects of the variable change, even if it was made somewhere outside the rendering class, provided you actually transfer the settings pointer and didn't copy the settings object by value accidentally.
        From this point on we can only speculate, because we don't see more code of yours. You could start by turning "SettingsPasser &settings" in the rendering class ctor to "SettingsPasser *settings" in order to prevent flipping back and forth between pointer and reference semantics - maybe you accidentally invoke a copyconstructor/assignment operator there.
        To rule this out completely, you may temporarily add this to the private section of your settings object:
        Q_DISABLE_COPY(SettingsPasser)
        This will cause a compile time error when a SettingsPasser object is copied (makes copyctor and assignment private).

        If you indeed want notifications to be sent to the objects dependant on the settings, this is the place where signals/slots are appropriate, but between the settings object and the simulation/rendering objects only. Possibly even reduced to one signal "settingsChanged" and one slot "updateSettings". So when your controller changes the settings, it may call updateSettings which in turn emits settingsChanged. All objects interested in settingschanges can listen to this signal and do whatever they do with new settings. Of course you can inflate this all the way to setter-slots for every single setting and signals for every single setting. Whether this is necessary depends on your needs and the complexity of the final application.

        Note: If you're aiming for HPC, i.e. heavy multithreading, try to avoid signals/slots during the simulation at all costs. In the setup phase where settings are loaded/evaluated/forked, signals/slots are fine.

        1 Reply Last reply
        0
        • D Offline
          D Offline
          DerManu
          wrote on last edited by
          #13

          I see you've just created a follow-up post on the volatile issue:
          Volatile is only interesting when the variable value in memory can change externally. Externally means here, by another process or thread, not just by some other object in the same thread, as probably in your case.
          Whether volatile might have anything to do with your problem can be answered easily: Do you change the settings object in a different thread than read from the object?

          I, too, don't think volatile plays a role here, especially if the phenomenon of "not changing setting variable" happens consistently across changes in the code and recompiles. If it was volatile, I'd expect the settings change to have effect most of the time, only sometimes not (in the seldom events where settings writing and reading happen simultaneously).

          1 Reply Last reply
          0
          • T Offline
            T Offline
            TheDestroyer
            wrote on last edited by
            #14

            [quote author="DerManu" date="1336483777"]I strongly disagree with Andre.
            Signals/Slots is not appropriate for connecting your controlWidget with your rendering mechanism as a replacement for your settings object, for many reasons. First of all, it lacks state, which might become necessary some day (think of queuing settings-changes or saving/loading different presets). It is very cumbersome and error-prone creating all the signals/slots and managing the connections, especially when your simulation grows to more objects that need to see or even interact with the settings. You'd basically have all your setting variables scattered all over the place, connected wildly with signals/slots. A central settings object is the correct way to go. Since I work on numerical physics myself, I can say that the observer pattern is well suited for the task. It's especially easy to extend the simulation to multiple cores (which you'll surely want), even in non-shared memory architectures, by extending the capabilities of the settings object.

            About your problem: Let's make sure we're talking about the same thing here. Andre suspects you expect the change of the pointed-to variable to automatically invoke a method in the rendering class. As he already pointed out, this is not the case.
            I'm not sure you're actually saying that. Your rendering class surely does something continously, i.e. render a frame via a QTimer timeout-slot. In this slot, you check the current settings state and render accordingly. In that setup, you indeed should see the effects of the variable change, even if it was made somewhere outside the rendering class, provided you actually transfer the settings pointer and didn't copy the settings object by value accidentally.
            From this point on we can only speculate, because we don't see more code of yours. You could start by turning "SettingsPasser &settings" in the rendering class ctor to "SettingsPasser *settings" in order to prevent flipping back and forth between pointer and reference semantics - maybe you accidentally invoke a copyconstructor/assignment operator there.
            To rule this out completely, you may temporarily add this to the private section of your settings object:
            Q_DISABLE_COPY(SettingsPasser)
            This will cause a compile time error when a SettingsPasser object is copied (makes copyctor and assignment private).

            If you indeed want notifications to be sent to the objects dependant on the settings, this is the place where signals/slots are appropriate, but between the settings object and the simulation/rendering objects only. Possibly even reduced to one signal "settingsChanged" and one slot "updateSettings". So when your controller changes the settings, it may call updateSettings which in turn emits settingsChanged. All objects interested in settingschanges can listen to this signal and do whatever they do with new settings. Of course you can inflate this all the way to setter-slots for every single setting and signals for every single setting. Whether this is necessary depends on your needs and the complexity of the final application.

            Note: If you're aiming for HPC, i.e. heavy multithreading, try to avoid signals/slots during the simulation at all costs. In the setup phase where settings are loaded/evaluated/forked, signals/slots are fine.[/quote]

            Thank you for your reply.

            Your last suggestion is exactly what I do right now. I have an update function for each widget, and when I pass a SettingsPasser object to it, it updates its controls according to the data in that object. But unfortunately the update function copies the new settings to the new widget, where every widget has a copy of the object. Whenever some setting changes in one Widget, a signal is sent to update the (relevant) settings in the other widgets.

            Actually, in my first try for the observer approach, I was seeing the variables getting changed by the debugger, but the program couldn't see it; that's why I was looking for an answer to this problem, and till now I can't understand why the debugger can see the change and not my widget. I'm thinking now of volatile variables, and I don't know if this is the right way to go. I tried converting everything to pointers where I used the new operator only once, to make sure that there are no other copies... and yet it didn't work.

            1 Reply Last reply
            0
            • D Offline
              D Offline
              DerManu
              wrote on last edited by
              #15

              [quote author="TheDestroyer" date="1336485177"]But unfortunately the update function copies the new settings to the new widget, where every widget has a copy of the object. Whenever some setting changes in one Widget, a signal is sent to update the (relevant) objects in the other widgets.[/quote]That's not ideal as it recreates the decentralized signal/slot network I was warning about earlier.

              [quote author="TheDestroyer" date="1336485177"]I was seeing the variables getting changed by the debugger, but the program couldn't see it[/quote]Well there's clearly a bug in your program (haha). What I mean is this is not expected behaviour when sharing pointers between different objects. Your approach of injecting a pointer to the one-and-only central settings object is sensible and should in my opinion be favored over the "every widget has its own settings copy" approach.
              About the bug, we can only speculate without code. If you like you could post the code that creates/stores the one-and-only settings object, the code that injects the settings object pointer to the other objects/widgets, and the code inside the widget that supposedly doesn't see the new settings values when it accesses its pointer to the one-and-only settings object.

              1 Reply Last reply
              0
              • A Offline
                A Offline
                andre
                wrote on last edited by
                #16

                [quote author="DerManu" date="1336483777"]I strongly disagree with Andre.
                Signals/Slots is not appropriate for connecting your controlWidget with your rendering mechanism as a replacement for your settings object, for many reasons. [/quote]
                I guess you missed that my very first suggestion was to look into using the Observer pattern...

                1 Reply Last reply
                0
                • T Offline
                  T Offline
                  TheDestroyer
                  wrote on last edited by
                  #17

                  Thanks for your reply.

                  The project is closed now and the program is done. With the wrong approach, yeah; but I would like to get the right answer for future reference.

                  Well, let me assure you, in my single copy pointer-injection approach, there was no mistakes at all. Trust me on that. I had only a single copy of the pointer and all widgets were reading from it, and yet it didn't work. I use this approach all the time in other applications. I use very complicated polymorphic classes and I always register pointers for automated update; it's not my first time. But it only made problems in Qt widgets. I tried every way to debug it, but no use. Something was preventing the variable to get updated in the widget.

                  1 Reply Last reply
                  0
                  • D Offline
                    D Offline
                    DerManu
                    wrote on last edited by
                    #18

                    [quote author="Andre" date="1336487338"]I guess you missed that my very first suggestion was to look into using the Observer pattern...[/quote]Oh, I interpreted your first and "second":https://qt-project.org/forums/viewreply/74740/ post as saying signal/slots were more appropriate than observer pattern for this situation, sorry. (I strongly agree with you, now ;)

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      DerManu
                      wrote on last edited by
                      #19

                      [quote author="TheDestroyer" date="1336487441"]Well, let me assure you, in my single copy pointer-injection approach, there was no mistakes at all. Trust me on that.[/quote]Okay. I guess you've witnessed a miracle then...um...hallelujah? ;)

                      1 Reply Last reply
                      0
                      • T Offline
                        T Offline
                        TheDestroyer
                        wrote on last edited by
                        #20

                        Well, if this can never happen unless there's a bug in my code, how do you explain Andre's response? I think he would've suggested there's a problem in my code if there really would be, don't you think?

                        1 Reply Last reply
                        0
                        • D Offline
                          D Offline
                          DerManu
                          wrote on last edited by
                          #21

                          [quote author="TheDestroyer" date="1336489463"]Well, if this can never happen unless there's a bug in my code, how do you explain Andre's response? I think he would've suggested there's a problem in my code if there really would be, don't you think?[/quote]
                          I think "this post of his":http://qt-project.org/forums/viewreply/74751/ implies that, but I guess he may explain what he thinks the source of the problem is in follow-up posts.

                          For me this is a question of probabilities. Either there's a tremendous bug with catastrophic effects in GCC (think about it, this problem doesn't occur in one of a million runs but consistently!) and nobody else has noticed it yet. Or there's a glitch in your code that you've just overlooked.
                          When I understand you correctly, you have used the pointer injected observer pattern in projects before, and it worked, right?

                          1 Reply Last reply
                          0
                          • T Offline
                            T Offline
                            TheDestroyer
                            wrote on last edited by
                            #22

                            The thing is that the way those GUI's work is different. That's why I could expect a different behaviour.

                            Yes, this approach works when I use it outside Qt. But with GUIs of Qt it won't work. No one knows how those meta files of the GUIs are managed..., and how they take information from other objects.

                            1 Reply Last reply
                            0
                            • D Offline
                              D Offline
                              DerManu
                              wrote on last edited by
                              #23

                              [quote author="TheDestroyer" date="1336490799"]The thing is that the way those GUI's work is different. That's why I could expect a different behaviour.[/quote]Not in such a fundamental way. A QWidget subclass still is a normal C++ class after the moc run, and when it has a pointer member you can do with it whatever you can also do in a non GUI class.
                              [quote author="TheDestroyer" date="1336490799"]No one knows how those meta files of the GUIs are managed..., and how they take information from other objects.[/quote]That's not right, what the meta object compiler does is relatively transparent when you look at the outputted moc_ files. No magic going on, it just adds some homebrew RTTI class and boilerplate code to every QObject class to make sigs/slots work. Specifically, it does not touch your settings pointer member.

                              I've tried it. Here are three files: main.pro, main.h and main.cpp:
                              main.pro:
                              @QT += core gui
                              TEMPLATE = app
                              HEADERS += main.h
                              SOURCES += main.cpp@
                              main.h:
                              @#ifndef HEADER_H
                              #define HEADER_H
                              #include <QtGui>

                              class Settings
                              {
                              public:
                              Settings():intValue(0), boolValue(false) {};
                              ~Settings() {}
                              int intValue;
                              bool boolValue;
                              };

                              class QTestWidget : public QWidget
                              {
                              Q_OBJECT
                              public:
                              explicit QTestWidget(QWidget *parent, Settings *settings);
                              protected:
                              virtual void paintEvent(QPaintEvent *event);
                              private:
                              Settings *mSettings;
                              QTimer mRenderTimer;
                              };

                              class MainWindow : public QMainWindow
                              {
                              Q_OBJECT
                              public:
                              explicit MainWindow(QWidget *parent = 0);
                              ~MainWindow() { delete mSettings; }
                              private slots:
                              void changeBoolSetting();
                              void changeIntSetting();
                              private:
                              Settings *mSettings;
                              };

                              #endif // HEADER_H@
                              and main.cpp:
                              @#include "main.h"

                              int main(int argc, char *argv[])
                              {
                              QApplication a(argc, argv);
                              MainWindow w;
                              w.show();
                              return a.exec();
                              }

                              // === Implementation of MainWindow, QTestWidget and Settings ===

                              MainWindow::MainWindow(QWidget *parent) :
                              QMainWindow(parent),
                              mSettings(new Settings)
                              {
                              setGeometry(50, 50, 100, 110);
                              QTestWidget *tw = new QTestWidget(this, mSettings);
                              QPushButton *b1 = new QPushButton(this);
                              QPushButton *b2 = new QPushButton(this);
                              tw->setGeometry(5, 5, 90, 70);
                              b1->setGeometry(25, 75, 25, 25);
                              b2->setGeometry(50, 75, 25, 25);
                              connect(b1, SIGNAL(clicked()), SLOT(changeBoolSetting()));
                              connect(b2, SIGNAL(clicked()), SLOT(changeIntSetting()));
                              }

                              void MainWindow::changeBoolSetting()
                              {
                              mSettings->boolValue = !mSettings->boolValue;
                              }

                              void MainWindow::changeIntSetting()
                              {
                              mSettings->intValue += 1;
                              }

                              QTestWidget::QTestWidget(QWidget *parent, Settings *settings) :
                              QWidget(parent),
                              mSettings(settings)
                              {
                              connect(&mRenderTimer, SIGNAL(timeout()), this, SLOT(update()));
                              mRenderTimer.start(500);
                              }

                              void QTestWidget::paintEvent(QPaintEvent *event)
                              {
                              Q_UNUSED(event)
                              QPainter painter(this);
                              painter.drawRect(rect().adjusted(0, 0, -1, -1));
                              painter.drawText(rect(),
                              Qt::AlignCenter,
                              QString::number(mSettings->intValue)+"\n"+
                              QString(mSettings->boolValue ? "true" : "false"));
                              painter.drawText(0, 13, QDateTime::currentDateTime().toString("hh:mm:ss:zzz"));
                              }@

                              run
                              qmake; make; ./main
                              and you'll see that it works as expected. Click the two buttons and see the QTestWidget update its display (in 500ms render-intervals), depending on it's injected Settings pointer.

                              1 Reply Last reply
                              0

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved