QWebEngineView::renderProcessTerminated signal not working in QT C++ - c++

I am trying to connect a signal and slot in qt c++. What I want to achieve is that when the browser finishes rendering the page I want it to emit the signal and receive it in my slot. I initially wrote it for urlChanged() signal and it works fine but when I change it to renderProcessTerminated, it doesnt output the statements in the slot function.
The following is a snippet of the MyClass.h file where the slot is declared:
private slots:
void onRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode);
The following is a snippet from the constructor of MyClass.cpp file where the signal and slot are connected:
connect(ui->webEngineView, &QWebEngineView::renderProcessTerminated, this, &MyClass::onRenderProcessTerminated);
The following is the slot function onRenderProcessTerminated from MyClass.cpp (cout is a function I created to output messages in the web engine view and works fine):
void MyClass::onRenderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) {
cout("INSIDE RENDER PROCESS TERMINATED");
}

What I want to achieve is that when the browser finishes rendering the page I want it to emit the signal
RenderProcessTerminated doesn't mean "finished rendering the page". It means that the operating system's process that was used for rendering has terminated abnormally. It happens e.g. when the renderer crashes. Qt documentation clearly states:
This signal is emitted when the render process is terminated with a non-zero exit status. terminationStatus is the termination status of the process and exitCode is the status code with which the process terminated.
In English, the verb you'd be looking for is finished instead of terminated. The former implies the latter: when a process is finished, it has terminated. But the reverse is not necessary: a process may well terminate before it's finished with its task, e.g. if it crashes, or is terminated when the parent process exits, etc. But also: the RenderProcess doesn't mean "a task of rendering something". It literally means "the operating system process that performs the rendering". That process normally must stay alive for as long as you have any web views active.
The only signal I can see that approximates what you want is QWebEngineView::loadFinished(bool ok). Try it out.
Ohterwise, for finer notifications, you'll need to inject some javascript into the view, and interact with it. It may be more effort than it's worth.

Related

Emitting a Qt::signal from worker thread makes the UI update on main thread by default?

I am new to Qt. I have worker thread that is an std::thread. The worker thread function continuously fetches some some data in a loop. The size of the data is frequently updated on a Text element on a QML UI. I have a listener callback which is nothing but an std::function and it gets called from the thread's function. It sends me callbacks based on which I updated the Text element on QML. I update it using signal slot mechanism.
Following is the QML : Text element:
Text {
id: mytext
objectName: "mytextobject"
function slotUpdateData(someValue){
mytext = someValue
}
}
SignalUpdateData is connected with slotUpdateData which resides on QML side. Every time I get the data event callback from the std::thread, I emit SignalUpdateData which updates the QML Text element on UI.
void CallBackReceivedFromWorkerThread(float someValue) {
emit SignalUpdateData(someValue)
}
Following is how I have connected this C++ signal with the QML slot
QObject::connect(this, SIGNAL(SignalUpdateData(QVariant)), myTextItemQObject, SLOT(slotUpdateData(QVariant)));
And all of this works fine. No crashes, lock-ups, nothing.
As per my understanding, since the worker thread's function is triggering the callback, the execution control is on the worker thread when the callback is received. So when doing emit SignalUpdateData(someValue), we'er still on the worker thread. And as far as I know from my previous experience in android & java, we cannot update the UI from anywhere outside the main thread of the application.
So, How is this working ? Is emit SignalUpdateData(someValue) putting the call into the main UI thread's event loop ? Is Qt still making the UI change on main thread in spite of me calling for it from a worker thread ? If my approach is fine, then does it have performance implications ? What is the best recommendation to do this ?
I want to be very sure about this & not just lucky about making this to work. Should I use a Qt::Connection_enum as well for best approach ?
You're leveraging Qt the way it was meant to be! And you've run into it accidentally: that's a sign of a decent design - it "just works". Hooray for you, hooray for Qt :)
It's working because Qt has been designed specifically to make it work, and you're using the default automatic connection whose raison d'ĂȘtre is to help you out in this specific case. So you happen to be doing everything right: change nothing!
When you emit a signal, Qt acquires relevant source and destination object mutexes, and compares the receiving object's thread() to QThread::currentThread(). If they are identical, the slot/functor is called immediately: it happens in the body of the signal, so the slot is called before the signal returns. This is safe as the target object is used from its thread(), where it's safe.
If target->thread() != QThread::currentThread(), then a QMetaCallEvent is queued to the target object. The event contains the (equivalent of) slot method pointer and a copy of any parameters passed by the slot. The QObject::event implementation handles the event and executes the call. The target object thread's event loop is on the call stack, since its job is to deliver the queued events to the object.
The above is, in a nutshell the meaning of a Qt::AutoConnection. If you're using Qt::QueuedConnection, the 2nd case applies no matter what the threads are. If you're using Qt::DirectConnection, the 1st case applies no matter what.
My guess is that >95% of the uses of a non-automatic connection type in Qt-related questions on SO are unnecessary and stem from lack of understanding and resorting to what amounts to magic incantations.

