5

As per the documentation, loadFinished should be emitted only after all the page elements have finished loading. This should mean that it'll be called only once, however I've noticed that on some sites like youtube.com, it gets called twice ? Is there any other way to get around this bug or whats the most reliable way to detect page.load event ?

Here's the test code :

import sys
from PyQt4 import QtCore, QtGui, QtWebKit
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QApplication

def onDone(val):
    print "Done ...",val

def onStart():
    print "Started..."   

app = QApplication(sys.argv)
ui =  QtWebKit.QWebView()
ui.loadStarted.connect(onStart)
ui.loadFinished.connect(onDone)

ui.load(QUrl("http://www.youtube.com"))   
ui.showMaximized()
sys.exit(app.exec_())

The output:

Started...
Done ... True
Started...
Done ... True

Edit: There's an almost same question but its > 2yrs old and still unanswered.

Community
  • 1
  • 1
Code freak
  • 695
  • 2
  • 8
  • 19

2 Answers2

4

The load* signals are fired once for each frame that is loaded.

To capture only the first set of signals, connect to the corresponding signals of the main frame:

ui.page().mainFrame().loadStarted.connect(onStart)
ui.page().mainFrame().loadFinished.connect(onDone)

You can verify that other frames are being loaded by connecting to the frameCreated signal, which will fire once for each subsequent frame created after the main frame has loaded:

def onFrame(val):
    print 'Frame Created:', val.frameName()

ui.page().frameCreated.connect(onFrame)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Thanks for your ans. There's a doubt though (not at system so can't check myself) - does the QWebFrame persist beyond the lifetime of a rendered page ? I was under the impression that a frame is created for each frame of the site and should there fore be destroyed as soon as the next page is loaded. Pardon my lack of insight but i'm rather new to qt. – Code freak Jan 08 '12 at 22:45
  • 1
    @Codefreak. If you're asking whether you need to disconnect and reconnect the signals before loading a new page, the answer is: no. And also note that there is always a `mainFrame` object, regardless of whether the webpage has any `` or ` – ekhumoro Jan 09 '12 at 00:27
  • Yup thats precisely what i wanted to know. Thanks for the info. – Code freak Jan 09 '12 at 01:00
  • @ekhumoro i still don't understand, how to detect that all frames has been loaded, and only after that I'd take screenshot? – holms Mar 12 '14 at 04:22
  • @holms. This is a different issue to the one in the original question, and so you should ask a new question. – ekhumoro Mar 12 '14 at 05:49
  • @ekhumoro I don't see how it's different. I've also got a problem that loadFinished() calls a callback multiple times. And I also would like to detect when it's called last time, when whole page is loaded. In question above user asks how to avoid repeated execution of loadFinished() callback. – holms Mar 12 '14 at 05:52
  • @holms. Detecting when the _first_ frame has loaded is easy; detecting when the _last_ frame has loaded is _much_ harder, because you cannot know beforehand how many sub-frames there are (in theory, they could be nested infinitely deeply). – ekhumoro Mar 12 '14 at 06:10
  • @ekhumoro so there's basically no chance to check when whole page is loaded? =/ – holms Mar 13 '14 at 00:34
  • 1
    @holms. I wouldn't say _no_ chance. My hunch is that solving the _general_ case would be extremely difficult, but if you are willing to impose limits (such as on the depth of recursion), then a practical workaround should be possible. Off the top of my head, I don't know exactly how to do it, but surely some other people must have looked at this issue before. That's why I originally suggested you should ask a new question - there's a much better chance of getting an answer that way (i.e. more people will look at it). – ekhumoro Mar 13 '14 at 01:20
3

I am quite sure that happens when you modify the DOM like if it was a string. I am sure QWebKit runs JS code, so it could modify the DOM after it was onDone().

You should probably create an onDoneFirst method that only fires once.

Fabián Heredia Montiel
  • 1,687
  • 1
  • 16
  • 30
  • I'll wait 24hrs for a better answer. In case I don't get any then I'll accept yours as the answer. – Code freak Jan 08 '12 at 04:04
  • You can change the accepted answer if a better answer is posted later. If the answer was helpful you are encourage to upvote. Please refer to http://stackoverflow.com/privileges/vote-up and http://stackoverflow.com/privileges/create-posts – Fabián Heredia Montiel Jan 08 '12 at 04:26