The script on this page appears to have a problem
-
First I want to apologize for my bad English. I'm a Newbie and this is my first post. Be patient with me :)
I'm facing this issue when using some jQuery code into my hybrid application.
I found that this message is thrown whenever the script takes long time.
'Saint Google' points me to QWebPage::shouldInterruptJavaScript() and it seems that the way to override this message is reimplementing this slot.
I did it but now, the script behavior it's not the desired. It seems like the slot it's called and interrupts the script although I always return false. The more annoying issue is that if I try to debug my custom slot, it's never been called!!!I should point out that the applications is running in a special scenario. The main application creates a form with a QWebView widget embedded. Different DLLs are called and a pointer to this form it's passed so they can use the QWebView widget.
This is the original DLL code, where uiExt is the pointer to the form where the WebView is implemented.
Everything works fine except the annoying script's message :(
@
Html::Html(Ui::Form *uiExt)
{
ui=uiExt;ui->webView->load(QUrl("inf.html")); page=ui->webView->page(); frame=page->mainFrame(); connect( frame, SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()) );
}
@This is the modified code using my custom class:
@
Html::Html(Ui::Form *uiExt)
{
ui=uiExt;
mypage=new CustomPage(ui->webView);
ui->webView->load(QUrl("inf.html"));
frame=mypage->mainFrame();
connect( frame, SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()) );
}@
This is my reimplemented QWebPage to override the slot
CustomPage.h
@
#ifndef CUSTOMPAGE_H
#define CUSTOMPAGE_H#include <QWebPage>
#include <QWebView>class CustomPage : public QWebPage
{
Q_OBJECT
public:
CustomPage(QWebView *parent=0);signals:
public slots:
bool shouldInterruptJavaScript();};
#endif // CUSTOMPAGE_H
@CustomPage.cpp
@
#include "custompage.h"CustomPage::CustomPage(QWebView *parent) : QWebPage(parent)
{
parent->setPage(this);
}bool CustomPage::shouldInterruptJavaScript()
{
//return QWebPage::shouldInterruptJavaScript(); //original slot
return false; //to avoid the annoying message
}
@As I stated, using this approach, CustomPage::shouldInterruptJavaScript() it's never called although the script's behavior it's not normal.
What I'm missing?
Thx in advance.
-
I finally found the cause of the issue.
As I stated, this code belongs to a DLL. The main application (.exe) calls this DLL and pass it a pointer to the form where the QWebView is contained.The purpose of this method is to have a main Widget created in the main (exe) application and share the embedded QWebView Widget, so whenever a call to a DLL is performed, this pointer is passed thus allowing the DLL to access to the QWebView to show its own content.
Once the DLL is done, it returns back the control to the main application.The problem here is that I'm a newbie coming from VC++ and I probably inherit some bad manners. To my understand this code it's like a semi-modal dialog but I don't even create a dialog, I simply use the 'dialog' that the main application passes as a pointer. The DLL then perform their own actions and interacts with the user using the QWebView Widget.
In VC++ this is achieved using the DoEvents() function that must be called in the main loop.In my project, I used a main loop that runs the DLL's code until the user exits the application (DLL)
If I want to process the DLL's events, I need to place a QApplication::processEvents() so the loop looks like this:@ do
{
QApplication::processEvents();
ht->processHtml();
}while((ht->iAction==-1)||(ht->iAction==iMenu));
@ht is my object that contains all the code to process the event handler. processHtml contains some code for retrieving data (I'll change the way to do this) and the while declarative contains the conditions to end the loop.
Obviously this code is always performing multiple calls to processEvents but this way works like a charm in VC++. In Qt, this recurrent function call, takes more than 50% of the CPU usage and that's the reason why the script message error appears!!!!
However, this doesn't explain why my own ShouldInterruptJavaScript slot it's never called.I'm now considering to set up a timer to avoid this massive CPU usage.
Anyway I guess there are better approach to solve this issue.
I accept suggestions :) -
@this way works like a charm in VC++@
oh please, stop lying... clean endless loop eat 100% CPU everywhere...
And if you Develop with Qt(compiled with VS) in VS - YOU ARE using VC++. Qt is a set of libraries, framework(if you wish) and not a kind of compiler interpreter or something wild else...So, just use method that was found for a long long time ago: use Sleep(1) in endless loop if it eats to much CPU!
-
Yeap, you are absolutely right. I forgot to mention the Sleep which, of course, I use in VC++. Sorry, it's my fault. But it doesn't take 100% CPU, I guess it depends on the platform or microprocessor architecture but in modern computers it only takes about 50% (which confirms what happened to me)
In fact, in the last part of my post I mentioned some kind of solution using something similar to the Sleep() function: a timer. What is the best way to achieve this in Qt? I read something about QThread::msleep or QWaitCondition but I don't know if it's better build my own timer.
-
I'm just using WINAPI Sleep(mseconds) on Win platforms and usleep() on *nix... have never had problems with them...
-
And something native in Qt? Is there a Sleep() function in Qt?
As I can see there are some tricks like those I mentioned before or even the QTest:qWait() function.
Maybe QThreat is the best way but in such case I need to reimplement the function because it's static protected. -
Here is the QTest:qSleep source:
@void QTest::qSleep(int ms)
{
QTEST_ASSERT(ms > 0);#ifdef Q_OS_WIN
Sleep(uint(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}@bq. Sleeps for ms milliseconds, blocking execution of the
test. qSleep() will not do any event processing and leave your test
unresponsive. Network communication might time out while
sleeping. Use qWait() to do non-blocking sleeping.About qWait:
bq. Waits for ms milliseconds. While waiting, events will be processed and
your test will stay responsive to user interface events or network communication. -
Thx AcerExtensa.
In fact, while I'm posting, I'm modifying my code to include QTest:qWait().
This method includes events processor which is what I'm looking for. -
Well, it seems this issue is solved (thx AcerExtensa again)
I use the QTest:qWait() function and did the trick but instead of import QTest, I had to include <QtTest/QTest> and then include qtestlib in the project.Anyway this left unresolved why I can't reimplement ShouldInterruptJavaScript().
What's wrong with my custom QWebPage? -
bq. Warning: Because of binary compatibility constraints, this function is not virtual. If you want to provide your own implementation in a QWebPage subclass, reimplement the shouldInterruptJavaScript() slot in your subclass instead. QtWebKit will dynamically detect the slot and call it.
Your implementation is correct for Qt 4.8... which version are you using actually?
-
4.7.4. And if I create an object derived from CustomPage and set a degug point in ShouldInterr....., this slot it's never called. What is more susprising is the fact that using my custom class, the "The script on this page appears to have a problem" message it's never displayed but, instead, the script ceases to work normally.
-
I need to go for today.. will test this tomorrow...
-
Thx. I'll try to determine the cause of this strange behavior.
-
Hi, I've tested this function today and it does work properly... So, the problem is in your code somewhere...
Here is the test project: "WebPageTest.tar.gz":http://vip2006.net/WebPageTest.tar.gz
Just run it and click Test button... in about 20-30 second you will get function name printed in output...
-
Ok, I'll check it out and compare with my code.
Thanks again -
Well, I've tried out your code and... Obviously works fine :)
When I start your script, the custom "ShouldInterru..." slot is called after 10-15 seconds (as expected).
Surprisingly, when I get the script error message in my code (not always), is displayed after 1 or 2 seconds. In fact I though this was the normal behavior.In order to check if there were something I missed in my html code, I modified my code to call your html from my DLL and... the "ShouldInterrupt..." it's never called!!!!!!.
And what is most strange, neither with the original class or the custom one. The application simply freezes.This takes me to square one. There must be something I'm doing terrifyingly wrong in my code.
As I stated previously I'm calling a DLL and passing a pointer to the form which contains the QWebPage.To discard an issue in this call I'm gonna try to recreate the same issue in the EXE application and override the "ShouldInterr..." slot.
-
Today I've tried to reproduce again the problem using the code AcerExtensa sent me and it takes more than 1 minute to "ShouldInterruptJavaScript" to be called the first time. I don't know if this is a normal behavior (I'm debugging the code). After such time, the slot it's triggered every 15 seconds (as expected). Friday (when I tried this the very first time, the slot was called after just 15 seconds).
Anyway in my case, the problem I think it's a different one.
My project consists in a main application (EXE) and different DLLs. The EXE creates a window with a WebView Widget. This main application interacts with the user using this Widget so I must connect the javaScriptWindowObjectCleared signal with the populateJavaScriptWindowObject slot.@
connect(ui.webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()));
@Whenever a DLL is called, the main application pass it a pointer to the WebView so it can perform the same action thus allowing the interaction through the same WebView.
Before doing that I disconnect the signal:@
disconnect(ui.webView->page()->mainFrame());
@Probably this is where I screwed up. I guess I'm not disconnecting the signal properly and there are some abnormal behavior behind this. Maybe the Script error I get is not from the DLL's side but the EXE side. This could be the reason why my ShouldInterruptJavaScript slot is never called (in the DLL side).
With this in mind, I tried this at home:
@
disconnect(ui.webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()));
@
but the same occurs.Things seems to change when I tried this:
@ui.webView->page()->disconnect();@Unfortunately my HDD crashed and now I'm recovering the mess so I can't confirm the problem is solved.
-
Finally I discovered what was causing the issue.
The problem is the way I use QWebView. In my project I have a main application (exe) that creates a QWebView widget. In order to interact with it I connect javaScriptWindowObjectCleared with populateJavaScriptWindowObject@connect(ui.webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()));
@In the html side I call my slot using this way
@
a href=""onClick=" javaskript:setCommand('INF');MyEXE.submit()">ELEMENTOS</a>
@(Note: I deliberate misspelled the <a> & javascript tag in this post to avoid errors in the preview)
So whenever the user clicks in this option my function MyExe.submit() is called in the EXE side.
This function calls a DLL and passes a pointer to the QWebView but before doing that I disconnect the signal in the EXE@
void MyEXE::submit()
{
...
QLibrary myLib("C:\Users\mahg\Documents\Qt\DLL\debug\DLL_Test2.dll");
typedef int (MyDLL)(Ui::Form, int);
MyDLL myDLL = (MyDLL) myLib.resolve("Dll");
if (myDLL)
{
...
disconnect(ui.webView->page()->mainFrame(),0,0,0);
int i=myDLL(&ui);
...
}
...
}
@Note: the original code I wrote to disconnect was:
@
disconnect(ui.webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()));
@Then, the DLL connects the signal javaScriptWindowObjectCleared with its own populateJavaScriptWindowObject and interacts with the user through the QWebView.
So far everything worked fine but there is a problem with the ShouldInterruptJavaScript. This function is triggered if the JavaScript code takes long time, but I discovered that the trigger doesn't occurs in the DLL but in the EXE.
This only occurs if I call the DLL inside the function MyEXE::submit(). If I call it outside this function everything works fine.
I guess Qt can't disconnect theses slots if we are still processing some code inside the slot called from the htmlIs this a normal behavior?
I can override the ShouldInterruptJavaScript in the main (EXE) code but this is not fair for me.
If there is no workaround for this I could try to call the DLL outside the MyEXE::submit()