Force Qt custom signal to be processed immediately?

I have a question about Qt and its signals/slots mechanism.
I have created a custom widget and in that I have created a custom SIGNAL (ShowMessage). This signal is connected to a SLOT, which displays the message (along with the specified timeout) in my main window's status bar.
Now, I have an operation in my class that takes a long time to execute, and it's blocking the UI. I was hoping to emit my signal before starting the operation and when it's finished, emit it again to update the status bar; something like this:
emit ShowMessage(message, timeout);
// Do the long operation
emit ShowMessage(newMessage, timeout);
But my problem is that it seems that Qt waits until the whole operation is finished, and only updates the status bar with newMessage.
Is there a way to somehow "force" immediate processing of my signal, because if I want to resort to threads, then my life will get much more complicated!
Is there a way to somehow "force" immediate processing of my signal
Yes, there is. :-).
After you show your first message, call QCoreApplication::processEvents(). This forces all pending events to be processed at the point of call. For example,
emit ShowMessage(message, timeout);
QCoreApplication::processEvents();
// Do the long operation
emit ShowMessage(newMessage, timeout);

Qt/C++ how to wait a slot when signal emitted

I have developed an app in Qt/C++, I have used signal/slot mechanism to interact between 2 threads. the first thread run the UI/TreeWidget and the second one run the framework
I got an issue on one action.
In the UI side, before starting my action, I'm connect signal/slot between UI and framework such as below in the treewidget.cpp
connect(&m_Framework, &Framework::RequestIfNameExist, this, &TreeWidget::RequestIfNameExist);
connect(this, &TreeWidget::SendAnswerIfNameExist, &m_Framework, &Framework::NotifIfNameExist);
The framework, start and send the RequestIfNameExist:
emit RequestIfNameExist(tmpname, item, fileInfo.isDir());
while(WaitingResponse == false){
usleep(200);
}
I have added a loop because I need to wait the feedback. Strange things is that in the treewidget.cpp, I never enter in
void TreeWidget::RequestIfNameExist(QString name, TreeWidgetItem *parent, bool isFolder) {
#ifdef PULS_LOG
QLOG_INFO() << "[TreeWidget] [RequestIfNameExist] ";
#endif
emit SendAnswerIfNameExist(isNameExist(name, parent), isFolder);
}
I never access to RequestIfNameExist in the TreeWidget but the signal is emitted.
I have also put a while loop in the framework to wait the feedback from TreeWidget
void Framework::NotifIfNameExist(QTreeWidgetItem *item, bool isFolder){
if(item != NULL)
item->isFolder = isFolder;
WaitingResponse = true;
}
Any idea why the signal emitted by framework never arrived on the treewidget ? is it coming from the while ??
Is there a way to not use while such as a "wait event" + timeout
Thanks
My first thought is that having either thread block until an operation in the other thread completes is a poor design -- it partially defeats the purpose of having multiple threads, which is to allow multiple operations to run in parallel. It's also liable to result in deadlocks if you're not careful (e.g. if both threads decide to emit-and-wait at approximately the same time!)
A better design would have the initiating method do the emit RequestIfNameExit and then return immediately, so that the initiating thread's event loop can continue running as usual during the operation. Then, when the other thread has done its work, it responds by emitting its own response-signal, causing the appropriate/connected slot-method in the first thread to be called, at which point the results are handled back in the first thread.
That said, if you insist on wanting to block the execution of the signal-emitting thread inside a method, until the other thread has finished executing the associated slot-method, you can get that behavior by setting the signal/slot connection's type to be Qt::BlockingQueuedConnection (the connection type can be specified via an optional extra argument to connect()). If you do that, then you emit call won't return until the slot-method (in the other thread) has finished executing. Given that, you can get the results from the other thread by passing a pointer to a data object as one of the arguments in the signal/slot method signature, and having the other thread populate that data object as necessary. When the emit returns you can just examine the contents of that data object to see the results.

