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. Show a QMessage box from the context of a function defined outside mainwindow.cpp
Qt 6.11 is out! See what's new in the release blog

Show a QMessage box from the context of a function defined outside mainwindow.cpp

Scheduled Pinned Locked Moved Solved General and Desktop
16 Posts 8 Posters 1.4k Views 3 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.
  • L Offline
    L Offline
    lukester88
    wrote last edited by
    #1

    Hello,

    I am working on a QT project that solves some equations iteratively, based on user input parameters in the GUI. I have 5 separate equations which require an iterative solution, and the equations are called using void equationName(); The way I have the ui set up right now is the user presses a button, and the 5 functions are run to iteratively solve the equations. The solution may not be reached within the specified number of iterations, so I want the program to show an error or warning message box to inform the user that the function was not able to converge on a solution. The challenge is, these functions are NOT defined in the mainwindow.cpp file, they are defined externally. A major theme I have in my code is keeping UI code and solver code completely separate, and I would like to continue that trend with this specific task.

    My question is - how can I make these functions show a message box to the user when the function is executed? For example, when the user presses the button, and the function executes, if it exceeds the maximum number of iterations, the function should finish executing, and then a message box should show up warning the user that the function failed to converge. Furthermore, how can I implement such a thing without using UI code in the file with the solver source code?

    Below I have included an example of one of the iterative solvers I am referring to. The thermo and kinetic things are structs that contain a list of associated variables, and the variables are updated through the iterative solver.

    void iterativeSolver_T1_fromMachNumber() {

    double maxIterations = 100;
    double maxTolerance = 1e-4;
    
    double T01 = thermo.T01;
    double Mc1_abs = kinetic.Mc1_abs;
    
    double T1_guess = thermo.T01;
    double T1_new;
    double gamma1;
    
    for (int i = 0; i < maxIterations; i++) {
    
        // Use the T1 guess to recalculate T1 and check for convergence
        gamma1 = gammaData.linterp(T1_guess);
    
        double pow1 = std::pow(Mc1_abs, 2);
        double powArg = 1 + (gamma1 - 1) / 2 * pow1;
        double pow2 = std::pow(powArg, -1);
    
        T1_new = T01 * pow2;
        thermo.T1 = T1_new;
    
        if (std::abs(T1_new - T1_guess) < maxTolerance) {
            break;
        }
    
        T1_guess = T1_new;
    
        if (i == maxIterations) {
            qDebug() << "Solver did not converge within specified iterations.";
            break;
        }
    }
    

    }

    JonBJ JKSHJ 2 Replies Last reply
    0
    • JoeCFDJ Offline
      JoeCFDJ Offline
      JoeCFD
      wrote last edited by
      #2
      This post is deleted!
      1 Reply Last reply
      0
      • L Offline
        L Offline
        lukester88
        wrote last edited by
        #3

        Thank you for the reply! Do you happen to have a brief example of how this would be accomplished?

        JoeCFDJ 1 Reply Last reply
        0
        • L lukester88

          Hello,

          I am working on a QT project that solves some equations iteratively, based on user input parameters in the GUI. I have 5 separate equations which require an iterative solution, and the equations are called using void equationName(); The way I have the ui set up right now is the user presses a button, and the 5 functions are run to iteratively solve the equations. The solution may not be reached within the specified number of iterations, so I want the program to show an error or warning message box to inform the user that the function was not able to converge on a solution. The challenge is, these functions are NOT defined in the mainwindow.cpp file, they are defined externally. A major theme I have in my code is keeping UI code and solver code completely separate, and I would like to continue that trend with this specific task.

          My question is - how can I make these functions show a message box to the user when the function is executed? For example, when the user presses the button, and the function executes, if it exceeds the maximum number of iterations, the function should finish executing, and then a message box should show up warning the user that the function failed to converge. Furthermore, how can I implement such a thing without using UI code in the file with the solver source code?

          Below I have included an example of one of the iterative solvers I am referring to. The thermo and kinetic things are structs that contain a list of associated variables, and the variables are updated through the iterative solver.

          void iterativeSolver_T1_fromMachNumber() {

          double maxIterations = 100;
          double maxTolerance = 1e-4;
          
          double T01 = thermo.T01;
          double Mc1_abs = kinetic.Mc1_abs;
          
          double T1_guess = thermo.T01;
          double T1_new;
          double gamma1;
          
          for (int i = 0; i < maxIterations; i++) {
          
              // Use the T1 guess to recalculate T1 and check for convergence
              gamma1 = gammaData.linterp(T1_guess);
          
              double pow1 = std::pow(Mc1_abs, 2);
              double powArg = 1 + (gamma1 - 1) / 2 * pow1;
              double pow2 = std::pow(powArg, -1);
          
              T1_new = T01 * pow2;
              thermo.T1 = T1_new;
          
              if (std::abs(T1_new - T1_guess) < maxTolerance) {
                  break;
              }
          
              T1_guess = T1_new;
          
              if (i == maxIterations) {
                  qDebug() << "Solver did not converge within specified iterations.";
                  break;
              }
          }
          

          }

          JonBJ Online
          JonBJ Online
          JonB
          wrote last edited by
          #4

          @lukester88
          You can use quite a number of ways. @JoeCFD's suggestion of a socket is fine, though I don't know why he has recommended that in particular. I would say the canonical Qt way is just to emit a signal. You place a slot on that somewhere in the UI to display a message box for that. Unlike a socket which I believe would require the UI to connect the other end of the socket, signal does not demand other end has a slot. And is possibly a bit less code.

          Whether you use socket, signal or similar, your solver module may not need knowledge of UI code but will still need to include Qt headers to call it. If you want to avoid that, to keep your solver non-Qt-aware, you can use a function pointer or class with virtual method to do the socketing/signalling from the solver side. Since there are static methods of QMessageBox (https://doc.qt.io/qt-6/qmessagebox.html#static-public-members) which display a dialog and do not demand any knowledge of the UI if you go for application modal you can even use one of those in the function to display it directly without sockets/signals etc. if you want the simplest, dirty solution. Or even Qt's logging/qInstallMessageHandler(QtMessageHandler handler) where you could cause your qDebug() or similar calls to be shown to the user in a message box. So many ways! :)

          JoeCFDJ 1 Reply Last reply
          0
          • S Offline
            S Offline
            SimonSchroeder
            wrote last edited by
            #5

            In my projects, if I want to separate these kind of things I tend to use callback functions (basically @JonB's function pointer suggestion). Callback functions might have specific callback data associated with it. This would help with your specific version including a main window.

            This might look like the following:

            typedef void (*solver_warning_callback_t)(const std::string &message, int current_iteration, int max_iterations, void *callback_data);
            ...
            solver_warning_callback_t solver_warning_callback = nullptr;
            void *solver_warning_callback_data = nullptr;
            

            From your main window you would have to register the callback and set the callback data:

            solver_warning_callback = [](const std::string &message, int current_iteration, int max_iterations, void *callback_data)
            {
                MainWindow *mw = reinterpret_cast<MainWindow*>(callback_data);
                QMessageBox::warning(mw, tr("Solver warning"), QString::fromStdString(message));
            };
            solver_warning_callback_data = this; // setting callback data from a member function within MainWindow
            

            Then you can call it from your solver function:

            solver_warning_callback("Solver did not converge withing specified iterations", i, maxIterations, callback_data);
            

            Notice that I included the iterations and max iterations in this example to show you would handle additional parameters (but they don't have to be used by the callback itself). Assuming you might want to have no Qt inside your solver I also used std::string instead of QString. Usually, the callback data is the last parameter to a callback function. It is always a void* pointer to allow for any data. This can safely be cast back and forth. If you want to use more than just a single parameter as the callback data you just put it into a struct. However, you have to make sure that the struct variable lives long enough! If you don't have any callback data, just leave it as nullptr. The callback data does not have to be used by the callback function, but usually sooner or later you'll need it. So, any callback function should have that callback data as a parameter. Using a lambda function that captures the data instead would not work. The capture list needs to be empty (if you are using a lambda; regular functions also work!).

            1 Reply Last reply
            0
            • Christian EhrlicherC Offline
              Christian EhrlicherC Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote last edited by
              #6

              One problem with a simple callback will arise when you run the solver in a different thread. Then you have to add a context switch eg. with a QTimer single shot or a signal to switch to the main thread.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              SGaistS 1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                One problem with a simple callback will arise when you run the solver in a different thread. Then you have to add a context switch eg. with a QTimer single shot or a signal to switch to the main thread.

                SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote last edited by
                #7

                @Christian-Ehrlicher said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

                One problem with a simple callback will arise when you run the solver in a different thread. Then you have to add a context switch eg. with a QTimer single shot or a signal to switch to the main thread.

                Beside the suggestion of @Christian-Ehrlicher, one can also make use of invokeMethod so everything GUI can properly stay in the place of concern rather than having unrelated code handling GUI related stuff.

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

                S 1 Reply Last reply
                1
                • SGaistS SGaist

                  @Christian-Ehrlicher said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

                  One problem with a simple callback will arise when you run the solver in a different thread. Then you have to add a context switch eg. with a QTimer single shot or a signal to switch to the main thread.

                  Beside the suggestion of @Christian-Ehrlicher, one can also make use of invokeMethod so everything GUI can properly stay in the place of concern rather than having unrelated code handling GUI related stuff.

                  S Offline
                  S Offline
                  SimonSchroeder
                  wrote last edited by
                  #8

                  @SGaist Yes, invokeMethod() is also my general solution if I'm multithreaded. As a second option, the callback could emit a signal and the connected slot can show the dialog in the GUI thread because signal/slot connections properly cross thread boundaries (it'll be automatically a queued connection). Sure, you could emit a signal directly from the solver (as has been suggested before). But a callback would allow you to not have anything Qt-related in your solver.

                  SGaistS 1 Reply Last reply
                  0
                  • S SimonSchroeder

                    @SGaist Yes, invokeMethod() is also my general solution if I'm multithreaded. As a second option, the callback could emit a signal and the connected slot can show the dialog in the GUI thread because signal/slot connections properly cross thread boundaries (it'll be automatically a queued connection). Sure, you could emit a signal directly from the solver (as has been suggested before). But a callback would allow you to not have anything Qt-related in your solver.

                    SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote last edited by
                    #9

                    @SimonSchroeder I wasn't clear but I was thinking about using invokeMethod from the callback so indeed, the solver can be independent from Qt.

                    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
                    0
                    • JonBJ Online
                      JonBJ Online
                      JonB
                      wrote last edited by
                      #10

                      Never used invokeMethod(). Is it synchronous or asynchronous?

                      jsulmJ S 2 Replies Last reply
                      0
                      • JonBJ JonB

                        Never used invokeMethod(). Is it synchronous or asynchronous?

                        jsulmJ Offline
                        jsulmJ Offline
                        jsulm
                        Lifetime Qt Champion
                        wrote last edited by
                        #11

                        @JonB Depends how you call it, see https://doc.qt.io/archives/qt-5.15/qmetaobject.html#invokeMethod

                        https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        0
                        • JonBJ JonB

                          Never used invokeMethod(). Is it synchronous or asynchronous?

                          S Offline
                          S Offline
                          SimonSchroeder
                          wrote last edited by
                          #12

                          @JonB said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

                          Never used invokeMethod(). Is it synchronous or asynchronous?

                          invokeMethod() basically lets you post calls to slots in the event queue. That's at least how I am using it. I makes it easier to not have a bunch of signals just so you connect them and call them once.

                          JonBJ 1 Reply Last reply
                          0
                          • JKSHJ JKSH forked this topic
                          • JonBJ JonB

                            @lukester88
                            You can use quite a number of ways. @JoeCFD's suggestion of a socket is fine, though I don't know why he has recommended that in particular. I would say the canonical Qt way is just to emit a signal. You place a slot on that somewhere in the UI to display a message box for that. Unlike a socket which I believe would require the UI to connect the other end of the socket, signal does not demand other end has a slot. And is possibly a bit less code.

                            Whether you use socket, signal or similar, your solver module may not need knowledge of UI code but will still need to include Qt headers to call it. If you want to avoid that, to keep your solver non-Qt-aware, you can use a function pointer or class with virtual method to do the socketing/signalling from the solver side. Since there are static methods of QMessageBox (https://doc.qt.io/qt-6/qmessagebox.html#static-public-members) which display a dialog and do not demand any knowledge of the UI if you go for application modal you can even use one of those in the function to display it directly without sockets/signals etc. if you want the simplest, dirty solution. Or even Qt's logging/qInstallMessageHandler(QtMessageHandler handler) where you could cause your qDebug() or similar calls to be shown to the user in a message box. So many ways! :)

                            JoeCFDJ Offline
                            JoeCFDJ Offline
                            JoeCFD
                            wrote last edited by
                            #13
                            This post is deleted!
                            1 Reply Last reply
                            0
                            • L lukester88

                              Thank you for the reply! Do you happen to have a brief example of how this would be accomplished?

                              JoeCFDJ Offline
                              JoeCFDJ Offline
                              JoeCFD
                              wrote last edited by JoeCFD
                              #14

                              @lukester88 sorry I thought you are running two different processes.

                              1 Reply Last reply
                              0
                              • L lukester88

                                Hello,

                                I am working on a QT project that solves some equations iteratively, based on user input parameters in the GUI. I have 5 separate equations which require an iterative solution, and the equations are called using void equationName(); The way I have the ui set up right now is the user presses a button, and the 5 functions are run to iteratively solve the equations. The solution may not be reached within the specified number of iterations, so I want the program to show an error or warning message box to inform the user that the function was not able to converge on a solution. The challenge is, these functions are NOT defined in the mainwindow.cpp file, they are defined externally. A major theme I have in my code is keeping UI code and solver code completely separate, and I would like to continue that trend with this specific task.

                                My question is - how can I make these functions show a message box to the user when the function is executed? For example, when the user presses the button, and the function executes, if it exceeds the maximum number of iterations, the function should finish executing, and then a message box should show up warning the user that the function failed to converge. Furthermore, how can I implement such a thing without using UI code in the file with the solver source code?

                                Below I have included an example of one of the iterative solvers I am referring to. The thermo and kinetic things are structs that contain a list of associated variables, and the variables are updated through the iterative solver.

                                void iterativeSolver_T1_fromMachNumber() {

                                double maxIterations = 100;
                                double maxTolerance = 1e-4;
                                
                                double T01 = thermo.T01;
                                double Mc1_abs = kinetic.Mc1_abs;
                                
                                double T1_guess = thermo.T01;
                                double T1_new;
                                double gamma1;
                                
                                for (int i = 0; i < maxIterations; i++) {
                                
                                    // Use the T1 guess to recalculate T1 and check for convergence
                                    gamma1 = gammaData.linterp(T1_guess);
                                
                                    double pow1 = std::pow(Mc1_abs, 2);
                                    double powArg = 1 + (gamma1 - 1) / 2 * pow1;
                                    double pow2 = std::pow(powArg, -1);
                                
                                    T1_new = T01 * pow2;
                                    thermo.T1 = T1_new;
                                
                                    if (std::abs(T1_new - T1_guess) < maxTolerance) {
                                        break;
                                    }
                                
                                    T1_guess = T1_new;
                                
                                    if (i == maxIterations) {
                                        qDebug() << "Solver did not converge within specified iterations.";
                                        break;
                                    }
                                }
                                

                                }

                                JKSHJ Offline
                                JKSHJ Offline
                                JKSH
                                Moderators
                                wrote last edited by JKSH
                                #15

                                @lukester88 said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

                                A major theme I have in my code is keeping UI code and solver code completely separate, and I would like to continue that trend with this specific task.

                                My question is - how can I make these functions show a message box to the user when the function is executed? For example, when the user presses the button, and the function executes, if it exceeds the maximum number of iterations, the function should finish executing, and then a message box should show up warning the user that the function failed to converge. Furthermore, how can I implement such a thing without using UI code in the file with the solver source code?

                                Make your solver return information about whether it converged on an answer or not:

                                struct SolverResult {
                                    double finalValue;
                                    bool converged;
                                };
                                

                                Then, do extra checks when processing the result.

                                If your result-processing code currently looks like this...

                                void MainWindow::onSolverFinished(double finalValue)
                                {
                                    this->doSomethingWith(finalValue);
                                }
                                

                                ...now you can do extra checks:

                                void MainWindow::onSolverFinished(const SolverResult &result)
                                {
                                    if (result.converged)
                                    {
                                        // Yay, we found a solution!
                                        this->doSomethingWith(result.finalValue);
                                    }
                                    else
                                    {
                                        QMessageBox::warning(this,
                                            "No solution found", 
                                            QStringLiteral("Failed to converge on a solution within %1 iterations").arg(m_maxIterations)
                                        );
                                    }
                                }
                                

                                Alternatively, you could adopt a convention like "Return NaN if it fails to converge", and show the QMessageBox inside if (qIsNan(finalValue))

                                Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                1 Reply Last reply
                                1
                                • L Offline
                                  L Offline
                                  lukester88
                                  wrote last edited by
                                  #16

                                  Thank you everyone for your answers to this, I ended up going with the callback function logic as it made the most sense for my implementation. The solvers contain their own packet of information about convergence, and then deliver that packet of information to a separate function that parses it into an error message and passes it to the mainwindow for display

                                  1 Reply Last reply
                                  0
                                  • L lukester88 has marked this topic as solved

                                  • Login

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