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.
-
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.
@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.
-
@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.
@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. -
@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.@SimonSchroeder I wasn't clear but I was thinking about using
invokeMethodfrom the callback so indeed, the solver can be independent from Qt. -
@JonB Depends how you call it, see https://doc.qt.io/archives/qt-5.15/qmetaobject.html#invokeMethod
-
@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. -
J JKSH forked this topic
-
@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 yourqDebug()or similar calls to be shown to the user in a message box. So many ways! :) -
Thank you for the reply! Do you happen to have a brief example of how this would be accomplished?
@lukester88 sorry I thought you are running two different processes.
-
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; } }}
@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)) -
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
-
L lukester88 has marked this topic as solved