How can I find the source of a Qt5 signal during gdb session?

I have set a break-point on a slot method and started up gdb to debug my Qt5 application. I would like to know from where in the code this slot gets called from (via the Qt5 signal system).
My naive approach ends in suspension of the program at the break-point, but the stack-trace is all Qt5 internals with no clue as to which part of the program actually sent the signal to this slot (or weather it was a queued or direct invocation:
Is this at all possible? How?
Thanks!
UPDATED
The only time you won't see the signal caller in the stack backtrace is when the connection is queued.
For direct connections you should see something like this:
0 Receiver::baz() <-- slot function that received the signal
1 Receiver::qt_static_metacall()
2 QMetaObject::activate()
3 Sender::bar() <-- function with the name of the signal
4 Sender::foo() <-- function that called emit
5 QWidget::event()
...
For queued connections, the situation is more complicated. But you can add the following to your slot:
QString __sender__ = sender()->metaObject()->className();
This will give you class name of the object, which had sent the signal. You can make it into a macro and sprinkle in your code.
Alternatively, if you have multiple objects of the same class and you need to know which one had sent the signal, you can use the sender() function and compare object address, etc.
Guessing that the signal and slot are connected through a Qt::QueuedConnection, I usually put a breakpoint in every emit of a signal connected to that slot in that case, if there aren't too many of them.
If you otherwise temporarily make it a Qt::DirectConnection (or Qt::BlockingQueuedConnection if across threads) you should be able to see the emission in the stack trace of the emitter thread, waiting for the slot to complete.

How to put wait condition in Signal-Slot?

I am doing one web related project. Recently I hit on this situation. This is just a stub
Class My_Class
{
public:
My_Class();
void start();
public slots():
void after_Load_Function();
}
My_Class::My_Class()
{
//Some initializations
connect(WebPage,SIGNAL(finished()),this,SLOTS(after_Load_Function()));
}
void My_Class::start()
{
WebPage->load();
}
void My_Class::after_Load_Function()
{
//Do something with the finished WebPage
}
int main(int argc,char * argv[])
{
//Some Qt things
My_Class a;
a.start();
}
"WebPage" emits the signal "finished" when it loaded fully.
Now the problem is before the "webPage" got loaded the "start" is returning. Thereby the control reaches the "main". So, now the control should return from "start" only after "after_Load_Function" finishes it's job. Thereby I want the below sequence,
main creates the My_Class object A.
main calls "start" from A.
start calls load from "WebPage" and it waits untill the "WebPage" emits "finished",
and that emit in turn calls the "after_Load_Function", and "after_Load_Function"
finishes it's job.
now, the "start" returns
main returns
But, I don't know how to make this kind of wait condition. How can I go about it?
You can do this by running a local event loop, letting the components process network income and load the page. When they emit the signal, you execute a slot on the event loop to quit it.
void My_Class::start()
{
QEventLoop qel;
QObject::connect(WebPage, SIGNAL(finished()), &qel, SLOT(quit()));
WebPage->load();
qel.exec();
}
I've been using this before and it works fine. I don't advice to use this too often though, because it will process events, including those that the caller of start might not be expecting to be processed during the call to start, so you need to document this to its callers. You can prevent the processing of some events by passing certain flags to QEventLoop::exec, like preventing to process user interface events.
You should never wait in UI code. You need to break your "main" function into pieces so the later part can be executed separately.
Use condition variables thats what they are used for. You can make threads wait on a condition variable and proceed when notified.
The WebPage->load() method is asynchronous, meaning that it runs immediately, not when the loading is complete. The operation runs in the background while you go to do other things.
This is considered a good thing, as it enables your app to be more responsive and get more done. For example, if your app has a GUI, you could update the GUI with some sort of animation that indicates that the web page is being retrieved.
If you prefer a model in which the application blocks until the page is fully loaded, then consider making this change:
void My_Class::start()
{
WebPage->load();
while (!WebPage->isLoaded())
Sleep(1);
after_Load_Function();
}
Notes:
the Sleep function will work on Windows. If you are on a Unix OS you can use usleep.
since this function will effectively block until the web page is loaded, there is no reason to use the signal from the web page object, you can just simply call your handler after the wait completes, as this will make your handler run in the same thread.
doing this is really bad practice. You may get away with it if your program is command line and has no GUI and/or event loop, but you should consider a better design for your app where the loading of web pages does not block the whole app.